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,186 @@
1
+ module Apipie
2
+ class Configuration
3
+
4
+ attr_accessor :app_name, :app_info, :copyright, :compress_examples,
5
+ :markup, :disqus_shortname,
6
+ :api_base_url, :doc_base_url, :required_by_default, :layout,
7
+ :default_version, :debug, :version_in_url, :namespaced_resources,
8
+ :validate, :validate_value, :validate_presence, :validate_key, :authenticate, :doc_path,
9
+ :show_all_examples, :process_params, :update_checksum, :checksum_path,
10
+ :link_extension, :record, :languages, :translate, :locale, :default_locale,
11
+ :persist_show_in_doc, :authorize,
12
+ :swagger_include_warning_tags, :swagger_content_type_input, :swagger_json_input_uses_refs,
13
+ :swagger_suppress_warnings, :swagger_api_host, :swagger_generate_x_computed_id_field,
14
+ :swagger_allow_additional_properties_in_response, :swagger_responses_use_refs
15
+
16
+ alias_method :validate?, :validate
17
+ alias_method :required_by_default?, :required_by_default
18
+ alias_method :namespaced_resources?, :namespaced_resources
19
+ alias_method :swagger_include_warning_tags?, :swagger_include_warning_tags
20
+ alias_method :swagger_json_input_uses_refs?, :swagger_json_input_uses_refs
21
+ alias_method :swagger_responses_use_refs?, :swagger_responses_use_refs
22
+ alias_method :swagger_generate_x_computed_id_field?, :swagger_generate_x_computed_id_field
23
+
24
+ # matcher to be used in Dir.glob to find controllers to be reloaded e.g.
25
+ #
26
+ # "#{Rails.root}/app/controllers/api/*.rb"
27
+ attr_accessor :api_controllers_matcher
28
+
29
+ # set to true if you want to reload the controllers at each refresh of the
30
+ # documentation. It requires +:api_controllers_matcher+ to be set to work
31
+ # properly.
32
+ attr_writer :reload_controllers
33
+
34
+ # specify routes if used router differ from default e.g.
35
+ #
36
+ # Api::Engine.routes
37
+ attr_accessor :api_routes
38
+
39
+ # a object responsible for transforming the routes loaded from Rails to a form
40
+ # to be used in the documentation, when using the `api!` keyword. By default,
41
+ # it's Apipie::RoutesFormatter. To customize the behaviour, one can inherit from
42
+ # from this class and override the methods as needed.
43
+ attr_accessor :routes_formatter
44
+
45
+ def reload_controllers?
46
+ @reload_controllers = Rails.env.development? unless defined? @reload_controllers
47
+ return @reload_controllers && @api_controllers_matcher
48
+ end
49
+
50
+ def validate_value
51
+ return (validate? && @validate_value)
52
+ end
53
+ alias_method :validate_value?, :validate_value
54
+
55
+ def validate_presence
56
+ return (validate? && @validate_presence)
57
+ end
58
+ alias_method :validate_presence?, :validate_presence
59
+
60
+ def validate_key
61
+ return (validate? && @validate_key)
62
+ end
63
+ alias_method :validate_key?, :validate_key
64
+
65
+ def process_value?
66
+ @process_params
67
+ end
68
+ # set to true if you want to use pregenerated documentation cache and avoid
69
+ # generating the documentation on runtime (usefull for production
70
+ # environment).
71
+ # You can generate the cache by running
72
+ #
73
+ # rake apipie:cache
74
+ attr_accessor :use_cache
75
+ alias_method :use_cache?, :use_cache
76
+
77
+ attr_writer :cache_dir
78
+ def cache_dir
79
+ @cache_dir ||= File.join(Rails.root, "public", "apipie-cache")
80
+ end
81
+
82
+ # if there is not obvious reason why the DSL should be turned on (no
83
+ # validations, cache turned on etc.), it's disabled to avoid unneeded
84
+ # allocation. It you need the DSL for other reasons, you can force the
85
+ # activation.
86
+ attr_writer :force_dsl
87
+ def force_dsl?
88
+ @force_dsl
89
+ end
90
+
91
+ # array of controller names (strings) (might include actions as well)
92
+ # to be ignored # when extracting description form calls.
93
+ # e.g. %w[Api::CommentsController Api::PostsController#post]
94
+ attr_writer :ignored_by_recorder
95
+ def ignored_by_recorder
96
+ @ignored_by_recorder ||= []
97
+ @ignored_by_recorder.map(&:to_s)
98
+ end
99
+
100
+ # array of controller names (strings) (might include actions as well)
101
+ # to be ignored # when generationg the documentation
102
+ # e.g. %w[Api::CommentsController Api::PostsController#post]
103
+ attr_writer :ignored
104
+ def ignored
105
+ @ignored ||= []
106
+ @ignored.map(&:to_s)
107
+ end
108
+
109
+ # Persist the show_in_doc value in the examples if true. Use this if you
110
+ # cannot set the flag in the tests themselves (no rspec for example).
111
+ attr_writer :persist_show_in_doc
112
+
113
+ # comment to put before docs that was generated automatically. It's used to
114
+ # determine if the description should be overwritten next recording.
115
+ # If you want to keep the documentation (prevent from overriding), remove
116
+ # the line above the docs.
117
+ attr_writer :generated_doc_disclaimer
118
+ def generated_doc_disclaimer
119
+ @generated_doc_disclaimer ||= "# DOC GENERATED AUTOMATICALLY: REMOVE THIS LINE TO PREVENT REGENERATING NEXT TIME"
120
+ end
121
+
122
+ def use_disqus?
123
+ !@disqus_shortname.blank?
124
+ end
125
+
126
+ # set app description for default version
127
+ # to maintain backward compatibility
128
+ # new way: config.app_info[version] = description
129
+ def app_info=(description)
130
+ version = Apipie.configuration.default_version
131
+ @app_info[version] = description
132
+ end
133
+
134
+ # set base url for default version of API
135
+ # to set it for specific version use
136
+ # config.api_base_url[version] = url
137
+ def api_base_url=(url)
138
+ version = Apipie.configuration.default_version
139
+ @api_base_url[version] = url
140
+ end
141
+
142
+ def api_routes
143
+ @api_routes || Rails.application.routes
144
+ end
145
+
146
+ def initialize
147
+ @markup = Apipie::Markup::RDoc.new
148
+ @app_name = "Another API"
149
+ @app_info = HashWithIndifferentAccess.new
150
+ @copyright = nil
151
+ @validate = :implicitly
152
+ @validate_value = true
153
+ @validate_presence = true
154
+ @validate_key = false
155
+ @required_by_default = false
156
+ @api_base_url = HashWithIndifferentAccess.new
157
+ @doc_base_url = "/apipie"
158
+ @layout = "apipie/apipie"
159
+ @disqus_shortname = nil
160
+ @default_version = "1.0"
161
+ @debug = false
162
+ @version_in_url = true
163
+ @namespaced_resources = false
164
+ @doc_path = "doc"
165
+ @process_params = false
166
+ @checksum_path = [@doc_base_url, '/api/']
167
+ @update_checksum = false
168
+ @link_extension = ".html"
169
+ @record = false
170
+ @languages = []
171
+ @default_locale = 'en'
172
+ @locale = lambda { |locale| @default_locale }
173
+ @translate = lambda { |str, locale| str }
174
+ @persist_show_in_doc = false
175
+ @routes_formatter = RoutesFormatter.new
176
+ @swagger_content_type_input = :form_data # this can be :json or :form_data
177
+ @swagger_json_input_uses_refs = false
178
+ @swagger_include_warning_tags = false
179
+ @swagger_suppress_warnings = false #[105,100,102]
180
+ @swagger_api_host = "localhost:3000"
181
+ @swagger_generate_x_computed_id_field = false
182
+ @swagger_allow_additional_properties_in_response = false
183
+ @swagger_responses_use_refs = true
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,607 @@
1
+ # Apipie DSL functions.
2
+
3
+ module Apipie
4
+
5
+ # DSL is a module that provides #api, #error, #param, #returns.
6
+ module DSL
7
+
8
+ module Base
9
+ attr_reader :apipie_resource_descriptions, :api_params
10
+
11
+ def _apipie_eval_dsl(*args, &block)
12
+ raise 'The Apipie DLS data need to be cleared before evaluating new block' if @_apipie_dsl_data
13
+ instance_exec(*args, &block)
14
+ return _apipie_dsl_data
15
+ ensure
16
+ _apipie_dsl_data_clear
17
+ end
18
+
19
+ private
20
+
21
+ def _apipie_dsl_data
22
+ @_apipie_dsl_data ||= _apipie_dsl_data_init
23
+ end
24
+
25
+ def _apipie_dsl_data_clear
26
+ @_apipie_dsl_data = nil
27
+ end
28
+
29
+ def _apipie_dsl_data_init
30
+ @_apipie_dsl_data = {
31
+ :api => false,
32
+ :api_args => [],
33
+ :api_from_routes => nil,
34
+ :errors => [],
35
+ :tag_list => [],
36
+ :returns => {},
37
+ :params => [],
38
+ :headers => [],
39
+ :resource_id => nil,
40
+ :short_description => nil,
41
+ :description => nil,
42
+ :examples => [],
43
+ :see => [],
44
+ :formats => nil,
45
+ :api_versions => [],
46
+ :meta => nil,
47
+ :show => true,
48
+ :deprecated => false
49
+ }
50
+ end
51
+ end
52
+
53
+ module Resource
54
+ # by default, the resource id is derived from controller_name
55
+ # it can be overwritten with.
56
+ #
57
+ # resource_id "my_own_resource_id"
58
+ def resource_id(resource_id)
59
+ Apipie.set_resource_id(@controller, resource_id)
60
+ end
61
+
62
+ def name(name)
63
+ _apipie_dsl_data[:resource_name] = name
64
+ end
65
+
66
+ def api_base_url(url)
67
+ _apipie_dsl_data[:api_base_url] = url
68
+ end
69
+
70
+ def short(short)
71
+ _apipie_dsl_data[:short_description] = short
72
+ end
73
+ alias :short_description :short
74
+
75
+ def path(path)
76
+ _apipie_dsl_data[:path] = path
77
+ end
78
+
79
+ def app_info(app_info)
80
+ _apipie_dsl_data[:app_info] = app_info
81
+ end
82
+
83
+ def deprecated(value)
84
+ _apipie_dsl_data[:deprecated] = value
85
+ end
86
+
87
+ end
88
+
89
+ module Action
90
+
91
+ def def_param_group(name, &block)
92
+ Apipie.add_param_group(self, name, &block)
93
+ end
94
+
95
+ #
96
+ # # load paths from routes and don't provide description
97
+ # api
98
+ #
99
+ def api(method, path, desc = nil, options={}) #:doc:
100
+ return unless Apipie.active_dsl?
101
+ _apipie_dsl_data[:api] = true
102
+ _apipie_dsl_data[:api_args] << [method, path, desc, options]
103
+ end
104
+
105
+ # # load paths from routes
106
+ # api! "short description",
107
+ #
108
+ def api!(desc = nil, options={}) #:doc:
109
+ return unless Apipie.active_dsl?
110
+ _apipie_dsl_data[:api] = true
111
+ _apipie_dsl_data[:api_from_routes] = { :desc => desc, :options =>options }
112
+ end
113
+
114
+ # Reference other similar method
115
+ #
116
+ # api :PUT, '/articles/:id'
117
+ # see "articles#create"
118
+ # def update; end
119
+ def see(*args)
120
+ return unless Apipie.active_dsl?
121
+ _apipie_dsl_data[:see] << args
122
+ end
123
+
124
+ # Show some example of what does the described
125
+ # method return.
126
+ def example(example) #:doc:
127
+ return unless Apipie.active_dsl?
128
+ _apipie_dsl_data[:examples] << example.strip_heredoc
129
+ end
130
+
131
+ # Determine if the method should be included
132
+ # in the documentation
133
+ def show(show)
134
+ return unless Apipie.active_dsl?
135
+ _apipie_dsl_data[:show] = show
136
+ end
137
+
138
+ # Describe whole resource
139
+ #
140
+ # Example:
141
+ # api :desc => "Show user profile", :path => "/users/", :version => '1.0 - 3.4.2012'
142
+ # param :id, Fixnum, :desc => "User ID", :required => true
143
+ # desc <<-EOS
144
+ # Long description...
145
+ # EOS
146
+ def resource_description(options = {}, &block) #:doc:
147
+ return unless Apipie.active_dsl?
148
+ raise ArgumentError, "Block expected" unless block_given?
149
+
150
+ dsl_data = ResourceDescriptionDsl.eval_dsl(self, &block)
151
+ versions = dsl_data[:api_versions]
152
+ @apipie_resource_descriptions = versions.map do |version|
153
+ Apipie.define_resource_description(self, version, dsl_data)
154
+ end
155
+ Apipie.set_controller_versions(self, versions)
156
+ end
157
+ end
158
+
159
+ module Common
160
+ def api_versions(*versions)
161
+ _apipie_dsl_data[:api_versions].concat(versions)
162
+ end
163
+ alias :api_version :api_versions
164
+
165
+ # Describe the next method.
166
+ #
167
+ # Example:
168
+ # desc "print hello world"
169
+ # def hello_world
170
+ # puts "hello world"
171
+ # end
172
+ #
173
+ def desc(description) #:doc:
174
+ return unless Apipie.active_dsl?
175
+ if _apipie_dsl_data[:description]
176
+ raise "Double method description."
177
+ end
178
+ _apipie_dsl_data[:description] = description
179
+ end
180
+ alias :description :desc
181
+ alias :full_description :desc
182
+
183
+ # describe next method with document in given path
184
+ # in convension, these doc located under "#{Rails.root}/doc"
185
+ # Example:
186
+ # document "hello_world.md"
187
+ # def hello_world
188
+ # puts "hello world"
189
+ # end
190
+ def document path
191
+ content = File.open(File.join(Rails.root, Apipie.configuration.doc_path, path)).read
192
+ desc content
193
+ end
194
+
195
+ # Describe available request/response formats
196
+ #
197
+ # formats ['json', 'jsonp', 'xml']
198
+ def formats(formats) #:doc:
199
+ return unless Apipie.active_dsl?
200
+ _apipie_dsl_data[:formats] = formats
201
+ end
202
+
203
+ # Describe additional metadata
204
+ #
205
+ # meta :author => { :name => 'John', :surname => 'Doe' }
206
+ def meta(meta) #:doc:
207
+ _apipie_dsl_data[:meta] = meta
208
+ end
209
+
210
+
211
+ # Describe possible errors
212
+ #
213
+ # Example:
214
+ # error :desc => "speaker is sleeping", :code => 500, :meta => [:some, :more, :data]
215
+ # error 500, "speaker is sleeping"
216
+ # def hello_world
217
+ # return 500 if self.speaker.sleeping?
218
+ # puts "hello world"
219
+ # end
220
+ #
221
+ def error(code_or_options, desc=nil, options={}) #:doc:
222
+ return unless Apipie.active_dsl?
223
+ _apipie_dsl_data[:errors] << [code_or_options, desc, options]
224
+ end
225
+
226
+ # Add tags to resources and actions group operations together.
227
+ def tags(*args)
228
+ return unless Apipie.active_dsl?
229
+ tags = args.length == 1 ? args.first : args
230
+ _apipie_dsl_data[:tag_list] += tags
231
+ end
232
+
233
+ def _apipie_define_validators(description)
234
+
235
+ # [re]define method only if validation is turned on
236
+ if description && (Apipie.configuration.validate == true ||
237
+ Apipie.configuration.validate == :implicitly ||
238
+ Apipie.configuration.validate == :explicitly)
239
+
240
+ _apipie_save_method_params(description.method, description.params)
241
+
242
+ unless instance_methods.include?(:apipie_validations)
243
+ define_method(:apipie_validations) do
244
+ method_params = self.class._apipie_get_method_params(action_name)
245
+
246
+ if Apipie.configuration.validate_presence?
247
+ method_params.each do |_, param|
248
+ # check if required parameters are present
249
+ raise ParamMissing.new(param) if param.required && !params.has_key?(param.name)
250
+ end
251
+ end
252
+
253
+ if Apipie.configuration.validate_value?
254
+ method_params.each do |_, param|
255
+ # params validations
256
+ param.validate(params[:"#{param.name}"]) if params.has_key?(param.name)
257
+ end
258
+ end
259
+
260
+ # Only allow params passed in that are defined keys in the api
261
+ # Auto skip the default params (format, controller, action)
262
+ if Apipie.configuration.validate_key?
263
+ params.reject{|k,_| %w[format controller action].include?(k.to_s) }.each_pair do |param, _|
264
+ # params allowed
265
+ raise UnknownParam.new(param) if method_params.select {|_,p| p.name.to_s == param.to_s}.empty?
266
+ end
267
+ end
268
+
269
+ if Apipie.configuration.process_value?
270
+ @api_params ||= {}
271
+ method_params.each do |_, param|
272
+ # params processing
273
+ @api_params[param.as] = param.process_value(params[:"#{param.name}"]) if params.has_key?(param.name)
274
+ end
275
+ end
276
+ end
277
+ end
278
+
279
+ if (Apipie.configuration.validate == :implicitly || Apipie.configuration.validate == true)
280
+ old_method = instance_method(description.method)
281
+
282
+ define_method(description.method) do |*args|
283
+ apipie_validations
284
+
285
+ # run the original method code
286
+ old_method.bind(self).call(*args)
287
+ end
288
+ end
289
+
290
+ end
291
+ end
292
+
293
+ def _apipie_save_method_params(method, params)
294
+ @method_params ||= {}
295
+ @method_params[method] = params
296
+ end
297
+
298
+ def _apipie_get_method_params(method)
299
+ @method_params[method]
300
+ end
301
+
302
+ # Describe request header.
303
+ # Headers can't be validated with config.validate_presence = true
304
+ #
305
+ # Example:
306
+ # header 'ClientId', "client-id"
307
+ # def show
308
+ # render :text => headers['HTTP_CLIENT_ID']
309
+ # end
310
+ #
311
+ def header(header_name, description, options = {}) #:doc
312
+ return unless Apipie.active_dsl?
313
+ _apipie_dsl_data[:headers] << {
314
+ name: header_name,
315
+ description: description,
316
+ options: options
317
+ }
318
+ end
319
+ end
320
+
321
+
322
+ # this describes the params, it's in separate module because it's
323
+ # used in Validators as well
324
+ module Param
325
+ # Describe method's parameter
326
+ #
327
+ # Example:
328
+ # param :greeting, String, :desc => "arbitrary text", :required => true
329
+ # def hello_world(greeting)
330
+ # puts greeting
331
+ # end
332
+ #
333
+ def param(param_name, validator, desc_or_options = nil, options = {}, &block) #:doc:
334
+ return unless Apipie.active_dsl?
335
+ _apipie_dsl_data[:params] << [param_name,
336
+ validator,
337
+ desc_or_options,
338
+ options.merge(:param_group => @_current_param_group),
339
+ block]
340
+ end
341
+
342
+ def property(param_name, validator, desc_or_options = nil, options = {}, &block) #:doc:
343
+ return unless Apipie.active_dsl?
344
+ options[:only_in] ||= :response
345
+ options[:required] = true if options[:required].nil?
346
+ param(param_name, validator, desc_or_options, options, &block)
347
+ end
348
+
349
+ # Reuses param group for this method. The definition is looked up
350
+ # in scope of this controller. If the group was defined in
351
+ # different controller, the second param can be used to specify it.
352
+ # when using action_aware parmas, you can specify :as =>
353
+ # :create or :update to explicitly say how it should behave
354
+ def param_group(name, scope_or_options = nil, options = {})
355
+ if scope_or_options.is_a? Hash
356
+ options.merge!(scope_or_options)
357
+ scope = options[:scope]
358
+ else
359
+ scope = scope_or_options
360
+ end
361
+ scope ||= _default_param_group_scope
362
+
363
+ @_current_param_group = {
364
+ :scope => scope,
365
+ :name => name,
366
+ :options => options,
367
+ :from_concern => scope.apipie_concern?
368
+ }
369
+ self.instance_exec(&Apipie.get_param_group(scope, name))
370
+ ensure
371
+ @_current_param_group = nil
372
+ end
373
+
374
+ # Describe possible responses
375
+ #
376
+ # Example:
377
+ # def_param_group :user do
378
+ # param :user, Hash do
379
+ # param :name, String
380
+ # end
381
+ # end
382
+ #
383
+ # returns :user, "the speaker"
384
+ # returns "the speaker" do
385
+ # param_group: :user
386
+ # end
387
+ # returns :param_group => :user, "the speaker"
388
+ # returns :user, :code => 201, :desc => "the created speaker record"
389
+ # returns :array_of => :user, "many speakers"
390
+ # def hello_world
391
+ # render json: {user: {name: "Alfred"}}
392
+ # end
393
+ #
394
+ def returns(pgroup_or_options, desc_or_options=nil, options={}, &block) #:doc:
395
+ return unless Apipie.active_dsl?
396
+
397
+
398
+ if desc_or_options.is_a? Hash
399
+ options.merge!(desc_or_options)
400
+ elsif !desc_or_options.nil?
401
+ options[:desc] = desc_or_options
402
+ end
403
+
404
+ if pgroup_or_options.is_a? Hash
405
+ options.merge!(pgroup_or_options)
406
+ else
407
+ options[:param_group] = pgroup_or_options
408
+ end
409
+
410
+ code = options[:code] || 200
411
+ scope = options[:scope] || _default_param_group_scope
412
+ descriptor = options[:param_group] || options[:array_of]
413
+
414
+ if block.nil?
415
+ if descriptor.is_a? ResponseDescriptionAdapter
416
+ adapter = descriptor
417
+ elsif descriptor.respond_to? :describe_own_properties
418
+ adapter = ResponseDescriptionAdapter.from_self_describing_class(descriptor)
419
+ else
420
+ begin
421
+ block = Apipie.get_param_group(scope, descriptor) if descriptor
422
+ rescue
423
+ raise "No param_group or self-describing class named #{descriptor}"
424
+ end
425
+ end
426
+ elsif descriptor
427
+ raise "cannot specify both block and param_group"
428
+ end
429
+
430
+ _apipie_dsl_data[:returns][code] = [options, scope, block, adapter]
431
+ end
432
+
433
+ # where the group definition should be looked up when no scope
434
+ # given. This is expected to return a controller.
435
+ def _default_param_group_scope
436
+ self
437
+ end
438
+ end
439
+
440
+ module Controller
441
+ include Apipie::DSL::Base
442
+ include Apipie::DSL::Common
443
+ include Apipie::DSL::Action
444
+ include Apipie::DSL::Param
445
+
446
+ # defines the substitutions to be made in the API paths deifned
447
+ # in concerns included. For example:
448
+ #
449
+ # There is this method defined in concern:
450
+ #
451
+ # api GET ':controller_path/:id'
452
+ # def show
453
+ # # ...
454
+ # end
455
+ #
456
+ # If you include the concern into some controller, you can
457
+ # specify the value for :controller_path like this:
458
+ #
459
+ # apipie_concern_subst(:controller_path => '/users')
460
+ # include ::Concerns::SampleController
461
+ #
462
+ # The resulting path will be '/users/:id'.
463
+ #
464
+ # It has to be specified before the concern is included.
465
+ #
466
+ # If not specified, the default predefined substitions are
467
+ #
468
+ # {:conroller_path => controller.controller_path,
469
+ # :resource_id => `resource_id_from_apipie` }
470
+ def apipie_concern_subst(subst_hash)
471
+ _apipie_concern_subst.merge!(subst_hash)
472
+ end
473
+
474
+ # Allows to update existing params after definition was made (usually needed
475
+ # when extending the API form plugins).
476
+ #
477
+ # UsersController.apipie_update_params([:create, :update]) do
478
+ # param :user, Hash do
479
+ # param :oauth, String
480
+ # end
481
+ # end
482
+ #
483
+ # The block is evaluated in scope of the controller. Ohe can pass some additional
484
+ # objects via additional arguments like this:
485
+ #
486
+ # UsersController.apipie_update_params([:create, :update], [:name, :secret]) do |param_names|
487
+ # param :user, Hash do
488
+ # param_names.each { |p| param p, String }
489
+ # end
490
+ # end
491
+ def apipie_update_params(methods, *args, &block)
492
+ methods.each do |method|
493
+ method_description = Apipie.get_method_description(self, method)
494
+ unless method_description
495
+ raise "Could not find method description for #{self}##{method}. Was the method defined?"
496
+ end
497
+ dsl_data = _apipie_eval_dsl(*args, &block)
498
+ params_ordered = dsl_data[:params].map do |args|
499
+ Apipie::ParamDescription.from_dsl_data(method_description, args)
500
+ end
501
+ ParamDescription.merge(method_description.params_ordered_self, params_ordered)
502
+ end
503
+ end
504
+
505
+ def _apipie_concern_subst
506
+ @_apipie_concern_subst ||= {:controller_path => self.controller_path,
507
+ :resource_id => Apipie.get_resource_name(self)}
508
+ end
509
+
510
+ def _apipie_perform_concern_subst(string)
511
+ return _apipie_concern_subst.reduce(string) do |ret, (key, val)|
512
+ ret.gsub(":#{key}", val)
513
+ end
514
+ end
515
+
516
+ def apipie_concern?
517
+ false
518
+ end
519
+
520
+ # create method api and redefine newly added method
521
+ def method_added(method_name) #:doc:
522
+ super
523
+ return if !Apipie.active_dsl? || !_apipie_dsl_data[:api]
524
+
525
+ return if _apipie_dsl_data[:api_args].blank? && _apipie_dsl_data[:api_from_routes].blank?
526
+
527
+ # remove method description if exists and create new one
528
+ Apipie.remove_method_description(self, _apipie_dsl_data[:api_versions], method_name)
529
+ description = Apipie.define_method_description(self, method_name, _apipie_dsl_data)
530
+
531
+ _apipie_dsl_data_clear
532
+ _apipie_define_validators(description)
533
+ ensure
534
+ _apipie_dsl_data_clear
535
+ end
536
+ end
537
+
538
+ module Concern
539
+ include Apipie::DSL::Base
540
+ include Apipie::DSL::Common
541
+ include Apipie::DSL::Action
542
+ include Apipie::DSL::Param
543
+
544
+ # the concern was included into a controller
545
+ def included(controller)
546
+ super
547
+ _apipie_concern_data.each do |method_name, _apipie_dsl_data|
548
+ # remove method description if exists and create new one
549
+ description = Apipie.define_method_description(controller, method_name, _apipie_dsl_data)
550
+ controller._apipie_define_validators(description)
551
+ end
552
+ _apipie_concern_update_api_blocks.each do |(methods, block)|
553
+ controller.apipie_update_params(methods, &block)
554
+ end
555
+ end
556
+
557
+ def _apipie_concern_data
558
+ @_apipie_concern_data ||= []
559
+ end
560
+
561
+ def _apipie_concern_update_api_blocks
562
+ @_apipie_concern_update_api_blocks ||= []
563
+ end
564
+
565
+ def apipie_concern?
566
+ true
567
+ end
568
+
569
+ # create method api and redefine newly added method
570
+ def method_added(method_name) #:doc:
571
+ super
572
+
573
+ return if ! Apipie.active_dsl? || !_apipie_dsl_data[:api]
574
+
575
+ _apipie_concern_data << [method_name, _apipie_dsl_data.merge(:from_concern => true)]
576
+ ensure
577
+ _apipie_dsl_data_clear
578
+ end
579
+
580
+ def update_api(*methods, &block)
581
+ _apipie_concern_update_api_blocks << [methods, block]
582
+ end
583
+
584
+ end
585
+
586
+ class ResourceDescriptionDsl
587
+ include Apipie::DSL::Base
588
+ include Apipie::DSL::Common
589
+ include Apipie::DSL::Resource
590
+ include Apipie::DSL::Param
591
+
592
+ def initialize(controller)
593
+ @controller = controller
594
+ end
595
+
596
+ # evaluates resource description DSL and returns results
597
+ def self.eval_dsl(controller, &block)
598
+ dsl_data = self.new(controller)._apipie_eval_dsl(&block)
599
+ if dsl_data[:api_versions].empty?
600
+ dsl_data[:api_versions] = Apipie.controller_versions(controller)
601
+ end
602
+ dsl_data
603
+ end
604
+ end
605
+
606
+ end # module DSL
607
+ end # module Apipie