rspec_api_documentation 4.9.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rspec_api_documentation/api_documentation.rb +2 -0
  3. data/lib/rspec_api_documentation/client_base.rb +8 -8
  4. data/lib/rspec_api_documentation/configuration.rb +12 -1
  5. data/lib/rspec_api_documentation/curl.rb +7 -2
  6. data/lib/rspec_api_documentation/dsl/endpoint/params.rb +19 -3
  7. data/lib/rspec_api_documentation/dsl/endpoint/set_param.rb +18 -5
  8. data/lib/rspec_api_documentation/dsl/endpoint.rb +44 -2
  9. data/lib/rspec_api_documentation/dsl/resource.rb +48 -1
  10. data/lib/rspec_api_documentation/dsl.rb +1 -1
  11. data/lib/rspec_api_documentation/example.rb +4 -0
  12. data/lib/rspec_api_documentation/open_api/contact.rb +9 -0
  13. data/lib/rspec_api_documentation/open_api/example.rb +7 -0
  14. data/lib/rspec_api_documentation/open_api/header.rb +12 -0
  15. data/lib/rspec_api_documentation/open_api/headers.rb +7 -0
  16. data/lib/rspec_api_documentation/open_api/helper.rb +29 -0
  17. data/lib/rspec_api_documentation/open_api/info.rb +12 -0
  18. data/lib/rspec_api_documentation/open_api/license.rb +8 -0
  19. data/lib/rspec_api_documentation/open_api/node.rb +112 -0
  20. data/lib/rspec_api_documentation/open_api/operation.rb +18 -0
  21. data/lib/rspec_api_documentation/open_api/parameter.rb +33 -0
  22. data/lib/rspec_api_documentation/open_api/path.rb +13 -0
  23. data/lib/rspec_api_documentation/open_api/paths.rb +7 -0
  24. data/lib/rspec_api_documentation/open_api/response.rb +10 -0
  25. data/lib/rspec_api_documentation/open_api/responses.rb +9 -0
  26. data/lib/rspec_api_documentation/open_api/root.rb +21 -0
  27. data/lib/rspec_api_documentation/open_api/schema.rb +15 -0
  28. data/lib/rspec_api_documentation/open_api/security_definitions.rb +7 -0
  29. data/lib/rspec_api_documentation/open_api/security_schema.rb +14 -0
  30. data/lib/rspec_api_documentation/open_api/tag.rb +9 -0
  31. data/lib/rspec_api_documentation/railtie.rb +1 -1
  32. data/lib/rspec_api_documentation/views/api_blueprint_example.rb +116 -0
  33. data/lib/rspec_api_documentation/views/api_blueprint_index.rb +105 -0
  34. data/lib/rspec_api_documentation/views/markdown_example.rb +1 -1
  35. data/lib/rspec_api_documentation/views/markup_example.rb +12 -3
  36. data/lib/rspec_api_documentation/views/markup_index.rb +2 -4
  37. data/lib/rspec_api_documentation/views/slate_index.rb +4 -0
  38. data/lib/rspec_api_documentation/writers/api_blueprint_writer.rb +29 -0
  39. data/lib/rspec_api_documentation/writers/combined_json_writer.rb +1 -1
  40. data/lib/rspec_api_documentation/writers/general_markup_writer.rb +20 -7
  41. data/lib/rspec_api_documentation/writers/json_iodocs_writer.rb +3 -2
  42. data/lib/rspec_api_documentation/writers/json_writer.rb +10 -6
  43. data/lib/rspec_api_documentation/writers/markdown_writer.rb +1 -1
  44. data/lib/rspec_api_documentation/writers/open_api_writer.rb +244 -0
  45. data/lib/rspec_api_documentation/writers/slate_writer.rb +2 -8
  46. data/lib/rspec_api_documentation.rb +29 -0
  47. data/templates/rspec_api_documentation/api_blueprint_index.mustache +80 -0
  48. data/templates/rspec_api_documentation/html_index.mustache +1 -1
  49. data/templates/rspec_api_documentation/markdown_example.mustache +4 -3
  50. data/templates/rspec_api_documentation/markdown_index.mustache +1 -0
  51. data/templates/rspec_api_documentation/slate_example.mustache +2 -2
  52. data/templates/rspec_api_documentation/slate_index.mustache +8 -0
  53. data/templates/rspec_api_documentation/textile_index.mustache +1 -0
  54. metadata +61 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 16b47e6bedc1c86cc5e418233eca8b80d16b5628
4
- data.tar.gz: e1da890616a2fa4cf6a8ff8c44eff5977abc32f6
3
+ metadata.gz: 8e1f18cb4e1bbf1939b21e8a4bdeb0ca17aae8f2
4
+ data.tar.gz: 98c99830570aad0754d38787cbe528cde8d795f5
5
5
  SHA512:
6
- metadata.gz: c16d4338f5d6e06f1c913a951c1370b31f2e6c85a6aef38a593d5fbd332226ad99c9fae76207e9bed5089500010a5b588a123e0354cdef25d057cbc0483a1933
7
- data.tar.gz: 03ef3fbf5306d2951fa6f3b82f08e2679306069e791ef9bf5d30f58693dbb83528bb78009821cc4b26fb1da166c33620c1e5d327c9d91f8008bd45afa93eead4
6
+ metadata.gz: 000471a180aa638ee4ac2852410f4202f210d3694118a0aafb0b31a7dde2d61baeb1e40fcc45cdfaf149962479de12390ee88096b338e7a6ad979436468ca83e
7
+ data.tar.gz: b2bb72596bdbe8896243c14b69a022e8c820e57fba621c45518ccea38b304c08b165d8b2e910644bbf96af256c989157950785654f91dd554b6a6a7042a85782
@@ -1,3 +1,5 @@
1
+ require 'rspec_api_documentation/writers/json_iodocs_writer'
2
+
1
3
  module RspecApiDocumentation
2
4
  class ApiDocumentation
3
5
  attr_reader :configuration, :index
@@ -96,14 +96,14 @@ module RspecApiDocumentation
96
96
  end
97
97
 
98
98
  def clean_out_uploaded_data(params, request_body)
99
- params.each do |_, value|
100
- if value.is_a?(Hash)
101
- if value.has_key?(:tempfile)
102
- data = value[:tempfile].read
103
- request_body = request_body.gsub(data, "[uploaded data]")
104
- else
105
- request_body = clean_out_uploaded_data(value,request_body)
106
- end
99
+ params.each do |value|
100
+ if [Hash, Array].member? value.class
101
+ request_body = if value.respond_to?(:has_key?) && value.has_key?(:tempfile)
102
+ data = value[:tempfile].read
103
+ request_body.gsub(data, "[uploaded data]")
104
+ else
105
+ clean_out_uploaded_data(value, request_body)
106
+ end
107
107
  end
108
108
  end
109
109
  request_body
@@ -51,6 +51,14 @@ module RspecApiDocumentation
51
51
  end
52
52
  end
53
53
 
54
+ add_setting :configurations_dir, :default => lambda { |config|
55
+ if defined?(Rails)
56
+ Rails.root.join('doc', 'configurations', 'api')
57
+ else
58
+ Pathname.new('doc/configurations/api')
59
+ end
60
+ }
61
+
54
62
  add_setting :docs_dir, :default => lambda { |config|
55
63
  if defined?(Rails)
56
64
  Rails.root.join("doc", "api")
@@ -75,6 +83,7 @@ module RspecApiDocumentation
75
83
  add_setting :curl_host, :default => nil
76
84
  add_setting :keep_source_order, :default => false
77
85
  add_setting :api_name, :default => "API Documentation"
86
+ add_setting :api_explanation, :default => nil
78
87
  add_setting :io_docs_protocol, :default => "http"
79
88
  add_setting :request_headers_to_include, :default => nil
80
89
  add_setting :response_headers_to_include, :default => nil
@@ -109,7 +118,7 @@ module RspecApiDocumentation
109
118
  # See RspecApiDocumentation::DSL::Endpoint#do_request
110
119
  add_setting :response_body_formatter, default: Proc.new { |_, _|
111
120
  Proc.new do |content_type, response_body|
112
- if content_type =~ /application\/json/
121
+ if content_type =~ /application\/.*json/
113
122
  JSON.pretty_generate(JSON.parse(response_body))
114
123
  else
115
124
  response_body
@@ -118,6 +127,8 @@ module RspecApiDocumentation
118
127
  }
119
128
 
120
129
  def client_method=(new_client_method)
130
+ return if new_client_method == client_method
131
+
121
132
  RspecApiDocumentation::DSL::Resource.module_eval <<-RUBY
122
133
  alias :#{new_client_method} #{client_method}
123
134
  undef #{client_method}
@@ -16,7 +16,7 @@ module RspecApiDocumentation
16
16
  end
17
17
 
18
18
  def get
19
- "curl \"#{url}#{get_data}\" -X GET #{headers}"
19
+ "curl -g \"#{url}#{get_data}\" -X GET #{headers}"
20
20
  end
21
21
 
22
22
  def head
@@ -69,7 +69,12 @@ module RspecApiDocumentation
69
69
  end
70
70
 
71
71
  def format_full_header(header, value)
72
- formatted_value = value ? value.gsub(/"/, "\\\"") : ''
72
+ formatted_value = if value.is_a?(Numeric)
73
+ value
74
+ else
75
+ value ? value.gsub(/"/, "\\\"") : ''
76
+ end
77
+
73
78
  "#{format_header(header)}: #{formatted_value}"
74
79
  end
75
80
 
@@ -13,11 +13,27 @@ module RspecApiDocumentation
13
13
  end
14
14
 
15
15
  def call
16
- parameters = example.metadata.fetch(:parameters, {}).inject({}) do |hash, param|
16
+ set_param = -> hash, param {
17
17
  SetParam.new(self, hash, param).call
18
+ }
19
+
20
+ example.metadata.fetch(:parameters, {}).inject({}, &set_param)
21
+ .deep_merge(
22
+ example.metadata.fetch(:attributes, {}).inject({}, &set_param)
23
+ ).deep_merge(extra_params)
24
+ end
25
+
26
+ def extended
27
+ example.metadata.fetch(:parameters, {}).map do |param|
28
+ p = Marshal.load(Marshal.dump(param))
29
+ p[:value] = SetParam.new(self, nil, p).value
30
+ unless p[:value]
31
+ cur = extra_params
32
+ [*p[:scope]].each { |scope| cur = cur && (cur[scope.to_sym] || cur[scope.to_s]) }
33
+ p[:value] = cur && (cur[p[:name].to_s] || cur[p[:name].to_sym])
34
+ end
35
+ p
18
36
  end
19
- parameters.deep_merge!(extra_params)
20
- parameters
21
37
  end
22
38
 
23
39
  private
@@ -15,6 +15,10 @@ module RspecApiDocumentation
15
15
  hash.deep_merge build_param_hash(key_scope || [key])
16
16
  end
17
17
 
18
+ def value
19
+ example_group.send(method_name) if method_name
20
+ end
21
+
18
22
  private
19
23
 
20
24
  attr_reader :parent, :hash, :param
@@ -36,6 +40,10 @@ module RspecApiDocumentation
36
40
  param[:method]
37
41
  end
38
42
 
43
+ def set_value
44
+ param[:value]
45
+ end
46
+
39
47
  def path_name
40
48
  scoped_key || key
41
49
  end
@@ -45,15 +53,20 @@ module RspecApiDocumentation
45
53
  end
46
54
 
47
55
  def method_name
48
- @method_name ||= begin
49
- [custom_method_name, scoped_key, key].find do |name|
50
- name && example_group.respond_to?(name)
51
- end
56
+ if custom_method_name
57
+ custom_method_name if example_group.respond_to?(custom_method_name)
58
+ elsif scoped_key && example_group.respond_to?(scoped_key)
59
+ scoped_key
60
+ elsif key && example_group.respond_to?(key)
61
+ key
62
+ elsif key && set_value
63
+ key
52
64
  end
53
65
  end
54
66
 
55
67
  def build_param_hash(keys)
56
- value = keys[1] ? build_param_hash(keys[1..-1]) : example_group.send(method_name)
68
+ value = param[:value] if param.has_key?(:value)
69
+ value ||= keys[1] ? build_param_hash(keys[1..-1]) : example_group.send(method_name)
57
70
  { keys[0].to_s => value }
58
71
  end
59
72
  end
@@ -9,6 +9,8 @@ module RspecApiDocumentation::DSL
9
9
  extend ActiveSupport::Concern
10
10
  include Rack::Test::Utils
11
11
 
12
+ URL_PARAMS_REGEX = /[:\{](\w+)\}?/.freeze
13
+
12
14
  delegate :response_headers, :response_status, :response_body, :to => :rspec_api_documentation_client
13
15
 
14
16
  module ClassMethods
@@ -36,6 +38,9 @@ module RspecApiDocumentation::DSL
36
38
  params_or_body = nil
37
39
  path_or_query = path
38
40
 
41
+ extended_parameters
42
+ extract_route_parameters!
43
+
39
44
  if http_method == :get && !query_string.blank?
40
45
  path_or_query += "?#{query_string}"
41
46
  else
@@ -72,6 +77,36 @@ module RspecApiDocumentation::DSL
72
77
  example.metadata[:headers][name] = value
73
78
  end
74
79
 
80
+ def authentication(type, value, opts = {})
81
+ name, new_opts =
82
+ case type
83
+ when :basic then ['Authorization', opts.merge(type: type)]
84
+ when :apiKey then [opts[:name], opts.merge(type: type, in: :header)]
85
+ else raise 'Not supported type for authentication'
86
+ end
87
+ header(name, value)
88
+ example.metadata[:authentications] ||= {}
89
+ example.metadata[:authentications][name] = new_opts
90
+ end
91
+
92
+ def extract_route_parameters!
93
+ example.metadata[:route].gsub(URL_PARAMS_REGEX) do |match|
94
+ value =
95
+ if extra_params.keys.include?($1)
96
+ extra_params[$1]
97
+ elsif respond_to?($1)
98
+ send($1)
99
+ else
100
+ match
101
+ end
102
+ extended_parameters << {name: match[1..-1], value: value, in: :path}
103
+ end
104
+ end
105
+
106
+ def extended_parameters
107
+ example.metadata[:extended_parameters] ||= Params.new(self, example, extra_params).extended
108
+ end
109
+
75
110
  def headers
76
111
  return unless example.metadata[:headers]
77
112
  example.metadata[:headers].inject({}) do |hash, (header, value)|
@@ -96,8 +131,16 @@ module RspecApiDocumentation::DSL
96
131
  rspec_api_documentation_client.status
97
132
  end
98
133
 
134
+ def in_path?(param)
135
+ path_params.include?(param)
136
+ end
137
+
138
+ def path_params
139
+ example.metadata[:route].scan(URL_PARAMS_REGEX).flatten
140
+ end
141
+
99
142
  def path
100
- example.metadata[:route].gsub(/:(\w+)/) do |match|
143
+ example.metadata[:route].gsub(URL_PARAMS_REGEX) do |match|
101
144
  if extra_params.keys.include?($1)
102
145
  delete_extra_param($1)
103
146
  elsif respond_to?($1)
@@ -134,6 +177,5 @@ module RspecApiDocumentation::DSL
134
177
  def delete_extra_param(key)
135
178
  @extra_params.delete(key.to_sym) || @extra_params.delete(key.to_s)
136
179
  end
137
-
138
180
  end
139
181
  end
@@ -8,7 +8,12 @@ module RspecApiDocumentation::DSL
8
8
  define_method method do |*args, &block|
9
9
  options = args.extract_options!
10
10
  options[:method] = method
11
- options[:route] = args.first
11
+ if metadata[:route_uri]
12
+ options[:route] = metadata[:route_uri]
13
+ options[:action_name] = args.first
14
+ else
15
+ options[:route] = args.first
16
+ end
12
17
  options[:api_doc_dsl] = :endpoint
13
18
  args.push(options)
14
19
  args[0] = "#{method.to_s.upcase} #{args[0]}"
@@ -38,10 +43,25 @@ module RspecApiDocumentation::DSL
38
43
  context(*args, &block)
39
44
  end
40
45
 
46
+ def route(*args, &block)
47
+ raise "You must define the route URI" if args[0].blank?
48
+ raise "You must define the route name" if args[1].blank?
49
+ options = args.extract_options!
50
+ options[:route_uri] = args[0].gsub(/\{.*\}/, "")
51
+ options[:route_optionals] = (optionals = args[0].match(/(\{.*\})/) and optionals[-1])
52
+ options[:route_name] = args[1]
53
+ args.push(options)
54
+ context(*args, &block)
55
+ end
56
+
41
57
  def parameter(name, *args)
42
58
  parameters.push(field_specification(name, *args))
43
59
  end
44
60
 
61
+ def attribute(name, *args)
62
+ attributes.push(field_specification(name, *args))
63
+ end
64
+
45
65
  def response_field(name, *args)
46
66
  response_fields.push(field_specification(name, *args))
47
67
  end
@@ -50,6 +70,25 @@ module RspecApiDocumentation::DSL
50
70
  headers[name] = value
51
71
  end
52
72
 
73
+ def authentication(type, value, opts = {})
74
+ name, new_opts =
75
+ case type
76
+ when :basic then ['Authorization', opts.merge(type: type)]
77
+ when :apiKey then [opts[:name], opts.merge(type: type, in: :header)]
78
+ else raise 'Not supported type for authentication'
79
+ end
80
+ header(name, value)
81
+ authentications[name] = new_opts
82
+ end
83
+
84
+ def route_summary(text)
85
+ safe_metadata(:route_summary, text)
86
+ end
87
+
88
+ def route_description(text)
89
+ safe_metadata(:route_description, text)
90
+ end
91
+
53
92
  def explanation(text)
54
93
  safe_metadata(:resource_explanation, text)
55
94
  end
@@ -75,6 +114,10 @@ module RspecApiDocumentation::DSL
75
114
  safe_metadata(:parameters, [])
76
115
  end
77
116
 
117
+ def attributes
118
+ safe_metadata(:attributes, [])
119
+ end
120
+
78
121
  def response_fields
79
122
  safe_metadata(:response_fields, [])
80
123
  end
@@ -83,6 +126,10 @@ module RspecApiDocumentation::DSL
83
126
  safe_metadata(:headers, {})
84
127
  end
85
128
 
129
+ def authentications
130
+ safe_metadata(:authentications, {})
131
+ end
132
+
86
133
  def parameter_keys
87
134
  parameters.map { |param| param[:name] }
88
135
  end
@@ -21,7 +21,7 @@ module RspecApiDocumentation
21
21
  options = args.last.is_a?(Hash) ? args.pop : {}
22
22
  options[:api_doc_dsl] = :resource
23
23
  options[:resource_name] = args.first.to_s
24
- options[:document] ||= :all
24
+ options[:document] = :all unless options.key?(:document)
25
25
  args.push(options)
26
26
  describe(*args, &block)
27
27
  end
@@ -38,6 +38,10 @@ module RspecApiDocumentation
38
38
  respond_to?(:parameters) && parameters.present?
39
39
  end
40
40
 
41
+ def has_attributes?
42
+ respond_to?(:attributes) && attributes.present?
43
+ end
44
+
41
45
  def has_response_fields?
42
46
  respond_to?(:response_fields) && response_fields.present?
43
47
  end
@@ -0,0 +1,9 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Contact < Node
4
+ add_setting :name, :default => 'API Support'
5
+ add_setting :url, :default => 'http://www.open-api.io/support'
6
+ add_setting :email, :default => 'support@open-api.io'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Example < Node
4
+ CHILD_CLASS = true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Header < Node
4
+ add_setting :description, :default => ''
5
+ add_setting :type, :required => true, :default => lambda { |header|
6
+ Helper.extract_type(header.public_send('x-example-value'))
7
+ }
8
+ add_setting :format
9
+ add_setting 'x-example-value'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Headers < Node
4
+ CHILD_CLASS = Header
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ module Helper
4
+ module_function
5
+
6
+ def extract_type(value)
7
+ case value
8
+ when Rack::Test::UploadedFile then :file
9
+ when Array then :array
10
+ when Hash then :object
11
+ when TrueClass, FalseClass then :boolean
12
+ when Integer then :integer
13
+ when Float then :number
14
+ else :string
15
+ end
16
+ end
17
+
18
+ def extract_items(value, opts = {})
19
+ result = {type: extract_type(value)}
20
+ if result[:type] == :array
21
+ result[:items] = extract_items(value[0], opts)
22
+ else
23
+ opts.each { |k, v| result[k] = v if v }
24
+ end
25
+ result
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Info < Node
4
+ add_setting :title, :default => 'OpenAPI Specification', :required => true
5
+ add_setting :description, :default => 'This is a sample server Petstore server.'
6
+ add_setting :termsOfService, :default => 'http://open-api.io/terms/'
7
+ add_setting :contact, :default => Contact.new, :schema => Contact
8
+ add_setting :license, :default => License.new, :schema => License
9
+ add_setting :version, :default => '1.0.0', :required => true
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class License < Node
4
+ add_setting :name, :default => 'Apache 2.0', :required => true
5
+ add_setting :url, :default => 'http://www.apache.org/licenses/LICENSE-2.0.html'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,112 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Node
4
+ # this is used to define class of incoming option attribute
5
+ # If +false+ then do not create new setting
6
+ # If +true+ then create new setting with raw passed value
7
+ # If RspecApiDocumentation::OpenApi::Node then create new setting and wrap it in this class
8
+ CHILD_CLASS = false
9
+
10
+ # This attribute allow us to hide some of children through configuration file
11
+ attr_accessor :hide
12
+
13
+ def self.add_setting(name, opts = {})
14
+ class_settings << name
15
+
16
+ define_method("#{name}_schema") { opts[:schema] || NilClass }
17
+ define_method("#{name}=") { |value| settings[name] = value }
18
+ define_method("#{name}") do
19
+ if settings.has_key?(name)
20
+ settings[name]
21
+ elsif !opts[:default].nil?
22
+ if opts[:default].respond_to?(:call)
23
+ opts[:default].call(self)
24
+ else
25
+ opts[:default]
26
+ end
27
+ elsif opts[:required]
28
+ raise "setting: #{name} required in #{self}"
29
+ end
30
+ end
31
+ end
32
+
33
+ def initialize(opts = {})
34
+ return unless opts
35
+
36
+ opts.each do |name, value|
37
+ if name.to_s == 'hide'
38
+ self.hide = value
39
+ elsif self.class::CHILD_CLASS
40
+ add_setting name, :value => self.class::CHILD_CLASS === true ? value : self.class::CHILD_CLASS.new(value)
41
+ elsif setting_exist?(name.to_sym)
42
+ schema = setting_schema(name)
43
+ converted =
44
+ case
45
+ when schema.is_a?(Array) && schema[0] <= Node then value.map { |v| v.is_a?(schema[0]) ? v : schema[0].new(v) }
46
+ when schema <= Node then value.is_a?(schema) ? value : schema.new(value)
47
+ else
48
+ value
49
+ end
50
+ assign_setting(name, converted)
51
+ else
52
+ public_send("#{name}=", value) if respond_to?("#{name}=")
53
+ end
54
+ end
55
+ end
56
+
57
+ def assign_setting(name, value); public_send("#{name}=", value) unless value.nil? end
58
+ def safe_assign_setting(name, value); assign_setting(name, value) unless settings.has_key?(name) end
59
+ def setting(name); public_send(name) end
60
+ def setting_schema(name); public_send("#{name}_schema") end
61
+ def setting_exist?(name); existing_settings.include?(name) end
62
+ def existing_settings; self.class.class_settings + instance_settings end
63
+
64
+ def add_setting(name, opts = {})
65
+ return false if setting_exist?(name)
66
+
67
+ instance_settings << name
68
+
69
+ settings[name] = opts[:value] if opts[:value]
70
+
71
+ define_singleton_method("#{name}_schema") { opts[:schema] || NilClass }
72
+ define_singleton_method("#{name}=") { |value| settings[name] = value }
73
+ define_singleton_method("#{name}") do
74
+ if settings.has_key?(name)
75
+ settings[name]
76
+ elsif !opts[:default].nil?
77
+ if opts[:default].respond_to?(:call)
78
+ opts[:default].call(self)
79
+ else
80
+ opts[:default]
81
+ end
82
+ elsif opts[:required]
83
+ raise "setting: #{name} required in #{self}"
84
+ end
85
+ end
86
+ end
87
+
88
+ def as_json
89
+ existing_settings.inject({}) do |hash, name|
90
+ value = setting(name)
91
+ case
92
+ when value.is_a?(Node)
93
+ hash[name] = value.as_json unless value.hide
94
+ when value.is_a?(Array) && value[0].is_a?(Node)
95
+ tmp = value.select { |v| !v.hide }.map { |v| v.as_json }
96
+ hash[name] = tmp unless tmp.empty?
97
+ else
98
+ hash[name] = value
99
+ end unless value.nil?
100
+
101
+ hash
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def settings; @settings ||= {} end
108
+ def instance_settings; @instance_settings ||= [] end
109
+ def self.class_settings; @class_settings ||= [] end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,18 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Operation < Node
4
+ add_setting :tags, :default => []
5
+ add_setting :summary
6
+ add_setting :description, :default => ''
7
+ add_setting :externalDocs
8
+ add_setting :operationId
9
+ add_setting :consumes
10
+ add_setting :produces
11
+ add_setting :parameters, :default => [], :schema => [Parameter]
12
+ add_setting :responses, :required => true, :schema => Responses
13
+ add_setting :schemes
14
+ add_setting :deprecated, :default => false
15
+ add_setting :security
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Parameter < Node
4
+ # Required to write example values to description of parameter when option `with_example: true` is provided
5
+ attr_accessor :value
6
+ attr_accessor :with_example
7
+
8
+ add_setting :name, :required => true
9
+ add_setting :in, :required => true
10
+ add_setting :description, :default => ''
11
+ add_setting :required, :default => lambda { |parameter| parameter.in.to_s == 'path' ? true : false }
12
+ add_setting :schema
13
+ add_setting :type
14
+ add_setting :items
15
+ add_setting :default
16
+ add_setting :minimum
17
+ add_setting :maximum
18
+ add_setting :enum
19
+
20
+ def description_with_example
21
+ str = description_without_example.dup || ''
22
+ if with_example && value
23
+ str << "\n" unless str.empty?
24
+ str << "Eg, `#{value}`"
25
+ end
26
+ str
27
+ end
28
+
29
+ alias_method :description_without_example, :description
30
+ alias_method :description, :description_with_example
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Path < Node
4
+ add_setting :get, :schema => Operation
5
+ add_setting :put, :schema => Operation
6
+ add_setting :post, :schema => Operation
7
+ add_setting :delete, :schema => Operation
8
+ add_setting :options, :schema => Operation
9
+ add_setting :head, :schema => Operation
10
+ add_setting :patch, :schema => Operation
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Paths < Node
4
+ CHILD_CLASS = Path
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ module RspecApiDocumentation
2
+ module OpenApi
3
+ class Response < Node
4
+ add_setting :description, :required => true, :default => 'Successful operation'
5
+ add_setting :schema, :schema => Schema
6
+ add_setting :headers, :schema => Headers
7
+ add_setting :examples, :schema => Example
8
+ end
9
+ end
10
+ end