itrigga-param_fu 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/trigga/param_fu/param_fu.rb +61 -15
- data/spec/param_fu_spec.rb +274 -11
- metadata +4 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Trigga
|
2
2
|
module ParamFu
|
3
3
|
def self.included(base)
|
4
|
-
base.extend(
|
5
|
-
base.send(:include,
|
4
|
+
base.extend(AllMethods)
|
5
|
+
base.send(:include, AllMethods)
|
6
6
|
end
|
7
7
|
|
8
|
-
module
|
8
|
+
module AllMethods
|
9
9
|
def require_obj_or_id(opts, key)
|
10
10
|
obj_or_id(opts,key)
|
11
11
|
raise ArgumentError.new("#{key} or #{key_with_id(key)} are required") unless opts[key_with_id(key)]
|
@@ -47,24 +47,70 @@ module Trigga
|
|
47
47
|
condition
|
48
48
|
end
|
49
49
|
|
50
|
+
|
50
51
|
# fallback when we don't have ActiveSupport's pluralize method available
|
51
52
|
def to_plural(s)
|
52
53
|
(s.match(/[aeiou]$/i) ? s + 's' : s + 'es' )
|
53
54
|
end
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
|
56
|
+
# Give this a hash per model in the format:
|
57
|
+
# Model class => { param_name => { :operator=>(db operator - defaults to '='),
|
58
|
+
# => :field_name=>(field_name in the database - defaults to param_name)
|
59
|
+
# => }
|
60
|
+
# => }
|
61
|
+
# and it will return an ActiveRecord finder :conditions clause using any params which are present in the given :params
|
62
|
+
# e.g. if you have params = { :created_date_from=>'2011-10-09 00:01:02', :status=>'A', :click_url=>'items.html' }
|
63
|
+
# then calling:
|
64
|
+
#
|
65
|
+
# params_to_conditions( :params=>params, :models=>{
|
66
|
+
# Click => {:click_url=>{ :operator=>"like", :field_name=>'request_path' },
|
67
|
+
# :status => {},
|
68
|
+
# :http_referer=>{:operator=>'like'},
|
69
|
+
# :created_date_from => {:operator=> ">=", :field_name=>'timestamp'}
|
70
|
+
# }
|
71
|
+
# })
|
72
|
+
#
|
73
|
+
#
|
74
|
+
# will generate:
|
75
|
+
#
|
76
|
+
# [ 'clicks.request_path like (?) AND clicks.status = ? AND clicks.created_date_from >= ?', '%items.html%', 'A', '2011-10-09 00:01:02' ]
|
77
|
+
#
|
78
|
+
# It will ignore any criteria given which are NOT in the given :params hash
|
79
|
+
#
|
80
|
+
def params_to_conditions( opts={} )
|
81
|
+
require_param(opts, :params, :models)
|
82
|
+
|
83
|
+
conds = { :where=>[], :values=>[] }
|
84
|
+
|
85
|
+
puts "<br />opts = #{opts.inspect}<br />"
|
86
|
+
opts[:models].each { |model_class, field_defs|
|
87
|
+
puts "model_class = #{model_class.inspect}"
|
88
|
+
parsed_model_conditions = model_conditions( opts[:params], model_class, field_defs )
|
89
|
+
puts "parsed_model_conditions = #{parsed_model_conditions.inspect}"
|
90
|
+
conds[:where] += parsed_model_conditions[:where]
|
91
|
+
conds[:values] += parsed_model_conditions[:values]
|
92
|
+
}
|
93
|
+
|
94
|
+
[ conds[:where].join(" AND ") ] + conds[:values]
|
62
95
|
end
|
63
|
-
|
64
|
-
|
96
|
+
|
97
|
+
def model_conditions( opts, model_class, field_defs )
|
98
|
+
h = {:where=>[], :values=>[]}
|
99
|
+
field_defs.each{ |field_name, definition|
|
100
|
+
parsed_field_def = parse_field_definition( opts, model_class, field_name, definition )
|
101
|
+
h[:where] += parsed_field_def[:where]
|
102
|
+
h[:values] += parsed_field_def[:values]
|
103
|
+
}
|
104
|
+
h
|
65
105
|
end
|
66
|
-
|
67
|
-
|
106
|
+
|
107
|
+
def parse_field_definition( opts, model_class, param_name, definition )
|
108
|
+
c = {:where=>[], :values=>[]}
|
109
|
+
if opts[param_name]
|
110
|
+
c[:where] << "( #{model_class.table_name}.#{definition[:field_name] || param_name.to_s} #{definition[:operator] || '='} (?) )"
|
111
|
+
c[:values] << opts[param_name]
|
112
|
+
end
|
113
|
+
c
|
68
114
|
end
|
69
115
|
end
|
70
116
|
end
|
data/spec/param_fu_spec.rb
CHANGED
@@ -145,21 +145,284 @@ describe ::Trigga::ParamFu do
|
|
145
145
|
end
|
146
146
|
end
|
147
147
|
end
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
@
|
148
|
+
|
149
|
+
describe "parse_field_definition" do
|
150
|
+
before(:each) do
|
151
|
+
@params = { :param_1 => 'param_1 value' }
|
152
|
+
@model_class = mock("model class")
|
153
|
+
@model_class.stub!(:table_name).and_return( 'model_class_table_name' )
|
154
|
+
@param_name = :param_name
|
155
|
+
@definition = { :operator=>'=', :field_name=>'field_name'}
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should return a Hash" do
|
159
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition ).should be_a(Hash)
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "returned Hash" do
|
163
|
+
it "should have a key for :where" do
|
164
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where].should_not be_nil
|
165
|
+
end
|
166
|
+
it "should have a key for :values" do
|
167
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should_not be_nil
|
168
|
+
end
|
169
|
+
|
170
|
+
context "when the given opts has a key matching the given param_name" do
|
171
|
+
before(:each) do
|
172
|
+
@param_name = :param_1
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should add an element to the :where key" do
|
176
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where].size.should == 1
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "where clause" do
|
180
|
+
it "should be wrapped in brackets" do
|
181
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].should =~ /^\s*\(.*\)\s*$/
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "inside the brackets" do
|
185
|
+
before(:each) do
|
186
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should start with the model_class's table name as a scope" do
|
190
|
+
@inside_the_brackets.should =~ /\s*model_class_table_name\..*/
|
191
|
+
end
|
192
|
+
|
193
|
+
context "When the definition has a :fieldname" do
|
194
|
+
before(:each) do
|
195
|
+
@definition[:field_name] = 'field_name'
|
196
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should use the :fieldname" do
|
200
|
+
@inside_the_brackets.should =~ /\s*[^\.]+\.field_name.*/
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "When the definition has no :fieldname" do
|
205
|
+
before(:each) do
|
206
|
+
@definition[:field_name] = nil
|
207
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should use the given param_name converted to a string as the field name" do
|
211
|
+
@inside_the_brackets.should =~ /\s*[^\.]+\.param_1.*/
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context "When the definition has a :operator" do
|
216
|
+
before(:each) do
|
217
|
+
@definition[:operator] = 'my_operator'
|
218
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should use the :operator" do
|
222
|
+
@inside_the_brackets.should =~ /.*\bmy_operator\b.*/
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context "When the definition has no :operator" do
|
227
|
+
before(:each) do
|
228
|
+
@definition[:operator] = nil
|
229
|
+
@inside_the_brackets = Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:where][0].gsub(/^\s*\((.*)\)\s*$/, '\1')
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should use = as the :operator" do
|
233
|
+
@inside_the_brackets.should =~ /[^=]+\s*=\s*[^=]+/
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should end with (?)" do
|
238
|
+
@inside_the_brackets.should =~ /\(\?\)\s*$/
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should add the corresponding value to the :values key" do
|
244
|
+
Tester.parse_field_definition( @params, @model_class, @param_name, @definition )[:values].should == ['param_1 value']
|
245
|
+
end
|
246
|
+
end
|
155
247
|
end
|
156
248
|
end
|
157
249
|
|
158
|
-
describe "
|
159
|
-
|
160
|
-
|
161
|
-
@
|
250
|
+
describe "model_conditions" do
|
251
|
+
before(:each) do
|
252
|
+
@params = { :param_1 => 'param_1 value' }
|
253
|
+
@model_class = mock("model class")
|
254
|
+
@mock_parsed_field_def_1 = {:where=>['where 1'], :values=>['values 1']}
|
255
|
+
@mock_parsed_field_def_2 = {:where=>['where 2'], :values=>['values 2']}
|
256
|
+
Tester.stub!(:parse_field_definition).and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
257
|
+
@definitions = { :key=>'=', :field_name=>'field_name'}
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should return a Hash" do
|
261
|
+
Tester.model_conditions( @params, @model_class, @definitions ).should be_a(Hash)
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "returned Hash" do
|
265
|
+
it "should have a key for :where" do
|
266
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:where].should_not be_nil
|
267
|
+
end
|
268
|
+
it "should have a key for :values" do
|
269
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:values].should_not be_nil
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
context "for each given field_def" do
|
274
|
+
before(:each) do
|
275
|
+
@definitions = { :field_name_1 => (@mock_definition_1={}), :field_name_2 => (@mock_definition_2={}) }
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should call parse_field_definition" do
|
279
|
+
Tester.should_receive(:parse_field_definition).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
280
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
281
|
+
end
|
282
|
+
|
283
|
+
describe "parse_field_definition call params" do
|
284
|
+
it "should pass the given opts" do
|
285
|
+
Tester.should_receive(:parse_field_definition).with( @params, anything, anything, anything ).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
286
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
287
|
+
end
|
288
|
+
|
289
|
+
it "should pass the given model class" do
|
290
|
+
Tester.should_receive(:parse_field_definition).with( anything, @model_class, anything, anything ).twice.and_return( @mock_parsed_field_def_1, @mock_parsed_field_def_2 )
|
291
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
292
|
+
end
|
293
|
+
|
294
|
+
it "should pass each field_name" do
|
295
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
296
|
+
args[2].should == :field_name_1
|
297
|
+
@mock_parsed_field_def_1
|
298
|
+
end
|
299
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
300
|
+
args[2].should == :field_name_2
|
301
|
+
@mock_parsed_field_def_2
|
302
|
+
end
|
303
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should pass the field_name's definition" do
|
307
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
308
|
+
args[3].should == @mock_definition_1
|
309
|
+
@mock_parsed_field_def_1
|
310
|
+
end
|
311
|
+
Tester.should_receive(:parse_field_definition) do |args|
|
312
|
+
args[3].should == @mock_definition_2
|
313
|
+
@mock_parsed_field_def_2
|
314
|
+
end
|
315
|
+
Tester.model_conditions( @params, @model_class, @definitions )
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should add the :where key from the parsed field definition to the :where key of the return hash " do
|
321
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:where].should == ['where 1', 'where 2']
|
322
|
+
end
|
323
|
+
|
324
|
+
it "should add the :values key from the parsed field definition to the :values key of the return hash " do
|
325
|
+
Tester.model_conditions( @params, @model_class, @definitions )[:values].should == ['values 1', 'values 2']
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
|
331
|
+
describe "params_to_conditions" do
|
332
|
+
before(:each) do
|
333
|
+
@mock_params = mock('params')
|
334
|
+
@model_class_1 = "model class 1"
|
335
|
+
@model_class_2 = "model class 2"
|
336
|
+
@models = { @model_class_1 => 'model class def 1', @model_class_2 => 'model class def 2' }
|
337
|
+
@mock_parsed_model_def_1 = {:where=>['where 1'], :values=>['values 1']}
|
338
|
+
@mock_parsed_model_def_2 = {:where=>['where 2'], :values=>['values 2']}
|
339
|
+
Tester.stub!(:model_conditions).and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 )
|
340
|
+
end
|
341
|
+
|
342
|
+
context "when not given a :params key" do
|
343
|
+
it "should raise an ArgumentError" do
|
344
|
+
lambda{ Tester.params_to_conditions(:blart=>'flange', :models=>'models') }.should raise_error(ArgumentError)
|
345
|
+
end
|
162
346
|
end
|
347
|
+
context "when not given a :models key" do
|
348
|
+
it "should raise an ArgumentError" do
|
349
|
+
lambda{ Tester.params_to_conditions(:blart=>'flange', :params=>'params') }.should raise_error(ArgumentError)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
context "for each given model" do
|
354
|
+
before(:each) do
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
it "should call model_conditions" do
|
359
|
+
Tester.should_receive(:model_conditions).twice.and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 )
|
360
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
361
|
+
end
|
362
|
+
|
363
|
+
describe "model_conditions_call_params" do
|
364
|
+
it "should pass on the given :params" do
|
365
|
+
Tester.should_receive(:model_conditions).with(@mock_params, anything, anything).twice.and_return( @mock_parsed_model_def_1, @mock_parsed_model_def_2 )
|
366
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
367
|
+
end
|
368
|
+
|
369
|
+
it "should pass each model class" do
|
370
|
+
Tester.should_receive(:model_conditions) do |args|
|
371
|
+
args[1].should == 'model class 1'
|
372
|
+
@mock_parsed_model_def_1
|
373
|
+
end
|
374
|
+
Tester.should_receive(:model_conditions) do |args|
|
375
|
+
args[1].should == 'model class 2'
|
376
|
+
@mock_parsed_model_def_2
|
377
|
+
end
|
378
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
379
|
+
end
|
380
|
+
|
381
|
+
it "should pass the models field definitions" do
|
382
|
+
Tester.should_receive(:model_conditions) do |args|
|
383
|
+
args[2].should == 'model class def 1'
|
384
|
+
@mock_parsed_model_def_1
|
385
|
+
end
|
386
|
+
Tester.should_receive(:model_conditions) do |args|
|
387
|
+
args[2].should == 'model class def 2'
|
388
|
+
@mock_parsed_model_def_2
|
389
|
+
end
|
390
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
describe "returned value" do
|
396
|
+
it "should be an array" do
|
397
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models ).should be_a(Array)
|
398
|
+
end
|
399
|
+
|
400
|
+
describe "first element" do
|
401
|
+
it "should be a string" do
|
402
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[0].should be_a(String)
|
403
|
+
end
|
404
|
+
|
405
|
+
it "should have the :where keys from the parsed model definitions joined with AND " do
|
406
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[0].should == "where 1 AND where 2"
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
describe "subsequent elements" do
|
411
|
+
it "should be the values from the parsed model definitions" do
|
412
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[1].should == 'values 1'
|
413
|
+
Tester.params_to_conditions( :params=>@mock_params, :models=>@models )[2].should == 'values 2'
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
describe "instance_methods" do
|
422
|
+
it "should not raise an error" do
|
423
|
+
lambda {
|
424
|
+
@t.require_obj_or_id( {:key=>'val'}, :key )
|
425
|
+
}.should_not raise_error
|
163
426
|
end
|
164
427
|
end
|
165
428
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: itrigga-param_fu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 3
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Al Davidson
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2011-11-
|
19
|
+
date: 2011-11-10 00:00:00 +00:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|