doctor-swagger 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in doctor-swagger.gemspec
4
+ gemspec
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec', :version => 2 do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara request specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Donald Plummer
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Doctor::Swagger
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'doctor-swagger'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install doctor-swagger
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require "rspec/core/rake_task"
5
+
6
+ desc "Default: run specs."
7
+ task :default => :spec
8
+
9
+ desc "Run specs"
10
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
3
+ puts File.expand_path(File.join(File.basename(__FILE__), 'lib'))
4
+ require 'doctor_swagger/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.authors = ["Donald Plummer", "Michael Xavier"]
8
+ gem.email = ["developers@crystalcommerce.com"]
9
+ gem.description = %q{DSL for generating swagger resource documentation}
10
+ gem.summary = <<-EOS
11
+ Provides a mixin which gives a high-level DSL for describing a swagger
12
+ resource. Use this to generate a documentation endpoint to describe an API that
13
+ you wish to document with swagger.
14
+ EOS
15
+ gem.homepage = ""
16
+
17
+ gem.files = `git ls-files`.split($\)
18
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
19
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
20
+ gem.name = "doctor-swagger"
21
+ gem.require_paths = ["lib"]
22
+ gem.version = DoctorSwagger::VERSION
23
+
24
+ gem.add_dependency("rdiscount", "~>1.6.8")
25
+
26
+ gem.add_development_dependency("rake", "~>0.9.2")
27
+ gem.add_development_dependency("rspec", "~>2.10.0")
28
+ gem.add_development_dependency("guard", "~>1.2.1")
29
+ gem.add_development_dependency("guard-rspec", "~>1.1.0")
30
+ end
@@ -0,0 +1 @@
1
+ require "doctor_swagger"
@@ -0,0 +1,78 @@
1
+ require 'doctor_swagger/endpoint'
2
+ require 'doctor_swagger/swagger_doc'
3
+ require 'doctor_swagger/error_response'
4
+ require 'doctor_swagger/errors'
5
+ require 'doctor_swagger/operation'
6
+ require 'doctor_swagger/parameter'
7
+ require 'doctor_swagger/query_parameter'
8
+ require 'doctor_swagger/post_parameter'
9
+ require 'doctor_swagger/path_parameter'
10
+ require 'doctor_swagger/post_body'
11
+ require 'doctor_swagger/root_swagger_doc'
12
+
13
+ module DoctorSwagger
14
+ #global settings, override with DSL
15
+ def self.swagger_version
16
+ @swagger_version ||= '1.0'
17
+ end
18
+
19
+ def self.api_version
20
+ @api_version ||= lambda { raise 'Set your API version with DoctorSwagger.api_version= or at the resource level'}
21
+ end
22
+
23
+ def self.base_path
24
+ @base_path ||= lambda { raise 'Set your base URL with DoctorSwagger.base_path= or at the resource level'}
25
+ end
26
+
27
+ def self.swagger_version=(version)
28
+ @swagger_version = version
29
+ end
30
+
31
+ def self.api_version=(version)
32
+ @api_version = version
33
+ end
34
+
35
+ def self.base_path=(url)
36
+ @base_path = url
37
+ end
38
+
39
+ module ClassMethods
40
+ def swagger_version(version)
41
+ @swagger_version = version
42
+ end
43
+
44
+ def api_version(version)
45
+ @api_version = version
46
+ end
47
+
48
+ def base_path(url)
49
+ @base_path = url
50
+ end
51
+
52
+ def swagger_doc
53
+ @swagger_doc
54
+ end
55
+
56
+ def swagger_resource(resource_path, &block)
57
+ @swagger_doc = SwaggerDoc.new(resource_path,
58
+ :swagger_version => @swagger_version,
59
+ :api_version => @api_version,
60
+ :base_path => @base_path,
61
+ &block)
62
+ end
63
+
64
+ def swagger_root_resource(resource_path, &block)
65
+ @swagger_doc = RootSwaggerDoc.new(resource_path,
66
+ :swagger_version => @swagger_version,
67
+ :api_version => @api_version,
68
+ :base_path => @base_path,
69
+ &block)
70
+ end
71
+ end
72
+
73
+ def self.included(receiver)
74
+ receiver.extend(ClassMethods)
75
+ end
76
+ end
77
+
78
+ require "doctor_swagger/version"
@@ -0,0 +1,32 @@
1
+ module DoctorSwagger
2
+ class Endpoint
3
+ def initialize(path, &block)
4
+ @path = path
5
+ @operations = []
6
+ instance_eval(&block)
7
+ end
8
+
9
+ def operations_as_json
10
+ if @operations && !@operations.empty?
11
+ {'operations' => @operations.map(&:as_json)}
12
+ else
13
+ {}
14
+ end
15
+ end
16
+
17
+ def as_json(*)
18
+ {
19
+ 'path' => @path,
20
+ 'description' => @description,
21
+ }.merge(operations_as_json)
22
+ end
23
+
24
+ def description(desc)
25
+ @description = desc
26
+ end
27
+
28
+ def operation(nickname, &block)
29
+ @operations << Operation.new(nickname, &block)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module DoctorSwagger
2
+ class ErrorResponse
3
+ def initialize(http_status, error)
4
+ @error = error
5
+ @http_status = http_status
6
+ end
7
+
8
+ def as_json(*)
9
+ {
10
+ 'error' => @error,
11
+ 'http_status' => @http_status
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module DoctorSwagger
2
+ module Errors
3
+ def self.standard_errors
4
+ [resource_not_found, access_denied]
5
+ end
6
+
7
+ def self.resource_not_found
8
+ ErrorResponse.new(404, 'resource_not_found')
9
+ end
10
+
11
+ def self.access_denied
12
+ ErrorResponse.new(401, 'access_denied')
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,100 @@
1
+ require 'rdiscount'
2
+
3
+ module DoctorSwagger
4
+ class Operation
5
+ def initialize(nickname, &block)
6
+ @nickname = nickname
7
+ @summary = ''
8
+ @parameters = []
9
+ @error_responses = []
10
+ @embeds = []
11
+ @scopes = []
12
+ @type = ""
13
+ @internal_type = ""
14
+ instance_eval(&block)
15
+ add_embedded_parameter unless @embeds.empty?
16
+ end
17
+
18
+ def query_parameter(param, &block)
19
+ @parameters << QueryParameter.new(param, &block)
20
+ end
21
+
22
+ def path_parameter(param, &block)
23
+ @parameters << PathParameter.new(param, &block)
24
+ end
25
+
26
+ def post_parameter(param, &block)
27
+ @parameters << PostParameter.new(param, &block)
28
+ end
29
+
30
+ def post_body(&block)
31
+ @parameters << PostBody.new(&block)
32
+ end
33
+
34
+ def method(meth)
35
+ @method = meth
36
+ end
37
+
38
+ def notes(notes)
39
+ @notes = process_markdown(notes)
40
+ end
41
+
42
+ def summary(summary)
43
+ @summary = summary
44
+ end
45
+
46
+ def standard_errors
47
+ @error_responses |= Errors.standard_errors
48
+ end
49
+
50
+ def error(http_status, error)
51
+ @error_responses << ErrorResponse.new(http_status, error)
52
+ end
53
+
54
+ def embeds(*embeds)
55
+ @embeds |= embeds
56
+ end
57
+
58
+ def scopes(*scopes)
59
+ @scopes |= scopes
60
+ end
61
+
62
+ def type(type)
63
+ @type = type
64
+ end
65
+
66
+ def internal_type(internal_type)
67
+ @internal_type = internal_type
68
+ end
69
+
70
+ def as_json(*)
71
+
72
+ {
73
+ 'parameters' => @parameters.map(&:as_json),
74
+ 'httpMethod' => @method.to_s.upcase,
75
+ 'notes' => @notes,
76
+ 'embeds' => @embeds.map(&:to_s),
77
+ 'scopes' => @scopes.map(&:to_s),
78
+ 'errorResponses' => @error_responses.map(&:as_json),
79
+ 'summary' => @summary,
80
+ 'nickname' => @nickname.to_s,
81
+ 'responseClass' => @type,
82
+ 'responseTypeInternal' => @internal_type
83
+ }
84
+ end
85
+
86
+ private
87
+ def add_embedded_parameter
88
+ embeds = @embeds
89
+ query_parameter(:embedded) do
90
+ description "Optional records to embed, comma-separated"
91
+ allow_multiple! if embeds.length > 1
92
+ allowable_values(*embeds)
93
+ end
94
+ end
95
+
96
+ def process_markdown(text)
97
+ RDiscount.new(text).to_html
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,65 @@
1
+ module DoctorSwagger
2
+ class Parameter
3
+ ALLOWED_TYPES = [:string, :integer, :long, :double, :boolean]
4
+ class InvalidType < StandardError
5
+ def initialize(bad_type)
6
+ @message = "The type of '#{bad_type}' is not valid. Choose from #{ALLOWED_TYPES.inspect}"
7
+ end
8
+ end
9
+
10
+ def initialize(name, &block)
11
+ @name = name
12
+ @description = ""
13
+ @required = false
14
+ @allow_multiple = false
15
+ @allowable_values = []
16
+ @data_type = :string
17
+ instance_eval(&block)
18
+ end
19
+
20
+ def description(description)
21
+ @description = description
22
+ end
23
+
24
+ def required!
25
+ @required = true
26
+ end
27
+
28
+ def allow_multiple!
29
+ @allow_multiple = true
30
+ end
31
+
32
+ def allowable_values(*values)
33
+ @allowable_values |= values
34
+ end
35
+
36
+ def type(type)
37
+ raise InvalidType.new(type) unless ALLOWED_TYPES.include?(type)
38
+ @data_type = type
39
+ end
40
+
41
+ def allowable_values_as_json
42
+ if @allowable_values && !@allowable_values.empty?
43
+ {
44
+ 'allowableValues' => {
45
+ 'valueType' => 'LIST',
46
+ 'values' => @allowable_values.map(&:to_s)
47
+ }
48
+ }
49
+ else
50
+ {}
51
+ end
52
+ end
53
+
54
+ def as_json(*)
55
+ {
56
+ 'name' => @name.to_s,
57
+ 'description' => @description,
58
+ 'dataType' => @data_type.to_s,
59
+ 'required' => @required,
60
+ 'allowMultiple' => @allow_multiple,
61
+ 'paramType' => param_type
62
+ }.merge(allowable_values_as_json)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,7 @@
1
+ module DoctorSwagger
2
+ class PathParameter < Parameter
3
+ def param_type
4
+ 'path'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module DoctorSwagger
2
+ class PostBody < PostParameter
3
+ def initialize(&block)
4
+ super(:body, &block)
5
+ end
6
+
7
+ def example(example)
8
+ @example = example
9
+ end
10
+
11
+ def as_json(*)
12
+ if @example && !@example.empty?
13
+ super.merge('example' => @example)
14
+ else
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,7 @@
1
+ module DoctorSwagger
2
+ class PostParameter < Parameter
3
+ def param_type
4
+ 'post'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module DoctorSwagger
2
+ class QueryParameter < Parameter
3
+ def param_type
4
+ 'query'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,16 @@
1
+ #TODO: specme
2
+ module DoctorSwagger
3
+ class RootSwaggerDoc < SwaggerDoc
4
+ def initialize(base_path_extension, options = {}, &block)
5
+ options[:swagger_version] ||= DoctorSwagger.swagger_version
6
+ options[:api_version] ||= DoctorSwagger.api_version
7
+ options[:base_path] ||= DoctorSwagger.base_path
8
+ @swagger_version = options[:swagger_version]
9
+ @api_version = options[:api_version]
10
+ @base_path = try_call(options[:base_path])
11
+ @base_path += base_path_extension
12
+ @endpoints = []
13
+ instance_eval(&block)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,37 @@
1
+ module DoctorSwagger
2
+ class SwaggerDoc
3
+
4
+ def initialize(resource_path, options = {}, &block)
5
+ @resource_path = resource_path
6
+ options[:swagger_version] ||= DoctorSwagger.swagger_version
7
+ options[:api_version] ||= DoctorSwagger.api_version
8
+ options[:base_path] ||= DoctorSwagger.base_path
9
+ @swagger_version = options[:swagger_version]
10
+ @api_version = options[:api_version]
11
+ @base_path = options[:base_path]
12
+ @endpoints = []
13
+ instance_eval(&block)
14
+ end
15
+
16
+ def endpoint(path, &block)
17
+ @endpoints << Endpoint.new(path, &block)
18
+ end
19
+
20
+ #TODO: add DSL for
21
+ def as_json(*)
22
+ {
23
+ 'apiVersion' => try_call(@api_version),
24
+ 'swaggerVersion' => try_call(@swagger_version),
25
+ 'basePath' => try_call(@base_path),
26
+ 'resourcePath' => @resource_path,
27
+ 'apis' => @endpoints.map(&:as_json)
28
+ }
29
+ end
30
+
31
+ private
32
+
33
+ def try_call(value)
34
+ value.respond_to?(:call) ? value.call : value
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module DoctorSwagger
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,297 @@
1
+ require 'spec_helper'
2
+ require 'doctor-swagger'
3
+
4
+ describe DoctorSwagger do
5
+ module DoctorSwaggerTest
6
+ include DoctorSwagger
7
+
8
+ swagger_version 'some crazy version'
9
+ api_version '3.0'
10
+ base_path 'https://example.com/api'
11
+
12
+ swagger_resource '/products' do
13
+ endpoint '/products' do
14
+ description 'Products'
15
+
16
+ operation :index do
17
+ query_parameter :category_id do
18
+ description 'The category id of the products you want'
19
+ required!
20
+ type :integer
21
+ end
22
+
23
+ method :get
24
+ notes 'Returns lots of products'
25
+
26
+ type '[product]'
27
+ internal_type '[Product]'
28
+
29
+ standard_errors
30
+ error 418, "im_a_teapot"
31
+
32
+ embeds :category, :variants
33
+ scopes 'read-inventory', 'other-scope'
34
+ summary 'Find products by category id'
35
+ end
36
+ end
37
+
38
+ endpoint '/products/{product_id}' do
39
+ description 'Show product'
40
+
41
+ operation :show do
42
+ path_parameter :product_id do
43
+ description 'The product id of the product you want'
44
+ required!
45
+ type :integer
46
+ end
47
+
48
+ method :get
49
+ notes 'Returns a product'
50
+
51
+ type 'product'
52
+ internal_type 'Product'
53
+
54
+ standard_errors
55
+ embeds :category, :variants
56
+ scopes 'read-inventory', 'other-scope'
57
+ summary 'Find product by product id'
58
+ end
59
+
60
+ operation :update do
61
+ path_parameter :product_id do
62
+ description 'The product id of the product you want'
63
+ required!
64
+ type :integer
65
+ end
66
+
67
+ post_body do
68
+ description 'The JSON representation of the product'
69
+ required!
70
+
71
+ example 'product' => {
72
+ 'foo' => 'bar',
73
+ 'wat' => nil
74
+ }
75
+ end
76
+
77
+ method :put
78
+ notes <<-EOS
79
+ # Updates a *product*
80
+ EOS
81
+
82
+ type 'product'
83
+ internal_type 'Product'
84
+
85
+ standard_errors
86
+ scopes 'read-inventory', 'other-scope'
87
+ summary 'Update product by product id'
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ subject { DoctorSwaggerTest.swagger_doc }
94
+
95
+ before(:each) do
96
+ @actual = DoctorSwaggerTest.swagger_doc
97
+ end
98
+
99
+ its(:as_json) do
100
+ should == {
101
+ 'apiVersion' => '3.0',
102
+ 'swaggerVersion' => 'some crazy version',
103
+ 'basePath' => "https://example.com/api",
104
+ 'resourcePath' => '/products',
105
+ 'apis' => [
106
+ {
107
+ 'path' => '/products',
108
+ 'description' => 'Products',
109
+ 'operations' => [
110
+ {
111
+ 'parameters' => [
112
+ {
113
+ 'name' => 'category_id',
114
+ 'description' => 'The category id of the products you want',
115
+ 'dataType' => 'integer',
116
+ 'required' => true,
117
+ 'allowMultiple' => false,
118
+ 'paramType' => 'query'
119
+ },
120
+ {
121
+ 'name' => 'embedded',
122
+ 'description' => 'Optional records to embed, comma-separated',
123
+ 'dataType' => 'string',
124
+ 'required' => false,
125
+ 'allowMultiple' => true,
126
+ 'paramType' => 'query',
127
+ 'allowableValues' => {
128
+ 'values' => %w[category variants],
129
+ 'valueType' => 'LIST'
130
+ }
131
+ }
132
+ ],
133
+ 'httpMethod' => 'GET',
134
+ 'notes' => "<p>Returns lots of products</p>\n",
135
+ 'embeds' => %w[category variants],
136
+ 'scopes' => %w[read-inventory other-scope],
137
+ 'responseTypeInternal' => '[Product]',
138
+ 'responseClass' => '[product]',
139
+ 'errorResponses' => [
140
+ {
141
+ 'error' => 'resource_not_found',
142
+ 'http_status' => 404
143
+ },
144
+ {
145
+ 'error' => 'access_denied',
146
+ 'http_status' => 401
147
+ },
148
+ {
149
+ 'error' => 'im_a_teapot',
150
+ 'http_status' => 418
151
+ }
152
+ ],
153
+ 'summary' => 'Find products by category id',
154
+ 'nickname' => 'index'
155
+
156
+ }
157
+ ]
158
+ },
159
+ {
160
+ 'path' => '/products/{product_id}',
161
+ 'description' => 'Show product',
162
+ 'operations' => [
163
+ {
164
+ 'parameters' => [
165
+ {
166
+ 'name' => 'product_id',
167
+ 'description' => 'The product id of the product you want',
168
+ 'dataType' => 'integer',
169
+ 'required' => true,
170
+ 'allowMultiple' => false,
171
+ 'paramType' => 'path'
172
+ },
173
+ {
174
+ 'name' => 'embedded',
175
+ 'description' => 'Optional records to embed, comma-separated',
176
+ 'dataType' => 'string',
177
+ 'required' => false,
178
+ 'allowMultiple' => true,
179
+ 'paramType' => 'query',
180
+ 'allowableValues' => {
181
+ 'values' => %w[category variants],
182
+ 'valueType' => 'LIST'
183
+ }
184
+ }
185
+
186
+ ],
187
+ 'httpMethod' => 'GET',
188
+ 'notes' => "<p>Returns a product</p>\n",
189
+ 'embeds' => %w[category variants],
190
+ 'scopes' => %w[read-inventory other-scope],
191
+ 'responseTypeInternal' => 'Product',
192
+ 'responseClass' => 'product',
193
+ 'errorResponses' => [
194
+ {
195
+ 'error' => 'resource_not_found',
196
+ 'http_status' => 404
197
+ },
198
+ {
199
+ 'error' => 'access_denied',
200
+ 'http_status' => 401
201
+ }
202
+ ],
203
+ 'summary' => 'Find product by product id',
204
+ 'nickname' => 'show',
205
+ 'scopes' => %w[read-inventory other-scope]
206
+
207
+ },
208
+ {
209
+ 'parameters' => [
210
+ {
211
+ 'name' => 'product_id',
212
+ 'description' => 'The product id of the product you want',
213
+ 'dataType' => 'integer',
214
+ 'required' => true,
215
+ 'allowMultiple' => false,
216
+ 'paramType' => 'path'
217
+ },
218
+ {
219
+ 'name' => 'body',
220
+ 'description' => 'The JSON representation of the product',
221
+ 'dataType' => 'string',
222
+ 'required' => true,
223
+ 'allowMultiple' => false,
224
+ 'paramType' => 'post',
225
+ 'example' => {
226
+ 'product' => {
227
+ 'foo' => 'bar',
228
+ 'wat' => nil
229
+ }
230
+ }
231
+ },
232
+ ],
233
+ 'httpMethod' => 'PUT',
234
+ 'notes' => "<h1>Updates a <em>product</em></h1>\n",
235
+ 'embeds' => %w[],
236
+ 'scopes' => %w[read-inventory other-scope],
237
+ 'responseTypeInternal' => 'Product',
238
+ 'responseClass' => 'product',
239
+ 'errorResponses' => [
240
+ {
241
+ 'error' => 'resource_not_found',
242
+ 'http_status' => 404
243
+ },
244
+ {
245
+ 'error' => 'access_denied',
246
+ 'http_status' => 401
247
+ }
248
+ ],
249
+ 'summary' => 'Update product by product id',
250
+ 'nickname' => 'update',
251
+ 'scopes' => %w[read-inventory other-scope]
252
+
253
+ }
254
+ ]
255
+ }
256
+ ]
257
+ }
258
+ end
259
+
260
+ context "dynamic version/path config" do
261
+ class DynamicSwaggerResource
262
+ include DoctorSwagger
263
+
264
+
265
+ def self.prefix=(prefix)
266
+ @prefix = prefix
267
+ end
268
+
269
+ def self.format(str)
270
+ "#{@prefix}#{str}"
271
+ end
272
+
273
+ swagger_version lambda { DynamicSwaggerResource.format('some crazy version') }
274
+ api_version lambda { DynamicSwaggerResource.format('3.0') }
275
+ base_path lambda { DynamicSwaggerResource.format('https://example.com/api') }
276
+
277
+ swagger_resource '/products' do
278
+ end
279
+ end
280
+
281
+ subject { DynamicSwaggerResource.swagger_doc }
282
+
283
+ before(:each) do
284
+ DynamicSwaggerResource.prefix = '!!!'
285
+ end
286
+
287
+ its(:as_json) do
288
+ should == {
289
+ 'apiVersion' => '!!!3.0',
290
+ 'swaggerVersion' => '!!!some crazy version',
291
+ 'basePath' => "!!!https://example.com/api",
292
+ 'resourcePath' => '/products',
293
+ 'apis' => []
294
+ }
295
+ end
296
+ end
297
+ end
@@ -0,0 +1,6 @@
1
+ $: << File.join(File.basename(__FILE__), '..', 'lib')
2
+ RSpec.configure do |config|
3
+ config.treat_symbols_as_metadata_keys_with_true_values = true
4
+ config.run_all_when_everything_filtered = true
5
+ config.filter_run :focus
6
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: doctor-swagger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Donald Plummer
9
+ - Michael Xavier
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-09-27 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rdiscount
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 1.6.8
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: 1.6.8
31
+ - !ruby/object:Gem::Dependency
32
+ name: rake
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 0.9.2
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 0.9.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.10.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 2.10.0
63
+ - !ruby/object:Gem::Dependency
64
+ name: guard
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: 1.2.1
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 1.2.1
79
+ - !ruby/object:Gem::Dependency
80
+ name: guard-rspec
81
+ requirement: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ~>
85
+ - !ruby/object:Gem::Version
86
+ version: 1.1.0
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ version: 1.1.0
95
+ description: DSL for generating swagger resource documentation
96
+ email:
97
+ - developers@crystalcommerce.com
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - .gitignore
103
+ - .rspec
104
+ - .rvmrc
105
+ - Gemfile
106
+ - Guardfile
107
+ - LICENSE
108
+ - README.md
109
+ - Rakefile
110
+ - doctor-swagger.gemspec
111
+ - lib/doctor-swagger.rb
112
+ - lib/doctor_swagger.rb
113
+ - lib/doctor_swagger/endpoint.rb
114
+ - lib/doctor_swagger/error_response.rb
115
+ - lib/doctor_swagger/errors.rb
116
+ - lib/doctor_swagger/operation.rb
117
+ - lib/doctor_swagger/parameter.rb
118
+ - lib/doctor_swagger/path_parameter.rb
119
+ - lib/doctor_swagger/post_body.rb
120
+ - lib/doctor_swagger/post_parameter.rb
121
+ - lib/doctor_swagger/query_parameter.rb
122
+ - lib/doctor_swagger/root_swagger_doc.rb
123
+ - lib/doctor_swagger/swagger_doc.rb
124
+ - lib/doctor_swagger/version.rb
125
+ - spec/doctor_swagger_spec.rb
126
+ - spec/spec_helper.rb
127
+ homepage: ''
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: '0'
145
+ requirements: []
146
+ rubyforge_project:
147
+ rubygems_version: 1.8.24
148
+ signing_key:
149
+ specification_version: 3
150
+ summary: Provides a mixin which gives a high-level DSL for describing a swagger resource.
151
+ Use this to generate a documentation endpoint to describe an API that you wish to
152
+ document with swagger.
153
+ test_files:
154
+ - spec/doctor_swagger_spec.rb
155
+ - spec/spec_helper.rb
156
+ has_rdoc: