hash_params 0.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +8 -8
  3. data/README.md +167 -109
  4. data/coverage/assets/0.9.0/application.css +799 -0
  5. data/coverage/assets/0.9.0/application.js +1707 -0
  6. data/coverage/assets/0.9.0/colorbox/border.png +0 -0
  7. data/coverage/assets/0.9.0/colorbox/controls.png +0 -0
  8. data/coverage/assets/0.9.0/colorbox/loading.gif +0 -0
  9. data/coverage/assets/0.9.0/colorbox/loading_background.png +0 -0
  10. data/coverage/assets/0.9.0/favicon_green.png +0 -0
  11. data/coverage/assets/0.9.0/favicon_red.png +0 -0
  12. data/coverage/assets/0.9.0/favicon_yellow.png +0 -0
  13. data/coverage/assets/0.9.0/loading.gif +0 -0
  14. data/coverage/assets/0.9.0/magnify.png +0 -0
  15. data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  16. data/coverage/assets/0.9.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  17. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  18. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  19. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  20. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  21. data/coverage/assets/0.9.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  22. data/coverage/assets/0.9.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  23. data/coverage/assets/0.9.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  24. data/coverage/assets/0.9.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  25. data/coverage/assets/0.9.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  26. data/coverage/assets/0.9.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  27. data/coverage/assets/0.9.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  28. data/coverage/index.html +1597 -369
  29. data/hash_params.gemspec +14 -5
  30. data/lib/hash_params/binding_validator.rb +26 -0
  31. data/lib/hash_params/hash_validator.rb +71 -0
  32. data/lib/hash_params/validator.rb +119 -0
  33. data/lib/hash_params/yaml_params.rb +93 -0
  34. data/lib/hash_params.rb +15 -142
  35. data/spec/hash_params_spec.rb +100 -63
  36. data/spec/spec_helper.rb +0 -11
  37. data/tmp/hash_params.rb +181 -0
  38. data/tmp/hash_params_spec.rb +102 -0
  39. data/tmp/module_spec.rb +27 -0
  40. data/tmp/var_spec.rb +9 -0
  41. data/tmp/yaml_params.rb +109 -0
  42. metadata +36 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: abdd09167a6fd3901a89dffde275cd74b5e5a826
4
- data.tar.gz: 5b08703d583b1cbe23dd78a31f79394a237aebf4
3
+ metadata.gz: 65d13d16e642e22b531b671ea8315bc477fd6bd3
4
+ data.tar.gz: 5f600d5a2f1172920a37870367e9f8e232f35df1
5
5
  SHA512:
6
- metadata.gz: 6e8d8e6e267c324e6dced4200cad1e4d5540cd0cd73f192f3b66a634c096a436a5d6afd100e7349f37c5442c40dc97ae2155f0cb31cbc4b2684fda6478086aa6
7
- data.tar.gz: 4f1c4ea78c5a726d4d37401235941efa4a09f568301e84ab82396056b3bef8dd958d24e9621714405e81b435fe0018fd8cbd432f1c64702525d23b31c65bc917
6
+ metadata.gz: 6e7207b5832175aa5f2aa9b0e151c1537209d8effc8ad13d480275362d4b1ef0615428ab27151cfa8b7d048ec5f19b9b95af01490d1a016110271850c2edb102
7
+ data.tar.gz: 1bf66afcaca1c077dabe5e9b46ad9f26201f4c9349f99aff490ce3df9cd102746327764f04be01e61636353d04144e1ba16f291ebb5755ee2ccf51db9519fee2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hash_params (0.0.1)
4
+ hash_params (2.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -9,20 +9,20 @@ GEM
9
9
  coderay (1.1.0)
10
10
  docile (1.1.5)
11
11
  method_source (0.8.2)
12
- minitest (5.4.1)
12
+ minitest (5.5.1)
13
13
  minitest-spec (0.0.2.1)
14
14
  minitest (>= 3.0)
15
- multi_json (1.10.1)
15
+ multi_json (1.11.0)
16
16
  pry (0.10.1)
17
17
  coderay (~> 1.1.0)
18
18
  method_source (~> 0.8.1)
19
19
  slop (~> 3.4)
20
- rake (10.3.2)
21
- simplecov (0.9.0)
20
+ rake (10.4.2)
21
+ simplecov (0.9.2)
22
22
  docile (~> 1.1.0)
23
- multi_json
24
- simplecov-html (~> 0.8.0)
25
- simplecov-html (0.8.0)
23
+ multi_json (~> 1.0)
24
+ simplecov-html (~> 0.9.0)
25
+ simplecov-html (0.9.0)
26
26
  slop (3.6.0)
27
27
 
28
28
  PLATFORMS
data/README.md CHANGED
@@ -4,69 +4,131 @@ _Lightweight Parameter Validation & Type Coercion_
4
4
  This is a variation of the sinatra-param gem https://github.com/mattt/sinatra-param
5
5
  with the sinatra specific things taken out and slight modifications to make it more useful for generic applications.
6
6
 
7
- **`hash-params` allows you to declare, validate, and transform endpoint parameters as you would in frameworks like [ActiveModel](http://rubydoc.info/gems/activemodel/3.2.3/frames) or [DataMapper](http://datamapper.org/). but in a lighterweight fashion**
7
+ `hash-params` allows you to declare, validate, and transform endpoint parameters as you would in frameworks like [ActiveModel](http://rubydoc.info/gems/activemodel/3.2.3/frames) or [DataMapper](http://datamapper.org/). but in a lighterweight fashion
8
8
 
9
+ See the spec down the page for usage scenarios
10
+
11
+ ## Validations
12
+
13
+ - Validations are passed as a hash.
14
+ - You can validate either individual values or hashes.
15
+ - Hashes can be validated recursively
16
+ - You can call the coersion methods separately if you wish
17
+ - If you don't pass in any validations you'll get the same hash back unless you set the strict option (see below)
18
+
19
+ ## Coercions
20
+
21
+ By declaring parameter types, incoming parameters will automatically be coerced into an object of that type.
22
+
23
+ - `String`
24
+ - `Integer`
25
+ - `Float`
26
+ - `Array` _("1,2,3,4,5")_
27
+ - `Hash` _(key1:value1,key2:value2)_
28
+ - `Date`, `Time`, & `DateTime`
29
+ - `:boolean` _("1/0", "true/false", "t/f", "yes/no", "y/n")_
30
+
31
+
32
+ Note that the `Hash` and `Array` coercions are not deep (only one level). The internal elements are not validated or coerced, everything is returned as a string.
33
+
34
+ Since Ruby doesn't have a Boolean type use the symbol :boolean. This will attempt to cast the commonly used values to either true or false (`TrueClass` or `FalseClass`)
35
+
36
+ You can also use anything that will respond to `to_proc` such as `:to_i`, `:downcase`, etc. It's up to you to make sure the value will obey the method
37
+
38
+
39
+ ## Validation Options (Only applies to validating hashes and yaml files)
40
+
41
+ You can pass in the following options along with your validations
42
+
43
+ - `strict`: Defaults to true. Only the elements mentioned in the validation will be returned. If set to false all elements will be returned by the validated values will replace the originals
44
+ - `make_methods`: If passed the returned hash will have methods defined for each key in the new hash. This will allow you access the values using standard dot notation.
45
+ - `raise_errors`: Defaults to true. All errors will be collected during processing and raised just once. If you set this to false no error will be raised, you can check the ```hash.valid?``` method or the ```hash.errors``` collection
46
+
47
+
48
+ ## Yaml files
49
+
50
+ ```validate_yaml_file``` and ```validate_default_yaml_files``` methods are provided for convenience.
51
+
52
+ ```validate_yaml_file``` works exactly like ```validate_hash``` but takes a file name instead of a hash
53
+
54
+ ```validate_default_file_names``` scours various directories for yaml files and intelligently merges them together before validation. See the source code for the standard paths and file name patterns.
55
+
56
+
57
+ You can specify the following in the options hash they will all have sensible defaults except the ```app_name```
58
+
59
+ - app_name
60
+ - env
61
+ - roots
62
+ - file_separator
63
+ - file_extension
9
64
 
10
65
  ## Example
11
66
 
12
67
  ``` ruby
13
68
  describe HashParams do
69
+ let (:sample_hash) {
70
+
71
+ h= {
72
+ ignored: "this will be ignored because it's not mentioned",
73
+ to_be_renamed: :to_be_renamed,
74
+ integer_coercion: "1",
75
+ bad_number: '1aaa2',
76
+ array_with_delim: '1|2|3',
77
+ hash_as_string: "{a => 1,b => 2,c => d}",
78
+ proc_validation: "is_this_valid?",
79
+ some_number: 122,
80
+ some_string: 'this is a test string',
81
+ is_true: 'true',
82
+ is_false: 'f',
83
+ recursive: {}
84
+ }
14
85
 
15
- let (:r) {
16
- HashParams.new(
17
- {
18
- ignored: "this will be ignored because it's not mentioned",
19
- to_be_renamed: :to_be_renamed,
20
- integer_coercion: "1",
21
- bad_number: '1aaa2',
22
- array_with_delim: '1|2|3',
23
- hash_as_string: "{a => 1,b => 2,c => d}",
24
- proc_validation: "is_this_valid?",
25
- some_number: 122,
26
- some_string: 'this is a test string' ,
27
- is_true: 'true',
28
- is_false: 'f',
29
- recursive: {}
86
+ }
87
+ let (:validations) {
88
+ v={
89
+ doesnt_exist: {required: true},
90
+ to_be_renamed: {as: :renamed},
91
+ no_value: {default: 1},
92
+ #proc default relying on previously set value
93
+ proc_default: {default: lambda { |o| 1 * 5 }},
94
+ integer_coercion: {coerce: Integer},
95
+ #chained coersions of various types
96
+ bad_number: {coerce: [lambda { |o| o.gsub('a', '') }, :to_i, Float]},
97
+ #arrays and hashes
98
+ array_with_delim: {coerce: Array, delimiter: '|'},
99
+ hash_as_string: {coerce: Hash, delimiter: ',', separator: '=>'},
100
+ proc_validation: {validate: lambda { |v| v == 'Failed_proc_validation' }},
101
+ #validations
102
+ some_number: {min: 120, max: 500, in: (100..200), is: 122},
103
+ some_string: {min_length: 21, max_length: 30, format: /^t.*g$/},
104
+ #combinations
105
+ missing_with_validation: {coerce: Integer, :default => 60 * 60, :validate => lambda { |v| v >= 60 * 60 }},
106
+ is_true: {coerce: :boolean},
107
+ is_false: {coerce: :boolean},
108
+ #recursive}
109
+ recursive: {
110
+ wasnt_here_before: {default: true}
30
111
  }
31
- ) do
32
- param :doesnt_exist, required: true
33
- param :to_be_renamed, as: :renamed
34
- param :no_value, default: 1
35
- #proc default relying on previously set value
36
- param :proc_default, default: lambda { |o| o[:no_value] * 5 }
37
- param :integer_coercion, coerce: Integer
38
- #chained coersions of various types
39
- param :bad_number, coerce: [lambda { |o| o.gsub('a', '') }, :to_i, Float]
40
- #arrays and hashes
41
- param :array_with_delim, coerce: Array, delimiter: '|'
42
- param :hash_as_string, coerce: Hash, delimiter: ',', separator: '=>'
43
- param :proc_validation, validate: lambda { |v| v == 'Failed_proc_validation' }
44
- #validations
45
- param :some_number, min: 120, max: 500, in: (100..200), is: 122
46
- param :some_string, min_length: 21, max_length: 30, format: /^t.*g$/
47
- #combinations
48
- param :missing_with_validation, coerce: Integer, :default => 60 * 60, :validate => lambda { |v| v >= 60 * 60 }
49
- param :is_true, coerce: :boolean
50
- param :is_false, coerce: :boolean
51
- #recursive
52
- param :recursive do
53
- param :wasnt_here_before, default: true
54
- end
55
- end
112
+ }
113
+ }
114
+ let (:r) {
115
+ HashParams.validate_hash(sample_hash, validations, {raise_errors: false})
56
116
  }
57
117
 
58
118
 
59
119
  it 'does amazing things' do
120
+
60
121
  (r.valid?).must_equal false
122
+
61
123
  r[:ignored].must_be_nil
62
124
  r[:no_value].must_equal 1
63
125
  r[:proc_default].must_equal 5
64
- r[:renamed].must_equal :to_be_renamed
126
+ r[:to_be_renamed].must_equal :to_be_renamed
65
127
  r[:integer_coercion].must_equal 1
66
128
  r[:bad_number].must_equal 12.0
67
129
 
68
130
  r[:array_with_delim].must_equal ["1", "2", "3"]
69
- r[:hash_as_string].must_equal ({ "a" => "1", "b" => "2", "c" => "d" })
131
+ r[:hash_as_string].must_equal ({"a" => "1", "b" => "2", "c" => "d"})
70
132
  r[:missing_with_validation].must_equal 60 * 60
71
133
  r[:is_true].must_equal true
72
134
  r[:is_false].must_equal false
@@ -74,98 +136,94 @@ describe HashParams do
74
136
  #recursive checking
75
137
  r[:recursive][:wasnt_here_before].must_equal true
76
138
 
139
+
77
140
  #failed items don't show up
78
141
  r.errors.size.must_equal 2
79
142
  r[:doesnt_exist].must_be_nil
80
143
  r[:proc_validation].must_be_nil
81
- r.errors[0].must_equal 'Parameter doesnt_exist is required and missing'
82
- r.errors[1].must_equal 'is_this_valid? failed validation using proc'
144
+ r.errors[:doesnt_exist].must_equal 'Required Parameter missing and has no default specified'
145
+ r.errors[:proc_validation].must_equal 'is_this_valid? failed validation using proc'
83
146
 
84
147
  end
85
148
 
86
- it 'injects into current class' do
87
- r = HashParams.new({will_be_injected: 12345}, self) do
88
- param :will_be_injected
89
- end
149
+ it 'injects methods into returned hash' do
150
+
151
+ #set strict to false so all keys will pass trough
152
+ hash={will_be_injected: 12345}
153
+ opts={make_methods: true, strict: false}
154
+
155
+ r=HashParams.validate_hash(hash, {}, opts)
90
156
  r[:will_be_injected].must_equal 12345
91
- @will_be_injected.must_equal 12345
92
- will_be_injected.must_equal 12345
157
+ r.will_be_injected.must_equal 12345
93
158
  end
94
159
 
95
160
  end
96
161
 
97
- ```
98
-
99
-
100
- ### Defaults
101
-
102
- Passing a `default` option will provide a default value for a parameter if none is passed. A `default` can defined as either a default or as a `Proc`:
103
-
104
- ```ruby
105
- param :attribution, String, default: "©"
106
- param :year, Integer, default: lambda { Time.now.year }
107
- ```
108
-
109
-
110
- ### Coercions
111
-
112
- By declaring parameter types, incoming parameters will automatically be coerced into an object of that type.
113
-
114
- - `String`
115
- - `Integer`
116
- - `Float`
117
- - `Array` _("1,2,3,4,5")_
118
- - `Hash` _(key1:value1,key2:value2)_
119
- - `Date`, `Time`, & `DateTime`
120
-
121
- Note that the `Hash` and `Array` coercions are not deep (only one level). The internal elements are not validated or coerced, everything is returned as a string.
122
-
123
- Since Ruby doesn't have a Boolean type use the symbol :boolean. This will attempt to cast the commonly used values to either true or false (`TrueClass` or `FalseClass`)
124
- - `:boolean` _("1/0", "true/false", "t/f", "yes/no", "y/n")_
162
+ describe HashParams do
163
+ let(:v) { HashParams}
125
164
 
126
- You can also use anything that will respond to `to_proc` such as `:to_i`, `:downcase`, etc. It's up to you to make sure the value will obey the method
165
+ it 'raises error if required and missing' do
166
+ proc {
167
+ v.validate(nil, required: true)
168
+ }.must_raise HashParams::ValidationError
169
+ end
170
+ it 'runs multiple coersions' do
171
+ v.validate('1aaa2', coerce: [lambda { |o| o.gsub('a', '') }, :to_i, Float]).must_equal 12.0
172
+ end
127
173
 
174
+ it 'defaults missing values' do
175
+ v.validate(nil, default: 1).must_equal 1
176
+ v.validate(nil, default: lambda { |o| 2 * 5 }).must_equal 10
177
+ end
128
178
 
129
- ### Validations
179
+ it 'applies defaults before other actions' do
180
+ v.validate(nil, coerce: Integer, :default => 60 * 60, :validate => lambda { |v| v >= 60 * 60 }).must_equal 60 * 60
181
+ end
130
182
 
131
- Encapsulate business logic in a consistent way with validations. If a parameter does not satisfy a particular condition the parameter is not added to the result and an entry is made into the errors collection.
183
+ it 'validates with procs' do
184
+ proc {
185
+ v.validate('is_this_valid?') do |v|
186
+ v == 'Failed_proc_validation'
187
+ end
188
+ }.must_raise HashParams::ValidationError
189
+ end
132
190
 
133
- - `required`
134
- - `blank`
135
- - `is`
136
- - `in`, `within`, `range`
137
- - `min` / `max`
138
- - `format`
191
+ it 'verifies numbers with common params' do
192
+ v.validate(122, min: 120, max: 500, in: (100..200), is: 122).must_equal 122
193
+ end
194
+ it 'verifies strings with common params' do
195
+ v.validate('this is a test string', min_length: 21, max_length: 30, format: /^t.*g$/).must_equal 'this is a test string'
196
+ end
139
197
 
140
- **Only valid entries are returned, all others are ignored**
198
+ it 'coerces true' do
199
+ v.coerce('t', :boolean).must_equal true
200
+ v.coerce('true', :boolean).must_equal true
201
+ v.coerce('yes', :boolean).must_equal true
202
+ v.coerce('1',:boolean).must_equal true
203
+ v.coerce(1,:boolean).must_equal true
204
+ end
205
+ it 'coerces false' do
206
+ v.coerce('f', :boolean).must_equal false
207
+ v.coerce('false', :boolean).must_equal false
208
+ v.coerce('no', :boolean).must_equal false
209
+ v.coerce('0',:boolean).must_equal false
210
+ v.coerce(0,:boolean).must_equal false
211
+ end
212
+ it 'coerces array' do
213
+ v.coerce('1|2|3', Array, delimiter: '|').must_equal ["1", "2", "3"]
214
+ end
215
+ it 'coerces hash' do
216
+ v.coerce('{a => 1,b => 2,c => d}', Hash, delimiter: ',', separator: '=>').must_equal({"a" => "1", "b" => "2", "c" => "d"})
217
+ end
141
218
 
142
219
 
143
- ### Exceptions and Validation Failures
220
+ end
144
221
 
145
- All recorded validation errors, coercion errors, and exceptions are in the errors collection of the returned object. You can also call the valid? method to check to see if everything went OK.
146
222
 
147
- ```ruby
148
- p = HashParams.new({a: :b}) do
149
- param :a
150
- end
151
223
 
152
- p.errors.inspect unless p.valid?
153
224
  ```
154
225
 
155
- ### Injection into classes
156
-
157
- You can if you choose inject all passing variables (but not valid? or errors collection) into a given class. The injection is done via `attr_accessor` The values are injected into the singleton so no need to worry about polluting other objects.
158
226
 
159
- ```ruby
160
- it 'injects into current class' do
161
- r = HashParams.new({will_be_injected: 12345}, self) do
162
- param :will_be_injected
163
- end
164
- r[:will_be_injected].must_equal 12345
165
- @will_be_injected.must_equal 12345
166
- will_be_injected.must_equal 12345
167
- end
168
- ```
169
227
 
170
228
 
171
229
  ## Contact