grape-swagger 2.1.2 → 2.1.4

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,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrapeSwagger
4
+ module RequestParamParsers
5
+ class Headers
6
+ attr_reader :route
7
+
8
+ def self.parse(route, params, settings, endpoint)
9
+ new(route, params, settings, endpoint).parse
10
+ end
11
+
12
+ def initialize(route, _params, _settings, _endpoint)
13
+ @route = route
14
+ end
15
+
16
+ def parse
17
+ return {} unless route.headers
18
+
19
+ route.headers.each_with_object({}) do |(name, definition), accum|
20
+ # Extract the description from any key type (string or symbol)
21
+ description = definition[:description] || definition['description']
22
+ doc = { desc: description, in: 'header' }
23
+
24
+ header_attrs = definition.symbolize_keys.except(:description, 'description')
25
+ header_attrs[:type] = definition[:type].titleize if definition[:type]
26
+ header_attrs[:documentation] = doc
27
+
28
+ accum[name] = header_attrs
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrapeSwagger
4
+ module RequestParamParsers
5
+ class Route
6
+ DEFAULT_PARAM_TYPE = { required: true, type: 'Integer' }.freeze
7
+
8
+ attr_reader :route
9
+
10
+ def self.parse(route, params, settings, endpoint)
11
+ new(route, params, settings, endpoint).parse
12
+ end
13
+
14
+ def initialize(route, _params, _settings, _endpoint)
15
+ @route = route
16
+ end
17
+
18
+ def parse
19
+ stackable_values = route.app&.inheritable_setting&.namespace_stackable
20
+
21
+ path_params = build_path_params(stackable_values)
22
+
23
+ fulfill_params(path_params)
24
+ end
25
+
26
+ private
27
+
28
+ def build_path_params(stackable_values)
29
+ params = {}
30
+
31
+ while stackable_values.is_a?(Grape::Util::StackableValues)
32
+ params.merge!(fetch_inherited_params(stackable_values))
33
+ stackable_values = stackable_values.inherited_values
34
+ end
35
+
36
+ params
37
+ end
38
+
39
+ def fetch_inherited_params(stackable_values)
40
+ return {} unless stackable_values.new_values
41
+
42
+ namespaces = stackable_values.new_values[:namespace] || []
43
+
44
+ namespaces.each_with_object({}) do |namespace, params|
45
+ space = namespace.space.to_s.gsub(':', '')
46
+ params[space] = namespace.options || {}
47
+ end
48
+ end
49
+
50
+ def fulfill_params(path_params)
51
+ # Merge path params options into route params
52
+ route.params.each_with_object({}) do |(param, definition), accum|
53
+ # The route.params hash includes both parametrized params (with a string as a key)
54
+ # and well-defined params from body/query (with a symbol as a key).
55
+ # We avoid overriding well-defined params with parametrized ones.
56
+ key = param.is_a?(String) ? param.to_sym : param
57
+ next if param.is_a?(String) && accum.key?(key)
58
+
59
+ defined_options = definition.is_a?(Hash) ? definition : {}
60
+ value = (path_params[param] || {}).merge(defined_options)
61
+ accum[key] = value.empty? ? DEFAULT_PARAM_TYPE : value
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GrapeSwagger
4
+ class TokenOwnerResolver
5
+ class << self
6
+ SUPPORTED_ARITY_TYPES = %i[req opt rest keyreq key keyrest].freeze
7
+ UNRESOLVED = Object.new.freeze
8
+ private_constant :UNRESOLVED
9
+
10
+ def resolve(endpoint, method_name)
11
+ return if method_name.nil?
12
+
13
+ method_name = method_name.to_sym
14
+ return endpoint.public_send(method_name) if endpoint.respond_to?(method_name, true)
15
+
16
+ helper_value = resolve_from_helpers(endpoint, method_name)
17
+ return helper_value unless helper_value.equal?(UNRESOLVED)
18
+
19
+ raise Errors::TokenOwnerNotFound, "undefined method `#{method_name}` for #{endpoint.class}"
20
+ end
21
+
22
+ def evaluate_proc(callable, token_owner)
23
+ return callable.call unless accepts_argument?(callable)
24
+
25
+ callable.call(token_owner)
26
+ end
27
+
28
+ private
29
+
30
+ def resolve_from_helpers(endpoint, method_name)
31
+ helpers = gather_helpers(endpoint)
32
+ return UNRESOLVED if helpers.empty?
33
+
34
+ helpers.each do |helper|
35
+ resolved = resolve_from_helper(endpoint, helper, method_name)
36
+ return resolved unless resolved.equal?(UNRESOLVED)
37
+ end
38
+
39
+ UNRESOLVED
40
+ end
41
+
42
+ def gather_helpers(endpoint)
43
+ return [] if endpoint.nil?
44
+
45
+ stackable_helpers = fetch_stackable_helpers(endpoint)
46
+ normalize_helpers(stackable_helpers)
47
+ end
48
+
49
+ def fetch_stackable_helpers(endpoint)
50
+ return unless endpoint.respond_to?(:inheritable_setting)
51
+
52
+ setting = endpoint.inheritable_setting
53
+ return unless setting.respond_to?(:namespace_stackable)
54
+
55
+ namespace_stackable = setting.namespace_stackable
56
+ return unless namespace_stackable.respond_to?(:[])
57
+
58
+ namespace_stackable[:helpers]
59
+ rescue NameError
60
+ nil
61
+ end
62
+
63
+ def normalize_helpers(helpers)
64
+ case helpers
65
+ when nil, false
66
+ []
67
+ when Module
68
+ [helpers]
69
+ when Array
70
+ helpers.compact
71
+ else
72
+ if helpers.respond_to?(:key?) && helpers.respond_to?(:[]) && helpers.key?(:helpers)
73
+ normalize_helpers(helpers[:helpers])
74
+ elsif helpers.respond_to?(:to_a)
75
+ Array(helpers.to_a).flatten.compact
76
+ else
77
+ Array(helpers).compact
78
+ end
79
+ end
80
+ end
81
+
82
+ def resolve_from_helper(endpoint, helper, method_name)
83
+ return UNRESOLVED unless helper_method_defined?(helper, method_name)
84
+
85
+ helper.instance_method(method_name).bind(endpoint).call
86
+ rescue NameError
87
+ UNRESOLVED
88
+ end
89
+
90
+ def helper_method_defined?(helper, method_name)
91
+ helper.method_defined?(method_name) || helper.private_method_defined?(method_name)
92
+ end
93
+
94
+ def accepts_argument?(callable)
95
+ return false unless callable.respond_to?(:parameters)
96
+
97
+ callable.parameters.any? { |type, _| SUPPORTED_ARITY_TYPES.include?(type) }
98
+ end
99
+ end
100
+ end
101
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrapeSwagger
4
- VERSION = '2.1.2'
4
+ VERSION = '2.1.4'
5
5
  end
data/lib/grape-swagger.rb CHANGED
@@ -10,22 +10,28 @@ require 'grape-swagger/errors'
10
10
 
11
11
  require 'grape-swagger/doc_methods'
12
12
  require 'grape-swagger/model_parsers'
13
+ require 'grape-swagger/request_param_parser_registry'
14
+ require 'grape-swagger/token_owner_resolver'
13
15
 
14
16
  module GrapeSwagger
15
17
  class << self
16
18
  def model_parsers
17
19
  @model_parsers ||= GrapeSwagger::ModelParsers.new
18
20
  end
21
+
22
+ def request_param_parsers
23
+ @request_param_parsers ||= GrapeSwagger::RequestParamParserRegistry.new
24
+ end
19
25
  end
20
26
  autoload :Rake, 'grape-swagger/rake/oapi_tasks'
21
27
 
22
28
  # Copied from https://github.com/ruby-grape/grape/blob/v2.2.0/lib/grape/formatter.rb
23
29
  FORMATTER_DEFAULTS = {
30
+ xml: Grape::Formatter::Xml,
31
+ serializable_hash: Grape::Formatter::SerializableHash,
24
32
  json: Grape::Formatter::Json,
25
33
  jsonapi: Grape::Formatter::Json,
26
- serializable_hash: Grape::Formatter::SerializableHash,
27
- txt: Grape::Formatter::Txt,
28
- xml: Grape::Formatter::Xml
34
+ txt: Grape::Formatter::Txt
29
35
  }.freeze
30
36
 
31
37
  # Copied from https://github.com/ruby-grape/grape/blob/v2.2.0/lib/grape/content_types.rb
@@ -179,12 +185,13 @@ module SwaggerDocumentationAdder
179
185
  endpoint = endpoints.shift
180
186
 
181
187
  endpoints.push(*endpoint.options[:app].endpoints) if endpoint.options[:app]
182
- ns = endpoint.namespace_stackable(:namespace).last
188
+ namespace_stackable = endpoint.inheritable_setting.namespace_stackable
189
+ ns = (namespace_stackable[:namespace] || []).last
183
190
  next unless ns
184
191
 
185
192
  # use the full namespace here (not the latest level only)
186
193
  # and strip leading slash
187
- mount_path = (endpoint.namespace_stackable(:mount_path) || []).join('/')
194
+ mount_path = (namespace_stackable[:mount_path] || []).join('/')
188
195
  full_namespace = (mount_path + endpoint.namespace).sub(/\/{2,}/, '/').sub(/^\//, '')
189
196
  combined_namespaces[full_namespace] = ns
190
197
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-swagger
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - LeFnord
8
8
  - Tim Vandecasteele
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2025-01-07 00:00:00.000000000 Z
12
+ date: 2026-02-03 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: grape
@@ -19,7 +20,7 @@ dependencies:
19
20
  version: '1.7'
20
21
  - - "<"
21
22
  - !ruby/object:Gem::Version
22
- version: '3.0'
23
+ version: '4.0'
23
24
  type: :runtime
24
25
  prerelease: false
25
26
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,21 +30,8 @@ dependencies:
29
30
  version: '1.7'
30
31
  - - "<"
31
32
  - !ruby/object:Gem::Version
32
- version: '3.0'
33
- - !ruby/object:Gem::Dependency
34
- name: rack-test
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '2'
40
- type: :runtime
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '2'
33
+ version: '4.0'
34
+ description:
47
35
  email:
48
36
  - pscholz.le@gmail.com
49
37
  - tim.vandecasteele@gmail.com
@@ -52,6 +40,7 @@ extensions: []
52
40
  extra_rdoc_files: []
53
41
  files:
54
42
  - CHANGELOG.md
43
+ - CLAUDE.md
55
44
  - CONTRIBUTING.md
56
45
  - LICENSE.txt
57
46
  - README.md
@@ -64,7 +53,6 @@ files:
64
53
  - lib/grape-swagger/doc_methods/data_type.rb
65
54
  - lib/grape-swagger/doc_methods/extensions.rb
66
55
  - lib/grape-swagger/doc_methods/format_data.rb
67
- - lib/grape-swagger/doc_methods/headers.rb
68
56
  - lib/grape-swagger/doc_methods/move_params.rb
69
57
  - lib/grape-swagger/doc_methods/operation_id.rb
70
58
  - lib/grape-swagger/doc_methods/optional_object.rb
@@ -75,17 +63,22 @@ files:
75
63
  - lib/grape-swagger/doc_methods/tag_name_description.rb
76
64
  - lib/grape-swagger/doc_methods/version.rb
77
65
  - lib/grape-swagger/endpoint.rb
78
- - lib/grape-swagger/endpoint/params_parser.rb
79
66
  - lib/grape-swagger/errors.rb
80
67
  - lib/grape-swagger/instance.rb
81
68
  - lib/grape-swagger/model_parsers.rb
82
69
  - lib/grape-swagger/rake/oapi_tasks.rb
70
+ - lib/grape-swagger/request_param_parser_registry.rb
71
+ - lib/grape-swagger/request_param_parsers/body.rb
72
+ - lib/grape-swagger/request_param_parsers/headers.rb
73
+ - lib/grape-swagger/request_param_parsers/route.rb
74
+ - lib/grape-swagger/token_owner_resolver.rb
83
75
  - lib/grape-swagger/version.rb
84
76
  homepage: https://github.com/ruby-grape/grape-swagger
85
77
  licenses:
86
78
  - MIT
87
79
  metadata:
88
80
  rubygems_mfa_required: 'true'
81
+ post_install_message:
89
82
  rdoc_options: []
90
83
  require_paths:
91
84
  - lib
@@ -100,7 +93,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
93
  - !ruby/object:Gem::Version
101
94
  version: '0'
102
95
  requirements: []
103
- rubygems_version: 3.6.2
96
+ rubygems_version: 3.5.22
97
+ signing_key:
104
98
  specification_version: 4
105
99
  summary: Add auto generated documentation to your Grape API that can be displayed
106
100
  with Swagger.
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GrapeSwagger
4
- module DocMethods
5
- class Headers
6
- class << self
7
- def parse(route)
8
- route.headers.to_a.map do |route_header|
9
- route_header.tap do |header|
10
- hash = header[1]
11
- description = hash.delete('description')
12
- hash[:documentation] = { desc: description, in: 'header' }
13
- hash[:type] = hash['type'].titleize if hash['type']
14
- end
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end