simple_params 0.0.2.pre1 → 0.0.2.pre2

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