simple_params 1.0.3 → 1.0.4

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.
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