apipie-rails 0.0.17 → 0.0.18

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,26 +17,33 @@ module Apipie
17
17
 
18
18
  attr_reader :full_description, :method, :resource, :apis, :examples, :see, :formats
19
19
 
20
- def initialize(method, resource, app)
20
+ def initialize(method, resource, dsl_data)
21
21
  @method = method.to_s
22
22
  @resource = resource
23
23
 
24
- @apis = app.last_dsl_data[:api_args]
25
- @see = app.last_dsl_data[:see]
26
- @formats = app.last_dsl_data[:formats]
24
+ @apis = dsl_data[:api_args].map do |method, path, desc|
25
+ MethodDescription::Api.new(method, path, desc)
26
+ end
27
27
 
28
- desc = app.last_dsl_data[:description] || ''
28
+ desc = dsl_data[:description] || ''
29
29
  @full_description = Apipie.markup_to_html(desc)
30
- @errors = app.last_dsl_data[:errors]
31
- @params_ordered = app.last_dsl_data[:params]
32
- @examples = app.last_dsl_data[:examples]
33
30
 
31
+ @errors = dsl_data[:errors].map do |args|
32
+ Apipie::ErrorDescription.new(args)
33
+ end
34
+
35
+ @see = dsl_data[:see].map do |args|
36
+ Apipie::SeeDescription.new(args)
37
+ end
38
+
39
+ @formats = dsl_data[:formats]
40
+ @examples = dsl_data[:examples]
34
41
  @examples += load_recorded_examples
35
42
 
36
- parent = @resource.controller.superclass
37
- if parent != ActionController::Base
38
- @parent_resource = parent.controller_name
43
+ @params_ordered = dsl_data[:params].map do |args|
44
+ Apipie::ParamDescription.from_dsl_data(self, args)
39
45
  end
46
+ @params_ordered = ParamDescription.unify(@params_ordered)
40
47
  end
41
48
 
42
49
  def id
@@ -49,15 +56,14 @@ module Apipie
49
56
 
50
57
  def params_ordered
51
58
  all_params = []
52
- # get params from parent resource description
53
- if @parent_resource
54
- parent = Apipie.get_resource_description(@parent_resource)
55
- merge_params(all_params, parent._params_ordered) if parent
56
- end
59
+ parent = Apipie.get_resource_description(@resource.controller.superclass)
57
60
 
58
- # get params from actual resource description
59
- if @resource
60
- merge_params(all_params, resource._params_ordered)
61
+ # get params from parent resource description
62
+ [parent, @resource].compact.each do |resource|
63
+ resource_params = resource._params_args.map do |args|
64
+ Apipie::ParamDescription.from_dsl_data(self, args)
65
+ end
66
+ merge_params(all_params, resource_params)
61
67
  end
62
68
 
63
69
  merge_params(all_params, @params_ordered)
@@ -68,8 +74,12 @@ module Apipie
68
74
  return @merged_errors if @merged_errors
69
75
  @merged_errors = []
70
76
  if @resource
77
+ resource_errors = @resource._errors_args.map do |args|
78
+ Apipie::ErrorDescription.new(args)
79
+ end
80
+
71
81
  # exclude overwritten parent errors
72
- @merged_errors = @resource._errors_ordered.find_all do |err|
82
+ @merged_errors = resource_errors.find_all do |err|
73
83
  !@errors.any? { |e| e.code == err.code }
74
84
  end
75
85
  end
@@ -8,14 +8,24 @@ module Apipie
8
8
  # validator - Validator::BaseValidator subclass
9
9
  class ParamDescription
10
10
 
11
- attr_reader :name, :desc, :required, :allow_nil, :validator
11
+ attr_reader :method_description, :name, :desc, :allow_nil, :validator, :options
12
12
 
13
- attr_accessor :parent
13
+ attr_accessor :parent, :required
14
14
 
15
- def initialize(name, validator, desc_or_options = nil, options = {}, &block)
15
+ def self.from_dsl_data(method_description, args)
16
+ param_name, validator, desc_or_options, options, block = args
17
+ Apipie::ParamDescription.new(method_description,
18
+ param_name,
19
+ validator,
20
+ desc_or_options,
21
+ options,
22
+ &block)
23
+ end
24
+
25
+ def initialize(method_description, name, validator, desc_or_options = nil, options = {}, &block)
16
26
 
17
- if desc_or_options.is_a?(Hash) && options.empty?
18
- options = desc_or_options
27
+ if desc_or_options.is_a?(Hash)
28
+ options = options.merge(desc_or_options)
19
29
  elsif desc_or_options.is_a?(String)
20
30
  options[:desc] = desc_or_options
21
31
  elsif !desc_or_options.nil?
@@ -24,19 +34,27 @@ module Apipie
24
34
 
25
35
  options.symbolize_keys!
26
36
 
37
+ # we save options to know what was passed in DSL
38
+ @options = options
39
+
40
+ @method_description = method_description
27
41
  @name = name
28
- @desc = Apipie.markup_to_html(options[:desc] || '')
29
- @required = if options.has_key? :required
30
- options[:required]
42
+ @desc = Apipie.markup_to_html(@options[:desc] || '')
43
+ @parent = @options[:parent]
44
+ @required = if @options.has_key? :required
45
+ @options[:required]
31
46
  else
32
47
  Apipie.configuration.required_by_default?
33
48
  end
34
- @allow_nil = options[:allow_nil] || false
49
+
50
+ @allow_nil = @options[:allow_nil] || false
51
+
52
+ action_awareness
35
53
 
36
54
  @validator = nil
37
55
  unless validator.nil?
38
56
  @validator =
39
- Validator::BaseValidator.find(self, validator, options, block)
57
+ Validator::BaseValidator.find(self, validator, @options, block)
40
58
  raise "Validator not found." unless validator
41
59
  end
42
60
  end
@@ -91,6 +109,76 @@ module Apipie
91
109
  end
92
110
  end
93
111
 
112
+ def merge_with(other_param_desc)
113
+ if self.validator && other_param_desc.validator
114
+ self.validator.merge_with(other_param_desc.validator)
115
+ else
116
+ self.validator ||= other_param_desc.validator
117
+ end
118
+ self
119
+ end
120
+
121
+ # merge param descripsiont. Allows defining hash params on more places
122
+ # (e.g. in param_groups). For example:
123
+ #
124
+ # def_param_group :user do
125
+ # param :user, Hash do
126
+ # param :name, String
127
+ # end
128
+ # end
129
+ #
130
+ # param_group :user
131
+ # param :user, Hash do
132
+ # param :password, String
133
+ # end
134
+ def self.unify(params)
135
+ ordering = params.map(&:name)
136
+ params.group_by(&:name).map do |name, param_descs|
137
+ param_descs.reduce(&:merge_with)
138
+ end.sort_by { |param| ordering.index(param.name) }
139
+ end
140
+
141
+ # action awareness is being inherited from ancestors (in terms of
142
+ # nested params)
143
+ def action_aware?
144
+ if @options.has_key?(:action_aware)
145
+ return @options[:action_aware]
146
+ elsif @parent
147
+ @parent.action_aware?
148
+ else
149
+ false
150
+ end
151
+ end
152
+
153
+ def as_action
154
+ if @options[:param_group] && @options[:param_group][:options] &&
155
+ @options[:param_group][:options][:as]
156
+ @options[:param_group][:options][:as].to_s
157
+ elsif @parent
158
+ @parent.as_action
159
+ else
160
+ @method_description.method
161
+ end
162
+ end
163
+
164
+ # makes modification that are based on the action that the param
165
+ # is defined for. Typical for required and allow_nil variations in
166
+ # crate/update actions.
167
+ def action_awareness
168
+ if action_aware?
169
+ if !@options.has_key?(:allow_nil)
170
+ if @required
171
+ @allow_nil = false
172
+ else
173
+ @allow_nil = true
174
+ end
175
+ end
176
+ if as_action != "create"
177
+ @required = false
178
+ end
179
+ end
180
+ end
181
+
94
182
  end
95
183
 
96
184
  end
@@ -2,7 +2,10 @@ module Apipie
2
2
  class Railtie < Rails::Railtie
3
3
  initializer 'apipie.controller_additions' do
4
4
  ActiveSupport.on_load :action_controller do
5
- extend Apipie::DSL
5
+ extend Apipie::DSL::Base
6
+ extend Apipie::DSL::Common
7
+ extend Apipie::DSL::Action
8
+ extend Apipie::DSL::Param
6
9
  end
7
10
  end
8
11
  end
@@ -12,13 +12,13 @@ module Apipie
12
12
  class ResourceDescription
13
13
 
14
14
  attr_reader :controller, :_short_description, :_full_description, :_methods, :_id,
15
- :_path, :_name, :_params_ordered, :_errors_ordered, :_formats, :_parent
15
+ :_path, :_name, :_params_args, :_errors_args, :_formats, :_parent
16
16
 
17
17
  def initialize(controller, resource_name, dsl_data = nil, version = nil, &block)
18
18
 
19
19
  @_methods = ActiveSupport::OrderedHash.new
20
- @_params_ordered = []
21
- @_errors_ordered = []
20
+ @_params_args = []
21
+ @_errors_args = []
22
22
 
23
23
  @controller = controller
24
24
  @_id = resource_name
@@ -35,8 +35,9 @@ module Apipie
35
35
  @_short_description = dsl_data[:short_description]
36
36
  @_path = dsl_data[:path] || ""
37
37
  @_formats = dsl_data[:formats]
38
- @_errors_ordered = dsl_data[:errors]
39
- @_params_ordered = dsl_data[:params]
38
+ @_errors_args = dsl_data[:errors]
39
+ @_params_args = dsl_data[:params]
40
+
40
41
  if dsl_data[:app_info]
41
42
  Apipie.configuration.app_info[_version] = dsl_data[:app_info]
42
43
  end
@@ -66,6 +66,10 @@ module Apipie
66
66
  'string'
67
67
  end
68
68
 
69
+ def merge_with(other_validator)
70
+ raise NotImplementedError, "Dont know how to merge #{self.inspect} with #{other_validator.inspect}"
71
+ end
72
+
69
73
  end
70
74
 
71
75
  # validate arguments type
@@ -169,20 +173,33 @@ module Apipie
169
173
  end
170
174
 
171
175
  class HashValidator < BaseValidator
172
-
173
- attr_reader :hash_params_ordered
176
+ include Apipie::DSL::Base
177
+ include Apipie::DSL::Param
174
178
 
175
179
  def self.build(param_description, argument, options, block)
176
- self.new(param_description, block) if block.is_a?(Proc) && block.arity <= 0 && argument == Hash
180
+ self.new(param_description, block, options[:param_group]) if block.is_a?(Proc) && block.arity <= 0 && argument == Hash
177
181
  end
178
182
 
179
- def initialize(param_description, argument)
183
+ def initialize(param_description, argument, param_group)
180
184
  super(param_description)
181
185
  @proc = argument
182
- @hash_params_ordered = []
183
- @hash_params = {}
184
-
186
+ @param_group = param_group
185
187
  self.instance_exec(&@proc)
188
+ # specifying action_aware on Hash influences the child params,
189
+ # not the hash param itself: assuming it's required when
190
+ # updating as well
191
+ if param_description.options[:action_aware] && param_description.options[:required]
192
+ param_description.required = true
193
+ end
194
+ prepare_hash_params
195
+ end
196
+
197
+ def hash_params_ordered
198
+ @hash_params_ordered ||= _apipie_dsl_data[:params].map do |args|
199
+ options = args.find { |arg| arg.is_a? Hash }
200
+ options[:parent] = self.param_description
201
+ Apipie::ParamDescription.from_dsl_data(param_description.method_description, args)
202
+ end
186
203
  end
187
204
 
188
205
  def validate(value)
@@ -198,16 +215,30 @@ module Apipie
198
215
  "Must be a Hash"
199
216
  end
200
217
 
201
- def param(param_name, validator, desc_or_options = nil, options = {}, &block)
202
- param_description = Apipie::ParamDescription.new(param_name, validator, desc_or_options, options, &block)
203
- param_description.parent = self.param_description
204
- @hash_params_ordered << param_description
205
- @hash_params[param_name.to_sym] = param_description
206
- end
207
-
208
218
  def expected_type
209
219
  'hash'
210
220
  end
221
+
222
+ # where the group definition should be looked up when no scope
223
+ # given. This is expected to return a controller.
224
+ def _default_param_group_scope
225
+ @param_group && @param_group[:scope]
226
+ end
227
+
228
+ def merge_with(other_validator)
229
+ if other_validator.is_a? HashValidator
230
+ @hash_params_ordered = ParamDescription.unify(self.hash_params_ordered + other_validator.hash_params_ordered)
231
+ prepare_hash_params
232
+ else
233
+ super
234
+ end
235
+ end
236
+
237
+ def prepare_hash_params
238
+ @hash_params = hash_params_ordered.reduce({}) do |h, param|
239
+ h.update(param.name.to_sym => param)
240
+ end
241
+ end
211
242
  end
212
243
 
213
244
 
@@ -1,3 +1,3 @@
1
1
  module Apipie
2
- VERSION = '0.0.17'
2
+ VERSION = '0.0.18'
3
3
  end
@@ -110,10 +110,13 @@ describe Apipie::ApipiesController do
110
110
 
111
111
  Apipie.configuration.use_cache = true
112
112
  Apipie.configuration.cache_dir = cache_dir
113
+ @orig_version = Apipie.configuration.default_version
113
114
  Apipie.configuration.default_version = 'v1'
114
115
  end
115
116
 
116
117
  after do
118
+ Apipie.configuration.use_cache = false
119
+ Apipie.configuration.default_version = @orig_version
117
120
  # FileUtils.rm_r(cache_dir) if File.exists?(cache_dir)
118
121
  end
119
122
 
@@ -20,6 +20,8 @@ end
20
20
 
21
21
  describe UsersController do
22
22
 
23
+ let(:dsl_data) { ActionController::Base.send(:_apipie_dsl_data_init) }
24
+
23
25
  describe "resource description" do
24
26
  subject do
25
27
  Apipie.get_resource_description(UsersController, Apipie.configuration.default_version)
@@ -27,10 +29,10 @@ describe UsersController do
27
29
 
28
30
  it "should contain all resource methods" do
29
31
  methods = subject._methods
30
- methods.count.should == 5
31
32
  methods.keys.should include(:show)
32
33
  methods.keys.should include(:index)
33
34
  methods.keys.should include(:create)
35
+ methods.keys.should include(:update)
34
36
  methods.keys.should include(:two_urls)
35
37
  end
36
38
 
@@ -44,20 +46,11 @@ describe UsersController do
44
46
  end
45
47
 
46
48
  it "should contain params defined on resource level" do
47
- subject._params_ordered.count.should == 2
48
- p = subject._params_ordered.first
49
- p.should_not be(nil)
50
- p.name.should eq(:id)
51
- p.desc.should eq("\n<p>User ID</p>\n")
52
- p.required.should eq(false)
53
- p.validator.class.should eq(Apipie::Validator::IntegerValidator)
54
-
55
- p = subject._params_ordered.second
56
- p.should_not be(nil)
57
- p.name.should eq(:resource_param)
58
- p.desc.should eq("\n<p>Param description for all methods</p>\n")
59
- p.required.should eq(false)
60
- p.validator.class.should eq(Apipie::Validator::HashValidator)
49
+ subject._params_args.count.should == 2
50
+ name, type, options = subject._params_args.first
51
+ name.should == :id
52
+ type.should == Fixnum
53
+ options.should == {:required=>false, :desc=>"User ID"}
61
54
  end
62
55
  end
63
56
 
@@ -162,7 +155,7 @@ describe UsersController do
162
155
  param.count.should == 1
163
156
  param.first.validator.class.should eq(Apipie::Validator::HashValidator)
164
157
  hash_params = param.first.validator.hash_params_ordered
165
- hash_params.count.should == 3
158
+ hash_params.count.should == 4
166
159
  hash_params[0].name == :name
167
160
  hash_params[1].name == :pass
168
161
  hash_params[2].name == :membership
@@ -425,10 +418,10 @@ EOS2
425
418
  end
426
419
 
427
420
  it "skips the listed actions from the documentation" do
428
- Apipie.define_method_description(UsersController, :ignore)
421
+ Apipie.define_method_description(UsersController, :ignore, dsl_data)
429
422
  Apipie.get_method_description(UsersController, :ignore).should be_nil
430
423
 
431
- Apipie.define_method_description(UsersController, :dont_ignore)
424
+ Apipie.define_method_description(UsersController, :dont_ignore, dsl_data)
432
425
  Apipie.get_method_description(UsersController, :dont_ignore).should_not be_nil
433
426
  end
434
427
  end
@@ -439,9 +432,9 @@ EOS2
439
432
  end
440
433
 
441
434
  it "skips the listed controller from the documentation" do
442
- Apipie.define_method_description(IgnoredController, :ignore)
435
+ Apipie.define_method_description(IgnoredController, :ignore, dsl_data)
443
436
  Apipie.get_method_description(IgnoredController, :ignore).should be_nil
444
- Apipie.define_method_description(IgnoredController, :ignore)
437
+ Apipie.define_method_description(IgnoredController, :ignore, dsl_data)
445
438
  Apipie.get_method_description(IgnoredController, :ignore).should be_nil
446
439
  end
447
440
  end