simple_params 0.0.2.pre1 → 0.0.2.pre2

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
- MzEzZDlkYmYyYWJmZjI3NWI4OTg3ZTFhMjJiYmQzYjAwYjIwNmY1YQ==
4
+ MTYwZjZjZDIzZTBhYzk1OTljYWFmMzdmMWUzYjk0YmM1YWVjYWY2Mg==
5
5
  data.tar.gz: !binary |-
6
- MzViNGIyYmIxY2EyMDU4MzY0MmU1NTA3N2FiYzY1MWIxODJhYzNmNA==
6
+ NDJjZDI0YzI5ZTRjNTZmMjAzZmQ3MjZmODg1OGI1NzZhNzI2ODFiYQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MTlhMzg1OTVlZTE2YjQ0YzcxOWY5YTYzZjg5NDQzYmJkZTU1YjY5Y2NlM2Vm
10
- NjgwMzEyYjA2Mjg5ZTQ0MTJjYTgyN2JkOWNlMDI2MDgxMTc2ZjMzNzI5ZTMz
11
- YTg5MzUyMmRmYzc2N2RmODk2MDZlOWM5NzcyZGViZTUzMGRmMmQ=
9
+ MTE2MDAzNGUwNTg0MGVmZmJhMzdkZjVlMjE1M2RhODc1NGZjOTVkNTA2Zjhm
10
+ MDY5ZWNhMTZmYTAzMGQ3NTY3YjZjNjQwYjE2MmI5NGI5YWNkNjdhODY1ZDBl
11
+ NzIxNzUzNTQ5NzA3NmQwZmJlYzIzYzhiMjllMjJkYzJmOTk2NTM=
12
12
  data.tar.gz: !binary |-
13
- NDZmZmUzMWI4NGRhZmFjM2IxZTczOTNhMWVkODBhZTFkM2Y3Y2ZkMjU3YThi
14
- NWQxOWNkYzQwYjhhZGFhMDYwMjM3MWNmMTU1ZmIxNTJiOTUwM2FlM2I0NWJm
15
- ZDVlMjIzMGYyN2UyYTc0Y2FkZjI3ZDcxZmJkMjYxYmU2NWM4MDQ=
13
+ M2FjMTdhYTQ0NTM4M2E1MGIzZjZhMDcwNzI0MTBiNDY3NGM3YTYwOTcyMmM1
14
+ YjdiYmM2MjAyYTM2ODlmYTdmZTFiY2U2MDhmYTQ2OTdlYTMyZTI4MzZkOGZh
15
+ MWQ1YWMwMWIwODQ3NzdjNWY2MzFkODg3ZmM1ZjgzYmU0NDA1NTM=
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simple_params (0.0.1pre2)
4
+ simple_params (0.0.2.pre1)
5
5
  activemodel (>= 3.0, < 5.0)
6
6
  virtus (>= 1.0.0)
7
7
 
data/README.md CHANGED
@@ -29,8 +29,8 @@ All you need to do is create a class to specify accepted parameters and validati
29
29
  ```ruby
30
30
  class MyParams < SimpleParams::Params
31
31
  param :name
32
- param :age, type: Integer
33
- param :date_of_birth, type: Date, optional: true
32
+ param :age, type: :integer
33
+ param :date_of_birth, type: :date, optional: true
34
34
  param :hair_color, default: "brown", validations: { inclusion: { in: ["brown", "red", "blonde", "white"] }}
35
35
 
36
36
  nested_hash :address do
@@ -128,9 +128,9 @@ By default, params are assumed to be strings, so there is no need to specify Str
128
128
  ```ruby
129
129
  class CoercionParams < SimpleParams::Params
130
130
  param :name
131
- param :age, type: Integer
132
- param :date_of_birth, type: Date
133
- param :pocket_change, type: BigDecimal
131
+ param :age, type: :integer
132
+ param :date_of_birth, type: :date
133
+ param :pocket_change, type: :decimal
134
134
  end
135
135
 
136
136
  params = CoercionParams.new(name: "Bob", age: "21", date_of_birth: "June 1st, 1980", pocket_change: "2.35")
@@ -152,6 +152,47 @@ class CoercionParams < SimpleParams::Params
152
152
  end
153
153
  ```
154
154
 
155
+ # Formatters
156
+
157
+ SimpleParams also provides a way to define a formatter for your attributes. You can use either Proc, or a method name. If you do the latter, the method must accept an input value, which will be the un-formatted value of your attribute.
158
+
159
+ ```ruby
160
+ class FormattedParams < SimpleParams::Params
161
+ param :name, formatter: :first_ten
162
+ param :age, formatter: lambda { |params, age| [age, 100].min }
163
+
164
+ def first_ten(val)
165
+ val.first(10)
166
+ end
167
+ end
168
+
169
+ params = FormattedParams.new(name: "Thomas Paine", age: 500)
170
+
171
+ params.name #=> "Thomas Pai"
172
+ params.age #=> 100
173
+ ```
174
+
175
+ # Strict/Flexible Parameter Enforcement
176
+
177
+ By default, SimpleParams will throw an error if you try to assign a parameter not defined within your class. However, you can override this setting to allow for flexible parameter assignment.
178
+
179
+ ```ruby
180
+ class FlexibleParams < SimpleParams::Params
181
+ allow_undefined_params
182
+ param :name
183
+ param :age
184
+ end
185
+
186
+ params = FlexibleParams.new(name: "Bryce", age: 30, weight: 160, dog: { name: "Bailey", breed: "Shiba Inu" })
187
+
188
+ params.name #=> "Bryce"
189
+ params.age #=> 30
190
+ params.weight #=> 160
191
+ params.dog.name #=> "Bailey"
192
+ params.dog.breed #=> "Shiba Inu"
193
+ ```
194
+
195
+
155
196
  ## Contributing
156
197
 
157
198
  1. Fork it
@@ -0,0 +1,62 @@
1
+ require "active_model"
2
+ require "virtus"
3
+
4
+ module SimpleParams
5
+ class Attribute
6
+ TYPE_MAPPINGS = {
7
+ integer: Integer,
8
+ string: String,
9
+ decimal: BigDecimal,
10
+ datetime: DateTime,
11
+ date: Date,
12
+ time: Time,
13
+ float: Float,
14
+ boolean: Axiom::Types::Boolean, # See note on Virtus
15
+ array: Array,
16
+ hash: Hash
17
+ }
18
+
19
+ attr_reader :parent
20
+ attr_reader :name
21
+
22
+ def initialize(parent, name, opts={})
23
+ @parent = parent
24
+ @name = name.to_sym
25
+ @type = TYPE_MAPPINGS[opts[:type]]
26
+ @value = nil
27
+ @default = opts[:default]
28
+ @formatter = opts[:formatter]
29
+ end
30
+
31
+ def raw_value
32
+ @value.blank? ? default : @value
33
+ end
34
+
35
+ def value
36
+ return raw_value if raw_value.blank?
37
+ if @formatter.present?
38
+ Formatter.new(@parent, @formatter).format(raw_value)
39
+ else
40
+ raw_value
41
+ end
42
+ end
43
+
44
+ def value=(val)
45
+ @value = if @type.present?
46
+ virtus_attr = Virtus::Attribute.build(@type)
47
+ virtus_attr.coerce(val)
48
+ else
49
+ val
50
+ end
51
+ end
52
+
53
+ private
54
+ def default
55
+ if @default.is_a?(Proc)
56
+ @default.call(parent, self)
57
+ else
58
+ @default
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,20 @@
1
+ require "active_model"
2
+
3
+ module SimpleParams
4
+ class Formatter
5
+ extend ActiveSupport::Concern
6
+
7
+ def initialize(attribute, formatter)
8
+ @attribute = attribute
9
+ @formatter = formatter
10
+ end
11
+
12
+ def format(value)
13
+ if @formatter.is_a?(Proc)
14
+ @formatter.call(@attribute, value)
15
+ else
16
+ @attribute.send(@formatter, value)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -6,32 +6,40 @@ module SimpleParams
6
6
  include Virtus.model
7
7
  include ActiveModel::Validations
8
8
  include SimpleParams::Validations
9
- include SimpleParams::Formatters
10
9
 
11
10
  class << self
12
- TYPE_MAPPINGS = {
13
- integer: Integer,
14
- string: String,
15
- decimal: BigDecimal,
16
- datetime: DateTime,
17
- date: Time,
18
- time: DateTime,
19
- float: Float,
20
- boolean: Axiom::Types::Boolean, # See note on Virtus
21
- array: Array,
22
- hash: Hash
23
- }
24
-
25
- TYPE_MAPPINGS.each_pair do |sym, klass|
11
+ TYPES = [
12
+ :integer,
13
+ :string,
14
+ :decimal,
15
+ :datetime,
16
+ :date,
17
+ :time,
18
+ :float,
19
+ :boolean,
20
+ :array,
21
+ :hash
22
+ ]
23
+
24
+ TYPES.each do |sym|
26
25
  define_method("#{sym}_param") do |name, opts={}|
27
- param(name, opts.merge(type: klass))
26
+ param(name, opts.merge(type: sym))
28
27
  end
29
28
  end
30
29
 
30
+ attr_accessor :strict_enforcement
31
+
32
+ def strict
33
+ @strict_enforcement = true
34
+ end
35
+
36
+ def allow_undefined_params
37
+ @strict_enforcement = false
38
+ end
39
+
31
40
  def param(name, opts={})
32
41
  define_attribute(name, opts)
33
42
  add_validations(name, opts)
34
- add_formatters(name, opts)
35
43
  end
36
44
 
37
45
  def nested_hash(name, opts={}, &block)
@@ -47,14 +55,24 @@ module SimpleParams
47
55
  @nested_hashes || {}
48
56
  end
49
57
 
58
+ def defined_attributes
59
+ @define_attributes ||= {}
60
+ end
50
61
  private
62
+
51
63
  def define_attribute(name, opts = {})
52
- type = opts[:type] || String
53
- default = opts[:default]
54
- if default.present?
55
- attribute name, type, default: default
56
- else
57
- attribute name, type
64
+ opts[:type] ||= :string
65
+ defined_attributes[name.to_sym] = opts
66
+ attr_accessor "#{name}_attribute"
67
+
68
+ define_method("#{name}") do
69
+ attribute = send("#{name}_attribute")
70
+ attribute.send("value")
71
+ end
72
+
73
+ define_method("#{name}=") do |val|
74
+ attribute = send("#{name}_attribute")
75
+ attribute.send("value=", val)
58
76
  end
59
77
  end
60
78
 
@@ -64,13 +82,6 @@ module SimpleParams
64
82
  validates name, validations unless validations.empty?
65
83
  end
66
84
 
67
- def add_formatters(name, opts = {})
68
- formatter = opts[:format]
69
- unless formatter.nil?
70
- format name, formatter
71
- end
72
- end
73
-
74
85
  def define_nested_class(&block)
75
86
  Class.new(Params).tap do |klass|
76
87
  name_function = Proc.new {
@@ -85,41 +96,69 @@ module SimpleParams
85
96
  end
86
97
 
87
98
  def initialize(params={}, parent = nil)
99
+ # Set default strict params
100
+ if self.class.strict_enforcement.nil?
101
+ self.class.strict_enforcement = true
102
+ end
103
+
88
104
  @parent = parent
105
+ # Initializing Params
89
106
  @original_params = hash_to_symbolized_hash(params)
107
+ define_attributes(@original_params)
108
+
109
+ # Errors
90
110
  @nested_params = nested_hashes.keys
91
111
  @errors = SimpleParams::Errors.new(self, @nested_params)
92
- initialize_nested_classes
112
+
113
+ # Nested Classes
93
114
  set_accessors(params)
94
- run_formatters
95
- # This method comes from Virtus
96
- # virtus/lib/virtus/instance_methods.rb
97
- set_default_attributes
115
+ initialize_nested_classes
116
+ end
117
+
118
+ def define_attributes(params)
119
+ self.class.defined_attributes.each_pair do |key, opts|
120
+ send("#{key}_attribute=", Attribute.new(self, key, opts))
121
+ end
122
+ end
123
+
124
+ # Overriding this method to allow for non-strict enforcement!
125
+ def method_missing(method_name, *arguments, &block)
126
+ if strict_enforcement?
127
+ raise SimpleParamsError, "parameter #{method_name} is not defined."
128
+ else
129
+ if @original_params.include?(method_name.to_sym)
130
+ value = @original_params[method_name.to_sym]
131
+ if value.is_a?(Hash)
132
+ define_anonymous_class(value)
133
+ else
134
+ Attribute.new(self, method_name).value = value
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ def respond_to?(method_name, include_private = false)
141
+ if strict_enforcement?
142
+ super
143
+ else
144
+ @original_params.include?(method_name.to_sym) || super
145
+ end
146
+ end
147
+
148
+ private
149
+ def strict_enforcement?
150
+ self.class.strict_enforcement
98
151
  end
99
152
 
100
- protected
101
153
  def set_accessors(params={})
102
154
  params.each do |attribute_name, value|
103
155
  # Don't set accessors for nested classes
104
156
  unless value.is_a?(Hash)
105
157
  send("#{attribute_name}=", value)
106
- reset_blank_attributes
107
- end
108
- end
109
- end
110
-
111
- def reset_blank_attributes
112
- # Reset to the default value for blank attributes
113
- attributes.each do |attribute_name, value|
114
- if send(attribute_name).blank?
115
- # This method comes from Virtus
116
- # virtus/lib/virtus/instance_methods.rb
117
- reset_attribute(attribute_name)
118
158
  end
119
159
  end
120
160
  end
121
161
 
122
- private
123
162
  def hash_to_symbolized_hash(hash)
124
163
  hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
125
164
  end
@@ -134,5 +173,18 @@ module SimpleParams
134
173
  send("#{key}=", klass.new(initialization_params, self))
135
174
  end
136
175
  end
176
+
177
+ def define_anonymous_class(hash)
178
+ klass = Class.new(Params).tap do |klass|
179
+ name_function = Proc.new {
180
+ def self.model_name
181
+ ActiveModel::Name.new(self, nil, "temp")
182
+ end
183
+ }
184
+ klass.class_eval(&name_function)
185
+ end
186
+ klass.allow_undefined_params
187
+ klass.new(hash)
188
+ end
137
189
  end
138
190
  end
@@ -0,0 +1,8 @@
1
+ class SimpleParamsError < StandardError
2
+ attr_reader :original
3
+
4
+ def initialize(msg, original=nil)
5
+ super(msg)
6
+ @original = original
7
+ end
8
+ end
@@ -1,3 +1,3 @@
1
1
  module SimpleParams
2
- VERSION = "0.0.2.pre1"
2
+ VERSION = "0.0.2.pre2"
3
3
  end
data/lib/simple_params.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'simple_params/version'
2
- require 'simple_params/formatters'
2
+ require 'simple_params/attribute'
3
+ require 'simple_params/formatter'
3
4
  require 'simple_params/errors'
4
5
  require 'simple_params/validations'
5
6
  require 'simple_params/params'
7
+ require 'simple_params/simple_params_error'
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleParams::Attribute do
4
+ class House
5
+ def initialize(params={})
6
+ params.each { |k,v| send("#{k}=",v) }
7
+ end
8
+
9
+ attr_accessor :rooms, :rent
10
+
11
+ def name
12
+ "My house"
13
+ end
14
+
15
+ def capitalize(val)
16
+ val.upcase
17
+ end
18
+ end
19
+
20
+ let(:house) { House.new }
21
+
22
+ describe "attributes" do
23
+ let(:model) { described_class.new(house, "color")}
24
+
25
+ it "has correct parent attribute" do
26
+ model.parent.should eq(house)
27
+ end
28
+
29
+ it "has correct name attribute" do
30
+ model.name.should eq(:color)
31
+ end
32
+
33
+ describe "setting and getting value" do
34
+ let(:model) { described_class.new(house, "color")}
35
+
36
+ it "has nil value" do
37
+ model.value.should be_nil
38
+ end
39
+
40
+ it "can set value" do
41
+ model.value = "Dummy"
42
+ model.value.should eq("Dummy")
43
+ end
44
+ end
45
+ end
46
+
47
+ describe "coercion" do
48
+ context "without type" do
49
+ let(:model) { described_class.new(house, "color")}
50
+
51
+ it "does not coerce value" do
52
+ model.value = 1
53
+ model.value.should eq(1)
54
+ end
55
+ end
56
+
57
+ context "with :integer type" do
58
+ let(:model) { described_class.new(house, "color", { type: :integer })}
59
+
60
+ it "coerces values into Integer" do
61
+ model.value = "1"
62
+ model.value.should eq(1)
63
+ end
64
+ end
65
+
66
+ context "with :decimal type" do
67
+ let(:model) { described_class.new(house, "color", { type: :decimal })}
68
+
69
+ it "coerces values into BigDecimal" do
70
+ model.value = "1"
71
+ model.value.should eq(BigDecimal.new("1.0"))
72
+ end
73
+ end
74
+
75
+ context "with :float type" do
76
+ let(:model) { described_class.new(house, "color", { type: :float })}
77
+
78
+ it "coerces values into Float" do
79
+ model.value = "1"
80
+ model.value.should eq(1.0)
81
+ end
82
+ end
83
+
84
+ context "with :boolean type" do
85
+ let(:model) { described_class.new(house, "color", { type: :boolean })}
86
+
87
+ it "coerces values into Boolean" do
88
+ model.value = "0"
89
+ model.value.should be_falsey
90
+ end
91
+ end
92
+ end
93
+
94
+ describe "defaults" do
95
+ context "with static default" do
96
+ let(:model) { described_class.new(house, "color", { default: "something" })}
97
+
98
+ it "uses default when value not set" do
99
+ model.value.should eq("something")
100
+ end
101
+ end
102
+
103
+ context "with Proc default" do
104
+ let(:default) do
105
+ lambda { |parent, param| parent.name + " " + "rocks!" }
106
+ end
107
+ let(:model) { described_class.new(house, "color", { default: default })}
108
+
109
+ it "uses default when value not set" do
110
+ model.value.should eq("My house rocks!")
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "formatter" do
116
+ context "with function reference" do
117
+ let(:model) { described_class.new(house, "color", { formatter: :capitalize })}
118
+
119
+ it "uses method formatter from parent" do
120
+ model.value = "lower"
121
+ model.value.should eq("LOWER")
122
+ end
123
+ end
124
+
125
+ context "with Proc formatter" do
126
+ let(:formatter) do
127
+ lambda { |parent, param| parent.name + " " + param.upcase }
128
+ end
129
+
130
+ let(:model) { described_class.new(house, "color", { formatter: formatter })}
131
+
132
+ it "uses Proc formatter on value" do
133
+ model.value = "rocks"
134
+ model.value.should eq("My house ROCKS")
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleParams::Formatter do
4
+ class MyAttribute
5
+ def some_function(value)
6
+ "dummy value = " + value
7
+ end
8
+ end
9
+
10
+ let(:attribute) { MyAttribute.new }
11
+
12
+ describe "formatting" do
13
+ context "with method name formatter" do
14
+ let(:formatter) { described_class.new(attribute, :some_function) }
15
+
16
+ it "calls the method on the attribute" do
17
+ formatter.format("myval").should eq("dummy value = myval")
18
+ end
19
+ end
20
+
21
+ context "with Proc default" do
22
+ let(:default) do
23
+ lambda { |attribute, value| attribute.some_function("other") + ", not #{value}" }
24
+ end
25
+
26
+ let(:formatter) { described_class.new(attribute, default) }
27
+
28
+ it "calls the Proc with attribute and value" do
29
+ formatter.format("myval").should eq("dummy value = other, not myval")
30
+ end
31
+ end
32
+ end
33
+ end
data/spec/params_spec.rb CHANGED
@@ -4,23 +4,23 @@ class DummyParams < SimpleParams::Params
4
4
  string_param :name
5
5
  integer_param :age, optional: true
6
6
  string_param :first_initial, default: lambda { |params, param| params.name[0] if params.name.present? }
7
- decimal_param :amount, optional: true, default: 0.10, format: lambda { |params, param| param.round(2) }
8
- param :color, default: "red", validations: { inclusion: { in: ["red", "green"] }}, format: :lower_case_colors
7
+ decimal_param :amount, optional: true, default: 0.10, formatter: lambda { |params, param| param.round(2) }
8
+ param :color, default: "red", validations: { inclusion: { in: ["red", "green"] }}, formatter: :lower_case_colors
9
9
 
10
10
  nested_hash :address do
11
11
  string_param :street
12
12
  string_param :city, validations: { length: { in: 4..40 } }
13
13
  string_param :zip_code, optional: true, validations: { length: { in: 5..9 } }
14
- param :state, default: "North Carolina", format: :transform_state_code
14
+ param :state, default: "North Carolina", formatter: :transform_state_code
15
15
 
16
- def transform_state_code
17
- state == "SC" ? "South Carolina" : state
16
+ def transform_state_code(val)
17
+ val == "SC" ? "South Carolina" : val
18
18
  end
19
19
  end
20
20
 
21
21
  nested_hash :phone do
22
22
  boolean_param :cell_phone, default: true
23
- string_param :phone_number, validations: { length: { in: 7..10 } }, format: lambda { |params, attribute| attribute.gsub(/\D/, "") }
23
+ string_param :phone_number, validations: { length: { in: 7..10 } }, formatter: lambda { |params, attribute| attribute.gsub(/\D/, "") }
24
24
  string_param :area_code, default: lambda { |params, param|
25
25
  if params.phone_number.present?
26
26
  params.phone_number[0..2]
@@ -28,12 +28,45 @@ class DummyParams < SimpleParams::Params
28
28
  }
29
29
  end
30
30
 
31
- def lower_case_colors
32
- color.downcase
31
+ def lower_case_colors(val)
32
+ val.downcase
33
33
  end
34
34
  end
35
35
 
36
36
  describe SimpleParams::Params do
37
+ describe "strict parameter enforcement" do
38
+ context "with default handling (strict enforcement)" do
39
+ it "raises error on expected param" do
40
+ expect { DummyParams.new(other_param: 1) }.to raise_error(SimpleParamsError)
41
+ end
42
+ end
43
+
44
+ context "with strict enforcement" do
45
+ before(:each) do
46
+ DummyParams.strict
47
+ end
48
+
49
+ it "raises error on expected param" do
50
+ expect { DummyParams.new(other_param: 1) }.to raise_error(SimpleParamsError)
51
+ end
52
+ end
53
+
54
+ context "with allow_undefined_params" do
55
+ before(:each) do
56
+ DummyParams.allow_undefined_params
57
+ end
58
+
59
+ it "does not raises error on expected param" do
60
+ expect { DummyParams.new(other_param: 1) }.to_not raise_error
61
+ end
62
+
63
+ it "can access original value through accessor" do
64
+ model = DummyParams.new(other_param: 1)
65
+ model.other_param.should eq(1)
66
+ end
67
+ end
68
+ end
69
+
37
70
  describe "accessors", accessors: true do
38
71
  let(:params) { DummyParams.new }
39
72
 
@@ -250,4 +283,33 @@ describe SimpleParams::Params do
250
283
  end
251
284
  end
252
285
  end
286
+
287
+ describe "undefined params", undefined_params: true do
288
+ before(:each) do
289
+ DummyParams.allow_undefined_params
290
+ end
291
+
292
+ it "allows undefined params, and responds with their values" do
293
+ model = DummyParams.new(other_param: 1)
294
+ model.other_param.should eq(1)
295
+ end
296
+
297
+ describe "nested params" do
298
+ it "allows undefined nested params, and creates an anonymous Params class for them" do
299
+ model = DummyParams.new(nested: { some_value: 1 } )
300
+ model.nested.should be_a(SimpleParams::Params)
301
+ end
302
+
303
+ it "allows accessors for nested attributes" do
304
+ model = DummyParams.new(nested: { some_value: 1 } )
305
+ model.nested.some_value.should eq(1)
306
+ end
307
+
308
+ it "allows multilevel nested params, and creates an anonymous Params class for them" do
309
+ model = DummyParams.new(nested: { other_nested: { some_value: 1 } } )
310
+ model.nested.other_nested.should be_a(SimpleParams::Params)
311
+ model.nested.other_nested.some_value.should eq(1)
312
+ end
313
+ end
314
+ end
253
315
  end
data/spec/spec_helper.rb CHANGED
@@ -2,9 +2,8 @@ require 'rubygems'
2
2
  require 'bundler/setup'
3
3
  require 'simple_params'
4
4
 
5
- spec = Gem::Specification.find_by_name("simple_params")
6
- gem_root = spec.gem_dir
7
- Dir[("#{gem_root}/spec/support/**/*.rb")].each {|f| require f}
5
+ Dir[("../spec/support/**/*.rb")].each {|f| require f}
6
+
8
7
  I18n.config.enforce_available_locales = true
9
8
 
10
9
  RSpec.configure do |config|
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: 0.0.2.pre1
4
+ version: 0.0.2.pre2
5
5
  platform: ruby
6
6
  authors:
7
7
  - brycesenz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-24 00:00:00.000000000 Z
11
+ date: 2015-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -100,15 +100,18 @@ files:
100
100
  - Gemfile.lock
101
101
  - README.md
102
102
  - lib/simple_params.rb
103
+ - lib/simple_params/attribute.rb
103
104
  - lib/simple_params/errors.rb
104
- - lib/simple_params/formatters.rb
105
+ - lib/simple_params/formatter.rb
105
106
  - lib/simple_params/params.rb
107
+ - lib/simple_params/simple_params_error.rb
106
108
  - lib/simple_params/validations.rb
107
109
  - lib/simple_params/version.rb
108
110
  - simple_params.gemspec
109
111
  - spec/acceptance_spec.rb
112
+ - spec/attribute_spec.rb
110
113
  - spec/errors_spec.rb
111
- - spec/formatters_spec.rb
114
+ - spec/formatter_spec.rb
112
115
  - spec/params_spec.rb
113
116
  - spec/spec_helper.rb
114
117
  homepage: https://github.com/brycesenz/simple_params
@@ -131,13 +134,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
131
134
  version: 1.3.1
132
135
  requirements: []
133
136
  rubyforge_project:
134
- rubygems_version: 2.2.2
137
+ rubygems_version: 2.4.6
135
138
  signing_key:
136
139
  specification_version: 4
137
140
  summary: A DSL for specifying params, including type coercion and validation
138
141
  test_files:
139
142
  - spec/acceptance_spec.rb
143
+ - spec/attribute_spec.rb
140
144
  - spec/errors_spec.rb
141
- - spec/formatters_spec.rb
145
+ - spec/formatter_spec.rb
142
146
  - spec/params_spec.rb
143
147
  - spec/spec_helper.rb
@@ -1,41 +0,0 @@
1
- require "active_model"
2
-
3
- module SimpleParams
4
- module Formatters
5
- extend ActiveSupport::Concern
6
-
7
- module ClassMethods
8
- def _formatters
9
- @_formatters || {}
10
- end
11
-
12
- def format(attribute, formatter)
13
- @_formatters ||= {}
14
- @_formatters[attribute.to_sym] = formatter
15
- end
16
- end
17
-
18
- def run_formatters
19
- _formatters.each do |attribute, method|
20
- value = send(attribute.to_sym)
21
- unless value.blank?
22
- out = evaluate_proc_or_method(attribute, method, value)
23
- send("#{attribute.to_sym}=", out)
24
- end
25
- end
26
- end
27
-
28
- private
29
- def evaluate_proc_or_method(attribute, method, value)
30
- if method.is_a?(Proc)
31
- method.call(self, value)
32
- else
33
- self.send(method)
34
- end
35
- end
36
-
37
- def _formatters
38
- self.class._formatters || {}
39
- end
40
- end
41
- end
@@ -1,45 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe SimpleParams::Formatters do
4
- class Racecar
5
- include SimpleParams::Formatters
6
-
7
- def initialize(params={})
8
- params.each { |k,v| send("#{k}=",v) }
9
- run_formatters
10
- end
11
-
12
- attr_accessor :make, :model
13
-
14
- format :make, :strip_make_whitespace
15
- format :model, lambda { |car, model| model.upcase }
16
-
17
- def strip_make_whitespace
18
- self.make.strip
19
- end
20
- end
21
-
22
- describe "formatting with Procs" do
23
- it "does not break if initial attribute is nil" do
24
- car = Racecar.new
25
- car.model.should be_nil
26
- end
27
-
28
- it "formats attribute on initialize" do
29
- car = Racecar.new(make: "porsche", model: "boxster")
30
- car.model.should eq("BOXSTER")
31
- end
32
- end
33
-
34
- describe "formatting with methods" do
35
- it "does not break if initial attribute is nil" do
36
- car = Racecar.new
37
- car.make.should be_nil
38
- end
39
-
40
- it "formats attribute on initialize" do
41
- car = Racecar.new(make: " Porsche ")
42
- car.make.should eq("Porsche")
43
- end
44
- end
45
- end