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.
- data/.gitignore +2 -0
- data/CHANGELOG +6 -0
- data/README.rst +106 -1
- data/lib/apipie-rails.rb +1 -1
- data/lib/apipie/application.rb +14 -29
- data/lib/apipie/dsl_definition.rb +226 -158
- data/lib/apipie/method_description.rb +30 -20
- data/lib/apipie/param_description.rb +98 -10
- data/lib/apipie/railtie.rb +4 -1
- data/lib/apipie/resource_description.rb +6 -5
- data/lib/apipie/validator.rb +45 -14
- data/lib/apipie/version.rb +1 -1
- data/spec/controllers/apipies_controller_spec.rb +3 -0
- data/spec/controllers/users_controller_spec.rb +13 -20
- data/spec/dummy/app/controllers/api/v1/architectures_controller.rb +13 -3
- data/spec/dummy/app/controllers/api/v2/architectures_controller.rb +1 -3
- data/spec/dummy/app/controllers/users_controller.rb +26 -3
- data/spec/lib/method_description_spec.rb +6 -5
- data/spec/lib/param_description_spec.rb +82 -6
- data/spec/lib/param_group_spec.rb +45 -0
- data/spec/lib/resource_description_spec.rb +9 -7
- metadata +18 -18
- data/.rvmrc +0 -1
- data/Gemfile.lock +0 -117
@@ -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,
|
20
|
+
def initialize(method, resource, dsl_data)
|
21
21
|
@method = method.to_s
|
22
22
|
@resource = resource
|
23
23
|
|
24
|
-
@apis =
|
25
|
-
|
26
|
-
|
24
|
+
@apis = dsl_data[:api_args].map do |method, path, desc|
|
25
|
+
MethodDescription::Api.new(method, path, desc)
|
26
|
+
end
|
27
27
|
|
28
|
-
desc =
|
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
|
-
|
37
|
-
|
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
|
-
|
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
|
59
|
-
|
60
|
-
|
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 =
|
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, :
|
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
|
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)
|
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
|
-
@
|
30
|
-
|
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
|
-
|
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
|
data/lib/apipie/railtie.rb
CHANGED
@@ -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, :
|
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
|
-
@
|
21
|
-
@
|
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
|
-
@
|
39
|
-
@
|
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
|
data/lib/apipie/validator.rb
CHANGED
@@ -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
|
-
|
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
|
-
@
|
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
|
|
data/lib/apipie/version.rb
CHANGED
@@ -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.
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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 ==
|
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
|