jmoses_apipie-rails 0.0.23

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. data/.gitignore +11 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +4 -0
  4. data/APACHE-LICENSE-2.0 +202 -0
  5. data/CHANGELOG +55 -0
  6. data/Gemfile +3 -0
  7. data/MIT-LICENSE +20 -0
  8. data/NOTICE +4 -0
  9. data/README.rst +938 -0
  10. data/Rakefile +13 -0
  11. data/apipie-rails.gemspec +26 -0
  12. data/app/controllers/apipie/apipies_controller.rb +105 -0
  13. data/app/public/apipie/javascripts/apipie.js +6 -0
  14. data/app/public/apipie/javascripts/bundled/bootstrap-collapse.js +138 -0
  15. data/app/public/apipie/javascripts/bundled/bootstrap.js +1726 -0
  16. data/app/public/apipie/javascripts/bundled/jquery-1.7.2.js +9404 -0
  17. data/app/public/apipie/javascripts/bundled/prettify.js +28 -0
  18. data/app/public/apipie/stylesheets/application.css +20 -0
  19. data/app/public/apipie/stylesheets/bundled/bootstrap-responsive.min.css +12 -0
  20. data/app/public/apipie/stylesheets/bundled/bootstrap.min.css +689 -0
  21. data/app/public/apipie/stylesheets/bundled/prettify.css +30 -0
  22. data/app/views/apipie/apipies/_disqus.html.erb +11 -0
  23. data/app/views/apipie/apipies/_params.html.erb +29 -0
  24. data/app/views/apipie/apipies/_params_plain.html.erb +16 -0
  25. data/app/views/apipie/apipies/apipie_404.html.erb +12 -0
  26. data/app/views/apipie/apipies/getting_started.html.erb +4 -0
  27. data/app/views/apipie/apipies/index.html.erb +43 -0
  28. data/app/views/apipie/apipies/method.html.erb +71 -0
  29. data/app/views/apipie/apipies/plain.html.erb +70 -0
  30. data/app/views/apipie/apipies/resource.html.erb +98 -0
  31. data/app/views/apipie/apipies/static.html.erb +101 -0
  32. data/app/views/layouts/apipie/apipie.html.erb +26 -0
  33. data/lib/apipie-rails.rb +15 -0
  34. data/lib/apipie/apipie_module.rb +62 -0
  35. data/lib/apipie/application.rb +334 -0
  36. data/lib/apipie/client/generator.rb +135 -0
  37. data/lib/apipie/configuration.rb +128 -0
  38. data/lib/apipie/dsl_definition.rb +379 -0
  39. data/lib/apipie/error_description.rb +25 -0
  40. data/lib/apipie/errors.rb +38 -0
  41. data/lib/apipie/extractor.rb +151 -0
  42. data/lib/apipie/extractor/collector.rb +113 -0
  43. data/lib/apipie/extractor/recorder.rb +124 -0
  44. data/lib/apipie/extractor/writer.rb +367 -0
  45. data/lib/apipie/helpers.rb +52 -0
  46. data/lib/apipie/markup.rb +48 -0
  47. data/lib/apipie/method_description.rb +191 -0
  48. data/lib/apipie/param_description.rb +204 -0
  49. data/lib/apipie/railtie.rb +9 -0
  50. data/lib/apipie/resource_description.rb +102 -0
  51. data/lib/apipie/routing.rb +15 -0
  52. data/lib/apipie/see_description.rb +39 -0
  53. data/lib/apipie/static_dispatcher.rb +59 -0
  54. data/lib/apipie/validator.rb +310 -0
  55. data/lib/apipie/version.rb +3 -0
  56. data/lib/generators/apipie/install/README +6 -0
  57. data/lib/generators/apipie/install/install_generator.rb +25 -0
  58. data/lib/generators/apipie/install/templates/initializer.rb.erb +7 -0
  59. data/lib/tasks/apipie.rake +166 -0
  60. data/rel-eng/packages/.readme +3 -0
  61. data/rel-eng/packages/rubygem-apipie-rails +1 -0
  62. data/rel-eng/tito.props +5 -0
  63. data/spec/controllers/api/v1/architectures_controller_spec.rb +30 -0
  64. data/spec/controllers/api/v2/architectures_controller_spec.rb +12 -0
  65. data/spec/controllers/api/v2/nested/resources_controller_spec.rb +11 -0
  66. data/spec/controllers/apipies_controller_spec.rb +141 -0
  67. data/spec/controllers/concerns_controller_spec.rb +42 -0
  68. data/spec/controllers/users_controller_spec.rb +473 -0
  69. data/spec/dummy/Rakefile +7 -0
  70. data/spec/dummy/app/controllers/api/base_controller.rb +4 -0
  71. data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +42 -0
  72. data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
  73. data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +30 -0
  74. data/spec/dummy/app/controllers/api/v2/base_controller.rb +11 -0
  75. data/spec/dummy/app/controllers/api/v2/nested/architectures_controller.rb +30 -0
  76. data/spec/dummy/app/controllers/api/v2/nested/resources_controller.rb +33 -0
  77. data/spec/dummy/app/controllers/application_controller.rb +6 -0
  78. data/spec/dummy/app/controllers/concerns/sample_controller.rb +39 -0
  79. data/spec/dummy/app/controllers/concerns_controller.rb +8 -0
  80. data/spec/dummy/app/controllers/twitter_example_controller.rb +302 -0
  81. data/spec/dummy/app/controllers/users_controller.rb +251 -0
  82. data/spec/dummy/app/views/layouts/application.html.erb +21 -0
  83. data/spec/dummy/config.ru +4 -0
  84. data/spec/dummy/config/application.rb +45 -0
  85. data/spec/dummy/config/boot.rb +10 -0
  86. data/spec/dummy/config/database.yml +21 -0
  87. data/spec/dummy/config/environment.rb +8 -0
  88. data/spec/dummy/config/environments/development.rb +25 -0
  89. data/spec/dummy/config/environments/production.rb +49 -0
  90. data/spec/dummy/config/environments/test.rb +35 -0
  91. data/spec/dummy/config/initializers/apipie.rb +102 -0
  92. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  93. data/spec/dummy/config/initializers/inflections.rb +10 -0
  94. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  95. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  96. data/spec/dummy/config/initializers/session_store.rb +8 -0
  97. data/spec/dummy/config/locales/en.yml +5 -0
  98. data/spec/dummy/config/routes.rb +22 -0
  99. data/spec/dummy/db/.gitkeep +0 -0
  100. data/spec/dummy/doc/apipie_examples.yml +28 -0
  101. data/spec/dummy/public/404.html +26 -0
  102. data/spec/dummy/public/422.html +26 -0
  103. data/spec/dummy/public/500.html +26 -0
  104. data/spec/dummy/public/favicon.ico +0 -0
  105. data/spec/dummy/public/javascripts/application.js +2 -0
  106. data/spec/dummy/public/javascripts/controls.js +965 -0
  107. data/spec/dummy/public/javascripts/dragdrop.js +974 -0
  108. data/spec/dummy/public/javascripts/effects.js +1123 -0
  109. data/spec/dummy/public/javascripts/prototype.js +6001 -0
  110. data/spec/dummy/public/javascripts/rails.js +202 -0
  111. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  112. data/spec/dummy/script/rails +6 -0
  113. data/spec/lib/application_spec.rb +38 -0
  114. data/spec/lib/method_description_spec.rb +30 -0
  115. data/spec/lib/param_description_spec.rb +174 -0
  116. data/spec/lib/param_group_spec.rb +45 -0
  117. data/spec/lib/resource_description_spec.rb +30 -0
  118. data/spec/lib/validator_spec.rb +46 -0
  119. data/spec/spec_helper.rb +32 -0
  120. metadata +337 -0
@@ -0,0 +1,128 @@
1
+ module Apipie
2
+ class Configuration
3
+
4
+ attr_accessor :app_name, :app_info, :copyright, :markup, :disqus_shortname,
5
+ :api_base_url, :doc_base_url, :required_by_default, :layout,
6
+ :default_version, :debug, :version_in_url, :namespaced_resources,
7
+ :validate, :validate_value, :validate_presence
8
+
9
+
10
+ alias_method :validate?, :validate
11
+ alias_method :required_by_default?, :required_by_default
12
+ alias_method :namespaced_resources?, :namespaced_resources
13
+
14
+ # matcher to be used in Dir.glob to find controllers to be reloaded e.g.
15
+ #
16
+ # "#{Rails.root}/app/controllers/api/*.rb"
17
+ attr_accessor :api_controllers_matcher
18
+
19
+ # set to true if you want to reload the controllers at each refresh of the
20
+ # documentation. It requires +:api_controllers_matcher+ to be set to work
21
+ # properly.
22
+ attr_writer :reload_controllers
23
+
24
+ def reload_controllers?
25
+ @reload_controllers = Rails.env.development? unless defined? @reload_controllers
26
+ return @reload_controllers && @api_controllers_matcher
27
+ end
28
+
29
+ def validate_value
30
+ return (validate? && @validate_value)
31
+ end
32
+ alias_method :validate_value?, :validate_value
33
+
34
+ def validate_presence
35
+ return (validate? && @validate_presence)
36
+ end
37
+ alias_method :validate_presence?, :validate_presence
38
+
39
+ # set to true if you want to use pregenerated documentation cache and avoid
40
+ # generating the documentation on runtime (usefull for production
41
+ # environment).
42
+ # You can generate the cache by running
43
+ #
44
+ # rake apipie:cache
45
+ attr_accessor :use_cache
46
+ alias_method :use_cache?, :use_cache
47
+
48
+ attr_writer :cache_dir
49
+ def cache_dir
50
+ @cache_dir ||= File.join(Rails.root, "public", "apipie-cache")
51
+ end
52
+
53
+ # if there is not obvious reason why the DSL should be turned on (no
54
+ # validations, cache turned on etc.), it's disabled to avoid unneeded
55
+ # allocation. It you need the DSL for other reasons, you can force the
56
+ # activation.
57
+ attr_writer :force_dsl
58
+ def force_dsl?
59
+ @force_dsl
60
+ end
61
+
62
+ # array of controller names (strings) (might include actions as well)
63
+ # to be ignored # when extracting description form calls.
64
+ # e.g. %w[Api::CommentsController Api::PostsController#post]
65
+ attr_writer :ignored_by_recorder
66
+ def ignored_by_recorder
67
+ @ignored_by_recorder ||= []
68
+ @ignored_by_recorder.map(&:to_s)
69
+ end
70
+
71
+ # array of controller names (strings) (might include actions as well)
72
+ # to be ignored # when generationg the documentation
73
+ # e.g. %w[Api::CommentsController Api::PostsController#post]
74
+ attr_writer :ignored
75
+ def ignored
76
+ @ignored ||= []
77
+ @ignored.map(&:to_s)
78
+ end
79
+
80
+ # comment to put before docs that was generated automatically. It's used to
81
+ # determine if the description should be overwritten next recording.
82
+ # If you want to keep the documentation (prevent from overriding), remove
83
+ # the line above the docs.
84
+ attr_writer :generated_doc_disclaimer
85
+ def generated_doc_disclaimer
86
+ @generated_doc_disclaimer ||= "# DOC GENERATED AUTOMATICALLY: REMOVE THIS LINE TO PREVENT REGENARATING NEXT TIME"
87
+ end
88
+
89
+ def use_disqus?
90
+ !@disqus_shortname.blank?
91
+ end
92
+
93
+ # set app description for default version
94
+ # to maintain backward compatibility
95
+ # new way: config.app_info[version] = description
96
+ def app_info=(description)
97
+ version = Apipie.configuration.default_version
98
+ @app_info[version] = description
99
+ end
100
+
101
+ # set base url for default version of API
102
+ # to set it for specific version use
103
+ # config.api_base_url[version] = url
104
+ def api_base_url=(url)
105
+ version = Apipie.configuration.default_version
106
+ @api_base_url[version] = url
107
+ end
108
+
109
+ def initialize
110
+ @markup = Apipie::Markup::RDoc.new
111
+ @app_name = "Another API"
112
+ @app_info = HashWithIndifferentAccess.new
113
+ @copyright = nil
114
+ @validate = true
115
+ @validate_value = true
116
+ @validate_presence = true
117
+ @required_by_default = false
118
+ @api_base_url = HashWithIndifferentAccess.new
119
+ @doc_base_url = "/apipie"
120
+ @layout = "apipie/apipie"
121
+ @disqus_shortname = nil
122
+ @default_version = "1.0"
123
+ @debug = false
124
+ @version_in_url = true
125
+ @namespaced_resources = false
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,379 @@
1
+ # Apipie DSL functions.
2
+
3
+ module Apipie
4
+
5
+ # DSL is a module that provides #api, #error, #param, #error.
6
+ module DSL
7
+
8
+ module Base
9
+ attr_reader :apipie_resource_descriptions
10
+
11
+ private
12
+
13
+ def _apipie_dsl_data
14
+ @_apipie_dsl_data ||= _apipie_dsl_data_init
15
+ end
16
+
17
+ def _apipie_dsl_data_clear
18
+ @_apipie_dsl_data = nil
19
+ end
20
+
21
+ def _apipie_dsl_data_init
22
+ @_apipie_dsl_data = {
23
+ :api_args => [],
24
+ :errors => [],
25
+ :params => [],
26
+ :resouce_id => nil,
27
+ :short_description => nil,
28
+ :description => nil,
29
+ :examples => [],
30
+ :see => [],
31
+ :formats => nil,
32
+ :api_versions => []
33
+ }
34
+ end
35
+ end
36
+
37
+ module Resource
38
+ # by default, the resource id is derived from controller_name
39
+ # it can be overwritten with.
40
+ #
41
+ # resource_id "my_own_resource_id"
42
+ def resource_id(resource_id)
43
+ Apipie.set_resource_id(@controller, resource_id)
44
+ end
45
+
46
+ def name(name)
47
+ _apipie_dsl_data[:resource_name] = name
48
+ end
49
+
50
+ def api_base_url(url)
51
+ _apipie_dsl_data[:api_base_url] = url
52
+ end
53
+
54
+ def short(short)
55
+ _apipie_dsl_data[:short_description] = short
56
+ end
57
+ alias :short_description :short
58
+
59
+ def path(path)
60
+ _apipie_dsl_data[:path] = path
61
+ end
62
+
63
+ def app_info(app_info)
64
+ _apipie_dsl_data[:app_info] = app_info
65
+ end
66
+ end
67
+
68
+ module Action
69
+
70
+ def def_param_group(name, &block)
71
+ Apipie.add_param_group(self, name, &block)
72
+ end
73
+
74
+ # Declare an api.
75
+ #
76
+ # Example:
77
+ # api :GET, "/resource_route", "short description",
78
+ #
79
+ def api(method, path, desc = nil) #:doc:
80
+ return unless Apipie.active_dsl?
81
+ _apipie_dsl_data[:api_args] << [method, path, desc]
82
+ end
83
+
84
+ # Reference other similar method
85
+ #
86
+ # api :PUT, '/articles/:id'
87
+ # see "articles#create"
88
+ # def update; end
89
+ def see(*args)
90
+ return unless Apipie.active_dsl?
91
+ _apipie_dsl_data[:see] << args
92
+ end
93
+
94
+ # Show some example of what does the described
95
+ # method return.
96
+ def example(example) #:doc:
97
+ return unless Apipie.active_dsl?
98
+ _apipie_dsl_data[:examples] << example.strip_heredoc
99
+ end
100
+
101
+ # Describe whole resource
102
+ #
103
+ # Example:
104
+ # api :desc => "Show user profile", :path => "/users/", :version => '1.0 - 3.4.2012'
105
+ # param :id, Fixnum, :desc => "User ID", :required => true
106
+ # desc <<-EOS
107
+ # Long description...
108
+ # EOS
109
+ def resource_description(options = {}, &block) #:doc:
110
+ return unless Apipie.active_dsl?
111
+ raise ArgumentError, "Block expected" unless block_given?
112
+
113
+ dsl_data = ResourceDescriptionDsl.eval_dsl(self, &block)
114
+ versions = dsl_data[:api_versions]
115
+ @apipie_resource_descriptions = versions.map do |version|
116
+ Apipie.define_resource_description(self, version, dsl_data)
117
+ end
118
+ Apipie.set_controller_versions(self, versions)
119
+ end
120
+
121
+ end
122
+
123
+ module Common
124
+ def api_versions(*versions)
125
+ _apipie_dsl_data[:api_versions].concat(versions)
126
+ end
127
+ alias :api_version :api_versions
128
+
129
+ # Describe the next method.
130
+ #
131
+ # Example:
132
+ # desc "print hello world"
133
+ # def hello_world
134
+ # puts "hello world"
135
+ # end
136
+ #
137
+ def desc(description) #:doc:
138
+ return unless Apipie.active_dsl?
139
+ if _apipie_dsl_data[:description]
140
+ raise "Double method description."
141
+ end
142
+ _apipie_dsl_data[:description] = description
143
+ end
144
+ alias :description :desc
145
+ alias :full_description :desc
146
+
147
+ # Describe available request/response formats
148
+ #
149
+ # formats ['json', 'jsonp', 'xml']
150
+ def formats(formats) #:doc:
151
+ return unless Apipie.active_dsl?
152
+ _apipie_dsl_data[:formats] = formats
153
+ end
154
+
155
+ # Describe possible errors
156
+ #
157
+ # Example:
158
+ # error :desc => "speaker is sleeping", :code => 500
159
+ # error 500, "speaker is sleeping"
160
+ # def hello_world
161
+ # return 500 if self.speaker.sleeping?
162
+ # puts "hello world"
163
+ # end
164
+ #
165
+ def error(*args) #:doc:
166
+ return unless Apipie.active_dsl?
167
+ _apipie_dsl_data[:errors] << args
168
+ end
169
+
170
+ def _apipie_define_validators(description)
171
+ # redefine method only if validation is turned on
172
+ if description && Apipie.configuration.validate == true
173
+
174
+ old_method = instance_method(description.method)
175
+
176
+ define_method(description.method) do |*args|
177
+
178
+ if Apipie.configuration.validate_presence?
179
+ description.params.each do |_, param|
180
+ # check if required parameters are present
181
+ raise ParamMissing.new(param.name) if param.required && !params.has_key?(param.name)
182
+ end
183
+ end
184
+
185
+ if Apipie.configuration.validate_value?
186
+ description.params.each do |_, param|
187
+ # params validations
188
+ param.validate(params[:"#{param.name}"]) if params.has_key?(param.name)
189
+ end
190
+ end
191
+
192
+ # run the original method code
193
+ old_method.bind(self).call(*args)
194
+ end
195
+
196
+ end
197
+
198
+ end
199
+
200
+ end
201
+
202
+ # this describes the params, it's in separate module because it's
203
+ # used in Validators as well
204
+ module Param
205
+ # Describe method's parameter
206
+ #
207
+ # Example:
208
+ # param :greeting, String, :desc => "arbitrary text", :required => true
209
+ # def hello_world(greeting)
210
+ # puts greeting
211
+ # end
212
+ #
213
+ def param(param_name, validator, desc_or_options = nil, options = {}, &block) #:doc:
214
+ return unless Apipie.active_dsl?
215
+ _apipie_dsl_data[:params] << [param_name,
216
+ validator,
217
+ desc_or_options,
218
+ options.merge(:param_group => @_current_param_group),
219
+ block]
220
+ end
221
+
222
+ # Reuses param group for this method. The definition is looked up
223
+ # in scope of this controller. If the group was defined in
224
+ # different controller, the second param can be used to specify it.
225
+ # when using action_aware parmas, you can specify :as =>
226
+ # :create or :update to explicitly say how it should behave
227
+ def param_group(name, scope_or_options = nil, options = {})
228
+ if scope_or_options.is_a? Hash
229
+ options.merge!(scope_or_options)
230
+ scope = options[:scope]
231
+ else
232
+ scope = scope_or_options
233
+ end
234
+ scope ||= _default_param_group_scope
235
+ @_current_param_group = {:scope => scope, :name => name, :options => options}
236
+ self.instance_exec(&Apipie.get_param_group(scope, name))
237
+ ensure
238
+ @_current_param_group = nil
239
+ end
240
+
241
+ # where the group definition should be looked up when no scope
242
+ # given. This is expected to return a controller.
243
+ def _default_param_group_scope
244
+ self
245
+ end
246
+ end
247
+
248
+ module Controller
249
+ include Apipie::DSL::Base
250
+ include Apipie::DSL::Common
251
+ include Apipie::DSL::Action
252
+ include Apipie::DSL::Param
253
+
254
+ # defines the substitutions to be made in the API paths deifned
255
+ # in concerns included. For example:
256
+ #
257
+ # There is this method defined in concern:
258
+ #
259
+ # api GET ':controller_path/:id'
260
+ # def show
261
+ # # ...
262
+ # end
263
+ #
264
+ # If you include the concern into some controller, you can
265
+ # specify the value for :controller_path like this:
266
+ #
267
+ # apipie_concern_subst(:controller_path => '/users')
268
+ # include ::Concerns::SampleController
269
+ #
270
+ # The resulting path will be '/users/:id'.
271
+ #
272
+ # It has to be specified before the concern is included.
273
+ #
274
+ # If not specified, the default predefined substitions are
275
+ #
276
+ # {:conroller_path => controller.controller_path,
277
+ # :resource_id => `resource_id_from_apipie` }
278
+ def apipie_concern_subst(subst_hash)
279
+ _apipie_concern_subst.merge!(subst_hash)
280
+ end
281
+
282
+ def _apipie_concern_subst
283
+ @_apipie_concern_subst ||= {:controller_path => self.controller_path,
284
+ :resource_id => Apipie.get_resource_name(self)}
285
+ end
286
+
287
+ def _apipie_perform_concern_subst(string)
288
+ return _apipie_concern_subst.reduce(string) do |ret, (key, val)|
289
+ ret.gsub(":#{key}", val)
290
+ end
291
+ end
292
+
293
+ # create method api and redefine newly added method
294
+ def method_added(method_name) #:doc:
295
+ super
296
+
297
+ if ! Apipie.active_dsl? || _apipie_dsl_data[:api_args].blank?
298
+ _apipie_dsl_data_clear
299
+ return
300
+ end
301
+
302
+ begin
303
+ # remove method description if exists and create new one
304
+ Apipie.remove_method_description(self, _apipie_dsl_data[:api_versions], method_name)
305
+ description = Apipie.define_method_description(self, method_name, _apipie_dsl_data)
306
+ ensure
307
+ _apipie_dsl_data_clear
308
+ end
309
+
310
+ _apipie_define_validators(description)
311
+ end # def method_added
312
+ end
313
+
314
+ module Concern
315
+ include Apipie::DSL::Base
316
+ include Apipie::DSL::Common
317
+ include Apipie::DSL::Action
318
+ include Apipie::DSL::Param
319
+
320
+ # the concern was included into a controller
321
+ def included(controller)
322
+ super
323
+ _apipie_concern_data.each do |method_name, _apipie_dsl_data|
324
+ # remove method description if exists and create new one
325
+ description = Apipie.define_method_description(controller, method_name, _apipie_dsl_data)
326
+ controller._apipie_define_validators(description)
327
+ end
328
+ end
329
+
330
+ def _apipie_concern_data
331
+ @_apipie_concern_data ||= []
332
+ end
333
+
334
+ # create method api and redefine newly added method
335
+ def method_added(method_name) #:doc:
336
+ super
337
+
338
+ if ! Apipie.active_dsl? || _apipie_dsl_data[:api_args].blank?
339
+ _apipie_dsl_data_clear
340
+ return
341
+ end
342
+
343
+ begin
344
+ _apipie_concern_data << [method_name, _apipie_dsl_data.merge(:from_concern => true)]
345
+ ensure
346
+ _apipie_dsl_data_clear
347
+ end
348
+
349
+ end # def method_added
350
+
351
+ end
352
+
353
+ class ResourceDescriptionDsl
354
+ include Apipie::DSL::Base
355
+ include Apipie::DSL::Common
356
+ include Apipie::DSL::Resource
357
+ include Apipie::DSL::Param
358
+
359
+ def initialize(controller)
360
+ @controller = controller
361
+ end
362
+
363
+ def _eval_dsl(&block)
364
+ instance_eval(&block)
365
+ return _apipie_dsl_data
366
+ end
367
+
368
+ # evaluates resource description DSL and returns results
369
+ def self.eval_dsl(controller, &block)
370
+ dsl_data = self.new(controller)._eval_dsl(&block)
371
+ if dsl_data[:api_versions].empty?
372
+ dsl_data[:api_versions] = Apipie.controller_versions(controller)
373
+ end
374
+ dsl_data
375
+ end
376
+ end
377
+
378
+ end # module DSL
379
+ end # module Apipie