swaggard 1.0.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b3e1aa159808f0d01c9e6759727b97aff8a0cb4c383f441a3ca602e6b302da8b
4
- data.tar.gz: 4f3b2511fbd15049e5e8746af31174705544a477b70cc0cbbe30d24563897ee7
3
+ metadata.gz: 7a49ea847a04d150e7b42923bf6a8290950f5fa18c53deba16907c36a59a664f
4
+ data.tar.gz: 3986acba75f1b962c13ca5b93ceb2f1481609f3516b5438689822d0916675952
5
5
  SHA512:
6
- metadata.gz: 244da8fb5d6d234aab95d0b6e1b6bf13fd1dd7f519daf93aa2ff1f21dd05e2d0a886aa1e80f07ae7181d7541fc853b83bf5f711465976577cea725175bb0be36
7
- data.tar.gz: c82e666367b0555c8d7de02f785c9045aa53c77c591855afa5e1c093f294c8b69cff7cbcc5a9eb70cdda1004f855cf149148fede20be4f4296515878855aa34c
6
+ metadata.gz: 3fd5f67a5c03861c8e78a77088f1aa4712a75d9fb251a2c1acb2e597f5609ae81b935d5ac090f5e49ae9dba7ab0a0ceb17be40a553ea183185d3fc88cf14c13f
7
+ data.tar.gz: db5042eb41674f3f85f94aa860743eed9861eb49d0bc44b9ed02bc36dcb578816552ff44dc2016a61bb01c5f90d71c0b3a31b23f55fd538d8b53403a9ac3cc85
data/README.md CHANGED
@@ -11,6 +11,8 @@ the supported rails version.
11
11
 
12
12
  Swaggard Version | Swagger UI Version | Supported Rails Versions
13
13
  ---------------- | ------------------- | ------------------------
14
+ 1.1.x | 2.2.8 | 4 - 6
15
+ 1.0.x | 2.2.8 | 4 - 5
14
16
  0.5.x | 2.2.8 | 4 - 5
15
17
  0.4.x | 2.2.8 | 4
16
18
  0.3.x | 2.1.3 | 4
@@ -43,6 +45,13 @@ Mount your engine
43
45
 
44
46
  mount Swaggard::Engine, at: '/api_docs/swagger/'
45
47
 
48
+ Make sure the asset pipeline is enabled by either requiring all railties
49
+ or just the sprockets one:
50
+
51
+ # config/application.rb
52
+
53
+ require 'sprockets/railtie'
54
+
46
55
  Access your service documentation
47
56
 
48
57
  open http://localhost:3000/api_docs/swagger/
@@ -1,5 +1,8 @@
1
- Rails.application.config.assets.precompile += %w[swaggard/application_print.css
2
- swaggard/favicon-32x32.png
3
- swaggard/favicon-16x16.png
4
- swaggard/lang/*.js
5
- swaggard/logo_small.png]
1
+ if Rails::Application.instance_methods.include?(:assets_manifest)
2
+ Rails.application.config.assets.precompile += %w[swaggard/application_print.css
3
+ swaggard/favicon-32x32.png
4
+ swaggard/favicon-16x16.png
5
+ swaggard/lang/*.js
6
+ swaggard/logo_small.png]
7
+
8
+ end
@@ -7,7 +7,7 @@ module Swaggard
7
7
  def initialize
8
8
  @paths = {}
9
9
  @tags = {}
10
- @definitions = []
10
+ @definitions = {}
11
11
  end
12
12
 
13
13
  def add_tag(tag)
@@ -19,7 +19,7 @@ module Swaggard
19
19
  def add_operation(operation)
20
20
  @paths[operation.path] ||= Swagger::Path.new(operation.path)
21
21
  @paths[operation.path].add_operation(operation)
22
- @definitions.concat(operation.definitions)
22
+ @definitions.merge!(operation.definitions)
23
23
  end
24
24
 
25
25
  def ignore_put_if_patch!
@@ -51,7 +51,7 @@ module Swaggard
51
51
  'produces' => Swaggard.configuration.api_formats.map { |format| "application/#{format}" },
52
52
  'tags' => @tags.map { |_, tag| tag.to_doc },
53
53
  'paths' => Hash[@paths.values.map { |path| [format_path(path.path), path.to_doc] }],
54
- 'definitions' => Hash[@definitions.map { |definition| [definition.id, definition.to_doc] }]
54
+ 'definitions' => Hash[@definitions.map { |id, definition| [id, definition.to_doc(@definitions)] }]
55
55
  }
56
56
  end
57
57
 
@@ -1,20 +1,23 @@
1
- unless Rails::Application.instance_methods.include?(:assets_manifest)
2
- warn <<-END
3
- [Swaggard] It seems you are using an api only rails setup, but swaggard
4
- [Swaggard] neeeds sprockets in order to work so its going to require it.
5
- [Swaggard] This might have undesired side effects, if thats not the case
6
- [Swaggard] you can ignore this warning.
7
- END
8
- require 'sprockets/railtie'
9
- end
10
-
11
1
  module Swaggard
12
2
  class Engine < ::Rails::Engine
13
3
  isolate_namespace Swaggard
14
4
 
5
+ def rake?
6
+ File.basename($PROGRAM_NAME) == 'rake'
7
+ end
8
+
15
9
  initializer 'swaggard.finisher_hook', after: :finisher_hook do |app|
16
10
  app.reload_routes!
17
11
 
12
+ if Rails.env.development? && !rake? && !app.methods.include?(:assets_manifest)
13
+ warn <<~END
14
+ [Swaggard] It seems you are using an api only rails setup, but swaggard
15
+ [Swaggard] web app needs sprockets in order to work. Make sure to add
16
+ [Swaggard] require 'sprockets/railtie'.
17
+ [Swaggard] If you plan to use it
18
+ END
19
+ end
20
+
18
21
  Swaggard.configure do |config|
19
22
  unless config.controllers_path
20
23
  config.controllers_path = "#{app.root}/app/controllers/**/*.rb"
@@ -4,23 +4,29 @@ require_relative '../swagger/tag'
4
4
  module Swaggard
5
5
  module Parsers
6
6
  class Controller
7
-
8
7
  def run(yard_objects)
9
- tag = nil
8
+ tags = nil
10
9
  operations = {}
11
10
 
12
11
  yard_objects.each do |yard_object|
13
12
  if yard_object.type == :class
14
- tag = Swagger::Tag.new(yard_object)
15
- elsif tag && yard_object.type == :method
13
+ tags = get_tags(yard_object)
14
+ elsif tags && yard_object.type == :method
16
15
  name = yard_object.name
17
16
  operations[name.to_s] = yard_object
18
17
  end
19
18
  end
20
19
 
21
- return tag, operations
20
+ return tags, operations
22
21
  end
23
22
 
23
+ private
24
+
25
+ def get_tags(yard_object)
26
+ tags = yard_object.tags.select { |tag| tag.tag_name == 'tag' }
27
+
28
+ tags.map { |tag| Swagger::Tag.new(yard_object, tag) }
29
+ end
24
30
  end
25
31
  end
26
32
  end
@@ -6,24 +6,33 @@ module Swaggard
6
6
  class Models
7
7
 
8
8
  def run(yard_objects)
9
- definitions = []
9
+ definitions = {}
10
10
 
11
11
  yard_objects.each do |yard_object|
12
- next unless yard_object.type == :class
12
+ definition = parse_yard_object(yard_object)
13
13
 
14
- definition = Swagger::Definition.new(yard_object.path)
14
+ definitions[definition.id] = definition if definition
15
+ end
16
+
17
+ definitions
18
+ end
15
19
 
20
+ def parse_yard_object(yard_object)
21
+ return unless yard_object.type == :class
22
+
23
+ Swagger::Definition.new(yard_object.path, ancestors: yard_object.inheritance_tree.map(&:path)).tap do |definition|
16
24
  yard_object.tags.each do |tag|
17
- property = Swagger::Property.new(tag)
18
- definition.add_property(property)
25
+ case tag.tag_name
26
+ when 'attr'
27
+ property = Swagger::Property.new(tag)
28
+ definition.add_property(property)
29
+ when 'ignore_inherited'
30
+ definition.ignore_inherited = true
31
+ end
19
32
  end
20
-
21
- definitions << definition
22
33
  end
23
-
24
- definitions
25
34
  end
26
35
 
27
36
  end
28
37
  end
29
- end
38
+ end
@@ -3,13 +3,15 @@ module Swaggard
3
3
  class Definition
4
4
 
5
5
  attr_reader :id
6
- attr_writer :description, :title
6
+ attr_writer :description, :title, :ignore_inherited
7
7
 
8
- def initialize(id)
8
+ def initialize(id, ancestors: [])
9
9
  @id = id
10
10
  @title = ''
11
11
  @properties = []
12
12
  @description = ''
13
+ @ancestors = ancestors
14
+ @ignore_inherited = false
13
15
  end
14
16
 
15
17
  def add_property(property)
@@ -20,15 +22,35 @@ module Swaggard
20
22
  @properties.empty?
21
23
  end
22
24
 
23
- def to_doc
25
+ def properties(definitions)
26
+ inherited_properties(definitions)
27
+ .concat(@properties)
28
+ .uniq { |property| property.id }
29
+ end
30
+
31
+ def inherited_properties(definitions)
32
+ return [] if @ignore_inherited
33
+
34
+ @ancestors.flat_map do |ancestor|
35
+ definition = definitions[ancestor]
36
+
37
+ next unless definition && definition.id != id
38
+
39
+ definition.properties(definitions)
40
+ end.compact
41
+ end
42
+
43
+ def to_doc(definitions)
24
44
  {}.tap do |doc|
25
45
  doc['title'] = @title if @title.present?
26
46
  doc['type'] = 'object'
27
47
 
28
48
  doc['description'] = @description if @description.present?
29
49
 
30
- doc['properties'] = Hash[@properties.map { |property| [property.id, property.to_doc] }]
31
- required_properties = @properties.select(&:required?).map(&:id)
50
+ all_properties = properties(definitions)
51
+
52
+ doc['properties'] = Hash[all_properties.map { |property| [property.id, property.to_doc] }]
53
+ required_properties = all_properties.select(&:required?).map(&:id)
32
54
  doc['required'] = required_properties if required_properties.any?
33
55
  end
34
56
 
@@ -32,7 +32,7 @@ module Swaggard
32
32
 
33
33
  case yard_tag.tag_name
34
34
  when 'operation_id'
35
- @operation_id = value
35
+ @operation_id = "#{@tag.name}.#{value}"
36
36
  when 'query_parameter'
37
37
  @parameters << Parameters::Query.new(value)
38
38
  when 'form_parameter'
@@ -92,8 +92,12 @@ module Swaggard
92
92
  end
93
93
 
94
94
  def definitions
95
- @responses.map(&:definition).compact.tap do |definitions|
96
- definitions << @body_parameter.definition if @body_parameter
95
+ @responses.map(&:definition).compact.inject({}) do |definitions, definition|
96
+ definitions[definition.id] = definition
97
+ end.tap do |definitions|
98
+ next unless @body_parameter
99
+
100
+ definitions[@body_parameter.definition.id] = @body_parameter.definition
97
101
  end
98
102
  end
99
103
 
@@ -1,20 +1,20 @@
1
1
  module Swaggard
2
2
  module Swagger
3
3
  class Tag
4
-
5
4
  attr_accessor :name, :description
6
5
 
7
- attr_reader :controller_class
6
+ attr_reader :controller_class, :controller_name, :route
8
7
 
9
- def initialize(yard_object)
8
+ def initialize(yard_object, tag)
10
9
  controller_name = "#{yard_object.namespace}::#{yard_object.name}"
11
10
 
12
11
  @yard_name = yard_object.name
13
12
  @controller_class = controller_name.constantize
14
-
15
- tag = yard_object.tags.find { |tag| tag.tag_name == 'tag' }
13
+ @controller_name = controller_class.controller_path
16
14
 
17
15
  @name = tag ? tag.text : "#{@controller_class.controller_path}"
16
+ @name, @route = @name.split(' ')
17
+
18
18
  @description = yard_object.docstring || ''
19
19
  end
20
20
 
@@ -24,7 +24,6 @@ module Swaggard
24
24
  'description' => @description
25
25
  }
26
26
  end
27
-
28
27
  end
29
28
  end
30
29
  end
@@ -1,3 +1,3 @@
1
1
  module Swaggard
2
- VERSION = '1.0.1'
2
+ VERSION = '1.2.0'
3
3
  end
data/lib/swaggard.rb CHANGED
@@ -38,6 +38,7 @@ module Swaggard
38
38
  ::YARD::Tags::Library.define_tag('Response description', :response_description)
39
39
  ::YARD::Tags::Library.define_tag('Response example', :response_example)
40
40
  ::YARD::Tags::Library.define_tag('Response header', :response_header)
41
+ ::YARD::Tags::Library.define_tag('Ignore inherited attributes', :ignore_inherited)
41
42
  end
42
43
 
43
44
  def get_doc(host = nil)
@@ -61,21 +62,25 @@ module Swaggard
61
62
  @api.ignore_put_if_patch! if Swaggard.configuration.ignore_put_if_patch_exists
62
63
  end
63
64
 
65
+ def tag_matches?(tag, controller_name, path)
66
+ matches = tag.controller_name == controller_name
67
+
68
+ return matches unless tag.route.present?
69
+
70
+ matches && Regexp.new(tag.route).match?(path)
71
+ end
72
+
64
73
  def build_operation(path, verb, route)
65
74
  controller_name = route[:controller]
66
75
  action_name = route[:action]
67
76
 
68
- return unless controllers[controller_name]
69
-
70
- controller_tag = controllers[controller_name][:tag]
77
+ controller_tag, controller_operations = tags.find { |tag, _operations| tag_matches?(tag, controller_name, path) }
71
78
 
72
79
  return unless controller_tag
73
80
 
74
- return unless controllers[controller_name][:operations]
75
-
76
- return unless controllers[controller_name][:operations][action_name]
81
+ return unless controller_operations[action_name]
77
82
 
78
- operation_yard_object = controllers[controller_name][:operations][action_name]
83
+ operation_yard_object = controller_operations[action_name]
79
84
 
80
85
  return unless operation_yard_object
81
86
 
@@ -100,23 +105,25 @@ module Swaggard
100
105
  end
101
106
  end
102
107
 
103
- def controllers
104
- return @controllers if @controllers
108
+ def tags
109
+ return @tags if @tags
105
110
 
106
111
  parser = Parsers::Controller.new
107
112
 
108
- @controllers = {}
113
+ @tags = []
109
114
  Dir[configuration.controllers_path].each do |file|
110
115
  yard_objects = get_yard_objects(file)
111
116
 
112
- tag, operations = parser.run(yard_objects)
117
+ tags, operations = parser.run(yard_objects)
113
118
 
114
- next unless tag
119
+ next unless tags
115
120
 
116
- @controllers[tag.controller_class.controller_path] ||= { tag: tag, operations: operations }
121
+ tags.each do |tag|
122
+ @tags << [tag, operations]
123
+ end
117
124
  end
118
125
 
119
- @controllers
126
+ @tags
120
127
  end
121
128
 
122
129
  def routes
@@ -129,12 +136,12 @@ module Swaggard
129
136
  def parse_models
130
137
  parser = Parsers::Models.new
131
138
 
132
- definitions =[]
139
+ definitions = {}
133
140
  configuration.models_paths.each do |path|
134
141
  Dir[path].each do |file|
135
142
  yard_objects = get_yard_objects(file)
136
143
 
137
- definitions.concat(parser.run(yard_objects))
144
+ definitions.merge!(parser.run(yard_objects))
138
145
  end
139
146
 
140
147
  @api.definitions = definitions
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swaggard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Gomez
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-31 00:00:00.000000000 Z
11
+ date: 2021-12-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '4.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6.0'
22
+ version: '7.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '4.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6.0'
32
+ version: '7.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: sass-rails
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -192,7 +192,6 @@ files:
192
192
  - spec/fixtures/dummy/config/application.rb
193
193
  - spec/fixtures/dummy/config/environments/development.rb
194
194
  - spec/fixtures/dummy/config/routes.rb
195
- - spec/fixtures/dummy/log/development.log
196
195
  - spec/fixtures/swagger_schema.json
197
196
  - spec/integration/swaggard_spec.rb
198
197
  - spec/spec_helper.rb
@@ -200,7 +199,7 @@ homepage: https://github.com/adrian-gomez/swaggard
200
199
  licenses:
201
200
  - MIT
202
201
  metadata: {}
203
- post_install_message:
202
+ post_install_message:
204
203
  rdoc_options: []
205
204
  require_paths:
206
205
  - lib
@@ -215,19 +214,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
214
  - !ruby/object:Gem::Version
216
215
  version: '0'
217
216
  requirements: []
218
- rubygems_version: 3.0.3
219
- signing_key:
217
+ rubygems_version: 3.2.15
218
+ signing_key:
220
219
  specification_version: 4
221
220
  summary: 'Swaggard: Swagger Rails REST API doc using yard YARD'
222
221
  test_files:
223
- - spec/spec_helper.rb
224
- - spec/integration/swaggard_spec.rb
225
- - spec/fixtures/swagger_schema.json
226
- - spec/fixtures/dummy/app/controllers/pets_controller.rb
227
- - spec/fixtures/dummy/app/controllers/application_controller.rb
222
+ - spec/fixtures/api.json
228
223
  - spec/fixtures/dummy/app/controllers/admin/pets_controller.rb
229
- - spec/fixtures/dummy/config/routes.rb
230
- - spec/fixtures/dummy/config/environments/development.rb
224
+ - spec/fixtures/dummy/app/controllers/application_controller.rb
225
+ - spec/fixtures/dummy/app/controllers/pets_controller.rb
231
226
  - spec/fixtures/dummy/config/application.rb
232
- - spec/fixtures/dummy/log/development.log
233
- - spec/fixtures/api.json
227
+ - spec/fixtures/dummy/config/environments/development.rb
228
+ - spec/fixtures/dummy/config/routes.rb
229
+ - spec/fixtures/swagger_schema.json
230
+ - spec/integration/swaggard_spec.rb
231
+ - spec/spec_helper.rb
File without changes