parametric 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -7
- data/README.md +34 -4
- data/lib/parametric/hash.rb +1 -1
- data/lib/parametric/params.rb +1 -0
- data/lib/parametric/policies.rb +14 -0
- data/lib/parametric/typed_params.rb +23 -0
- data/lib/parametric/version.rb +1 -1
- data/lib/parametric.rb +1 -0
- data/parametric.gemspec +1 -1
- data/spec/parametric_spec.rb +113 -73
- metadata +63 -51
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
5
|
-
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2e111716f0cd0f60d10a0354e70ac7ecfea42634
|
4
|
+
data.tar.gz: 2012ce66941c5a24f4bf8b3f2dc7e7ceab86311a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f146875b9b83e0b8e85cc89ff04dc817e731653bbda09d0a54c85db1957ef68b6b0007e52a9cda1a704069d9438a4d0b205acc6ce12ef62429f1ab316c4ad800
|
7
|
+
data.tar.gz: d52634e2b6526a3c81ecef0126a6558351beb030b49f28ae6c07861d2d389d777cbbbfc710f6d32ebf55f9fe6f55b8d9fe8b7fb18b697363f20b7b49c828f767
|
data/README.md
CHANGED
@@ -57,7 +57,7 @@ class OrdersSearch
|
|
57
57
|
|
58
58
|
def results
|
59
59
|
query = Order.sort(params[:sort])
|
60
|
-
query = query.where(["code LIKE ? OR user_name ?", params[:q]]) if params[:q]
|
60
|
+
query = query.where(["code LIKE ? OR user_name LIKE ?", params[:q]]) if params[:q]
|
61
61
|
query = query.where(status: params[:status]) if params[:status].any?
|
62
62
|
query = query.paginate(page: params[:page], per_page: params[:per_page])
|
63
63
|
end
|
@@ -151,6 +151,36 @@ order_search.schema[:status].multiple # => true
|
|
151
151
|
order_search.schema[:status].default # => 'closed'
|
152
152
|
```
|
153
153
|
|
154
|
+
## Coercing values
|
155
|
+
|
156
|
+
Param definitions take an optional `:coerce` option with a symbol or proc to coerce resulting values.
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class UsersSearch
|
160
|
+
include Parametric::Params
|
161
|
+
param :age, 'User age', coerce: :to_i
|
162
|
+
param :name, 'User name', coerce: lambda{|name| "Mr. #{name}"}
|
163
|
+
end
|
164
|
+
|
165
|
+
search = UsersSearch.new(age: '36', name: 'Ismael')
|
166
|
+
|
167
|
+
search.available_params[:age] # => 36
|
168
|
+
search.available_params[:name] # => 'Mr. Ismael'
|
169
|
+
```
|
170
|
+
|
171
|
+
### Parametric::TypedParams
|
172
|
+
|
173
|
+
The `Parametric::TypedParams` module includes extra DSL methods to coerce values to standard Ruby types.
|
174
|
+
|
175
|
+
class UsersSearch
|
176
|
+
include Parametric::TypedParams
|
177
|
+
integer :age, 'User age'
|
178
|
+
array :accounts
|
179
|
+
string :country_code
|
180
|
+
# you can still use :coerce
|
181
|
+
param :name, 'User name', coerce: lambda{|name| "Mr. #{name}"}
|
182
|
+
end
|
183
|
+
|
154
184
|
## Parametric::Hash
|
155
185
|
|
156
186
|
The alternative `Parametric::Hash` class makes your objects quack like a hash, instead of exposing the `#params` object directly.
|
@@ -158,9 +188,9 @@ The alternative `Parametric::Hash` class makes your objects quack like a hash, i
|
|
158
188
|
```ruby
|
159
189
|
class OrdersParams < Parametric::Hash
|
160
190
|
param :q, 'Full text search query'
|
161
|
-
|
162
|
-
|
163
|
-
|
191
|
+
integer :page, 'Page number', default: 1
|
192
|
+
integer :per_page, 'Items per page', default: 30
|
193
|
+
array :status, 'Order status', options: ['checkout', 'pending', 'closed', 'shipped']
|
164
194
|
end
|
165
195
|
```
|
166
196
|
|
data/lib/parametric/hash.rb
CHANGED
data/lib/parametric/params.rb
CHANGED
@@ -43,6 +43,7 @@ module Parametric
|
|
43
43
|
def _reduce(raw_params)
|
44
44
|
self.class._allowed_params.each_with_object(ParamsHash.new) do |(key,options),memo|
|
45
45
|
policy = Policies::Policy.new((raw_params.has_key?(key) ? raw_params[key] : []), options)
|
46
|
+
policy = policy.wrap(Policies::CoercePolicy) if options[:coerce]
|
46
47
|
policy = policy.wrap(Policies::NestedPolicy) if options[:nested]
|
47
48
|
policy = policy.wrap(Policies::MultiplePolicy) if options[:multiple]
|
48
49
|
policy = policy.wrap(Policies::OptionsPolicy) if options[:options]
|
data/lib/parametric/policies.rb
CHANGED
@@ -44,6 +44,20 @@ module Parametric
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
+
class CoercePolicy < Policy
|
48
|
+
def value
|
49
|
+
decorated.value.map do |v|
|
50
|
+
if options[:coerce].is_a?(Symbol) && v.respond_to?(options[:coerce])
|
51
|
+
v.send(options[:coerce])
|
52
|
+
elsif options[:coerce].respond_to?(:call)
|
53
|
+
options[:coerce].call v
|
54
|
+
else
|
55
|
+
v
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
47
61
|
class SinglePolicy < Policy
|
48
62
|
def value
|
49
63
|
decorated.value.first
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'parametric/params'
|
2
|
+
module Parametric
|
3
|
+
module TypedParams
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, Params)
|
6
|
+
base.extend DSL
|
7
|
+
end
|
8
|
+
|
9
|
+
module DSL
|
10
|
+
def integer(field_name, label = '', opts = {}, &block)
|
11
|
+
param(field_name, label, opts.merge(coerce: :to_i), &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def string(field_name, label = '', opts = {}, &block)
|
15
|
+
param(field_name, label, opts.merge(coerce: :to_s), &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def array(field_name, label = '', opts = {}, &block)
|
19
|
+
param(field_name, label, opts.merge(multiple: true), &block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/parametric/version.rb
CHANGED
data/lib/parametric.rb
CHANGED
data/parametric.gemspec
CHANGED
data/spec/parametric_spec.rb
CHANGED
@@ -5,103 +5,133 @@ describe Parametric do
|
|
5
5
|
Parametric::VERSION.should_not be_nil
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
shared_examples 'a configurable params object' do
|
9
|
+
it 'ignores undeclared fields' do
|
10
|
+
subject.params.has_key?(:foo).should be_false
|
11
|
+
end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
include Parametric::Params
|
13
|
-
param :name, 'User name'
|
14
|
-
param :page, 'page number', default: 1
|
15
|
-
param :per_page, 'items per page', default: 50
|
16
|
-
param :status, 'status', options: ['one', 'two', 'three'], multiple: true
|
17
|
-
param :piped_status, 'status with pipes', multiple: true, separator: '|'
|
18
|
-
param :country, 'country', options: ['UK', 'CL', 'JPN']
|
19
|
-
param :email, 'email', match: /\w+@\w+\.\w+/
|
20
|
-
param :emails, 'emails', match: /\w+@\w+\.\w+/, multiple: true, default: 'default@email.com'
|
21
|
-
param :available, 'available', default: true
|
22
|
-
end
|
13
|
+
it 'sets passed values' do
|
14
|
+
subject.params[:per_page].should == 20
|
23
15
|
end
|
24
16
|
|
25
|
-
|
26
|
-
|
17
|
+
it 'uses defaults if no value passed' do
|
18
|
+
subject.params[:page].should == 1
|
19
|
+
end
|
27
20
|
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
it 'does not set value if outside of declared options' do
|
22
|
+
subject.params[:status].should == []
|
23
|
+
end
|
31
24
|
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
it 'does not set value if it does not :match' do
|
26
|
+
klass.new(email: 'my@email').params[:email].should be_nil
|
27
|
+
end
|
35
28
|
|
36
|
-
|
37
|
-
|
38
|
-
|
29
|
+
it 'does set value if it does :match' do
|
30
|
+
klass.new(email: 'my@email.com').params[:email].should == 'my@email.com'
|
31
|
+
end
|
39
32
|
|
40
|
-
|
41
|
-
|
42
|
-
|
33
|
+
it 'only sets value for :multiple values that :match' do
|
34
|
+
klass.new(emails: 'my@email,your,her@email.com').params[:emails].should == ['her@email.com']
|
35
|
+
end
|
43
36
|
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
it 'returns :default wrapped in array if :multiple' do
|
38
|
+
klass.new().params[:emails].should == ['default@email.com']
|
39
|
+
end
|
47
40
|
|
48
|
-
|
49
|
-
|
50
|
-
|
41
|
+
it 'turns :multiple comma-separated values into arrays' do
|
42
|
+
klass.new(status: 'one,three').params[:status].should == ['one', 'three']
|
43
|
+
end
|
51
44
|
|
52
|
-
|
53
|
-
|
54
|
-
|
45
|
+
it 'does set value if it does :match' do
|
46
|
+
klass.new(email: 'my@email.com').params[:email].should == 'my@email.com'
|
47
|
+
end
|
55
48
|
|
56
|
-
|
57
|
-
|
58
|
-
|
49
|
+
it ':multiple values can be arrays' do
|
50
|
+
klass.new(status: ['one','three']).params[:status].should == ['one', 'three']
|
51
|
+
end
|
59
52
|
|
60
|
-
|
61
|
-
|
62
|
-
|
53
|
+
it 'defaults work for false values' do
|
54
|
+
klass.new(email: 'my@email').params[:email].should be_nil
|
55
|
+
end
|
63
56
|
|
64
|
-
|
65
|
-
|
66
|
-
|
57
|
+
it 'does set value if it does :match' do
|
58
|
+
klass.new(available: false).params[:available].should be_false
|
59
|
+
end
|
67
60
|
|
68
|
-
|
69
|
-
|
70
|
-
|
61
|
+
it 'turns :multiple separated values with custom separator into arrays' do
|
62
|
+
klass.new(piped_status: 'one|three').params[:piped_status].should == ['one', 'three']
|
63
|
+
end
|
71
64
|
|
72
|
-
|
73
|
-
|
74
|
-
|
65
|
+
it 'does not turn non-multiple comma-separated values into arrays' do
|
66
|
+
klass.new(name: 'foo,bar').params[:name].should == 'foo,bar'
|
67
|
+
end
|
75
68
|
|
76
|
-
|
77
|
-
|
78
|
-
|
69
|
+
it 'filters out undeclared options' do
|
70
|
+
klass.new(status: 'one,three,fourteen').params[:status].should == ['one', 'three']
|
71
|
+
end
|
79
72
|
|
80
|
-
|
81
|
-
|
82
|
-
|
73
|
+
it 'defaults empty multiple options to empty array' do
|
74
|
+
klass.new().params[:status].should == []
|
75
|
+
end
|
83
76
|
|
84
|
-
|
85
|
-
|
86
|
-
|
77
|
+
it 'wraps single multiple options in array' do
|
78
|
+
klass.new(status: 'one').params[:status].should == ['one']
|
79
|
+
end
|
87
80
|
|
88
|
-
|
89
|
-
|
90
|
-
|
81
|
+
it 'does not accept comma-separated values outside of options unless :multiple == true' do
|
82
|
+
klass.new(country: 'UK,CL').params[:country].should be_nil
|
83
|
+
end
|
91
84
|
|
92
|
-
|
93
|
-
|
94
|
-
|
85
|
+
it 'does accept single option' do
|
86
|
+
klass.new(country: 'UK').params[:country].should == 'UK'
|
87
|
+
end
|
95
88
|
|
96
|
-
|
97
|
-
|
89
|
+
it 'does not accept single option if not in declared options' do
|
90
|
+
klass.new(country: 'USA').params[:country].should be_nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'TypedParams' do
|
95
|
+
let(:klass) do
|
96
|
+
Class.new do
|
97
|
+
include Parametric::TypedParams
|
98
|
+
string :name, 'User name'
|
99
|
+
integer :page, 'page number', default: 1
|
100
|
+
integer :per_page, 'items per page', default: 50
|
101
|
+
array :status, 'status', options: ['one', 'two', 'three']
|
102
|
+
array :piped_status, 'status with pipes', separator: '|'
|
103
|
+
string :country, 'country', options: ['UK', 'CL', 'JPN']
|
104
|
+
string :email, 'email', match: /\w+@\w+\.\w+/
|
105
|
+
array :emails, 'emails', match: /\w+@\w+\.\w+/, default: 'default@email.com'
|
98
106
|
end
|
107
|
+
end
|
108
|
+
|
109
|
+
let(:subject) { klass.new(foo: 'bar', per_page: '20', status: 'four') }
|
110
|
+
it_should_behave_like 'a configurable params object'
|
111
|
+
end
|
112
|
+
|
113
|
+
describe Parametric::Params do
|
99
114
|
|
100
|
-
|
101
|
-
|
115
|
+
let(:klass) do
|
116
|
+
Class.new do
|
117
|
+
include Parametric::Params
|
118
|
+
param :name, 'User name'
|
119
|
+
param :page, 'page number', default: 1, coerce: :to_i
|
120
|
+
param :per_page, 'items per page', default: 50, coerce: lambda{|value| value.to_i}
|
121
|
+
param :status, 'status', options: ['one', 'two', 'three'], multiple: true
|
122
|
+
param :piped_status, 'status with pipes', multiple: true, separator: '|'
|
123
|
+
param :country, 'country', options: ['UK', 'CL', 'JPN']
|
124
|
+
param :email, 'email', match: /\w+@\w+\.\w+/
|
125
|
+
param :emails, 'emails', match: /\w+@\w+\.\w+/, multiple: true, default: 'default@email.com'
|
126
|
+
param :available, 'available', default: true
|
102
127
|
end
|
103
128
|
end
|
104
129
|
|
130
|
+
describe '#params' do
|
131
|
+
let(:subject) { klass.new(foo: 'bar', per_page: 20, status: 'four') }
|
132
|
+
it_should_behave_like 'a configurable params object'
|
133
|
+
end
|
134
|
+
|
105
135
|
describe '#available_params' do
|
106
136
|
let(:subject) { klass.new(foo: 'bar', name: 'lala', per_page: 20, status: 'four', emails: 'one@email.com,two@email.com') }
|
107
137
|
|
@@ -113,6 +143,16 @@ describe Parametric do
|
|
113
143
|
subject.available_params[:page].should == 1
|
114
144
|
end
|
115
145
|
|
146
|
+
describe ':coerce option' do
|
147
|
+
it 'accepts method_name as a symbol' do
|
148
|
+
klass.new(page: '10').available_params[:page].should == 10
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'accepts a proc' do
|
152
|
+
klass.new(per_page: '10').available_params[:per_page].should == 10
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
116
156
|
describe '#flat' do
|
117
157
|
it 'joins values back' do
|
118
158
|
subject.available_params.flat[:emails].should == 'one@email.com,two@email.com'
|
@@ -163,8 +203,8 @@ describe Parametric do
|
|
163
203
|
describe Parametric::Hash do
|
164
204
|
let(:klass) do
|
165
205
|
Class.new(Parametric::Hash) do
|
166
|
-
|
167
|
-
|
206
|
+
string :name, 'User name'
|
207
|
+
integer :page, 'page number', default: 1
|
168
208
|
param :per_page, 'items per page', default: 50
|
169
209
|
end
|
170
210
|
end
|
metadata
CHANGED
@@ -1,55 +1,65 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: parametric
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
|
-
authors:
|
6
|
+
authors:
|
7
7
|
- Ismael Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2014-06-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
15
14
|
name: bundler
|
16
|
-
|
17
|
-
|
18
|
-
requirements:
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
19
17
|
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version:
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
22
20
|
type: :development
|
23
|
-
version_requirements: *id001
|
24
|
-
- !ruby/object:Gem::Dependency
|
25
|
-
name: rake
|
26
21
|
prerelease: false
|
27
|
-
|
28
|
-
requirements:
|
29
|
-
-
|
30
|
-
-
|
31
|
-
|
32
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
33
34
|
type: :development
|
34
|
-
version_requirements: *id002
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: rspec
|
37
35
|
prerelease: false
|
38
|
-
|
39
|
-
requirements:
|
40
|
-
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.14.1
|
41
48
|
type: :development
|
42
|
-
|
43
|
-
|
44
|
-
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.14.1
|
55
|
+
description: Useful for modelling search or form objects, white-listed query parameters
|
56
|
+
and safe parameter defaults.
|
57
|
+
email:
|
45
58
|
- ismaelct@gmail.com
|
46
59
|
executables: []
|
47
|
-
|
48
60
|
extensions: []
|
49
|
-
|
50
61
|
extra_rdoc_files: []
|
51
|
-
|
52
|
-
files:
|
62
|
+
files:
|
53
63
|
- .gitignore
|
54
64
|
- .rspec
|
55
65
|
- .travis.yml
|
@@ -61,37 +71,39 @@ files:
|
|
61
71
|
- lib/parametric/hash.rb
|
62
72
|
- lib/parametric/params.rb
|
63
73
|
- lib/parametric/policies.rb
|
74
|
+
- lib/parametric/typed_params.rb
|
64
75
|
- lib/parametric/utils.rb
|
65
76
|
- lib/parametric/version.rb
|
66
77
|
- parametric.gemspec
|
67
78
|
- spec/nested_params_spec.rb
|
68
79
|
- spec/parametric_spec.rb
|
69
80
|
- spec/spec_helper.rb
|
70
|
-
homepage:
|
71
|
-
licenses:
|
81
|
+
homepage: ''
|
82
|
+
licenses:
|
72
83
|
- MIT
|
73
84
|
metadata: {}
|
74
|
-
|
75
85
|
post_install_message:
|
76
86
|
rdoc_options: []
|
77
|
-
|
78
|
-
require_paths:
|
87
|
+
require_paths:
|
79
88
|
- lib
|
80
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
-
requirements:
|
82
|
-
-
|
83
|
-
|
84
|
-
|
85
|
-
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
86
99
|
requirements: []
|
87
|
-
|
88
100
|
rubyforge_project:
|
89
|
-
rubygems_version: 2.0.
|
101
|
+
rubygems_version: 2.0.3
|
90
102
|
signing_key:
|
91
103
|
specification_version: 4
|
92
|
-
summary: DSL for declaring allowed parameters with options, regexp patern and default
|
93
|
-
|
104
|
+
summary: DSL for declaring allowed parameters with options, regexp patern and default
|
105
|
+
values.
|
106
|
+
test_files:
|
94
107
|
- spec/nested_params_spec.rb
|
95
108
|
- spec/parametric_spec.rb
|
96
109
|
- spec/spec_helper.rb
|
97
|
-
has_rdoc:
|