swagger_yard 0.1.0 → 0.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6dfc1b55809fb818e9c2f1742a741ebbf72eb4d
4
- data.tar.gz: cb8f8253cb95a55c04d6a9cd5b7488ae6d40b47c
3
+ metadata.gz: d61bc284164e43af94017cc989f2dc61ac5a98e2
4
+ data.tar.gz: b312468a3884e80013827ed6e82b5b00fe3539cf
5
5
  SHA512:
6
- metadata.gz: b2c1e0eb8a9461f39d3161f62592c8cdf817f0c1fa9a8d3b9fc8231a171ee30246eb84fb74be727ed1671fde7244d740d5e4b774e5f5d0334c913e15270b7182
7
- data.tar.gz: d47a31030769ce82fb1a7cb5242899562c229ed023c3155f25be48fd5f91a9d8ab7f9c67587073d645a0958d9b3bec7dec2d23ca55b2cf5dcfcca2ce54d90c21
6
+ metadata.gz: efc555082f8433aecca02e2d811943b10e8487701b68632670fd6c8f82b052eb849127d14498c58513e6aece261e9d8ea1cf8ab5b5ea2b5ccc94404d8a585f70
7
+ data.tar.gz: 081c4133f4c53d1845b547229250c5296b60ccee71a46e1c9970a71fdfc941c76701ae8ea63c19ade023f905dd712f14402048f0be234b361d6154d609740a26
data/README.md CHANGED
@@ -23,10 +23,12 @@ Install the gem with Bunder:
23
23
  config.api_version = "1.0"
24
24
  config.reload = Rails.env.development?
25
25
 
26
- # where your swagger spec json will show up
27
- config.swagger_spec_base_path = "http://localhost:3000/swagger/api"
28
26
  # where your actual api is hosted from
29
27
  config.api_base_path = "http://localhost:3000/api"
28
+
29
+ # where your swagger spec json will show up
30
+ # configure this to match SwaggerYard::Rails mount point
31
+ config.swagger_spec_base_path = "http://localhost:3000/swagger/api"
30
32
  end
31
33
 
32
34
  # register swagger tags with YARD
@@ -129,12 +131,31 @@ end
129
131
 
130
132
  ## UI ##
131
133
 
132
- It is advisable to use something like [swagger-ui_rails](https://github.com/3scale/swagger-ui_rails/tree/dev-2.1.3) for your UI needs inside of Rails.
134
+ We suggest using something like [swagger-ui_rails](https://github.com/3scale/swagger-ui_rails/tree/dev-2.1.3) for your UI needs inside of Rails.
135
+
136
+ To generate JSON from your code on request, checkout the [swagger_yard-rails](https://github.com/tpitale/swagger_yard-rails) project. This provides an engine to parse and render the json required for use by swagger-ui_rails.
133
137
 
134
138
  ## More Information ##
135
139
 
136
- * [Swagger-ui](https://github.com/wordnik/swagger-ui)
137
140
  * [swagger-ui_rails](https://github.com/3scale/swagger-ui_rails/tree/dev-2.1.3)
138
- * [Yard](https://github.com/lsegal/yard)
139
- * [Swagger-spec version 1.2](https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md)
141
+ * [swagger_yard-rails](https://github.com/tpitale/swagger_yard-rails)
140
142
  * [Swagger-spec version 2.0](https://github.com/wordnik/swagger-spec/blob/master/versions/2.0.md)
143
+ * [Yard](https://github.com/lsegal/yard)
144
+
145
+ ## Current Parsing "Tree" Structure ##
146
+
147
+ ResourceListing
148
+ |
149
+ -> ApiDeclaration (controller)
150
+ | |
151
+ | -> ListingInfo (controller class)
152
+ | -> Authorization (header/param for auth, also added to ResourceListing?)
153
+ | -> Api(s) (controller action, by path)
154
+ | |
155
+ | -> Operation(s) (controller action with HTTP method)
156
+ | |
157
+ | -> Parameter(s) (action param)
158
+ |
159
+ -> Model (model)
160
+ |
161
+ -> Properties (model attributes)
@@ -11,6 +11,7 @@ require "swagger_yard/api_declaration"
11
11
  require "swagger_yard/model"
12
12
  require "swagger_yard/api"
13
13
  require "swagger_yard/listing_info"
14
+ require "swagger_yard/swagger"
14
15
 
15
16
  module SwaggerYard
16
17
  class << self
@@ -44,10 +45,6 @@ module SwaggerYard
44
45
  ::YARD::Registry.all
45
46
  end
46
47
 
47
- def yard_objects_from_resource(resource_name)
48
- yard_objects_from_file(resource_to_file_path[resource_name])
49
- end
50
-
51
48
  ##
52
49
  # Register some custom yard tags used by swagger-ui
53
50
  def register_custom_yard_tags!
@@ -1,6 +1,6 @@
1
1
  module SwaggerYard
2
2
  class Api
3
- attr_accessor :path, :description
3
+ attr_accessor :path, :description, :operations, :api_declaration
4
4
 
5
5
  def self.path_from_yard_object(yard_object)
6
6
  if tag = yard_object.tags.detect {|t| t.tag_name == "path"}
@@ -29,21 +29,16 @@ module SwaggerYard
29
29
  @operations << Operation.from_yard_object(yard_object, self)
30
30
  end
31
31
 
32
- def to_h
33
- {
34
- "path" => path,
35
- "description" => description,
36
- "operations" => @operations.map(&:to_h)
37
- }
38
- end
39
-
40
32
  def model_names
41
33
  @operations.map(&:model_names).flatten.compact.uniq
42
- # @parameters.select {|p| ref?(p['type'])}.map {|p| p['type']}.uniq
43
34
  end
44
35
 
45
36
  def ref?(data_type)
46
37
  @api_declaration.ref?(data_type)
47
38
  end
39
+
40
+ def operations_hash
41
+ Hash[@operations.map {|op| [op.http_method.downcase, op.to_h]}]
42
+ end
48
43
  end
49
- end
44
+ end
@@ -1,6 +1,6 @@
1
1
  module SwaggerYard
2
2
  class ApiDeclaration
3
- attr_accessor :description, :resource_path
3
+ attr_accessor :description, :resource, :resource_path
4
4
  attr_reader :apis, :authorizations
5
5
 
6
6
  def initialize(resource_listing)
@@ -23,17 +23,18 @@ module SwaggerYard
23
23
 
24
24
  def add_yard_object(yard_object)
25
25
  case yard_object.type
26
- when :class
26
+ when :class # controller
27
27
  add_listing_info(ListingInfo.new(yard_object))
28
28
  add_authorizations_to_resource_listing(yard_object)
29
- when :method
29
+ when :method # actions
30
30
  add_api(yard_object)
31
31
  end
32
32
  end
33
33
 
34
34
  def add_listing_info(listing_info)
35
- @description = listing_info.description
36
- @resource_path = listing_info.resource_path
35
+ @description = listing_info.description
36
+ @resource = listing_info.resource
37
+ @resource_path = listing_info.resource_path # required for valid? but nothing else
37
38
 
38
39
  # we only have api_key auth, the value for now is always empty array
39
40
  @authorizations = Hash[listing_info.authorizations.uniq.map {|k| [k, []]}]
@@ -67,23 +68,13 @@ module SwaggerYard
67
68
  @resource_listing.models.map(&:id).include?(name)
68
69
  end
69
70
 
70
- def to_h
71
- {
72
- "apiVersion" => SwaggerYard.config.api_version,
73
- "swaggerVersion" => SwaggerYard.config.swagger_version,
74
- "basePath" => SwaggerYard.config.api_base_path,
75
- "resourcePath" => resource_path,
76
- "apis" => apis.values.map(&:to_h),
77
- "models" => Hash[models.map {|m| [m.id, m.to_h]}],
78
- "authorizations" => authorizations
79
- }
71
+ def apis_hash
72
+ Hash[apis.map {|path, api| [path, api.operations_hash]}]
80
73
  end
81
74
 
82
- def listing_hash
83
- {
84
- "path" => resource_path,
85
- "description" => description
86
- }
75
+ def to_tag
76
+ { "name" => resource,
77
+ "description" => description }
87
78
  end
88
79
 
89
80
  private
@@ -26,11 +26,9 @@ module SwaggerYard
26
26
  end
27
27
 
28
28
  def to_h
29
- {
30
- "type" => type,
31
- "passAs" => @pass_as,
32
- "keyname" => @key
33
- }
29
+ { "type" => type,
30
+ "name" => @key,
31
+ "in" => @pass_as }
34
32
  end
35
33
  end
36
34
  end
@@ -2,13 +2,17 @@ module SwaggerYard
2
2
  class Configuration
3
3
  attr_accessor :swagger_spec_base_path, :api_base_path, :api_path
4
4
  attr_accessor :swagger_version, :api_version
5
+ attr_accessor :title, :description
5
6
  attr_accessor :enable, :reload
7
+ attr_accessor :controller_path, :model_path
6
8
 
7
9
  def initialize
8
10
  self.swagger_version = "1.1"
9
11
  self.api_version = "0.1"
10
12
  self.enable = false
11
13
  self.reload = true
14
+ self.title = "Configure title with SwaggerYard.config.title"
15
+ self.description = "Configure description with SwaggerYard.config.description"
12
16
  end
13
17
  end
14
- end
18
+ end
@@ -1,10 +1,14 @@
1
1
  module SwaggerYard
2
2
  class ListingInfo
3
- attr_reader :description, :resource_path, :authorizations
3
+ attr_reader :description, :resource, :resource_path, :authorizations
4
4
 
5
5
  def initialize(yard_object)
6
6
  @description = yard_object.docstring
7
7
 
8
+ if tag = yard_object.tags.detect {|t| t.tag_name == "resource"}
9
+ @resource = tag.text
10
+ end
11
+
8
12
  if tag = yard_object.tags.detect {|t| t.tag_name == "resource_path"}
9
13
  @resource_path = tag.text.downcase
10
14
  end
@@ -57,13 +57,10 @@ module SwaggerYard
57
57
  end
58
58
 
59
59
  def to_h
60
- raise "Model is missing @model tag" if id.nil?
61
-
62
- {
63
- "id" => id,
64
- "properties" => Hash[@properties.map {|property| [property.name, property.to_h]}],
65
- "required" => @properties.select(&:required?).map(&:name)
66
- }
60
+ {}.tap do |h|
61
+ h["properties"] = Hash[@properties.map {|p| [p.name, p.to_h]}]
62
+ h["required"] = @properties.select(&:required?).map(&:name) if @properties.detect(&:required?)
63
+ end
67
64
  end
68
65
  end
69
66
  end
@@ -1,6 +1,6 @@
1
1
  module SwaggerYard
2
2
  class Operation
3
- attr_accessor :summary, :notes
3
+ attr_accessor :summary, :notes, :ruby_method
4
4
  attr_reader :path, :http_method, :error_messages, :response_type
5
5
  attr_reader :parameters, :model_names
6
6
 
@@ -9,6 +9,7 @@ module SwaggerYard
9
9
  # TODO: extract to operation builder?
10
10
  def self.from_yard_object(yard_object, api)
11
11
  new(api).tap do |operation|
12
+ operation.ruby_method = yard_object.name(false)
12
13
  yard_object.tags.each do |tag|
13
14
  case tag.tag_name
14
15
  when "path"
@@ -45,17 +46,37 @@ module SwaggerYard
45
46
  end
46
47
 
47
48
  def to_h
49
+ method = http_method.downcase
50
+ description = notes || ""
51
+ params = parameters.map(&:to_h)
52
+ responses = { "default" => { "description" => summary || @api.description } }
53
+
54
+ if response_type
55
+ responses["default"]["schema"] = response_type.to_h
56
+ end
57
+
58
+ unless error_messages.empty?
59
+ error_messages.each do |err|
60
+ responses[err["code"].to_s] = {}.tap do |h|
61
+ h["description"] = err["message"]
62
+ h["schema"] = Type.from_type_list(Array(err["responseModel"])).to_h if err["responseModel"]
63
+ end
64
+ end
65
+ end
66
+
48
67
  {
49
- "httpMethod" => http_method,
50
- "nickname" => nickname,
51
- "type" => "void",
52
- "produces" => ["application/json", "application/xml"],
53
- "parameters" => parameters.map(&:to_h),
54
- "summary" => summary || @api.description,
55
- "notes" => notes,
56
- "responseMessages" => error_messages
68
+ "summary" => summary || @api.description,
69
+ "tags" => [@api.api_declaration.resource].compact,
70
+ "operationId" => "#{@api.api_declaration.resource}-#{ruby_method}",
71
+ "parameters" => params,
72
+ "responses" => responses,
57
73
  }.tap do |h|
58
- h.merge!(response_type.to_h) if response_type
74
+ h["description"] = description unless description.to_s.empty?
75
+
76
+ authorizations = @api.api_declaration.authorizations
77
+ unless authorizations.empty?
78
+ h["security"] = authorizations.map {|k,v| { k => v} }
79
+ end
59
80
  end
60
81
  end
61
82
 
@@ -55,14 +55,21 @@ module SwaggerYard
55
55
  end
56
56
 
57
57
  def to_h
58
- {
59
- "paramType" => param_type,
60
- "name" => name,
61
- "description" => description,
62
- "required" => required,
63
- "allowMultiple" => !!allow_multiple,
64
- "allowableValues" => allowable_values_hash
65
- }.merge(@type.to_h).reject {|k,v| v.nil?}
58
+ { "name" => name,
59
+ "description" => description,
60
+ "required" => required,
61
+ "in" => param_type
62
+ }.tap do |h|
63
+ if !Array(allowable_values).empty?
64
+ h["enum"] = allowable_values
65
+ end
66
+ if h["in"] == "body"
67
+ h["schema"] = @type.to_h
68
+ else
69
+ h.update(@type.to_h)
70
+ end
71
+ h["collectionFormat"] = 'multi' if !Array(allow_multiple).empty? && h["items"]
72
+ end
66
73
  end
67
74
  end
68
- end
75
+ end
@@ -28,9 +28,9 @@ module SwaggerYard
28
28
  end
29
29
 
30
30
  def to_h
31
- result = @type.to_h
32
- result["description"] = description if description
33
- result
31
+ @type.to_h.tap do |h|
32
+ h["description"] = description if description
33
+ end
34
34
  end
35
35
  end
36
36
  end
@@ -1,8 +1,11 @@
1
1
  module SwaggerYard
2
2
  class ResourceListing
3
- attr_reader :api_declarations, :resource_to_file_path
4
3
  attr_accessor :authorizations
5
4
 
5
+ def self.all
6
+ new(SwaggerYard.config.controller_path, SwaggerYard.config.model_path)
7
+ end
8
+
6
9
  def initialize(controller_path, model_path)
7
10
  @model_path = model_path
8
11
  @controller_path = controller_path
@@ -19,25 +22,33 @@ module SwaggerYard
19
22
  @controllers ||= parse_controllers
20
23
  end
21
24
 
22
- def declaration_for(resource_name)
23
- controllers[resource_name]
25
+ def to_h
26
+ { "paths" => path_objects,
27
+ "definitions" => model_objects,
28
+ "tags" => tag_objects,
29
+ "securityDefinitions" => security_objects }
30
+ end
31
+
32
+ def path_objects
33
+ controllers.map(&:apis_hash).inject({}) do |h, api_hash|
34
+ h.merge api_hash
35
+ end
24
36
  end
25
37
 
26
- def to_h
27
- {
28
- "apiVersion" => SwaggerYard.config.api_version,
29
- "swaggerVersion" => SwaggerYard.config.swagger_version,
30
- "basePath" => SwaggerYard.config.swagger_spec_base_path,
31
- "apis" => list_api_declarations,
32
- "authorizations" => authorizations_hash
33
- }
38
+ # Resources
39
+ def tag_objects
40
+ controllers.map(&:to_tag)
34
41
  end
35
42
 
36
- private
37
- def list_api_declarations
38
- controllers.values.sort_by(&:resource_path).map(&:listing_hash)
43
+ def model_objects
44
+ Hash[models.map {|m| [m.id, m.to_h]}]
39
45
  end
40
46
 
47
+ def security_objects
48
+ Hash[authorizations.map {|auth| [auth.name, auth.to_h]}]
49
+ end
50
+
51
+ private
41
52
  def parse_models
42
53
  return [] unless @model_path
43
54
 
@@ -47,13 +58,11 @@ module SwaggerYard
47
58
  end
48
59
 
49
60
  def parse_controllers
50
- return {} unless @controller_path
51
-
52
- Hash[Dir[@controller_path].map do |file_path|
53
- declaration = create_api_declaration(file_path)
61
+ return [] unless @controller_path
54
62
 
55
- [declaration.resource_name, declaration] if declaration.valid?
56
- end.compact]
63
+ Dir[@controller_path].map do |file_path|
64
+ create_api_declaration(file_path)
65
+ end.select(&:valid?)
57
66
  end
58
67
 
59
68
  def create_api_declaration(file_path)
@@ -61,11 +70,5 @@ module SwaggerYard
61
70
 
62
71
  ApiDeclaration.new(self).add_yard_objects(yard_objects)
63
72
  end
64
-
65
- def authorizations_hash
66
- Hash[
67
- authorizations.map(&:name).zip(authorizations.map(&:to_h)) # ugh
68
- ]
69
- end
70
73
  end
71
74
  end
@@ -0,0 +1,19 @@
1
+ module SwaggerYard
2
+ class Info
3
+ def to_h
4
+ { "title" => SwaggerYard.config.title,
5
+ "description" => SwaggerYard.config.description,
6
+ "version" => SwaggerYard.config.api_version }
7
+ end
8
+ end
9
+
10
+ class Swagger
11
+ def to_h
12
+ { "swagger" => "2.0",
13
+ "info" => Info.new.to_h,
14
+ "host" => URI(SwaggerYard.config.api_base_path).host,
15
+ "basePath" => URI(SwaggerYard.config.api_base_path).request_uri
16
+ }.merge(ResourceListing.all.to_h)
17
+ end
18
+ end
19
+ end
@@ -22,12 +22,32 @@ module SwaggerYard
22
22
 
23
23
  alias :array? :array
24
24
 
25
+ def json_type
26
+ type, format = name, nil
27
+ case name
28
+ when "float", "double"
29
+ type = "number"
30
+ format = name
31
+ when "date-time", "date", "time"
32
+ type = "string"
33
+ format = name
34
+ end
35
+ {}.tap do |h|
36
+ h["type"] = type
37
+ h["format"] = format if format
38
+ end
39
+ end
40
+
25
41
  def to_h
26
- type_tag = ref? ? "$ref" : "type"
42
+ type = if ref?
43
+ { "$ref" => "#/definitions/#{name}"}
44
+ else
45
+ json_type
46
+ end
27
47
  if array?
28
- {"type"=>"array", "items"=> { type_tag => name }}
48
+ { "type" => "array", "items" => type }
29
49
  else
30
- {"type"=>name}
50
+ type
31
51
  end
32
52
  end
33
53
  end
@@ -1,3 +1,3 @@
1
1
  module SwaggerYard
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swagger_yard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - chtrinh (Chris Trinh)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-15 00:00:00.000000000 Z
11
+ date: 2015-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: yard
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-its
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: apivore
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: simplecov
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -105,7 +133,6 @@ files:
105
133
  - MIT-LICENSE
106
134
  - README.md
107
135
  - Rakefile
108
- - config/routes.rb
109
136
  - lib/swagger_yard.rb
110
137
  - lib/swagger_yard/api.rb
111
138
  - lib/swagger_yard/api_declaration.rb
@@ -117,6 +144,7 @@ files:
117
144
  - lib/swagger_yard/parameter.rb
118
145
  - lib/swagger_yard/property.rb
119
146
  - lib/swagger_yard/resource_listing.rb
147
+ - lib/swagger_yard/swagger.rb
120
148
  - lib/swagger_yard/type.rb
121
149
  - lib/swagger_yard/version.rb
122
150
  homepage: http://www.synctv.com
@@ -1,6 +0,0 @@
1
- SwaggerYard::Engine.routes.draw do
2
- get '/doc', to: 'swagger#doc'
3
-
4
- get '/api', to: 'swagger#index'
5
- get '/api/*resource', to: 'swagger#show'
6
- end