simple_params 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OGYzOTBkMWI1YTA1MmNlZThiMzZiMzE1MGQyN2NlMmM3NTc1NTMwNQ==
4
+ MWQxN2I0ZTRlYjM1NmFmMDc0ZGRhNDA5YWQ3ZDhjMWUzZWMzM2QzMw==
5
5
  data.tar.gz: !binary |-
6
- NjExZWE4N2FiMDZhODJiNjM3M2EyNWFmM2E5Yzk4Y2RhNWM4YTk5ZQ==
6
+ MjA4ZmQ5NDcxMjM1OTRjNzAwZTMzM2Y3MjExMGJlZDIwNDVmY2YwZQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MjlmNDFhNzZiMTZlNTI1MDIyZTA3NzZiOGIxNTdjYTg2MTczNTY1OWIzZDY4
10
- N2VkMTM5NmU3ZDVmNWNkNzE5ZTRmOWNiMzI2OTM0MmNhYTc1NGFkMDlkMTQ1
11
- N2YyOTc3MmRkMjkyNmYwMDQyY2Q4YTJlNDY0MmMzMThhNzBhM2Y=
9
+ YTI0YjczMDJjMTI0OGQ4NmY4ZDZkZWYwMGNhYTA5NzIyZjZjODRiMGE4ZTZi
10
+ NzZkZDJlY2YyMDE4YzQ3OWQ1YWE3Mjg1MDg2MjlhZTAyZTJhMTc3NTRiN2M5
11
+ ZGM5MTFlMTE3NjFjZDhjMDFkMjJhMjZjYTEwNTQ0NzViN2JiNWY=
12
12
  data.tar.gz: !binary |-
13
- ZmQ2YTBiOWMyYTA4MWYwZmMzNDg2NGJmNTRjNjQwZGVlY2RjY2YwYmYyZGQ1
14
- MzIzOGRjYjYzOGZhNTBlNjY4YWZjYjE2MWE4OGQ2MWFmOWM1YzdlNmVmZWM4
15
- NmEzYjcyOGYzZDI3MjlmOGY0MjRlOTJlN2E1OGI4YzZlZjkxZjc=
13
+ YTY4MmRhMWRlYTQ1NmM1N2YzNmMwZjIzNTE3ZTNiZjQ3NDY0ZjhlMTI5MmI5
14
+ NTBiMmNjYTAxZWJiNzhkZTIxNThkMDFhMDc5NGE0OTdmYjI3ZTQ0ZmQ4ZDc0
15
+ Nzc4MjllNDYyZGZjNTJjM2FiNmFkNTUxMmEwNmM3ODFkODNlZmU=
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_params (1.0.2)
4
+ simple_params (1.0.3)
5
5
  activemodel (>= 3.0, < 5.0)
6
6
  shoulda-matchers (~> 2.8)
7
7
  virtus (>= 1.0.0)
@@ -0,0 +1,31 @@
1
+ module SimpleParams
2
+ class ApiPieDoc::NestedArray < ApiPieDoc::AttributeBase
3
+
4
+ attr_accessor :attributes
5
+
6
+ def initialize(simple_params_array)
7
+ super
8
+ self.attributes = attribute.values[0].map { |attribute| ApiPieDoc::Attribute.new(attribute) }
9
+ self.options ||= attribute.delete(:options) || attribute[1]
10
+ end
11
+
12
+ def name
13
+ attribute.keys.first.to_s
14
+ end
15
+
16
+ def to_s
17
+ return nil if do_not_document?
18
+ nested_description
19
+ end
20
+
21
+ private
22
+
23
+ def nested_description
24
+ start = "param :#{name}, Array, #{description}, #{requirement_description} do"
25
+ attribute_descriptors = []
26
+ attributes.each { |attribute| attribute_descriptors << attribute.to_s }
27
+ finish = "end"
28
+ [start, attribute_descriptors, finish].flatten.join("\n")
29
+ end
30
+ end
31
+ end
@@ -3,16 +3,21 @@ module SimpleParams
3
3
 
4
4
  attr_accessor :base_attributes,
5
5
  :nested_hashes,
6
+ :nested_arrays,
6
7
  :nested_attributes,
8
+ :nested_array_attributes,
7
9
  :docs
8
10
 
9
11
  def initialize(simple_params)
10
12
  self.base_attributes = simple_params.defined_attributes
11
13
  self.nested_hashes = simple_params.nested_hashes
14
+ self.nested_arrays = simple_params.nested_arrays
12
15
  self.nested_attributes = []
16
+ self.nested_array_attributes = []
13
17
  self.docs = []
14
18
 
15
19
  build_nested_attributes
20
+ build_nested_array_attributes
16
21
  end
17
22
 
18
23
  def build
@@ -24,6 +29,10 @@ module SimpleParams
24
29
  docs << NestedAttribute.new(nested_attribute).to_s
25
30
  end
26
31
 
32
+ nested_array_attributes.each do |nested_attribute|
33
+ docs << NestedArray.new(nested_attribute).to_s
34
+ end
35
+
27
36
  docs.join("\n")
28
37
  end
29
38
 
@@ -34,5 +43,11 @@ module SimpleParams
34
43
  nested_attributes << { name => parameter_set.defined_attributes, options: parameter_set.options }
35
44
  end
36
45
  end
46
+
47
+ def build_nested_array_attributes
48
+ nested_arrays.each do |name, parameter_set|
49
+ nested_array_attributes << { name => parameter_set.defined_attributes, options: parameter_set.options }
50
+ end
51
+ end
37
52
  end
38
53
  end
@@ -2,14 +2,23 @@ require "active_model"
2
2
 
3
3
  module SimpleParams
4
4
  class Errors < ActiveModel::Errors
5
+ attr_reader :base
5
6
 
6
- def initialize(base, nested_attributes = [])
7
+ def initialize(base, nested_hash_errors = {}, nested_array_errors = {})
7
8
  super(base)
8
- @nested_attributes = symbolize_nested(nested_attributes)
9
+ @base = base
10
+ @nested_hash_errors = symbolize_nested(nested_hash_errors)
11
+ @nested_array_errors = symbolize_nested(nested_array_errors)
9
12
  end
10
13
 
11
14
  def [](attribute)
12
- get(attribute.to_sym) || reset_attribute(attribute.to_sym)
15
+ if is_a_nested_hash_error_attribute?(attribute)
16
+ set(attribute.to_sym, @nested_hash_errors[attribute.to_sym])
17
+ elsif is_a_nested_array_error_attribute?(attribute)
18
+ set(attribute.to_sym, @nested_array_errors[attribute.to_sym])
19
+ else
20
+ get(attribute.to_sym) || set(attribute.to_sym, [])
21
+ end
13
22
  end
14
23
 
15
24
  def []=(attribute, error)
@@ -28,26 +37,18 @@ module SimpleParams
28
37
 
29
38
  def clear
30
39
  super
31
- @nested_attributes.each do |attribute|
32
- if fetch_nested_attribute(attribute).present?
33
- fetch_nested_attribute(attribute).errors.clear
34
- end
35
- end
40
+ @nested_hash_errors.map { |attribute, errors| errors.clear }
36
41
  end
37
42
 
38
43
  def empty?
39
44
  super &&
40
- @nested_attributes.all? do |attribute|
41
- if fetch_nested_attribute(attribute).present?
42
- fetch_nested_attribute(attribute).errors.empty?
43
- end
44
- end
45
+ @nested_hash_errors.all? { |attribute, errors| errors.empty? }
45
46
  end
46
47
  alias_method :blank?, :empty?
47
48
 
48
49
  def include?(attribute)
49
- if fetch_nested_attribute(attribute)
50
- !fetch_nested_attribute(attribute).errors.empty?
50
+ if is_a_nested_hash_error_attribute?(attribute)
51
+ !@nested_hash_errors[attribute.to_sym].empty?
51
52
  else
52
53
  messages[attribute].present?
53
54
  end
@@ -57,21 +58,16 @@ module SimpleParams
57
58
 
58
59
  def values
59
60
  messages.values +
60
- @nested_attributes.map do |attribute|
61
- if fetch_nested_attribute(attribute).present?
62
- fetch_nested_attribute(attribute).errors.values
63
- end
61
+ @nested_hash_errors.map do |attribute, errors|
62
+ errors.values
64
63
  end
65
64
  end
66
65
 
67
66
  def full_messages
68
67
  parent_messages = map { |attribute, message| full_message(attribute, message) }
69
- nested_messages = @nested_attributes.map do |attribute|
70
- if fetch_nested_attribute(attribute)
71
- messages = fetch_nested_attribute(attribute).errors.full_messages
72
- messages.map do |message|
73
- "#{attribute} " + message
74
- end
68
+ nested_messages = @nested_hash_errors.map do |attribute, errors|
69
+ unless errors.full_messages.nil?
70
+ errors.full_messages.map { |message| "#{attribute} " + message }
75
71
  end
76
72
  end
77
73
  (parent_messages + nested_messages).flatten
@@ -88,10 +84,10 @@ module SimpleParams
88
84
  self.messages.dup
89
85
  end
90
86
 
91
- @nested_attributes.map do |attribute|
92
- errors = nested_error_messages(attribute, full_messages)
87
+ @nested_hash_errors.map do |attribute, errors|
88
+ error_messages = nested_error_messages(attribute, full_messages)
93
89
  unless errors.empty?
94
- messages.merge!(attribute.to_sym => errors)
90
+ messages.merge!(attribute.to_sym => error_messages)
95
91
  end
96
92
  end
97
93
  messages
@@ -104,14 +100,14 @@ module SimpleParams
104
100
 
105
101
  private
106
102
  def nested_error_messages(attribute, full_messages = false)
107
- if fetch_nested_attribute(attribute)
108
- if full_messages
109
- errors = fetch_nested_attribute(attribute).errors
103
+ if is_a_nested_hash_error_attribute?(attribute)
104
+ errors = @nested_hash_errors[attribute.to_sym]
105
+ if full_messages
110
106
  errors.messages.each_with_object({}) do |(attr, array), messages|
111
107
  messages[attr] = array.map { |message| errors.full_message(attr, message) }
112
108
  end
113
109
  else
114
- fetch_nested_attribute(attribute).errors.messages.dup
110
+ errors.messages.dup
115
111
  end
116
112
  else
117
113
  {}
@@ -119,29 +115,23 @@ module SimpleParams
119
115
  end
120
116
 
121
117
  def add_error_to_attribute(attribute, error)
122
- if fetch_nested_attribute(attribute)
123
- fetch_nested_attribute(attribute).errors[:base] = error
118
+ if is_a_nested_hash_error_attribute?(attribute)
119
+ @nested_hash_errors[attribute.to_sym][:base] = error
124
120
  else
125
121
  self[attribute] << error
126
122
  end
127
123
  end
128
124
 
129
- def reset_attribute(attribute)
130
- if fetch_nested_attribute(attribute)
131
- set(attribute.to_sym, fetch_nested_attribute(attribute).errors)
132
- else
133
- set(attribute.to_sym, [])
134
- end
125
+ def is_a_nested_hash_error_attribute?(attribute)
126
+ @nested_hash_errors.keys.include?(attribute.to_sym)
135
127
  end
136
128
 
137
- def fetch_nested_attribute(attribute)
138
- if @nested_attributes.include?(attribute)
139
- @base.send(attribute)
140
- end
129
+ def is_a_nested_array_error_attribute?(attribute)
130
+ @nested_array_errors.keys.include?(attribute.to_sym)
141
131
  end
142
132
 
143
133
  def symbolize_nested(nested)
144
- nested.map { |x| x.to_sym }
134
+ nested.inject({}) { |memo,(k,v) | memo[k.to_sym] = v; memo }
145
135
  end
146
136
  end
147
137
  end
@@ -5,6 +5,7 @@ module SimpleParams
5
5
  class Params
6
6
  include Virtus.model
7
7
  include ActiveModel::Validations
8
+ extend ActiveModel::Naming
8
9
  include SimpleParams::Validations
9
10
 
10
11
  TYPES = [
@@ -31,6 +32,10 @@ module SimpleParams
31
32
 
32
33
  attr_accessor :strict_enforcement, :options
33
34
 
35
+ def model_name
36
+ ActiveModel::Name.new(self)
37
+ end
38
+
34
39
  def api_pie_documentation
35
40
  SimpleParams::ApiPieDoc.new(self).build
36
41
  end
@@ -61,11 +66,22 @@ module SimpleParams
61
66
  @nested_hashes ||= {}
62
67
  end
63
68
 
69
+ def nested_array(name, opts={}, &block)
70
+ attr_accessor name
71
+ nested_array_class = define_nested_class(name, opts, &block)
72
+ @nested_arrays ||= {}
73
+ @nested_arrays[name.to_sym] = nested_array_class
74
+ end
75
+
76
+ def nested_arrays
77
+ @nested_arrays ||= {}
78
+ end
79
+
64
80
  def defined_attributes
65
81
  @define_attributes ||= {}
66
82
  end
67
- private
68
83
 
84
+ private
69
85
  def define_attribute(name, opts = {})
70
86
  opts[:type] ||= :string
71
87
  defined_attributes[name.to_sym] = opts
@@ -103,12 +119,10 @@ module SimpleParams
103
119
  def define_nested_class(name, options, &block)
104
120
  klass_name = name.to_s.split('_').collect(&:capitalize).join
105
121
  Class.new(Params).tap do |klass|
106
- # def self.model_name
107
- # ActiveModel::Name.new(self)
108
- # end
122
+ self.const_set(klass_name, klass)
123
+ extend ActiveModel::Naming
109
124
  klass.class_eval(&block)
110
125
  klass.class_eval("self.options = #{options}")
111
- self.const_set(klass_name, klass)
112
126
  end
113
127
  end
114
128
  end
@@ -124,13 +138,16 @@ module SimpleParams
124
138
  @original_params = hash_to_symbolized_hash(params)
125
139
  define_attributes(@original_params)
126
140
 
127
- # Errors
141
+ # Nested Hashes
128
142
  @nested_params = nested_hashes.keys
129
- @errors = SimpleParams::Errors.new(self, @nested_params)
143
+
144
+ # Nested Arrays
145
+ @nested_arrays = nested_arrays.keys
130
146
 
131
147
  # Nested Classes
132
148
  set_accessors(params)
133
149
  initialize_nested_classes
150
+ initialize_nested_array_classes
134
151
  end
135
152
 
136
153
  def define_attributes(params)
@@ -140,7 +157,7 @@ module SimpleParams
140
157
  end
141
158
 
142
159
  def attributes
143
- (defined_attributes.keys + nested_hashes.keys).flatten
160
+ (defined_attributes.keys + nested_hashes.keys + nested_arrays.keys).flatten
144
161
  end
145
162
 
146
163
  def original_params
@@ -151,9 +168,6 @@ module SimpleParams
151
168
 
152
169
  def to_hash
153
170
  hash = {}
154
- # self.class.defined_attributes.each_pair do |key, opts|
155
- # hash[key.to_sym] = send(key)
156
- # end
157
171
  attributes.each do |attribute|
158
172
  if send(attribute).is_a?(SimpleParams::Params)
159
173
  hash[attribute] = send(attribute).to_hash
@@ -165,6 +179,20 @@ module SimpleParams
165
179
  hash
166
180
  end
167
181
 
182
+ def errors
183
+ nested_errors_hash = {}
184
+ @nested_params.each do |param|
185
+ nested_errors_hash[param.to_sym] = send(param).errors
186
+ end
187
+
188
+ nested_arrays_hash = {}
189
+ @nested_arrays.each do |array|
190
+ nested_arrays_hash[array.to_sym] = send(array).map(&:errors)
191
+ end
192
+
193
+ @errors ||= SimpleParams::Errors.new(self, nested_errors_hash, nested_arrays_hash)
194
+ end
195
+
168
196
  # Overriding this method to allow for non-strict enforcement!
169
197
  def method_missing(method_name, *arguments, &block)
170
198
  if strict_enforcement?
@@ -197,7 +225,7 @@ module SimpleParams
197
225
  def set_accessors(params={})
198
226
  params.each do |attribute_name, value|
199
227
  # Don't set accessors for nested classes
200
- unless value.is_a?(Hash)
228
+ unless value.is_a?(Hash)
201
229
  send("#{attribute_name}=", value)
202
230
  end
203
231
  end
@@ -226,6 +254,10 @@ module SimpleParams
226
254
  self.class.nested_hashes
227
255
  end
228
256
 
257
+ def nested_arrays
258
+ self.class.nested_arrays
259
+ end
260
+
229
261
  def initialize_nested_classes
230
262
  nested_hashes.each do |key, klass|
231
263
  initialization_params = @original_params[key.to_sym] || {}
@@ -233,6 +265,17 @@ module SimpleParams
233
265
  end
234
266
  end
235
267
 
268
+ def initialize_nested_array_classes
269
+ nested_arrays.each do |key, klass|
270
+ initialization_params = @original_params[key.to_sym] || []
271
+ initialization_array = []
272
+ initialization_params.each do |initialization_param|
273
+ initialization_array << klass.new(initialization_param, self)
274
+ end
275
+ send("#{key}=", initialization_array)
276
+ end
277
+ end
278
+
236
279
  def define_anonymous_class(name, hash)
237
280
  klass_name = name.to_s.split('_').collect(&:capitalize).join
238
281
  anonymous_klass = Class.new(Params).tap do |klass|
@@ -14,6 +14,11 @@ module SimpleParams
14
14
  nested_class = send("#{key}")
15
15
  nested_class.valid?
16
16
  end
17
+
18
+ nested_arrays.each do |key, array|
19
+ nested_array = send("#{key}")
20
+ nested_array.each { |a| a.valid? }
21
+ end
17
22
  errors.empty?
18
23
  ensure
19
24
  self.validation_context = current_context
@@ -1,3 +1,3 @@
1
1
  module SimpleParams
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.4"
3
3
  end
data/lib/simple_params.rb CHANGED
@@ -9,6 +9,7 @@ require 'simple_params/type_mappings'
9
9
  require 'simple_params/api_pie_doc'
10
10
  require 'simple_params/api_pie_doc/attribute_base'
11
11
  require 'simple_params/api_pie_doc/attribute'
12
+ require 'simple_params/api_pie_doc/nested_array'
12
13
  require 'simple_params/api_pie_doc/nested_attribute'
13
14
  require 'simple_params/validation_matchers/validation_matcher'
14
15
  require 'simple_params/validation_matchers/coercion_matcher'
@@ -6,6 +6,7 @@ class AcceptanceParams < SimpleParams::Params
6
6
  param :name
7
7
  param :age, type: :integer, optional: true, validations: { inclusion: { in: 18..100 } }
8
8
  param :color, default: "red", validations: { inclusion: { in: ["red", "green"] }}
9
+ param :sibling_names, type: :array, optional: true
9
10
  validate :name_has_letters
10
11
 
11
12
  nested_hash :address do
@@ -16,6 +17,11 @@ class AcceptanceParams < SimpleParams::Params
16
17
  param :company, optional: true
17
18
  end
18
19
 
20
+ nested_array :dogs do
21
+ param :name
22
+ param :age, type: :integer, validations: { inclusion: { in: 1..20 } }
23
+ end
24
+
19
25
  def name_has_letters
20
26
  if name.present? && !(name =~ /^[a-zA-Z]*$/)
21
27
  errors.add(:name, "must only contain letters")
@@ -59,13 +65,15 @@ describe SimpleParams::Params do
59
65
  name: "Tom",
60
66
  age: nil,
61
67
  color: "red",
68
+ sibling_names: nil,
62
69
  address: {
63
70
  street: "1 Main St.",
64
71
  city: nil,
65
72
  zip_code: nil,
66
73
  state: "North Carolina",
67
74
  company: nil
68
- }
75
+ },
76
+ dogs: []
69
77
  })
70
78
  end
71
79
  end
@@ -135,7 +143,7 @@ describe SimpleParams::Params do
135
143
  describe "attributes", attributes: true do
136
144
  it "returns array of attribute symbols" do
137
145
  params = AcceptanceParams.new
138
- params.attributes.should eq([:reference, :name, :age, :color, :address])
146
+ params.attributes.should eq([:reference, :name, :age, :color, :sibling_names, :address, :dogs])
139
147
  end
140
148
 
141
149
  it "returns array of attribute symbols for nested class" do
@@ -305,6 +313,7 @@ describe SimpleParams::Params do
305
313
  param :name, String, desc: '', required: true
306
314
  param :age, Integer, desc: '', required: false
307
315
  param :color, String, desc: '', required: false
316
+ param :sibling_names, Array, desc: '', required: false
308
317
  param :address, Hash, desc: '', required: true do
309
318
  param :street, String, desc: '', required: true
310
319
  param :city, String, desc: '', required: true
@@ -312,6 +321,10 @@ describe SimpleParams::Params do
312
321
  param :state, String, desc: '', required: false
313
322
  param :company, String, desc: '', required: false
314
323
  end
324
+ param :dogs, Array, desc: '', required: true do
325
+ param :name, String, desc: '', required: true
326
+ param :age, Integer, desc: '', required: true
327
+ end
315
328
  API_PIE_DOCS
316
329
 
317
330
  expect(documentation).to be_a String
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleParams::ApiPieDoc::NestedArray do
4
+
5
+ let(:simple_param_attribute) {
6
+ {:address=>
7
+ {:street=>{:type=>:string},
8
+ :city=>{:validations=>{:length=>{:in=>4..40}, :presence=>true}, :type=>:string},
9
+ :zip_code=>{:optional=>true, :type=>:string},
10
+ :state=>{:default=>"North Carolina", :type=>:string}
11
+ },
12
+ :options=>{desc: 'i like pie'}
13
+ }
14
+ }
15
+ let(:nested_attribute) { described_class.new(simple_param_attribute) }
16
+
17
+ it_behaves_like 'a base attribute'
18
+
19
+ describe '#initialize' do
20
+ specify 'should give instance an attribute' do
21
+ expect(nested_attribute.attribute).to eq simple_param_attribute
22
+ end
23
+
24
+ specify 'should give instance options' do
25
+ expect(nested_attribute.options).to eq({ desc: 'i like pie' })
26
+ end
27
+ end
28
+
29
+ describe '#name' do
30
+ specify 'should set respond with the right name' do
31
+ expect(nested_attribute.name).to eq 'address'
32
+ end
33
+ end
34
+
35
+ describe '#options' do
36
+ specify 'should return nested attribute options' do
37
+ expect(nested_attribute.options).to eq({desc: 'i like pie'})
38
+ end
39
+ end
40
+
41
+ describe '#to_s' do
42
+ specify 'should return properly formatted string' do
43
+ expect(nested_attribute.to_s).to eq("param :address, Array, desc: 'i like pie', required: true do\nparam :street, String, desc: '', required: true\nparam :city, String, desc: '', required: true\nparam :zip_code, String, desc: '', required: false\nparam :state, String, desc: '', required: false\nend")
44
+ end
45
+ end
46
+ end
@@ -16,17 +16,31 @@ describe SimpleParams::ApiPieDoc do
16
16
  expect(api_pie_doc.nested_hashes.keys).to eq [:address, :phone]
17
17
  end
18
18
 
19
+ specify "should give object nested_arrays" do
20
+ expect(api_pie_doc.nested_arrays.keys).to eq [:dogs]
21
+ end
22
+
19
23
  specify "should call #build_nested_attributes" do
20
24
  expect_any_instance_of(SimpleParams::ApiPieDoc).to receive(:build_nested_attributes)
21
25
  api_pie_doc
22
26
  end
23
27
 
28
+ specify "should call #build_nested_array_attributes" do
29
+ expect_any_instance_of(SimpleParams::ApiPieDoc).to receive(:build_nested_array_attributes)
30
+ api_pie_doc
31
+ end
32
+
24
33
  specify "should give object nested_attributes" do
25
34
  expect(api_pie_doc.nested_attributes.flat_map(&:keys)).to include(:address, :phone)
26
35
  expect(api_pie_doc.nested_attributes[0].values.flat_map(&:keys)).to eq [:street, :city, :zip_code, :state]
27
36
  expect(api_pie_doc.nested_attributes[1].values.flat_map(&:keys)).to eq [:cell_phone, :phone_number, :area_code]
28
37
  end
29
38
 
39
+ specify "should give object nested_array_attributes" do
40
+ expect(api_pie_doc.nested_array_attributes.flat_map(&:keys)).to include(:dogs)
41
+ expect(api_pie_doc.nested_array_attributes[0].values.flat_map(&:keys)).to eq [:name, :age]
42
+ end
43
+
30
44
  specify "should give object docs" do
31
45
  expect(api_pie_doc.docs).to eq []
32
46
  end
data/spec/errors_spec.rb CHANGED
@@ -4,7 +4,10 @@ describe SimpleParams::Errors do
4
4
  class Person
5
5
  extend ActiveModel::Naming
6
6
  def initialize
7
- @errors = SimpleParams::Errors.new(self, ["dog"])
7
+ @errors = SimpleParams::Errors.new(self,
8
+ { dog: dog.errors },
9
+ { cats: cats_errors },
10
+ )
8
11
  end
9
12
 
10
13
  attr_accessor :name, :age
@@ -14,6 +17,14 @@ describe SimpleParams::Errors do
14
17
  @dog ||= Dog.new
15
18
  end
16
19
 
20
+ def cats
21
+ @cats ||= [Cat.new]
22
+ end
23
+
24
+ def cats_errors
25
+ cats.map { |cat| cat.errors }
26
+ end
27
+
17
28
  def read_attribute_for_validation(attr)
18
29
  send(attr)
19
30
  end
@@ -49,7 +60,30 @@ describe SimpleParams::Errors do
49
60
  end
50
61
  end
51
62
 
52
- describe "setting and getting errors" do
63
+ class Cat
64
+ extend ActiveModel::Naming
65
+ def initialize
66
+ @errors = SimpleParams::Errors.new(self)
67
+ end
68
+
69
+ attr_accessor :name
70
+ attr_accessor :age
71
+ attr_reader :errors
72
+
73
+ def read_attribute_for_validation(attr)
74
+ send(attr)
75
+ end
76
+
77
+ def self.human_attribute_name(attr, options = {})
78
+ attr
79
+ end
80
+
81
+ def self.lookup_ancestors
82
+ [self]
83
+ end
84
+ end
85
+
86
+ describe "setting and getting errors", setters_getters: true do
53
87
  it "get returns the errors for the provided key" do
54
88
  errors = SimpleParams::Errors.new(self)
55
89
  errors[:foo] = "omg"
@@ -105,7 +139,7 @@ describe SimpleParams::Errors do
105
139
  end
106
140
  end
107
141
 
108
- describe "setting and getting nested error model" do
142
+ describe "setting and getting nested error model", nested_model: true do
109
143
  it "can access error model" do
110
144
  person = Person.new
111
145
  dog = person.dog
@@ -152,7 +186,55 @@ describe SimpleParams::Errors do
152
186
  end
153
187
  end
154
188
 
155
- describe "#clear" do
189
+ describe "setting and getting nested array error model", nested_array: true do
190
+ it "can access error model" do
191
+ person = Person.new
192
+ cats = person.cats
193
+ cat_errors = cats.first.errors
194
+ person.errors[:cats][0].should eq(cat_errors)
195
+ end
196
+
197
+ it "can add to nested errors through []", failing: true do
198
+ person = Person.new
199
+ person.errors[:cats].first[:base] = 'should not be nil'
200
+ person.errors[:cats].first[:base].should eq(['should not be nil'])
201
+ person.cats.first.errors[:base].should eq(['should not be nil'])
202
+ end
203
+
204
+ it "can add to nested errors through add" do
205
+ person = Person.new
206
+ person.errors[:cats].first.add(:age, 'should not be nil')
207
+ person.cats.first.errors[:age].should eq(['should not be nil'])
208
+ end
209
+
210
+ it "can add multiple errors to nested errors through []" do
211
+ person = Person.new
212
+ person.errors[:cats].first[:name] = 'should not be nil'
213
+ person.errors[:cats].first[:name] = 'must be cute'
214
+ person.cats.first.errors[:name].should eq(['should not be nil', 'must be cute'])
215
+ end
216
+
217
+ it "can add multiple errors to nested errors through add" do
218
+ person = Person.new
219
+ person.errors[:cats].first.add(:name, 'should not be nil')
220
+ person.errors[:cats].first.add(:name, 'must be cute')
221
+ person.cats.first.errors[:name].should eq(['should not be nil', 'must be cute'])
222
+ end
223
+
224
+ it "can add individual errors to nested attributes through []" do
225
+ person = Person.new
226
+ person.errors[:cats][0][:age] = 'should not be nil'
227
+ person.cats.first.errors[:age].should eq(['should not be nil'])
228
+ end
229
+
230
+ it "can add individual errors to nested attributes through add" do
231
+ person = Person.new
232
+ person.errors[:cats].first.add(:age, 'should not be nil')
233
+ person.cats.first.errors[:age].should eq(['should not be nil'])
234
+ end
235
+ end
236
+
237
+ describe "#clear", clear: true do
156
238
  it "clears errors" do
157
239
  person = Person.new
158
240
  person.errors[:name] = 'should not be nil'
@@ -173,7 +255,7 @@ describe SimpleParams::Errors do
173
255
  end
174
256
  end
175
257
 
176
- describe "#empty?, #blank?, and #include?" do
258
+ describe "#empty?, #blank?, and #include?", empty: true do
177
259
  it "is empty without any errors" do
178
260
  person = Person.new
179
261
  person.errors.should be_empty
@@ -201,7 +283,7 @@ describe SimpleParams::Errors do
201
283
  end
202
284
  end
203
285
 
204
- describe "#added?" do
286
+ describe "#added?", added: true do
205
287
  it "added? detects if a specific error was added to the object" do
206
288
  person = Person.new
207
289
  person.errors.add(:name, "can not be blank")
@@ -246,7 +328,7 @@ describe SimpleParams::Errors do
246
328
  end
247
329
  end
248
330
 
249
- describe "#size" do
331
+ describe "#size", size: true do
250
332
  it "size calculates the number of error messages" do
251
333
  person = Person.new
252
334
  person.errors.add(:name, "can not be blank")
@@ -260,7 +342,7 @@ describe SimpleParams::Errors do
260
342
  end
261
343
  end
262
344
 
263
- describe "#to_a" do
345
+ describe "#to_a", to_a: true do
264
346
  it "to_a returns the list of errors with complete messages containing the attribute names" do
265
347
  person = Person.new
266
348
  person.errors.add(:name, "can not be blank")
@@ -276,7 +358,7 @@ describe SimpleParams::Errors do
276
358
  end
277
359
  end
278
360
 
279
- describe "#to_s" do
361
+ describe "#to_s", to_s: true do
280
362
  it "to_a returns the list of errors with complete messages containing the attribute names" do
281
363
  person = Person.new
282
364
  person.errors.add(:name, "can not be blank")
@@ -292,8 +374,8 @@ describe SimpleParams::Errors do
292
374
  end
293
375
  end
294
376
 
295
- describe "#to_hash" do
296
- it "to_hash returns the error messages hash" do
377
+ describe "#to_hash", to_hash: true do
378
+ it "to_hash returns the error messages hash", hash_failing: true do
297
379
  person = Person.new
298
380
  person.errors.add(:name, "can not be blank")
299
381
  person.errors.to_hash.should eq({ name: ["can not be blank"] })
@@ -328,7 +410,7 @@ describe SimpleParams::Errors do
328
410
  end
329
411
  end
330
412
 
331
- describe "#as_json" do
413
+ describe "#as_json", as_json: true do
332
414
  it "as_json creates a json formatted representation of the errors hash" do
333
415
  person = Person.new
334
416
  person.errors[:name] = 'can not be nil'
@@ -368,7 +450,7 @@ describe SimpleParams::Errors do
368
450
  end
369
451
  end
370
452
 
371
- describe "#full_messages" do
453
+ describe "#full_messages", full_messages: true do
372
454
  it "full_messages creates a list of error messages with the attribute name included" do
373
455
  person = Person.new
374
456
  person.errors.add(:name, "can not be blank")
@@ -408,7 +490,7 @@ describe SimpleParams::Errors do
408
490
  end
409
491
  end
410
492
 
411
- describe "#generate_message" do
493
+ describe "#generate_message", generate_message: true do
412
494
  it "generate_message works without i18n_scope" do
413
495
  person = Person.new
414
496
  Person.should_not respond_to(:i18n_scope)
@@ -418,7 +500,7 @@ describe SimpleParams::Errors do
418
500
  end
419
501
  end
420
502
 
421
- describe "#adds_on_empty" do
503
+ describe "#adds_on_empty", add_on_empty: true do
422
504
  it "add_on_empty generates message" do
423
505
  person = Person.new
424
506
  person.errors.should_receive(:generate_message).with(:name, :empty, {})
@@ -446,7 +528,7 @@ describe SimpleParams::Errors do
446
528
  end
447
529
  end
448
530
 
449
- describe "#adds_on_blank" do
531
+ describe "#adds_on_blank", add_on_blank: true do
450
532
  it "add_on_blank generates message" do
451
533
  person = Person.new
452
534
  person.errors.should_receive(:generate_message).with(:name, :blank, {})
@@ -27,6 +27,11 @@ class DummyParams < SimpleParams::Params
27
27
  }
28
28
  end
29
29
 
30
+ nested_array :dogs do
31
+ param :name
32
+ param :age, type: :integer, validations: { inclusion: { in: 1..20 } }
33
+ end
34
+
30
35
  def lower_case_colors(val)
31
36
  val.downcase
32
37
  end
data/spec/params_spec.rb CHANGED
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'fixtures/dummy_params'
3
3
 
4
4
  describe SimpleParams::Params do
5
- describe "strict parameter enforcement" do
5
+ describe "strict parameter enforcement", param_enforcement: true do
6
6
  context "with default handling (strict enforcement)" do
7
7
  it "raises error on expected param" do
8
8
  expect { DummyParams.new(other_param: 1) }.to raise_error(SimpleParamsError)
@@ -67,12 +67,26 @@ describe SimpleParams::Params do
67
67
  params.address.zip_code.should eq("20165")
68
68
  end
69
69
  end
70
+
71
+ describe "nested arrays", nested: true do
72
+ it "can access nested arrays as arrays" do
73
+ params.dogs.should respond_to(:first)
74
+ params.dogs.first.should be_nil
75
+ end
76
+
77
+ it "can access nested arrays as arrays with data", failing: true do
78
+ params = DummyParams.new(dogs: [{ name: "Spot", age: 20 }])
79
+ params.dogs.should respond_to(:first)
80
+ params.dogs.first.should_not be_nil
81
+ params.dogs.first.name.should eq("Spot")
82
+ end
83
+ end
70
84
  end
71
85
 
72
86
  describe "attributes", attributes: true do
73
87
  it "returns array of attribute symbols" do
74
88
  params = DummyParams.new
75
- params.attributes.should eq([:name, :age, :first_initial, :amount, :color, :height, :address, :phone])
89
+ params.attributes.should eq([:name, :age, :first_initial, :amount, :color, :height, :address, :phone, :dogs])
76
90
  end
77
91
  end
78
92
 
@@ -123,7 +137,40 @@ describe SimpleParams::Params do
123
137
  end
124
138
  end
125
139
 
126
- describe "optional params with inclusion" do
140
+ describe "validations", validations: true do
141
+ let(:params) do
142
+ DummyParams.new(
143
+ name: nil,
144
+ age: 30,
145
+ address: {
146
+ city: "Greenville"
147
+ },
148
+ dogs: [
149
+ { name: "Spot", age: 12 },
150
+ { age: 14 }
151
+ ]
152
+ )
153
+ end
154
+
155
+ it "validates required params" do
156
+ params.should_not be_valid
157
+ params.errors[:name].should eq(["can't be blank"])
158
+ end
159
+
160
+ it "validates nested params" do
161
+ params.should_not be_valid
162
+ params.address.errors[:street].should eq(["can't be blank"])
163
+ params.errors[:address][:street].should eq(["can't be blank"])
164
+ end
165
+
166
+ it "validates nested arrays" do
167
+ params.should_not be_valid
168
+ params.errors[:dogs][0][:name].should eq([])
169
+ params.errors[:dogs][1][:name].should eq(["can't be blank"])
170
+ end
171
+ end
172
+
173
+ describe "optional params with inclusion", optional_params: true do
127
174
  let(:params) do
128
175
  DummyParams.new(
129
176
  name: "Bill",
@@ -311,7 +358,7 @@ describe SimpleParams::Params do
311
358
  end
312
359
 
313
360
  describe "api_pie_documentation", api_pie_documentation: true do
314
- it "generates valida api_pie documentation" do
361
+ it "generates valid api_pie documentation" do
315
362
  documentation = DummyParams.api_pie_documentation
316
363
  api_docs = <<-API_PIE_DOCS
317
364
  param :name, String, desc: '', required: true
@@ -331,6 +378,10 @@ describe SimpleParams::Params do
331
378
  param :phone_number, String, desc: '', required: true
332
379
  param :area_code, String, desc: '', required: false
333
380
  end
381
+ param :dogs, Array, desc: '', required: true do
382
+ param :name, String, desc: '', required: true
383
+ param :age, Integer, desc: '', required: true
384
+ end
334
385
  API_PIE_DOCS
335
386
 
336
387
  expect(documentation).to be_a String
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_params
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - brycesenz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-23 00:00:00.000000000 Z
11
+ date: 2015-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -131,6 +131,7 @@ files:
131
131
  - lib/simple_params/api_pie_doc.rb
132
132
  - lib/simple_params/api_pie_doc/attribute.rb
133
133
  - lib/simple_params/api_pie_doc/attribute_base.rb
134
+ - lib/simple_params/api_pie_doc/nested_array.rb
134
135
  - lib/simple_params/api_pie_doc/nested_attribute.rb
135
136
  - lib/simple_params/attribute.rb
136
137
  - lib/simple_params/errors.rb
@@ -149,6 +150,7 @@ files:
149
150
  - simple_params.gemspec
150
151
  - spec/acceptance_spec.rb
151
152
  - spec/api_pie_doc/attribute_spec.rb
153
+ - spec/api_pie_doc/nested_array_spec.rb
152
154
  - spec/api_pie_doc/nested_attribute_spec.rb
153
155
  - spec/api_pie_doc_spec.rb
154
156
  - spec/attribute_spec.rb
@@ -191,6 +193,7 @@ summary: A DSL for specifying params, including type coercion and validation
191
193
  test_files:
192
194
  - spec/acceptance_spec.rb
193
195
  - spec/api_pie_doc/attribute_spec.rb
196
+ - spec/api_pie_doc/nested_array_spec.rb
194
197
  - spec/api_pie_doc/nested_attribute_spec.rb
195
198
  - spec/api_pie_doc_spec.rb
196
199
  - spec/attribute_spec.rb