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 +8 -8
- data/Gemfile.lock +1 -1
- data/README.md +46 -5
- data/lib/simple_params/attribute.rb +62 -0
- data/lib/simple_params/formatter.rb +20 -0
- data/lib/simple_params/params.rb +101 -49
- data/lib/simple_params/simple_params_error.rb +8 -0
- data/lib/simple_params/version.rb +1 -1
- data/lib/simple_params.rb +3 -1
- data/spec/attribute_spec.rb +138 -0
- data/spec/formatter_spec.rb +33 -0
- data/spec/params_spec.rb +70 -8
- data/spec/spec_helper.rb +2 -3
- metadata +10 -6
- data/lib/simple_params/formatters.rb +0 -41
- data/spec/formatters_spec.rb +0 -45
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MTYwZjZjZDIzZTBhYzk1OTljYWFmMzdmMWUzYjk0YmM1YWVjYWY2Mg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NDJjZDI0YzI5ZTRjNTZmMjAzZmQ3MjZmODg1OGI1NzZhNzI2ODFiYQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTE2MDAzNGUwNTg0MGVmZmJhMzdkZjVlMjE1M2RhODc1NGZjOTVkNTA2Zjhm
|
10
|
+
MDY5ZWNhMTZmYTAzMGQ3NTY3YjZjNjQwYjE2MmI5NGI5YWNkNjdhODY1ZDBl
|
11
|
+
NzIxNzUzNTQ5NzA3NmQwZmJlYzIzYzhiMjllMjJkYzJmOTk2NTM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
M2FjMTdhYTQ0NTM4M2E1MGIzZjZhMDcwNzI0MTBiNDY3NGM3YTYwOTcyMmM1
|
14
|
+
YjdiYmM2MjAyYTM2ODlmYTdmZTFiY2U2MDhmYTQ2OTdlYTMyZTI4MzZkOGZh
|
15
|
+
MWQ1YWMwMWIwODQ3NzdjNWY2MzFkODg3ZmM1ZjgzYmU0NDA1NTM=
|
data/Gemfile.lock
CHANGED
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:
|
33
|
-
param :date_of_birth, type:
|
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:
|
132
|
-
param :date_of_birth, type:
|
133
|
-
param :pocket_change, type:
|
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
|
data/lib/simple_params/params.rb
CHANGED
@@ -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
|
-
|
13
|
-
integer
|
14
|
-
string
|
15
|
-
decimal
|
16
|
-
datetime
|
17
|
-
date
|
18
|
-
time
|
19
|
-
float
|
20
|
-
boolean
|
21
|
-
array
|
22
|
-
hash
|
23
|
-
|
24
|
-
|
25
|
-
|
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:
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
attribute name
|
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
|
-
|
112
|
+
|
113
|
+
# Nested Classes
|
93
114
|
set_accessors(params)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
data/lib/simple_params.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'simple_params/version'
|
2
|
-
require 'simple_params/
|
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,
|
8
|
-
param :color, default: "red", validations: { inclusion: { in: ["red", "green"] }},
|
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",
|
14
|
+
param :state, default: "North Carolina", formatter: :transform_state_code
|
15
15
|
|
16
|
-
def transform_state_code
|
17
|
-
|
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 } },
|
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
|
-
|
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
|
-
|
6
|
-
|
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.
|
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-
|
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/
|
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/
|
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.
|
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/
|
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
|
data/spec/formatters_spec.rb
DELETED
@@ -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
|