parametric 0.0.3 → 0.0.4

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,7 +1,7 @@
1
- ---
2
- SHA1:
3
- metadata.gz: ea2ea42f0944e44e3fa09a487428f6b8cd6ef61f
4
- data.tar.gz: 5e058214303cc07ac28f93924529efe8b88875fc
5
- SHA512:
6
- metadata.gz: e418038925d9b0e9c302cfd616b8148dd855377aaf1fa3d69ec7cb9f821add9c6e649bb096bb539fb581b4c2fcb6ca2b51ea23fc953530930daa71cdb754d184
7
- data.tar.gz: 6efb123579da71f5195f3a36f5a02a0747193c55a60217c2061afc3186367cfe28bf5798c09ba11da82335b05a9e2cd83b2434964457685e9c3e905df621d45a
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
- param :page, 'Page number', default: 1
162
- param :per_page, 'Items per page', default: 30
163
- param :status, 'Order status', options: ['checkout', 'pending', 'closed', 'shipped'], multiple: true
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
 
@@ -1,7 +1,7 @@
1
1
  require 'forwardable'
2
2
  module Parametric
3
3
  class Hash
4
- include Params
4
+ include TypedParams
5
5
  include Enumerable
6
6
  extend ::Forwardable
7
7
  def_delegators(:params,
@@ -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]
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Parametric
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/parametric.rb CHANGED
@@ -6,4 +6,5 @@ require "parametric/utils"
6
6
  require "parametric/version"
7
7
  require "parametric/policies"
8
8
  require "parametric/params"
9
+ require "parametric/typed_params"
9
10
  require "parametric/hash"
data/parametric.gemspec CHANGED
@@ -20,5 +20,5 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.5"
22
22
  spec.add_development_dependency "rake"
23
- spec.add_development_dependency "rspec"
23
+ spec.add_development_dependency "rspec", '2.14.1'
24
24
  end
@@ -5,103 +5,133 @@ describe Parametric do
5
5
  Parametric::VERSION.should_not be_nil
6
6
  end
7
7
 
8
- describe Parametric::Params do
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
- let(:klass) do
11
- Class.new do
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
- describe '#params' do
26
- let(:subject) { klass.new(foo: 'bar', per_page: 20, status: 'four') }
17
+ it 'uses defaults if no value passed' do
18
+ subject.params[:page].should == 1
19
+ end
27
20
 
28
- it 'ignores undeclared fields' do
29
- subject.params.has_key?(:foo).should be_false
30
- end
21
+ it 'does not set value if outside of declared options' do
22
+ subject.params[:status].should == []
23
+ end
31
24
 
32
- it 'sets passed values' do
33
- subject.params[:per_page].should == 20
34
- end
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
- it 'uses defaults if no value passed' do
37
- subject.params[:page].should == 1
38
- end
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
- it 'does not set value if outside of declared options' do
41
- subject.params[:status].should == []
42
- end
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
- it 'does not set value if it does not :match' do
45
- klass.new(email: 'my@email').params[:email].should be_nil
46
- end
37
+ it 'returns :default wrapped in array if :multiple' do
38
+ klass.new().params[:emails].should == ['default@email.com']
39
+ end
47
40
 
48
- it 'defaults work for false values' do
49
- klass.new(email: 'my@email').params[:email].should be_nil
50
- end
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
- it 'does set value if it does :match' do
53
- klass.new(available: false).params[:available].should be_false
54
- end
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
- it 'only sets value for :multiple values that :match' do
57
- klass.new(emails: 'my@email,your,her@email.com').params[:emails].should == ['her@email.com']
58
- end
49
+ it ':multiple values can be arrays' do
50
+ klass.new(status: ['one','three']).params[:status].should == ['one', 'three']
51
+ end
59
52
 
60
- it 'returns :default wrapped in array if :multiple' do
61
- klass.new().params[:emails].should == ['default@email.com']
62
- end
53
+ it 'defaults work for false values' do
54
+ klass.new(email: 'my@email').params[:email].should be_nil
55
+ end
63
56
 
64
- it 'turns :multiple comma-separated values into arrays' do
65
- klass.new(status: 'one,three').params[:status].should == ['one', 'three']
66
- end
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
- it ':multiple values can be arrays' do
69
- klass.new(status: ['one','three']).params[:status].should == ['one', 'three']
70
- end
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
- it 'turns :multiple separated values with custom separator into arrays' do
73
- klass.new(piped_status: 'one|three').params[:piped_status].should == ['one', 'three']
74
- end
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
- it 'does not turn non-multiple comma-separated values into arrays' do
77
- klass.new(name: 'foo,bar').params[:name].should == 'foo,bar'
78
- end
69
+ it 'filters out undeclared options' do
70
+ klass.new(status: 'one,three,fourteen').params[:status].should == ['one', 'three']
71
+ end
79
72
 
80
- it 'filters out undeclared options' do
81
- klass.new(status: 'one,three,fourteen').params[:status].should == ['one', 'three']
82
- end
73
+ it 'defaults empty multiple options to empty array' do
74
+ klass.new().params[:status].should == []
75
+ end
83
76
 
84
- it 'defaults empty multiple options to empty array' do
85
- klass.new().params[:status].should == []
86
- end
77
+ it 'wraps single multiple options in array' do
78
+ klass.new(status: 'one').params[:status].should == ['one']
79
+ end
87
80
 
88
- it 'wraps single multiple options in array' do
89
- klass.new(status: 'one').params[:status].should == ['one']
90
- end
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
- it 'does not accept comma-separated values outside of options unless :multiple == true' do
93
- klass.new(country: 'UK,CL').params[:country].should be_nil
94
- end
85
+ it 'does accept single option' do
86
+ klass.new(country: 'UK').params[:country].should == 'UK'
87
+ end
95
88
 
96
- it 'does accept single option' do
97
- klass.new(country: 'UK').params[:country].should == 'UK'
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
- it 'does not accept single option if not in declared options' do
101
- klass.new(country: 'USA').params[:country].should be_nil
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
- param :name, 'User name'
167
- param :page, 'page number', default: 1
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
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
- date: 2014-04-03 00:00:00 Z
13
- dependencies:
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
- prerelease: false
17
- requirement: &id001 !ruby/object:Gem::Requirement
18
- requirements:
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
19
17
  - - ~>
20
- - !ruby/object:Gem::Version
21
- version: "1.5"
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
- requirement: &id002 !ruby/object:Gem::Requirement
28
- requirements:
29
- - &id003
30
- - ">="
31
- - !ruby/object:Gem::Version
32
- version: "0"
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
- requirement: &id004 !ruby/object:Gem::Requirement
39
- requirements:
40
- - *id003
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
- version_requirements: *id004
43
- description: Useful for modelling search or form objects, white-listed query parameters and safe parameter defaults.
44
- email:
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
- - *id003
83
- required_rubygems_version: !ruby/object:Gem::Requirement
84
- requirements:
85
- - *id003
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.5
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 values.
93
- test_files:
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: