rspec_api_documentation 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ require 'active_support'
2
+
3
+ module RspecApiDocumentation
4
+ extend ActiveSupport::Autoload
5
+
6
+ require 'rspec_api_documentation/railtie' if defined?(Rails)
7
+ include ActiveSupport::JSON
8
+
9
+ eager_autoload do
10
+ autoload :Configuration
11
+ autoload :ApiDocumentation
12
+ autoload :ApiFormatter
13
+ autoload :Example
14
+ autoload :ExampleGroup
15
+ autoload :Index
16
+ autoload :TestClient
17
+ end
18
+
19
+ autoload :DSL
20
+ autoload :TestServer
21
+ autoload :HtmlWriter
22
+ autoload :JsonWriter
23
+ autoload :IndexWriter
24
+
25
+ def self.configuration
26
+ @configuration ||= Configuration.new
27
+ end
28
+
29
+ def self.documentations
30
+ @documentations ||= configuration.map { |config| ApiDocumentation.new(config) }
31
+ end
32
+
33
+ def self.configure
34
+ yield configuration if block_given?
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ module RspecApiDocumentation
2
+ class ApiDocumentation
3
+ attr_reader :configuration, :index
4
+
5
+ delegate :docs_dir, :format, :to => :configuration
6
+
7
+ def initialize(configuration)
8
+ @configuration = configuration
9
+ @index = Index.new
10
+ end
11
+
12
+ def clear_docs
13
+ if File.exists?(docs_dir)
14
+ FileUtils.rm_rf(docs_dir, :secure => true)
15
+ end
16
+ FileUtils.mkdir_p(docs_dir)
17
+ end
18
+
19
+ def document_example(rspec_example)
20
+ example = Example.new(rspec_example, configuration)
21
+ if example.should_document?
22
+ index.examples << example
23
+ end
24
+ end
25
+
26
+ def write
27
+ writers.each do |writer|
28
+ writer.write(index, configuration)
29
+ end
30
+ end
31
+
32
+ def writers
33
+ [*configuration.format].map do |format|
34
+ RspecApiDocumentation.const_get("#{format}_writer".classify)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ require 'rspec/core/formatters/base_formatter'
2
+
3
+ module RspecApiDocumentation
4
+ class ApiFormatter < RSpec::Core::Formatters::BaseFormatter
5
+ def initialize(output)
6
+ super
7
+
8
+ output.puts "Generating API Docs"
9
+ end
10
+
11
+ def start(example_count)
12
+ super
13
+
14
+ RspecApiDocumentation.documentations.each(&:clear_docs)
15
+ end
16
+
17
+ def example_group_started(example_group)
18
+ super
19
+
20
+ output.puts " #{example_group.description}"
21
+ end
22
+
23
+ def example_passed(example)
24
+ super
25
+
26
+ output.puts " * #{example.description}"
27
+
28
+ RspecApiDocumentation.documentations.each do |documentation|
29
+ documentation.document_example(example)
30
+ end
31
+ end
32
+
33
+ def example_failed(example)
34
+ super
35
+
36
+ output.puts " ! #{example.description} (FAILED)"
37
+ end
38
+
39
+ def stop
40
+ super
41
+
42
+ RspecApiDocumentation.documentations.each(&:write)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,66 @@
1
+ module RspecApiDocumentation
2
+ class Configuration
3
+ include Enumerable
4
+
5
+ attr_reader :parent
6
+
7
+ def initialize(parent = nil)
8
+ @parent = parent
9
+ @settings = parent.settings.clone if parent
10
+ end
11
+
12
+ def groups
13
+ @groups ||= []
14
+ end
15
+
16
+ def define_group(name, &block)
17
+ subconfig = self.class.new(self)
18
+ subconfig.filter = name
19
+ subconfig.docs_dir = self.docs_dir.join(name.to_s)
20
+ yield subconfig
21
+ groups << subconfig
22
+ end
23
+
24
+ def self.add_setting(name, opts = {})
25
+ define_method("#{name}=") { |value| settings[name] = value }
26
+ define_method("#{name}") do
27
+ if settings.has_key?(name)
28
+ settings[name]
29
+ elsif opts[:default].respond_to?(:call)
30
+ opts[:default].call(self)
31
+ else
32
+ opts[:default]
33
+ end
34
+ end
35
+ end
36
+
37
+ add_setting :docs_dir, :default => lambda { |config|
38
+ if defined?(Rails)
39
+ Rails.root.join("docs")
40
+ else
41
+ Pathname.new("docs")
42
+ end
43
+ }
44
+
45
+ add_setting :format, :default => :html
46
+ add_setting :template_path, :default => File.expand_path("../../../templates", __FILE__)
47
+ add_setting :filter, :default => :all
48
+ add_setting :exclusion_filter, :default => nil
49
+ add_setting :app, :default => lambda { |config|
50
+ if defined?(Rails)
51
+ Rails.application
52
+ else
53
+ nil
54
+ end
55
+ }
56
+
57
+ def settings
58
+ @settings ||= {}
59
+ end
60
+
61
+ def each(&block)
62
+ yield self
63
+ groups.map { |g| g.each &block }
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,204 @@
1
+ require 'rack/test/methods'
2
+ require 'rack'
3
+ require 'webmock'
4
+
5
+ module RspecApiDocumentation
6
+ module DSL
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def self.define_action(method)
11
+ define_method method do |*args, &block|
12
+ options = if args.last.is_a?(Hash) then args.pop else {} end
13
+ options[:method] = method
14
+ options[:path] = args.first
15
+ args.push(options)
16
+ args[0] = "#{method.to_s.upcase} #{args[0]}"
17
+ context(*args, &block)
18
+ end
19
+ end
20
+
21
+ define_action :get
22
+ define_action :post
23
+ define_action :put
24
+ define_action :delete
25
+
26
+ def parameter(name, description, options = {})
27
+ parameters.push(options.merge(:name => name.to_s, :description => description))
28
+ end
29
+
30
+ def required_parameters(*names)
31
+ names.each do |name|
32
+ param = parameters.find { |param| param[:name] == name.to_s }
33
+ raise "Undefined parameters can not be required." unless param
34
+ param[:required] = true
35
+ end
36
+ end
37
+
38
+ def callback(description, &block)
39
+ self.send(:include, WebMock::API)
40
+ context(description, &block)
41
+ end
42
+
43
+ def trigger_callback(&block)
44
+ define_method(:do_callback) do
45
+ stub_request(:any, callback_url).to_rack(destination)
46
+ instance_eval &block
47
+ end
48
+ end
49
+
50
+ def scope_parameters(scope, keys)
51
+ return unless metadata[:parameters]
52
+
53
+ if keys == :all
54
+ keys = parameter_keys.map(&:to_s)
55
+ else
56
+ keys = keys.map(&:to_s)
57
+ end
58
+
59
+ keys.each do |key|
60
+ param = parameters.detect { |param| param[:name] == key }
61
+ param[:scope] = scope if param
62
+ end
63
+ end
64
+
65
+ def example_request(description, params = {}, &block)
66
+ example(description) do
67
+ do_request(params)
68
+ instance_eval &block if block_given?
69
+ end
70
+ end
71
+
72
+ private
73
+ def parameters
74
+ metadata[:parameters] ||= []
75
+ if superclass_metadata && metadata[:parameters].equal?(superclass_metadata[:parameters])
76
+ metadata[:parameters] = Marshal.load(Marshal.dump(superclass_metadata[:parameters]))
77
+ end
78
+ metadata[:parameters]
79
+ end
80
+
81
+ def parameter_keys
82
+ parameters.map { |param| param[:name] }
83
+ end
84
+ end
85
+
86
+ module InstanceMethods
87
+ def client
88
+ @client ||= TestClient.new(self)
89
+ end
90
+
91
+ def destination
92
+ @destination ||= TestServer.new(self)
93
+ end
94
+
95
+ def callback_url
96
+ raise "You must define callback_url"
97
+ end
98
+
99
+ def do_request(extra_params = {})
100
+ @extra_params = extra_params
101
+ params_or_body = nil
102
+ path_or_query = path
103
+
104
+ if method == :get && !query_string.blank?
105
+ path_or_query = path + "?#{query_string}"
106
+ else
107
+ params_or_body = respond_to?(:raw_post) ? raw_post : params
108
+ end
109
+
110
+ client.send(method, path_or_query, params_or_body)
111
+ end
112
+
113
+ def query_string
114
+ query = params.to_a.map do |param|
115
+ param.map! { |a| CGI.escape(a.to_s) }
116
+ param.join("=")
117
+ end
118
+ query.join("&")
119
+ end
120
+
121
+ def params
122
+ return unless example.metadata[:parameters]
123
+ parameters = example.metadata[:parameters].inject({}) do |hash, param|
124
+ set_param(hash, param)
125
+ end
126
+ parameters.merge!(extra_params)
127
+ parameters
128
+ end
129
+
130
+ def method
131
+ example.metadata[:method]
132
+ end
133
+
134
+ def in_path?(param)
135
+ path_params.include?(param)
136
+ end
137
+
138
+ def path_params
139
+ example.metadata[:path].scan(/:(\w+)/).flatten
140
+ end
141
+
142
+ def path
143
+ example.metadata[:path].gsub(/:(\w+)/) do |match|
144
+ if respond_to?($1)
145
+ send($1)
146
+ else
147
+ match
148
+ end
149
+ end
150
+ end
151
+
152
+ def app
153
+ RspecApiDocumentation.configuration.app
154
+ end
155
+
156
+ def explanation(text)
157
+ example.metadata[:explanation] = text
158
+ end
159
+
160
+ def status
161
+ last_response.status
162
+ end
163
+
164
+ def response_body
165
+ last_response.body
166
+ end
167
+
168
+ private
169
+ def extra_params
170
+ return {} if @extra_params.nil?
171
+ @extra_params.inject({}) do |h, (k, v)|
172
+ h[k.to_s] = v
173
+ h
174
+ end
175
+ end
176
+
177
+ def set_param(hash, param)
178
+ key = param[:name]
179
+ return hash if !respond_to?(key) || in_path?(key)
180
+
181
+ if param[:scope]
182
+ hash[param[:scope].to_s] ||= {}
183
+ hash[param[:scope].to_s][key] = send(key)
184
+ else
185
+ hash[key] = send(key)
186
+ end
187
+
188
+ hash
189
+ end
190
+ end
191
+ end
192
+ end
193
+
194
+ def self.resource(*args, &block)
195
+ options = if args.last.is_a?(Hash) then args.pop else {} end
196
+ options[:api_docs_dsl] = true
197
+ options[:resource_name] = args.first
198
+ options[:document] = true
199
+ args.push(options)
200
+ describe(*args, &block)
201
+ end
202
+
203
+ RSpec.configuration.include RspecApiDocumentation::DSL, :api_docs_dsl => true
204
+ RSpec.configuration.include Rack::Test::Methods, :api_docs_dsl => true
@@ -0,0 +1,49 @@
1
+ module RspecApiDocumentation
2
+ class Example
3
+ attr_reader :example, :configuration
4
+
5
+ def initialize(example, configuration)
6
+ @example = example
7
+ @configuration = configuration
8
+ end
9
+
10
+ def method_missing(method_sym, *args, &block)
11
+ if example.metadata.has_key?(method_sym)
12
+ example.metadata[method_sym]
13
+ else
14
+ example.send(method_sym, *args, &block)
15
+ end
16
+ end
17
+
18
+ def respond_to?(method_sym, include_private = false)
19
+ super || example.metadata.has_key?(method_sym) || example.respond_to?(method_sym, include_private)
20
+ end
21
+
22
+ def method
23
+ metadata[:method]
24
+ end
25
+
26
+ def should_document?
27
+ return false if pending? || !metadata[:resource_name] || !metadata[:document]
28
+ return true if configuration.filter == :all
29
+ return false if (Array(metadata[:document]) & Array(configuration.exclusion_filter)).length > 0
30
+ return true if (Array(metadata[:document]) & Array(configuration.filter)).length > 0
31
+ end
32
+
33
+ def public?
34
+ metadata[:public]
35
+ end
36
+
37
+ def has_parameters?
38
+ respond_to?(:parameters) && parameters.present?
39
+ end
40
+
41
+ def explanation
42
+ metadata[:explanation] || nil
43
+ end
44
+
45
+ def requests
46
+ metadata[:requests] || []
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,72 @@
1
+ require 'mustache'
2
+
3
+ module RspecApiDocumentation
4
+ class HtmlWriter
5
+ attr_accessor :index, :configuration
6
+
7
+ def initialize(index, configuration)
8
+ self.index = index
9
+ self.configuration = configuration
10
+ end
11
+
12
+ def self.write(index, configuration)
13
+ writer = new(index, configuration)
14
+ writer.write
15
+ end
16
+
17
+ def write
18
+ File.open(configuration.docs_dir.join("index.html"), "w+") do |f|
19
+ f.write HtmlIndex.new(index, configuration).render
20
+ end
21
+ index.examples.each do |example|
22
+ html_example = HtmlExample.new(example, configuration)
23
+ FileUtils.mkdir_p(configuration.docs_dir.join(html_example.dirname))
24
+ File.open(configuration.docs_dir.join(html_example.dirname, html_example.filename), "w+") do |f|
25
+ f.write html_example.render
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ class HtmlIndex < Mustache
32
+ def initialize(index, configuration)
33
+ @index = index
34
+ @configuration = configuration
35
+ self.template_path = configuration.template_path
36
+ end
37
+
38
+ def sections
39
+ IndexWriter.sections(examples)
40
+ end
41
+
42
+ def examples
43
+ @index.examples.map { |example| HtmlExample.new(example, @configuration) }
44
+ end
45
+ end
46
+
47
+ class HtmlExample < Mustache
48
+ delegate :method, :to => :@example
49
+
50
+ def initialize(example, configuration)
51
+ @example = example
52
+ self.template_path = configuration.template_path
53
+ end
54
+
55
+ def method_missing(method, *args, &block)
56
+ @example.send(method, *args, &block)
57
+ end
58
+
59
+ def respond_to?(method, include_private = false)
60
+ super || @example.respond_to?(method, include_private)
61
+ end
62
+
63
+ def dirname
64
+ resource_name.downcase.gsub(/\s+/, '_')
65
+ end
66
+
67
+ def filename
68
+ basename = description.downcase.gsub(/\s+/, '_').gsub(/[^a-z_]/, '')
69
+ "#{basename}.html"
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,7 @@
1
+ module RspecApiDocumentation
2
+ class Index
3
+ def examples
4
+ @examples ||= []
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module RspecApiDocumentation
2
+ module IndexWriter
3
+ def sections(examples)
4
+ resources = examples.group_by(&:resource_name).inject([]) do |arr, (resource_name, examples)|
5
+ arr << { :resource_name => resource_name, :examples => examples.sort_by(&:description) }
6
+ end
7
+ resources.sort_by { |resource| resource[:resource_name] }
8
+ end
9
+ module_function :sections
10
+ end
11
+ end
@@ -0,0 +1,93 @@
1
+ module RspecApiDocumentation
2
+ class JsonWriter
3
+ attr_accessor :index, :configuration
4
+ delegate :docs_dir, :to => :configuration
5
+
6
+ def initialize(index, configuration)
7
+ self.index = index
8
+ self.configuration = configuration
9
+ end
10
+
11
+ def self.write(index, configuration)
12
+ writer = new(index, configuration)
13
+ writer.write
14
+ end
15
+
16
+ def write
17
+ File.open(docs_dir.join("index.json"), "w+") do |f|
18
+ f.write JsonIndex.new(index).to_json
19
+ end
20
+ index.examples.each do |example|
21
+ json_example = JsonExample.new(example)
22
+ FileUtils.mkdir_p(docs_dir.join(json_example.dirname))
23
+ File.open(docs_dir.join(json_example.dirname, json_example.filename), "w+") do |f|
24
+ f.write json_example.to_json
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ class JsonIndex
31
+ def initialize(index)
32
+ @index = index
33
+ end
34
+
35
+ def sections
36
+ IndexWriter.sections(examples)
37
+ end
38
+
39
+ def examples
40
+ @index.examples.map { |example| JsonExample.new(example) }
41
+ end
42
+
43
+ def to_json
44
+ sections.inject({:resources => []}) do |h, section|
45
+ h[:resources].push(
46
+ :name => section[:resource_name],
47
+ :examples => section[:examples].map { |example|
48
+ {
49
+ :description => example.description,
50
+ :link => "#{example.dirname}/#{example.filename}"
51
+ }
52
+ }
53
+ )
54
+ h
55
+ end.to_json
56
+ end
57
+ end
58
+
59
+ class JsonExample
60
+ delegate :method, :to => :@example
61
+
62
+ def initialize(example)
63
+ @example = example
64
+ end
65
+
66
+ def method_missing(method, *args, &block)
67
+ @example.send(method, *args, &block)
68
+ end
69
+
70
+ def respond_to?(method, include_private = false)
71
+ super || @example.respond_to?(method, include_private)
72
+ end
73
+
74
+ def dirname
75
+ resource_name.downcase.gsub(/\s+/, '_')
76
+ end
77
+
78
+ def filename
79
+ basename = description.downcase.gsub(/\s+/, '_').gsub(/[^a-z_]/, '')
80
+ "#{basename}.json"
81
+ end
82
+
83
+ def to_json
84
+ {
85
+ :resource => resource_name,
86
+ :description => description,
87
+ :explanation => explanation,
88
+ :parameters => respond_to?(:parameters) ? parameters : [],
89
+ :requests => requests
90
+ }.to_json
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,7 @@
1
+ module RspecApiDocumentation
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load "tasks/docs.rake"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,124 @@
1
+ module RspecApiDocumentation
2
+ class TestClient < Struct.new(:session, :options)
3
+ attr_accessor :user
4
+
5
+ delegate :example, :last_response, :last_request, :to => :session
6
+ delegate :metadata, :to => :example
7
+
8
+ def get(*args)
9
+ process :get, *args
10
+ end
11
+
12
+ def post(*args)
13
+ process :post, *args
14
+ end
15
+
16
+ def put(*args)
17
+ process :put, *args
18
+ end
19
+
20
+ def delete(*args)
21
+ process :delete, *args
22
+ end
23
+
24
+ def sign_in(user)
25
+ @user = user
26
+ end
27
+
28
+ def last_headers
29
+ session.last_request.env.select do |k, v|
30
+ k =~ /^(HTTP_|CONTENT_TYPE)/
31
+ end
32
+ end
33
+
34
+ def last_query_string
35
+ session.last_request.env["QUERY_STRING"]
36
+ end
37
+
38
+ def last_query_hash
39
+ strings = last_query_string.split("&")
40
+ arrays = strings.map do |segment|
41
+ segment.split("=")
42
+ end
43
+ Hash[arrays]
44
+ end
45
+
46
+ def headers(method, action, params)
47
+ if options && options[:headers]
48
+ options[:headers]
49
+ else
50
+ {}
51
+ end
52
+ end
53
+
54
+ private
55
+ def process(method, action, params = {})
56
+ session.send(method, action, params, headers(method, action, params))
57
+
58
+ document_example(method, action, params)
59
+ end
60
+
61
+ def document_example(method, action, params)
62
+ return unless metadata[:document]
63
+
64
+ input = last_request.env["rack.input"]
65
+ input.rewind
66
+ request_body = input.read
67
+
68
+ request_metadata = {}
69
+
70
+ request_metadata[:method] = method.to_s.upcase
71
+ request_metadata[:route] = action
72
+ if is_json?(request_body)
73
+ request_metadata[:request_body] = prettify_json(request_body)
74
+ else
75
+ request_metadata[:request_body] = prettify_request_body(request_body)
76
+ end
77
+ request_metadata[:request_headers] = format_headers(last_headers)
78
+ request_metadata[:request_query_parameters] = format_query_hash(last_query_hash)
79
+ request_metadata[:response_status] = last_response.status
80
+ request_metadata[:response_status_text] = Rack::Utils::HTTP_STATUS_CODES[last_response.status]
81
+ request_metadata[:response_body] = prettify_json(last_response.body)
82
+ request_metadata[:response_headers] = format_headers(last_response.headers)
83
+
84
+ metadata[:requests] ||= []
85
+ metadata[:requests] << request_metadata
86
+ end
87
+
88
+ def format_headers(headers)
89
+ headers.map do |key, value|
90
+ # HTTP_ACCEPT_CHARSET => Accept-Charset
91
+ formatted_key = key.gsub(/^HTTP_/, '').titleize.split.join("-")
92
+ "#{formatted_key}: #{value}"
93
+ end.join("\n")
94
+ end
95
+
96
+ def format_query_hash(query_hash)
97
+ return if query_hash.blank?
98
+ query_hash.map do |key, value|
99
+ "#{key}: #{CGI.unescape(value)}"
100
+ end.join("\n")
101
+ end
102
+
103
+ def prettify_json(json)
104
+ begin
105
+ JSON.pretty_generate(JSON.parse(json))
106
+ rescue
107
+ nil
108
+ end
109
+ end
110
+
111
+ def prettify_request_body(string)
112
+ return if string.blank?
113
+ CGI.unescape(string.split("&").join("\n"))
114
+ end
115
+
116
+ def is_json?(string)
117
+ begin
118
+ JSON.parse(string)
119
+ rescue
120
+ false
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,44 @@
1
+ module RspecApiDocumentation
2
+ class TestServer < Struct.new(:session)
3
+ delegate :example, :last_request, :last_response, :to => :session
4
+ delegate :metadata, :to => :example
5
+
6
+ def call(env)
7
+ env["rack.input"].rewind
8
+
9
+ request_metadata = {}
10
+
11
+ request_metadata[:method] = env["REQUEST_METHOD"]
12
+ request_metadata[:route] = env["PATH_INFO"]
13
+ request_metadata[:request_body] = prettify_json(env["rack.input"].read)
14
+ request_metadata[:request_headers] = headers(env)
15
+
16
+ metadata[:requests] ||= []
17
+ metadata[:requests] << request_metadata
18
+
19
+ return [200, {}, [""]]
20
+ end
21
+
22
+ private
23
+
24
+ def headers(env)
25
+ env.
26
+ select do |k, v|
27
+ k =~ /^(HTTP_|CONTENT_TYPE)/
28
+ end.
29
+ map do |key, value|
30
+ # HTTP_ACCEPT_CHARSET => Accept-Charset
31
+ formatted_key = key.gsub(/^HTTP_/, '').titleize.split.join("-")
32
+ "#{formatted_key}: #{value}"
33
+ end.join("\n")
34
+ end
35
+
36
+ def prettify_json(json)
37
+ begin
38
+ JSON.pretty_generate(JSON.parse(json))
39
+ rescue
40
+ nil
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ if Rails.env.test? || Rails.env.development?
4
+ desc 'Generate API request documentation from API specs'
5
+ RSpec::Core::RakeTask.new('docs:generate') do |t|
6
+ t.pattern = 'spec/acceptance/**/*_spec.rb'
7
+ t.rspec_opts = ["--format RspecApiDocumentation::ApiFormatter"]
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rspec_api_documentation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Cahoon
9
+ - Sam Goldman
10
+ - Eric Oestrich
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2012-01-25 00:00:00.000000000Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ requirement: &70151618292380 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: *70151618292380
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: &70151618291040 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *70151618291040
38
+ - !ruby/object:Gem::Dependency
39
+ name: i18n
40
+ requirement: &70151618289580 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ type: :runtime
47
+ prerelease: false
48
+ version_requirements: *70151618289580
49
+ - !ruby/object:Gem::Dependency
50
+ name: rack-test
51
+ requirement: &70151618288780 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ! '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ type: :runtime
58
+ prerelease: false
59
+ version_requirements: *70151618288780
60
+ - !ruby/object:Gem::Dependency
61
+ name: mustache
62
+ requirement: &70151618287740 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: *70151618287740
71
+ - !ruby/object:Gem::Dependency
72
+ name: webmock
73
+ requirement: &70151618286920 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: *70151618286920
82
+ - !ruby/object:Gem::Dependency
83
+ name: fakefs
84
+ requirement: &70151618285800 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: *70151618285800
93
+ - !ruby/object:Gem::Dependency
94
+ name: sinatra
95
+ requirement: &70151618283740 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ type: :development
102
+ prerelease: false
103
+ version_requirements: *70151618283740
104
+ description: Generate API docs from your test suite
105
+ email:
106
+ - chris@smartlogicsolutions.com
107
+ - sam@smartlogicsolutions.com
108
+ - eric@smartlogicsolutions.com
109
+ executables: []
110
+ extensions: []
111
+ extra_rdoc_files: []
112
+ files:
113
+ - lib/rspec_api_documentation/api_documentation.rb
114
+ - lib/rspec_api_documentation/api_formatter.rb
115
+ - lib/rspec_api_documentation/configuration.rb
116
+ - lib/rspec_api_documentation/dsl.rb
117
+ - lib/rspec_api_documentation/example.rb
118
+ - lib/rspec_api_documentation/html_writer.rb
119
+ - lib/rspec_api_documentation/index.rb
120
+ - lib/rspec_api_documentation/index_writer.rb
121
+ - lib/rspec_api_documentation/json_writer.rb
122
+ - lib/rspec_api_documentation/railtie.rb
123
+ - lib/rspec_api_documentation/test_client.rb
124
+ - lib/rspec_api_documentation/test_server.rb
125
+ - lib/rspec_api_documentation.rb
126
+ - lib/tasks/docs.rake
127
+ homepage: http://smartlogicsolutions.com
128
+ licenses: []
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ! '>='
143
+ - !ruby/object:Gem::Version
144
+ version: 1.3.6
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 1.8.10
148
+ signing_key:
149
+ specification_version: 3
150
+ summary: A double black belt for your docs
151
+ test_files: []