parametric 0.0.5 → 0.1.0

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.
@@ -1,23 +0,0 @@
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,24 +0,0 @@
1
- module Parametric
2
- module Utils
3
- def self.value(val, separator = ',')
4
- if val.nil?
5
- ''
6
- elsif val.is_a?(Array)
7
- val.join(separator)
8
- else
9
- val
10
- end
11
- end
12
-
13
- def self.present?(value)
14
- case value
15
- when String
16
- value.strip != ''
17
- when Array, Hash
18
- value.any?
19
- else
20
- !value.nil?
21
- end
22
- end
23
- end
24
- end
@@ -1,68 +0,0 @@
1
- begin
2
- require 'active_support/core_ext/class/attribute'
3
- rescue LoadError
4
- module Kernel
5
- # Returns the object's singleton class.
6
- def singleton_class
7
- class << self
8
- self
9
- end
10
- end unless respond_to?(:singleton_class) # exists in 1.9.2
11
-
12
- # class_eval on an object acts like singleton_class.class_eval.
13
- def class_eval(*args, &block)
14
- singleton_class.class_eval(*args, &block)
15
- end
16
- end
17
-
18
- class Module
19
- def remove_possible_method(method)
20
- if method_defined?(method) || private_method_defined?(method)
21
- remove_method(method)
22
- end
23
- rescue NameError
24
- # If the requested method is defined on a superclass or included module,
25
- # method_defined? returns true but remove_method throws a NameError.
26
- # Ignore this.
27
- end
28
-
29
- def redefine_method(method, &block)
30
- remove_possible_method(method)
31
- define_method(method, &block)
32
- end
33
- end
34
-
35
- class Class
36
- def class_attribute(*attrs)
37
- attrs.each do |name|
38
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
39
- def self.#{name}() nil end
40
- def self.#{name}?() !!#{name} end
41
-
42
- def self.#{name}=(val)
43
- singleton_class.class_eval do
44
- remove_possible_method(:#{name})
45
- define_method(:#{name}) { val }
46
- end
47
-
48
- if singleton_class?
49
- class_eval do
50
- remove_possible_method(:#{name})
51
- def #{name}
52
- defined?(@#{name}) ? @#{name} : singleton_class.#{name}
53
- end
54
- end
55
- end
56
- val
57
- end
58
- RUBY
59
-
60
- end
61
- end
62
-
63
- private
64
- def singleton_class?
65
- ancestors.first != self
66
- end
67
- end
68
- end
@@ -1,90 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Parametric do
4
-
5
- describe Parametric::Params do
6
-
7
- let(:klass) do
8
- Class.new do
9
- include Parametric::Params
10
- param :name, 'User name'
11
- param :tags, 'Tags', multiple: true, default: 'defaulttag'
12
- param :lala, 'Lala' do
13
- param :foo, 'foo'
14
- end
15
- param :account, 'Account' do
16
- param :name, 'Account name'
17
- param :admin, 'Admin user' do
18
- param :name, 'User name'
19
- end
20
- param :shop, 'Shop' do
21
- param :url, 'Shop url', default: 'http://google.com'
22
- end
23
- end
24
- param :variants, 'Product variants', multiple: true do
25
- param :name, 'variant name', default: 'default'
26
- param :price
27
- param :tags, 'Variant tags', multiple: true
28
- end
29
- end
30
- end
31
-
32
- let(:subject) do
33
- klass.new({
34
- foo: 'bar',
35
- name: 'user1',
36
- account: {
37
- name: 'account1',
38
- lala: 1,
39
- admin: {
40
- name: 'Joe Bloggs'
41
- }
42
- },
43
- variants: [
44
- {name: 'red', price: 10},
45
- {price: 11, tags: 'foo,bar'}
46
- ]
47
- })
48
- end
49
-
50
- describe '#params' do
51
- it 'filters nested objects' do
52
- expect(subject.params.has_key?(:foo)).to be_false
53
- expect(subject.params[:name]).to eql('user1')
54
- expect(subject.params[:account][:name]).to eql('account1')
55
- expect(subject.params[:account].has_key?(:lala)).to be_false
56
- expect(subject.params[:account][:admin][:name]).to eql('Joe Bloggs')
57
- end
58
-
59
- it 'nullifies nested objects that were not passed' do
60
- expect(subject.params[:account].has_key?(:shop)).to be_true
61
- expect(subject.params[:account][:shop]).to be_nil
62
- end
63
-
64
- it 'filters nested :multiple into arrays of objects' do
65
- expect(subject.params[:variants].size).to eql(2)
66
- expect(subject.params[:variants][0][:name]).to eql('red')
67
- expect(subject.params[:variants][0][:price]).to eql(10)
68
- expect(subject.params[:variants][0][:tags]).to match_array([])
69
- expect(subject.params[:variants][1][:name]).to eql('default')
70
- expect(subject.params[:variants][1][:price]).to eql(11)
71
- expect(subject.params[:variants][1][:tags]).to match_array(['foo', 'bar'])
72
- end
73
- end
74
-
75
- describe '#available_params' do
76
- it 'does not include key for nested objects that were not passed' do
77
- expect(subject.available_params.has_key?(:lala)).to be_false
78
- expect(subject.available_params[:account].has_key?(:shop)).to be_false
79
- end
80
- end
81
-
82
- describe '#schema' do
83
- it 'includes nested param schemas' do
84
- expect(subject.schema[:account].schema[:name].value).to eql('account1')
85
- expect(subject.schema[:account].schema[:name].label).to eql('Account name')
86
- expect(subject.schema[:account].schema[:admin].schema[:name].value).to eql('Joe Bloggs')
87
- end
88
- end
89
- end
90
- end
@@ -1,261 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Parametric do
4
- it 'should have a version number' do
5
- Parametric::VERSION.should_not be_nil
6
- end
7
-
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
12
-
13
- it 'sets passed values' do
14
- subject.params[:per_page].should == 20
15
- end
16
-
17
- it 'uses defaults if no value passed' do
18
- subject.params[:page].should == 1
19
- end
20
-
21
- it 'does not set value if outside of declared options' do
22
- subject.params[:status].should == []
23
- end
24
-
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
28
-
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
32
-
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
36
-
37
- it 'returns :default wrapped in array if :multiple' do
38
- klass.new().params[:emails].should == ['default@email.com']
39
- end
40
-
41
- it 'turns :multiple comma-separated values into arrays' do
42
- klass.new(status: 'one,three').params[:status].should == ['one', 'three']
43
- end
44
-
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
48
-
49
- it ':multiple values can be arrays' do
50
- klass.new(status: ['one','three']).params[:status].should == ['one', 'three']
51
- end
52
-
53
- it 'defaults work for false values' do
54
- klass.new(email: 'my@email').params[:email].should be_nil
55
- end
56
-
57
- it 'does set value if it does :match' do
58
- klass.new(available: false).params[:available].should be_false
59
- end
60
-
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
64
-
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
68
-
69
- it 'filters out undeclared options' do
70
- klass.new(status: 'one,three,fourteen').params[:status].should == ['one', 'three']
71
- end
72
-
73
- it 'defaults empty multiple options to empty array' do
74
- klass.new().params[:status].should == []
75
- end
76
-
77
- it 'wraps single multiple options in array' do
78
- klass.new(status: 'one').params[:status].should == ['one']
79
- end
80
-
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
84
-
85
- it 'does accept single option' do
86
- klass.new(country: 'UK').params[:country].should == 'UK'
87
- end
88
-
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
-
93
- it 'does not include parameters marked as :nullable' do
94
- klass.new.params.has_key?(:nullable).should be_false
95
- end
96
- end
97
-
98
- describe 'TypedParams' do
99
- let(:klass) do
100
- Class.new do
101
- include Parametric::TypedParams
102
- string :name, 'User name'
103
- integer :page, 'page number', default: 1
104
- integer :per_page, 'items per page', default: 50
105
- array :status, 'status', options: ['one', 'two', 'three']
106
- array :piped_status, 'status with pipes', separator: '|'
107
- string :country, 'country', options: ['UK', 'CL', 'JPN']
108
- string :email, 'email', match: /\w+@\w+\.\w+/
109
- array :emails, 'emails', match: /\w+@\w+\.\w+/, default: 'default@email.com'
110
- param :nullable, 'nullable param', nullable: true
111
- end
112
- end
113
-
114
- let(:subject) { klass.new(foo: 'bar', per_page: '20', status: 'four') }
115
- it_should_behave_like 'a configurable params object'
116
-
117
- it 'does not break when value is nil' do
118
- klass = Class.new do
119
- include Parametric::TypedParams
120
- array :friends, 'friends', nullable: true do
121
- string :name, 'Name'
122
- end
123
- end
124
- klass.new(friends: nil).params[:friends].should == []
125
- klass.new(friends: []).params[:friends].should == []
126
- klass.new(friends: [{name: 'foo'}]).params[:friends].first[:name].should == 'foo'
127
- klass.new.params.has_key?(:friends).should be_false
128
- end
129
- end
130
-
131
- describe Parametric::Params do
132
-
133
- let(:klass) do
134
- Class.new do
135
- include Parametric::Params
136
- param :name, 'User name'
137
- param :page, 'page number', default: 1, coerce: :to_i
138
- param :per_page, 'items per page', default: 50, coerce: lambda{|value| value.to_i}
139
- param :status, 'status', options: ['one', 'two', 'three'], multiple: true
140
- param :piped_status, 'status with pipes', multiple: true, separator: '|'
141
- param :country, 'country', options: ['UK', 'CL', 'JPN']
142
- param :email, 'email', match: /\w+@\w+\.\w+/
143
- param :emails, 'emails', match: /\w+@\w+\.\w+/, multiple: true, default: 'default@email.com'
144
- param :available, 'available', default: true
145
- param :nullable, 'nullable param', nullable: true
146
- end
147
- end
148
-
149
- describe '#params' do
150
- let(:subject) { klass.new(foo: 'bar', per_page: 20, status: 'four') }
151
- it_should_behave_like 'a configurable params object'
152
- end
153
-
154
- describe 'subclassing' do
155
- let(:subclass){ Class.new(klass) }
156
- let(:subject){ subclass.new(foo: 'bar', per_page: 20, status: 'four') }
157
- it_should_behave_like 'a configurable params object'
158
- end
159
-
160
- describe '#available_params' do
161
- let(:subject) { klass.new(foo: 'bar', name: 'lala', per_page: 20, status: 'four', emails: 'one@email.com,two@email.com') }
162
-
163
- it 'only includes declared params with values or defaults' do
164
- subject.available_params.keys.sort.should == [:available, :emails, :name, :page, :per_page]
165
- subject.available_params[:emails].should == ['one@email.com', 'two@email.com']
166
- subject.available_params[:name].should == 'lala'
167
- subject.available_params[:per_page].should == 20
168
- subject.available_params[:page].should == 1
169
- end
170
-
171
- describe ':coerce option' do
172
- it 'accepts method_name as a symbol' do
173
- klass.new(page: '10').available_params[:page].should == 10
174
- end
175
-
176
- it 'accepts a proc' do
177
- klass.new(per_page: '10').available_params[:per_page].should == 10
178
- end
179
- end
180
-
181
- describe '#flat' do
182
- it 'joins values back' do
183
- subject.available_params.flat[:emails].should == 'one@email.com,two@email.com'
184
- end
185
- end
186
- end
187
-
188
- describe '#schema' do
189
- let(:subject) { klass.new(foo: 'bar', name: 'lala', per_page: 20, status: 'four') }
190
-
191
- it 'returns full param definitions with populated value' do
192
- regexp = /\w+@\w+\.\w+/
193
-
194
- subject.schema[:name].label.should == 'User name'
195
- subject.schema[:name].value.should == 'lala'
196
-
197
- subject.schema[:page].label.should == 'page number'
198
- subject.schema[:page].value.should == 1
199
-
200
- subject.schema[:per_page].label.should == 'items per page'
201
- subject.schema[:per_page].value.should == 20
202
-
203
- subject.schema[:status].label.should == 'status'
204
- subject.schema[:status].value.should == ''
205
- subject.schema[:status].options.should == ['one', 'two', 'three']
206
- subject.schema[:status].multiple.should be_true
207
-
208
- subject.schema[:piped_status].label.should == 'status with pipes'
209
- subject.schema[:piped_status].value.should == ''
210
- subject.schema[:piped_status].multiple.should be_true
211
-
212
- subject.schema[:country].label.should == 'country'
213
- subject.schema[:country].value.should == ''
214
- subject.schema[:country].options.should == ['UK', 'CL', 'JPN']
215
-
216
- subject.schema[:email].label.should == 'email'
217
- subject.schema[:email].value.should == ''
218
- subject.schema[:email].match.should == regexp
219
-
220
- subject.schema[:emails].label.should == 'emails'
221
- subject.schema[:emails].value.should == 'default@email.com'
222
- subject.schema[:emails].multiple.should be_true
223
- subject.schema[:emails].match.should == regexp
224
- end
225
- end
226
- end
227
-
228
- describe Parametric::Hash do
229
- let(:klass) do
230
- Class.new(Parametric::Hash) do
231
- string :name, 'User name'
232
- integer :page, 'page number', default: 1
233
- param :per_page, 'items per page', default: 50
234
- end
235
- end
236
-
237
- let(:subject) { klass.new(name: 'Ismael', page: 2) }
238
-
239
- it 'quacks like a hash' do
240
- subject[:name].should == 'Ismael'
241
- subject[:page].should == 2
242
- subject[:per_page].should == 50
243
- subject.map{|k,v| k}.sort.should == [:name, :page, :per_page]
244
- subject.keys.sort.should == [:name, :page, :per_page]
245
- subject.values.map(&:to_s).sort.should == ['2', '50', 'Ismael']
246
- subject.fetch(:page, 0).should == 2
247
- subject.fetch(:foo, 0).should == 0
248
- subject.merge(foo: 22).should == {name: 'Ismael', page: 2, per_page: 50, foo: 22}
249
- subject.select{|k,v| k == :name}.should == {name: 'Ismael'}
250
- end
251
-
252
- it 'has #available_params' do
253
- subject.available_params[:name].should == 'Ismael'
254
- end
255
-
256
- it 'has #schema' do
257
- subject.schema[:name].label.should == 'User name'
258
- subject.schema[:name].value.should == 'Ismael'
259
- end
260
- end
261
- end