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 CHANGED
@@ -1 +1 @@
1
- 0.2.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(ClassMethods)
5
- base.send(:include, InstanceMethods)
4
+ base.extend(AllMethods)
5
+ base.send(:include, AllMethods)
6
6
  end
7
7
 
8
- module ClassMethods
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
- end
55
-
56
- module InstanceMethods
57
- def require_obj_or_id(opts,key)
58
- self.class.require_obj_or_id(opts, key)
59
- end
60
- def obj_or_id(opts, key)
61
- self.class.obj_or_id(opts, key)
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
- def require_param(opts, *keys)
64
- self.class.require_param(opts, *keys)
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
- def require_one_of( opts, *keys )
67
- self.class.require_one_of( opts, *keys )
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
@@ -145,21 +145,284 @@ describe ::Trigga::ParamFu do
145
145
  end
146
146
  end
147
147
  end
148
- end
149
-
150
- describe "instance_methods" do
151
- describe "require_obj_or_id" do
152
- it "should call the class method require_obj_or_id" do
153
- Tester.should_receive(:require_obj_or_id).with( {:key=>'val'}, :key )
154
- @t.require_obj_or_id( {:key=>'val'}, :key )
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 "obj_or_id" do
159
- it "should call the class method obj_or_id" do
160
- Tester.should_receive(:obj_or_id).with( {:key=>'val'}, :key )
161
- @t.obj_or_id( {:key=>'val'}, :key )
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: 23
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 0.2.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-03 00:00:00 +00:00
19
+ date: 2011-11-10 00:00:00 +00:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency