apipierails3 0.0.1

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.
Files changed (171) hide show
  1. checksums.yaml +17 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +27 -0
  5. data/APACHE-LICENSE-2.0 +202 -0
  6. data/CHANGELOG.md +469 -0
  7. data/Gemfile +1 -0
  8. data/Gemfile.rails32 +6 -0
  9. data/Gemfile.rails41 +6 -0
  10. data/Gemfile.rails42 +11 -0
  11. data/Gemfile.rails50 +6 -0
  12. data/Gemfile.rails51 +7 -0
  13. data/MIT-LICENSE +20 -0
  14. data/NOTICE +4 -0
  15. data/PROPOSAL_FOR_RESPONSE_DESCRIPTIONS.md +244 -0
  16. data/README.rst +1874 -0
  17. data/Rakefile +13 -0
  18. data/apipierails3.gemspec +27 -0
  19. data/app/controllers/apipie/apipies_controller.rb +199 -0
  20. data/app/helpers/apipie_helper.rb +10 -0
  21. data/app/public/apipie/javascripts/apipie.js +6 -0
  22. data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +138 -0
  23. data/app/public/apipie/javascripts/bundled/bootstrap.js +1726 -0
  24. data/app/public/apipie/javascripts/bundled/jquery.js +5 -0
  25. data/app/public/apipie/javascripts/bundled/prettify.js +28 -0
  26. data/app/public/apipie/stylesheets/application.css +7 -0
  27. data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +12 -0
  28. data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +689 -0
  29. data/app/public/apipie/stylesheets/bundled/prettify.css +30 -0
  30. data/app/views/apipie/apipies/_disqus.html.erb +13 -0
  31. data/app/views/apipie/apipies/_errors.html.erb +23 -0
  32. data/app/views/apipie/apipies/_headers.html.erb +26 -0
  33. data/app/views/apipie/apipies/_languages.erb +6 -0
  34. data/app/views/apipie/apipies/_metadata.erb +1 -0
  35. data/app/views/apipie/apipies/_method_detail.erb +61 -0
  36. data/app/views/apipie/apipies/_params.html.erb +42 -0
  37. data/app/views/apipie/apipies/_params_plain.html.erb +20 -0
  38. data/app/views/apipie/apipies/apipie_404.html.erb +17 -0
  39. data/app/views/apipie/apipies/apipie_checksum.json.erb +1 -0
  40. data/app/views/apipie/apipies/getting_started.html.erb +6 -0
  41. data/app/views/apipie/apipies/index.html.erb +56 -0
  42. data/app/views/apipie/apipies/method.html.erb +41 -0
  43. data/app/views/apipie/apipies/plain.html.erb +77 -0
  44. data/app/views/apipie/apipies/resource.html.erb +80 -0
  45. data/app/views/apipie/apipies/static.html.erb +103 -0
  46. data/app/views/layouts/apipie/apipie.html.erb +27 -0
  47. data/config/locales/de.yml +28 -0
  48. data/config/locales/en.yml +32 -0
  49. data/config/locales/es.yml +28 -0
  50. data/config/locales/fr.yml +31 -0
  51. data/config/locales/it.yml +31 -0
  52. data/config/locales/ja.yml +31 -0
  53. data/config/locales/pl.yml +28 -0
  54. data/config/locales/pt-BR.yml +28 -0
  55. data/config/locales/ru.yml +28 -0
  56. data/config/locales/tr.yml +28 -0
  57. data/config/locales/zh-CN.yml +28 -0
  58. data/config/locales/zh-TW.yml +28 -0
  59. data/images/screenshot-1.png +0 -0
  60. data/images/screenshot-2.png +0 -0
  61. data/lib/apipie/apipie_module.rb +83 -0
  62. data/lib/apipie/application.rb +462 -0
  63. data/lib/apipie/configuration.rb +186 -0
  64. data/lib/apipie/dsl_definition.rb +607 -0
  65. data/lib/apipie/error_description.rb +44 -0
  66. data/lib/apipie/errors.rb +86 -0
  67. data/lib/apipie/extractor.rb +177 -0
  68. data/lib/apipie/extractor/collector.rb +117 -0
  69. data/lib/apipie/extractor/recorder.rb +166 -0
  70. data/lib/apipie/extractor/writer.rb +454 -0
  71. data/lib/apipie/helpers.rb +73 -0
  72. data/lib/apipie/markup.rb +48 -0
  73. data/lib/apipie/method_description.rb +273 -0
  74. data/lib/apipie/middleware/checksum_in_headers.rb +35 -0
  75. data/lib/apipie/param_description.rb +280 -0
  76. data/lib/apipie/railtie.rb +9 -0
  77. data/lib/apipie/resource_description.rb +124 -0
  78. data/lib/apipie/response_description.rb +131 -0
  79. data/lib/apipie/response_description_adapter.rb +200 -0
  80. data/lib/apipie/routes_formatter.rb +33 -0
  81. data/lib/apipie/routing.rb +16 -0
  82. data/lib/apipie/rspec/response_validation_helper.rb +192 -0
  83. data/lib/apipie/see_description.rb +39 -0
  84. data/lib/apipie/static_dispatcher.rb +69 -0
  85. data/lib/apipie/swagger_generator.rb +707 -0
  86. data/lib/apipie/tag_list_description.rb +11 -0
  87. data/lib/apipie/validator.rb +526 -0
  88. data/lib/apipie/version.rb +3 -0
  89. data/lib/apipierails3.rb +25 -0
  90. data/lib/generators/apipie/install/README +6 -0
  91. data/lib/generators/apipie/install/install_generator.rb +25 -0
  92. data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
  93. data/lib/generators/apipie/views_generator.rb +11 -0
  94. data/lib/tasks/apipie.rake +345 -0
  95. data/rel-eng/packages/.readme +3 -0
  96. data/rel-eng/packages/rubygem-apipie-rails +1 -0
  97. data/rel-eng/tito.props +5 -0
  98. data/spec/controllers/api/v1/architectures_controller_spec.rb +29 -0
  99. data/spec/controllers/api/v2/architectures_controller_spec.rb +12 -0
  100. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +11 -0
  101. data/spec/controllers/apipies_controller_spec.rb +273 -0
  102. data/spec/controllers/concerns_controller_spec.rb +42 -0
  103. data/spec/controllers/extended_controller_spec.rb +11 -0
  104. data/spec/controllers/users_controller_spec.rb +740 -0
  105. data/spec/dummy/Rakefile +7 -0
  106. data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
  107. data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +43 -0
  108. data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
  109. data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +30 -0
  110. data/spec/dummy/app/controllers/api/v2/base_controller.rb +11 -0
  111. data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +32 -0
  112. data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +33 -0
  113. data/spec/dummy/app/controllers/application_controller.rb +18 -0
  114. data/spec/dummy/app/controllers/concerns/extending_concern.rb +11 -0
  115. data/spec/dummy/app/controllers/concerns/sample_controller.rb +41 -0
  116. data/spec/dummy/app/controllers/concerns_controller.rb +8 -0
  117. data/spec/dummy/app/controllers/extended_controller.rb +14 -0
  118. data/spec/dummy/app/controllers/files_controller.rb +5 -0
  119. data/spec/dummy/app/controllers/overridden_concerns_controller.rb +31 -0
  120. data/spec/dummy/app/controllers/pets_controller.rb +408 -0
  121. data/spec/dummy/app/controllers/pets_using_auto_views_controller.rb +73 -0
  122. data/spec/dummy/app/controllers/pets_using_self_describing_classes_controller.rb +95 -0
  123. data/spec/dummy/app/controllers/tagged_cats_controller.rb +32 -0
  124. data/spec/dummy/app/controllers/tagged_dogs_controller.rb +15 -0
  125. data/spec/dummy/app/controllers/twitter_example_controller.rb +307 -0
  126. data/spec/dummy/app/controllers/users_controller.rb +297 -0
  127. data/spec/dummy/app/views/layouts/application.html.erb +21 -0
  128. data/spec/dummy/config.ru +4 -0
  129. data/spec/dummy/config/application.rb +49 -0
  130. data/spec/dummy/config/boot.rb +10 -0
  131. data/spec/dummy/config/database.yml +21 -0
  132. data/spec/dummy/config/environment.rb +8 -0
  133. data/spec/dummy/config/environments/development.rb +28 -0
  134. data/spec/dummy/config/environments/production.rb +52 -0
  135. data/spec/dummy/config/environments/test.rb +38 -0
  136. data/spec/dummy/config/initializers/apipie.rb +110 -0
  137. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  138. data/spec/dummy/config/initializers/inflections.rb +10 -0
  139. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  140. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  141. data/spec/dummy/config/initializers/session_store.rb +8 -0
  142. data/spec/dummy/config/locales/en.yml +5 -0
  143. data/spec/dummy/config/routes.rb +51 -0
  144. data/spec/dummy/db/.gitkeep +0 -0
  145. data/spec/dummy/doc/apipie_examples.json +1 -0
  146. data/spec/dummy/doc/users/desc_from_file.md +1 -0
  147. data/spec/dummy/public/404.html +26 -0
  148. data/spec/dummy/public/422.html +26 -0
  149. data/spec/dummy/public/500.html +26 -0
  150. data/spec/dummy/public/favicon.ico +0 -0
  151. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  152. data/spec/dummy/script/rails +6 -0
  153. data/spec/lib/application_spec.rb +49 -0
  154. data/spec/lib/extractor/extractor_spec.rb +9 -0
  155. data/spec/lib/extractor/middleware_spec.rb +44 -0
  156. data/spec/lib/extractor/writer_spec.rb +110 -0
  157. data/spec/lib/file_handler_spec.rb +18 -0
  158. data/spec/lib/method_description_spec.rb +98 -0
  159. data/spec/lib/param_description_spec.rb +345 -0
  160. data/spec/lib/param_group_spec.rb +60 -0
  161. data/spec/lib/rake_spec.rb +71 -0
  162. data/spec/lib/resource_description_spec.rb +48 -0
  163. data/spec/lib/swagger/openapi_2_0_schema.json +1607 -0
  164. data/spec/lib/swagger/rake_swagger_spec.rb +139 -0
  165. data/spec/lib/swagger/response_validation_spec.rb +104 -0
  166. data/spec/lib/swagger/swagger_dsl_spec.rb +658 -0
  167. data/spec/lib/validator_spec.rb +113 -0
  168. data/spec/lib/validators/array_validator_spec.rb +85 -0
  169. data/spec/spec_helper.rb +109 -0
  170. data/spec/support/rake.rb +21 -0
  171. metadata +415 -0
@@ -0,0 +1,9 @@
1
+ module Apipie
2
+ class Railtie < Rails::Railtie
3
+ initializer 'apipie.controller_additions' do
4
+ ActiveSupport.on_load :action_controller do
5
+ extend Apipie::DSL::Controller
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,124 @@
1
+ module Apipie
2
+
3
+ # Resource description
4
+ #
5
+ # version - api version (1)
6
+ # description
7
+ # path - relative path (/api/articles)
8
+ # methods - array of keys to Apipie.method_descriptions (array of Apipie::MethodDescription)
9
+ # name - human readable alias of resource (Articles)
10
+ # id - resouce name
11
+ # formats - acceptable request/response format types
12
+ # headers - array of headers
13
+ # deprecated - boolean indicating if resource is deprecated
14
+ class ResourceDescription
15
+
16
+ attr_reader :controller, :_short_description, :_full_description, :_methods, :_id,
17
+ :_path, :_name, :_params_args, :_returns_args, :_tag_list_arg, :_errors_args,
18
+ :_formats, :_parent, :_metadata, :_headers, :_deprecated
19
+
20
+ def initialize(controller, resource_name, dsl_data = nil, version = nil, &block)
21
+
22
+ @_methods = ActiveSupport::OrderedHash.new
23
+ @_params_args = []
24
+ @_errors_args = []
25
+ @_returns_args = []
26
+
27
+ @controller = controller
28
+ @_id = resource_name
29
+ @_version = version || Apipie.configuration.default_version
30
+ @_name = @_id.humanize
31
+ @_parent = Apipie.get_resource_description(controller.superclass, version)
32
+
33
+ update_from_dsl_data(dsl_data) if dsl_data
34
+ end
35
+
36
+ def update_from_dsl_data(dsl_data)
37
+ @_name = dsl_data[:resource_name] if dsl_data[:resource_name]
38
+ @_full_description = Apipie.markup_to_html(dsl_data[:description])
39
+ @_short_description = dsl_data[:short_description]
40
+ @_path = dsl_data[:path] || ""
41
+ @_formats = dsl_data[:formats]
42
+ @_errors_args = dsl_data[:errors]
43
+ @_params_args = dsl_data[:params]
44
+ @_returns_args = dsl_data[:returns]
45
+ @_tag_list_arg = dsl_data[:tag_list]
46
+ @_metadata = dsl_data[:meta]
47
+ @_api_base_url = dsl_data[:api_base_url]
48
+ @_headers = dsl_data[:headers]
49
+ @_deprecated = dsl_data[:deprecated] || false
50
+
51
+ if dsl_data[:app_info]
52
+ Apipie.configuration.app_info[_version] = dsl_data[:app_info]
53
+ end
54
+ end
55
+
56
+ def _version
57
+ @_version || @_parent.try(:_version) || Apipie.configuration.default_version
58
+ end
59
+
60
+ def _api_base_url
61
+ @_api_base_url || @_parent.try(:_api_base_url) || Apipie.api_base_url(_version)
62
+ end
63
+
64
+ def add_method_description(method_description)
65
+ Apipie.debug "@resource_descriptions[#{self._version}][#{self._name}]._methods[#{method_description.method}] = #{method_description}"
66
+ @_methods[method_description.method.to_sym] = method_description
67
+ end
68
+
69
+ def method_description(method_name)
70
+ @_methods[method_name.to_sym]
71
+ end
72
+
73
+ def remove_method_description(method_name)
74
+ if @_methods.has_key?(method_name)
75
+ @_methods.delete(method_name)
76
+ end
77
+ end
78
+
79
+ def method_descriptions
80
+ @_methods.values
81
+ end
82
+
83
+ def doc_url
84
+ crumbs = []
85
+ crumbs << _version if Apipie.configuration.version_in_url
86
+ crumbs << @_id
87
+ Apipie.full_url crumbs.join('/')
88
+ end
89
+
90
+ def api_url; "#{Apipie.api_base_url(_version)}#{@_path}"; end
91
+
92
+ def valid_method_name?(method_name)
93
+ @_methods.keys.map(&:to_s).include?(method_name.to_s)
94
+ end
95
+
96
+ def to_json(method_name = nil, lang = nil)
97
+ if method_name && !valid_method_name?(method_name)
98
+ raise "Method #{method_name} not found for resource #{_name}"
99
+ end
100
+
101
+ methods = if method_name.blank?
102
+ @_methods.collect { |key, method_description| method_description.to_json(lang) }
103
+ else
104
+ [@_methods[method_name.to_sym].to_json(lang)]
105
+ end
106
+
107
+ {
108
+ :doc_url => doc_url,
109
+ :id => _id,
110
+ :api_url => api_url,
111
+ :name => @_name,
112
+ :short_description => Apipie.app.translate(@_short_description, lang),
113
+ :full_description => Apipie.app.translate(@_full_description, lang),
114
+ :version => _version,
115
+ :formats => @_formats,
116
+ :metadata => @_metadata,
117
+ :methods => methods,
118
+ :headers => _headers,
119
+ :deprecated => @_deprecated
120
+ }
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,131 @@
1
+ module Apipie
2
+
3
+ class ResponseDescription
4
+ class ResponseObject
5
+ include Apipie::DSL::Base
6
+ include Apipie::DSL::Param
7
+
8
+ attr_accessor :additional_properties, :typename
9
+
10
+ def initialize(method_description, scope, block, typename)
11
+ @method_description = method_description
12
+ @scope = scope
13
+ @param_group = {scope: scope}
14
+ @additional_properties = false
15
+ @typename = typename
16
+
17
+ self.instance_exec(&block) if block
18
+
19
+ prepare_hash_params
20
+ end
21
+
22
+ # this routine overrides Param#_default_param_group_scope and is called if Param#param_group is
23
+ # invoked during the instance_exec call in ResponseObject#initialize
24
+ def _default_param_group_scope
25
+ @scope
26
+ end
27
+
28
+ def name
29
+ "response #{@code} for #{@method_description.method}"
30
+ end
31
+
32
+ def params_ordered
33
+ @params_ordered ||= _apipie_dsl_data[:params].map do |args|
34
+ options = args.find { |arg| arg.is_a? Hash }
35
+ options[:param_group] = @param_group
36
+ Apipie::ParamDescription.from_dsl_data(@method_description, args) unless options[:only_in] == :request
37
+ end.compact
38
+ end
39
+
40
+ def prepare_hash_params
41
+ @hash_params = params_ordered.reduce({}) do |h, param|
42
+ h.update(param.name.to_sym => param)
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+
50
+ class ResponseDescription
51
+ include Apipie::DSL::Base
52
+ include Apipie::DSL::Param
53
+
54
+ attr_reader :code, :description, :scope, :type_ref, :hash_validator, :is_array_of
55
+
56
+ def self.from_dsl_data(method_description, code, args)
57
+ options, scope, block, adapter = args
58
+
59
+ Apipie::ResponseDescription.new(method_description,
60
+ code,
61
+ options,
62
+ scope,
63
+ block,
64
+ adapter)
65
+ end
66
+
67
+ def is_array?
68
+ @is_array_of != false
69
+ end
70
+
71
+ def typename
72
+ @response_object.typename
73
+ end
74
+
75
+
76
+ def initialize(method_description, code, options, scope, block, adapter)
77
+
78
+ @type_ref = options[:param_group]
79
+ @is_array_of = options[:array_of] || false
80
+ raise ReturnsMultipleDefinitionError, options if @is_array_of && @type_ref
81
+
82
+ @type_ref ||= @is_array_of
83
+
84
+ @method_description = method_description
85
+
86
+ if code.is_a? Symbol
87
+ @code = Rack::Utils::SYMBOL_TO_STATUS_CODE[code]
88
+ else
89
+ @code = code
90
+ end
91
+
92
+ @description = options[:desc]
93
+ if @description.nil?
94
+ @description = Rack::Utils::HTTP_STATUS_CODES[@code]
95
+ raise "Cannot infer description from status code #{@code}" if @description.nil?
96
+ end
97
+ @scope = scope
98
+
99
+ if adapter
100
+ @response_object = adapter
101
+ else
102
+ @response_object = ResponseObject.new(method_description, scope, block, @type_ref)
103
+ end
104
+
105
+ @response_object.additional_properties ||= options[:additional_properties]
106
+ end
107
+
108
+ def param_description
109
+ nil
110
+ end
111
+
112
+ def params_ordered
113
+ @response_object.params_ordered
114
+ end
115
+
116
+ def additional_properties
117
+ !!@response_object.additional_properties
118
+ end
119
+ alias :allow_additional_properties :additional_properties
120
+
121
+ def to_json(lang=nil)
122
+ {
123
+ :code => code,
124
+ :description => description,
125
+ :is_array => is_array?,
126
+ :returns_object => params_ordered.map{ |param| param.to_json(lang).tap{|h| h.delete(:validations) }}.flatten,
127
+ :additional_properties => additional_properties,
128
+ }
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,200 @@
1
+ module Apipie
2
+
3
+ def self.prop(name, expected_type, options={}, sub_properties=[])
4
+ Apipie::ResponseDescriptionAdapter::PropDesc.new(name, expected_type, options, sub_properties)
5
+ end
6
+
7
+ def self.additional_properties(yesno)
8
+ Apipie::ResponseDescriptionAdapter::AdditionalPropertiesModifier.new(yesno)
9
+ end
10
+
11
+ class ResponseDescriptionAdapter
12
+ class Modifier
13
+ def apply(adapter)
14
+ raise "Modifer subclass must implement 'apply' method"
15
+ end
16
+ end
17
+
18
+ class AdditionalPropertiesModifier < Modifier
19
+ def initialize(additional_properties_allowed)
20
+ @additional_properties_allowed = additional_properties_allowed
21
+ end
22
+
23
+ def apply(adapter)
24
+ adapter.additional_properties = @additional_properties_allowed
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+ class ResponseDescriptionAdapter
31
+
32
+ #
33
+ # A ResponseDescriptionAdapter::PropDesc object pretends to be an Apipie::Param in a ResponseDescription
34
+ #
35
+ # To successfully masquerade as such, it needs to:
36
+ # respond_to?('name') and/or ['name'] returning the name of the parameter
37
+ # respond_to?('required') and/or ['required'] returning boolean
38
+ # respond_to?('additional_properties') and/or ['additional_properties'] returning boolean
39
+ # respond_to?('validator') and/or ['validator'] returning 'nil' (so type is 'string'), or an object that:
40
+ # 1) describes a type. currently type is inferred as follows:
41
+ # if validator.is_a? Apipie::Validator::EnumValidator --> respond_to? 'values' (returns array). Type is enum or boolean
42
+ # else: use v.expected_type(). This is expected to be the swagger type, or:
43
+ # numeric ==> swagger type is 'number'
44
+ # hash ==> swagger type is 'object' and validator should respond_to? 'params_ordered'
45
+ # array ==> swagger type is array and validator (FUTURE) should indicate type of element
46
+
47
+ class PropDesc
48
+
49
+ def to_s
50
+ "PropDesc -- name: #{@name} type: #{@expected_type} required: #{@required} options: #{@options} subprop count: #{@sub_properties.length} additional properties: #{@additional_properties}"
51
+ end
52
+
53
+ #
54
+ # a ResponseDescriptionAdapter::PropDesc::Validator pretends to be an Apipie::Validator
55
+ #
56
+ class Validator
57
+ attr_reader :expected_type
58
+
59
+ def [](key)
60
+ return self.send(key) if self.respond_to?(key.to_s)
61
+ end
62
+
63
+ def initialize(expected_type, enum_values=nil, sub_properties=nil)
64
+ @expected_type = expected_type
65
+ @enum_values = enum_values
66
+ @is_enum = !!enum_values
67
+ @sub_properties = sub_properties
68
+ end
69
+
70
+ def is_enum?
71
+ !!@is_enum
72
+ end
73
+
74
+ def values
75
+ @enum_values
76
+ end
77
+
78
+ def params_ordered
79
+ raise "Only validators with expected_type 'object' can have sub-properties" unless @expected_type == 'object'
80
+ @sub_properties
81
+ end
82
+ end
83
+
84
+ #======================================================================
85
+
86
+
87
+ def initialize(name, expected_type, options={}, sub_properties=[])
88
+ @name = name
89
+ @required = true
90
+ @required = false if options[:required] == false
91
+ @expected_type = expected_type
92
+ @additional_properties = false
93
+
94
+ options[:desc] ||= options[:description]
95
+ @description = options[:desc]
96
+ @options = options
97
+ @is_array = options[:is_array] || false
98
+ @sub_properties = []
99
+ for prop in sub_properties do
100
+ add_sub_property(prop)
101
+ end
102
+ end
103
+
104
+ def [](key)
105
+ return self.send(key) if self.respond_to?(key.to_s)
106
+ end
107
+
108
+ def add_sub_property(prop_desc)
109
+ raise "Only properties with expected_type 'object' can have sub-properties" unless @expected_type == 'object'
110
+ if prop_desc.is_a? PropDesc
111
+ @sub_properties << prop_desc
112
+ elsif prop_desc.is_a? Modifier
113
+ prop_desc.apply(self)
114
+ else
115
+ raise "Unrecognized prop_desc type (#{prop_desc.class})"
116
+ end
117
+ end
118
+
119
+ def to_json(lang)
120
+ {
121
+ name: name,
122
+ required: required,
123
+ validator: validator,
124
+ description: description,
125
+ additional_properties: additional_properties,
126
+ is_array: is_array?,
127
+ options: options
128
+ }
129
+ end
130
+ attr_reader :name, :required, :expected_type, :options, :description
131
+ attr_accessor :additional_properties
132
+
133
+ alias_method :desc, :description
134
+
135
+ def is_array?
136
+ @is_array
137
+ end
138
+
139
+ def validator
140
+ Validator.new(@expected_type, options[:values], @sub_properties)
141
+ end
142
+ end
143
+ end
144
+
145
+ #======================================================================
146
+
147
+ class ResponseDescriptionAdapter
148
+
149
+ def self.from_self_describing_class(cls)
150
+ adapter = ResponseDescriptionAdapter.new(cls.to_s)
151
+ props = cls.describe_own_properties
152
+ adapter.add_property_descriptions(props)
153
+ adapter
154
+ end
155
+
156
+ def initialize(typename)
157
+ @property_descs = []
158
+ @additional_properties = false
159
+ @typename = typename
160
+ end
161
+
162
+ attr_accessor :additional_properties, :typename
163
+
164
+ def allow_additional_properties
165
+ additional_properties
166
+ end
167
+
168
+ def to_json
169
+ params_ordered.to_json
170
+ end
171
+
172
+ def add(prop_desc)
173
+ if prop_desc.is_a? PropDesc
174
+ @property_descs << prop_desc
175
+ elsif prop_desc.is_a? Modifier
176
+ prop_desc.apply(self)
177
+ else
178
+ raise "Unrecognized prop_desc type (#{prop_desc.class})"
179
+ end
180
+ end
181
+
182
+ def add_property_descriptions(prop_descs)
183
+ for prop_desc in prop_descs
184
+ add(prop_desc)
185
+ end
186
+ end
187
+
188
+ def property(name, expected_type, options)
189
+ @property_descs << PropDesc.new(name, expected_type, options)
190
+ end
191
+
192
+ def params_ordered
193
+ @property_descs
194
+ end
195
+
196
+ def is_array?
197
+ false
198
+ end
199
+ end
200
+ end