Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 2 commits
  • 3 files changed
  • 0 commit comments
  • 1 contributor
Commits on Feb 13, 2014
@chischaschos chischaschos Refactor into smaller methods, and allow custom strategies to define
file_name and captured-data stored-structure
bc33045
@chischaschos chischaschos With this commits api docs keeps the same features, but it adds the
chance to customize the way you save to files the api docs
bafc1f0
Showing with 105 additions and 61 deletions.
  1. +41 −3 lib/api_docs.rb
  2. +42 −36 lib/api_docs/test_helper.rb
  3. +22 −22 test/test_helper_test.rb
View
44 lib/api_docs.rb
@@ -6,15 +6,53 @@
module ApiDocs
class << self
-
+
+ attr_accessor :store_data_strategy, :file_name_strategy, :docs,
+ :automatic_write
+
def configure
yield configuration
end
-
+
+ def automatic_write?
+ self.automatic_write.nil? ? true : self.automatic_write
+ end
+
def configuration
@configuration ||= Configuration.new
end
alias :config :configuration
-
+
+ def store_data(captured_data)
+ strategy = store_data_strategy || method(:default_store_data)
+ strategy.call(docs, captured_data, default_key(captured_data))
+ end
+
+ def docs
+ @docs ||= Hash.new
+ end
+
+ private
+
+ def default_store_data(api_docs, captured_data, key)
+ api_docs[captured_data['action']] ||= { }
+ api_docs[captured_data['action']][key] = captured_data
+ end
+
+ # Marking response as an unique
+ def default_key(captured_data)
+ key = ""
+ key << captured_data['method']
+ key << captured_data['path']
+ key << captured_data['meta'].to_s
+ key << captured_data['params'].to_s
+ key << captured_data['status'].to_s
+ 'ID-' + Digest::MD5.hexdigest(key)
+ end
+
+ def default_file_name(captured_data)
+ "#{captured_data['controller'].gsub('/', ':')}.yml"
+ end
+
end
end
View
78 lib/api_docs/test_helper.rb
@@ -1,5 +1,5 @@
module ApiDocs::TestHelper
-
+
module InstanceMethods
# Method that allows test creation and will document results in a YAML file
# Example usage:
@@ -11,70 +11,76 @@ def api_call(method, path, params = {}, headers = {})
parsed_path = path.dup
parsed_params = params.dup
-
parsed_params.each do |k, v|
parsed_params.delete(k) if parsed_path.gsub!(":#{k}", v.to_s)
end
-
+
# Making actual test request. Based on the example above:
# get '/users/12345'
-
send(method, parsed_path, parsed_params, headers)
-
+
meta = Hash.new
yield meta if block_given?
-
+
# Not writing anything to the files unless there was a demand
if ApiDocs.config.generate_on_demand
return unless ENV['API_DOCS']
end
-
- # Assertions inside test block didn't fail. Preparing file
- # content to be written
- c = request.filtered_parameters['controller']
- a = request.filtered_parameters['action']
-
- file_path = File.expand_path("#{c.gsub('/', ':')}.yml", ApiDocs.config.docs_path)
- params = ApiDocs::TestHelper.api_deep_clean_params(params)
-
- # Marking response as an unique
- key = 'ID-' + Digest::MD5.hexdigest("
- #{method}#{path}#{meta}#{params}#{response.status}}
- ")
-
- data = if File.exists?(file_path)
- YAML.load_file(file_path) rescue Hash.new
- else
- Hash.new
- end
-
- data[a] ||= { }
- data[a][key] = {
+
+ captured_data = {
+ 'controller' => request.filtered_parameters['controller'],
+ 'action' => request.filtered_parameters['action'],
'meta' => meta,
- 'method' => request.method,
+ 'method' => method.upcase.to_s,
'path' => path,
'headers' => headers,
'params' => ApiDocs::TestHelper.api_deep_clean_params(params),
'status' => response.status,
'body' => response.body
}
- FileUtils.mkdir_p(File.dirname(file_path))
- File.open(file_path, 'w'){|f| f.write(data.to_yaml)}
+
+ read_api_docs(captured_data) if ApiDocs.automatic_write?
+ ApiDocs.store_data(captured_data)
+ write_api_docs(captured_data) if ApiDocs.automatic_write?
+ end
+
+ def read_api_docs(captured_data)
+ calculated_file_path = file_path(captured_data)
+ ApiDocs.docs = if File.exists?(calculated_file_path)
+ YAML.load_file(calculated_file_path) rescue Hash.new
+ else
+ Hash.new
+ end
end
+
+ def file_path(captured_data)
+ File.expand_path(file_name(captured_data), ApiDocs.config.docs_path)
+ end
+
+ def file_name(captured_data)
+ "#{captured_data['controller'].gsub('/', ':')}.yml"
+ end
+
+ def write_api_docs(captured_data)
+ calculated_file_path = file_path(captured_data)
+ FileUtils.mkdir_p(File.dirname(calculated_file_path))
+ File.open(calculated_file_path, 'w') {|f| f.write(ApiDocs.docs.to_yaml)}
+ end
+
end
-
+
# Cleans up params. Removes things like File object handlers
# Sets up ignored values so we don't generate new keys for same data
def self.api_deep_clean_params(params)
case params
when Hash
params.each_with_object({}) do |(key, value), res|
- res[key.to_s] = ApiDocs::TestHelper.api_deep_clean_params(value)
+ res[key.to_s] = api_deep_clean_params(value)
end
when Array
- params.collect{|value| ApiDocs::TestHelper.api_deep_clean_params(value)}
+ params.collect{|value| api_deep_clean_params(value)}
else
- case params
+ case params
when Rack::Test::UploadedFile
'BINARY'
else
@@ -84,4 +90,4 @@ def self.api_deep_clean_params(params)
end
end
-ActionDispatch::IntegrationTest.send :include, ApiDocs::TestHelper::InstanceMethods
+ActionDispatch::IntegrationTest.send :include, ApiDocs::TestHelper::InstanceMethods
View
44 test/test_helper_test.rb
@@ -1,7 +1,7 @@
require File.expand_path('test_helper', File.dirname(__FILE__))
class TestHelperTest < ActionDispatch::IntegrationTest
-
+
def setup
ApiDocs.config.ignored_attributes = %(created_at updated_at)
ApiDocs.config.generate_on_demand = false
@@ -10,26 +10,26 @@ def setup
FileUtils.rm(file_path)
end
end
-
+
def test_api_deep_clean_params
assert_equal ({'a' => 'b'}),
ApiDocs::TestHelper.api_deep_clean_params({:a => 'b'})
-
+
assert_equal ({'a' => {'b' => 'c'}}),
ApiDocs::TestHelper.api_deep_clean_params({:a => {:b => 'c'}})
-
+
assert_equal ([{'a' => 'b'}, {'c' => 'd'}]),
ApiDocs::TestHelper.api_deep_clean_params([{:a => 'b'}, {:c => 'd'}])
-
+
assert_equal ({'a'=>[{'b'=>'c'}]}),
ApiDocs::TestHelper.api_deep_clean_params({:a => [{:b => 'c'}]})
end
-
+
def test_api_deep_clean_params_with_file_handler
assert_equal ({'a' => 'BINARY'}),
ApiDocs::TestHelper.api_deep_clean_params({:a => Rack::Test::UploadedFile.new(__FILE__)})
end
-
+
def test_api_call
api_call(:get, '/users/:id', :id => 12345, :format => 'json') do |doc|
assert_response :success
@@ -38,7 +38,7 @@ def test_api_call
'name' => 'Test User'
}), JSON.parse(response.body)
end
-
+
api_call(:get, '/users/:id', :id => 'invalid', :format => 'json') do |doc|
doc[:description] = 'Invalid user id'
assert_response :not_found
@@ -46,25 +46,25 @@ def test_api_call
'message' => 'User not found'
}), JSON.parse(response.body)
end
-
+
output = begin
YAML.load_file(ApiDocs.config.docs_path.join('application.yml'))
rescue
fail 'api doc file not written'
end
-
+
assert output['show'].present?
assert_equal 2, output['show'].keys.size
-
+
assert_equal 'ID-', output['show'].keys.first[0..2]
-
+
object = output['show'][output['show'].keys.first]
assert_equal 'GET', object['method']
assert_equal '/users/:id', object['path']
assert_equal ({'id' => '12345', 'format' => 'json'}), object['params']
assert_equal 200, object['status']
assert_equal ({'id' => 12345, 'name' => 'Test User'}), JSON.parse(object['body'])
-
+
object = output['show'][output['show'].keys.last]
assert_equal 'GET', object['method']
assert_equal '/users/:id', object['path']
@@ -72,14 +72,14 @@ def test_api_call
assert_equal 404, object['status']
assert_equal ({'message' => 'User not found'}), JSON.parse(object['body'])
end
-
+
def test_api_call_with_ignored_attribute
api_call(:get, '/users/:id', :id => 12345, :format => 'json') do
assert_response :success
end
output = YAML.load_file(ApiDocs.config.docs_path.join('application.yml'))
assert_equal 1, output['show'].keys.size
-
+
ApiDocs.config.ignored_attributes << 'random'
api_call(:get, '/users/:id', :id => 12345, :random => 1, :format => 'json') do
assert_response :success
@@ -88,7 +88,7 @@ def test_api_call_with_ignored_attribute
assert_equal 2, output['show'].keys.size
object = output['show'][output['show'].keys.last]
assert_not_equal 'IGNORED', object['body']['random']
-
+
api_call(:get, '/users/:id', :id => 12345, :random => 1, :format => 'json') do
assert_response :success
end
@@ -111,7 +111,7 @@ def test_api_call_with_xml
output = YAML.load_file(ApiDocs.config.docs_path.join('application.yml'))
assert_equal 1, output['show'].keys.size
end
-
+
def test_api_call_with_httpauth
auth = ActionController::HttpAuthentication::Basic.encode_credentials('user', 'secret')
api_call(:get, '/authenticate', {:random => 1, :format => 'json'}, 'HTTP_AUTHORIZATION' => auth) do
@@ -119,13 +119,13 @@ def test_api_call_with_httpauth
assert_equal ({'message' => 'Authenticated'}), JSON.parse(response.body)
end
end
-
+
def test_api_call_with_httpauth_failure
api_call(:get, '/authenticate', :random => 1, :format => 'json') do
assert_response :unauthorized
end
end
-
+
def test_api_call_with_generate_on_demand_off
ApiDocs.config.generate_on_demand = true
api_call(:get, '/users/:id', :id => 12345, :format => 'json') do
@@ -133,14 +133,14 @@ def test_api_call_with_generate_on_demand_off
end
assert !File.exists?(ApiDocs.config.docs_path.join('application.yml'))
end
-
+
def test_api_call_with_generate_on_demand_on
ENV['API_DOCS'] = 'true'
ApiDocs.config.generate_on_demand = true
-
+
api_call(:get, '/users/:id', :id => 12345, :format => 'json') do
assert_response :success
end
assert File.exists?(ApiDocs.config.docs_path.join('application.yml'))
end
-end
+end

No commit comments for this range

Something went wrong with that request. Please try again.