birddog 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,6 +3,6 @@ source "http://rubygems.org"
3
3
  # Specify your gem's dependencies in birddog.gemspec
4
4
  gemspec
5
5
 
6
- group :development do
7
- gem "ruby-debug19", :require => 'ruby-debug'
6
+ group :development, :test do
7
+ gem 'pry'
8
8
  end
data/birddog.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "minitest"
23
23
  s.add_development_dependency "rake"
24
24
  s.add_development_dependency "sqlite3-ruby"
25
+ s.add_development_dependency "pry"
25
26
 
26
27
  s.add_runtime_dependency "chronic"
27
28
  s.add_runtime_dependency "activerecord"
@@ -8,12 +8,17 @@ module Birddog
8
8
  include ::Birddog::FieldConditions
9
9
 
10
10
  AREL_KEYS = [:select, :limit, :joins, :includes, :group, :from, :where, :having]
11
-
12
11
  attr_reader :fields
13
12
 
14
13
  def initialize(model)
15
14
  @model = model
16
15
  @fields = {}
16
+ @averagable = []
17
+ @minimumable = []
18
+ @maximumable = []
19
+ @sumable = []
20
+
21
+ define_common_aggregates_for(model)
17
22
  end
18
23
 
19
24
  def field(name, options={}, &mapping)
@@ -42,6 +47,30 @@ module Birddog
42
47
  aggregate?(name) ? define_aggregate_field(name, @fields[name]) : define_field(name, @fields[name])
43
48
  end
44
49
 
50
+ def averagable(*fields)
51
+ fields.flatten.each do |avg_field|
52
+ @averagable << avg_field
53
+ end
54
+ end
55
+
56
+ def minimumable(*fields)
57
+ fields.flatten.each do |min_field|
58
+ @minimumable << min_field
59
+ end
60
+ end
61
+
62
+ def maximumable(*fields)
63
+ fields.flatten.each do |max_field|
64
+ @maximumable << max_field
65
+ end
66
+ end
67
+
68
+ def sumable(*fields)
69
+ fields.flatten.each do |sum_field|
70
+ @sumable << sum_field
71
+ end
72
+ end
73
+
45
74
  def keyword(name, &block)
46
75
  define_scope(name, &block)
47
76
  end
@@ -95,12 +124,16 @@ module Birddog
95
124
  end
96
125
  private :scope_name_for
97
126
 
127
+ def define_static_scope(name, &scope)
128
+ @model.__send__(:scope, name, scope)
129
+ end
130
+ private :define_static_scope
131
+
98
132
  def define_scope(name, &scope)
99
- @model.send(:scope, scope_name_for(name), scope)
133
+ @model.__send__(:scope, scope_name_for(name), scope)
100
134
  end
101
135
  private :define_scope
102
136
 
103
-
104
137
  def callable_or_cast(field, condition, value)
105
138
  if field[:cast] && field[:cast].respond_to?(:call)
106
139
  field[:cast].call(value.gsub(condition, ""))
@@ -162,17 +195,106 @@ module Birddog
162
195
  end
163
196
  private :tokenize
164
197
 
198
+ def define_common_aggregates_for(model)
199
+ _common_average_for(model)
200
+ _common_sum_for(model)
201
+ _common_minimum_for(model)
202
+ _common_maximum_for(model)
203
+ end
204
+ private :define_common_aggregates_for
205
+
206
+ def _common_average_for(model)
207
+ define_static_scope(:_birddog_average) do |field, value|
208
+ field_name = "average_#{field}"
209
+ scope = { :select => @model.arel_table[field].average.as(field_name) }
210
+ warn_common_aggregate_conditional if conditional?(value)
211
+ scope
212
+ end
213
+ end
214
+ private :_common_average_for
215
+
216
+ def _common_sum_for(model)
217
+ define_static_scope(:_birddog_sum) do |field, value|
218
+ field_name = "sum_#{field}"
219
+ scope = { :select => @model.arel_table[field].sum.as(field_name) }
220
+ warn_common_aggregate_conditional if conditional?(value)
221
+ scope
222
+ end
223
+ end
224
+ private :_common_sum_for
225
+
226
+ def _common_minimum_for(model)
227
+ define_static_scope(:_birddog_minimum) do |field, value|
228
+ field_name = "minimum_#{field}"
229
+ scope = { :select => @model.arel_table[field].minimum.as(field_name) }
230
+ warn_common_aggregate_conditional if conditional?(value)
231
+ scope
232
+ end
233
+ end
234
+ private :_common_minimum_for
235
+
236
+ def _common_maximum_for(model)
237
+ define_static_scope(:_birddog_maximum) do |field, value|
238
+ field_name = "maximum_#{field}"
239
+ scope = { :select => @model.arel_table[field].maximum.as(field_name) }
240
+ warn_common_aggregate_conditional if conditional?(value)
241
+ scope
242
+ end
243
+ end
244
+ private :_common_maximum_for
245
+
246
+ def aggregate_scope_for(model, key, value)
247
+ aggregate_scope = nil
248
+ field_name = nil
249
+ key = key.to_s
250
+
251
+ case
252
+ when key =~ /^(average_)([a-zA-Z_]*)/ && @averagable.include?($2.to_sym) then
253
+ aggregate_scope = "_birddog_average"
254
+ field_name = $2
255
+ when key =~ /^(sum_)([a-zA-Z_]*)/ && @sumable.include?($2.to_sym) then
256
+ aggregate_scope = "_birddog_sum"
257
+ field_name = $2
258
+ when key =~ /^(minimum_)([a-zA-Z_]*)/ && @minimumable.include?($2.to_sym) then
259
+ aggregate_scope = "_birddog_minimum"
260
+ field_name = $2
261
+ when key =~ /^(maximum_)([a-zA-Z_]*)/ && @maximumable.include?($2.to_sym) then
262
+ aggregate_scope = "_birddog_maximum"
263
+ field_name = $2
264
+ end
265
+
266
+ [aggregate_scope, field_name]
267
+ end
268
+ private :aggregate_scope_for
269
+
165
270
  def scope_for(model, key, value)
166
- scope_name = scope_name_for(key)
271
+ scope_name, field = aggregate_scope_for(model, key, value)
272
+ scope_name = scope_name_for(key) unless scope_name
167
273
 
168
274
  if model.respond_to?(scope_name)
169
- model.send(scope_name, value)
275
+ send_params = [field, value].compact
276
+ model.__send__(scope_name, *send_params)
170
277
  else
171
278
  model.scoped
172
279
  end
173
280
  end
174
281
  private :scope_for
175
282
 
283
+ def warn_common_aggregate_conditional
284
+ raise "WARNING"
285
+ rescue => e
286
+ warn <<-WARNING
287
+ ===================================================================
288
+ Birddog currently does not process conditionals on common aggregates
289
+ your program may not behave as expected.
290
+
291
+ Called at:
292
+
293
+ #{e.backtrace.join("#{$/} ")}
294
+ ===================================================================
295
+ WARNING
296
+ end
297
+
176
298
  end
177
299
 
178
300
  end
@@ -1,3 +1,3 @@
1
1
  module Birddog
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -0,0 +1,76 @@
1
+ require "spec_helper"
2
+
3
+ describe Birddog::Birddog do
4
+ before :each do
5
+ User.destroy_all
6
+ Product.destroy_all
7
+ @john = User.create(:first_name => "John", :last_name => "Doe")
8
+ @ducky = @john.products.create(:name => "Rubber Duck", :value => 10)
9
+ @tv = @john.products.create(:name => "TV", :value => 200)
10
+ @bike = @john.products.create(:name => "Bike", :value => 100)
11
+ end
12
+
13
+ describe "averagable" do
14
+ it "implements the common average scope" do
15
+ Product.must_respond_to(:_birddog_average)
16
+ end
17
+
18
+ it "creates a query on the column desired when scope is average_*" do
19
+ sql = Product.scopes_for_query("average_value").to_sql
20
+ sql.must_match(/value/)
21
+ end
22
+
23
+ it "calculates the average and returns it in the result set" do
24
+ avg = Product.scopes_for_query("average_value").first
25
+ avg.average_value.must_equal((100 + 200 + 10) / 3.0)
26
+ end
27
+ end
28
+
29
+ describe "minimumable" do
30
+ it "implements the common minimum scope" do
31
+ Product.must_respond_to(:_birddog_minimum)
32
+ end
33
+
34
+ it "creates a query on the column desired when scope is minimum_*" do
35
+ sql = Product.scopes_for_query("minimum_value").to_sql
36
+ sql.must_match(/minimum/)
37
+ end
38
+
39
+ it "calculates the minimum and returns it in the result set" do
40
+ avg = Product.scopes_for_query("minimum_value").first
41
+ avg.minimum_value.must_equal(10)
42
+ end
43
+ end
44
+
45
+ describe "maximumable" do
46
+ it "implements the common maximum scope" do
47
+ Product.must_respond_to(:_birddog_maximum)
48
+ end
49
+
50
+ it "creates a query on the column desired when scope is maximum_*" do
51
+ sql = Product.scopes_for_query("maximum_value").to_sql
52
+ sql.must_match(/maximum/)
53
+ end
54
+
55
+ it "calculates the maximum and returns it in the result set" do
56
+ avg = Product.scopes_for_query("maximum_value").first
57
+ avg.maximum_value.must_equal(200)
58
+ end
59
+ end
60
+
61
+ describe "sumable" do
62
+ it "implements the common sum scope" do
63
+ Product.must_respond_to(:_birddog_sum)
64
+ end
65
+
66
+ it "creates a query on the column desired when scope is sum_*" do
67
+ sql = Product.scopes_for_query("sum_value").to_sql
68
+ sql.must_match(/sum/)
69
+ end
70
+
71
+ it "calculates the sum and returns it in the result set" do
72
+ avg = Product.scopes_for_query("sum_value").first
73
+ avg.sum_value.must_equal(310)
74
+ end
75
+ end
76
+ end
@@ -23,7 +23,6 @@ describe Birddog::Birddog do
23
23
 
24
24
  it "casts Date when a cast function is provided and is >" do
25
25
  prods = Product.scopes_for_query("cast_val:>9")
26
- debugger
27
26
  prods.must_include(@ducky)
28
27
  end
29
28
  end
data/specs/spec_helper.rb CHANGED
@@ -62,6 +62,10 @@ class Product < ActiveRecord::Base
62
62
  belongs_to :user
63
63
 
64
64
  birddog do |search|
65
+ search.averagable :value
66
+ search.minimumable :value
67
+ search.maximumable :value
68
+ search.sumable :value
65
69
  search.text_search "products.name", "products.value"
66
70
 
67
71
  search.field :name, :regex => true, :wildcard => true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: birddog
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-23 00:00:00.000000000Z
12
+ date: 2012-02-29 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
16
- requirement: &24507660 !ruby/object:Gem::Requirement
16
+ requirement: &12855260 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *24507660
24
+ version_requirements: *12855260
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &24507020 !ruby/object:Gem::Requirement
27
+ requirement: &12854640 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *24507020
35
+ version_requirements: *12854640
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sqlite3-ruby
38
- requirement: &24506140 !ruby/object:Gem::Requirement
38
+ requirement: &12854040 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,21 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *24506140
46
+ version_requirements: *12854040
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry
49
+ requirement: &12853440 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *12853440
47
58
  - !ruby/object:Gem::Dependency
48
59
  name: chronic
49
- requirement: &24505460 !ruby/object:Gem::Requirement
60
+ requirement: &12852700 !ruby/object:Gem::Requirement
50
61
  none: false
51
62
  requirements:
52
63
  - - ! '>='
@@ -54,10 +65,10 @@ dependencies:
54
65
  version: '0'
55
66
  type: :runtime
56
67
  prerelease: false
57
- version_requirements: *24505460
68
+ version_requirements: *12852700
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: activerecord
60
- requirement: &24504040 !ruby/object:Gem::Requirement
71
+ requirement: &12852260 !ruby/object:Gem::Requirement
61
72
  none: false
62
73
  requirements:
63
74
  - - ! '>='
@@ -65,10 +76,10 @@ dependencies:
65
76
  version: '0'
66
77
  type: :runtime
67
78
  prerelease: false
68
- version_requirements: *24504040
79
+ version_requirements: *12852260
69
80
  - !ruby/object:Gem::Dependency
70
81
  name: activesupport
71
- requirement: &24503320 !ruby/object:Gem::Requirement
82
+ requirement: &12851700 !ruby/object:Gem::Requirement
72
83
  none: false
73
84
  requirements:
74
85
  - - ! '>='
@@ -76,10 +87,10 @@ dependencies:
76
87
  version: '0'
77
88
  type: :runtime
78
89
  prerelease: false
79
- version_requirements: *24503320
90
+ version_requirements: *12851700
80
91
  - !ruby/object:Gem::Dependency
81
92
  name: squeel
82
- requirement: &24502200 !ruby/object:Gem::Requirement
93
+ requirement: &12850900 !ruby/object:Gem::Requirement
83
94
  none: false
84
95
  requirements:
85
96
  - - ! '>='
@@ -87,7 +98,7 @@ dependencies:
87
98
  version: '0'
88
99
  type: :runtime
89
100
  prerelease: false
90
- version_requirements: *24502200
101
+ version_requirements: *12850900
91
102
  description: Seeeeeeeee Readme
92
103
  email:
93
104
  - brandonsdewitt@gmail.com
@@ -109,6 +120,7 @@ files:
109
120
  - lib/birddog/searchable.rb
110
121
  - lib/birddog/version.rb
111
122
  - specs/birddog_spec.rb
123
+ - specs/common_aggregates_spec.rb
112
124
  - specs/complex_scope_spec.rb
113
125
  - specs/field_conditions_spec.rb
114
126
  - specs/spec_helper.rb
@@ -127,7 +139,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
139
  version: '0'
128
140
  segments:
129
141
  - 0
130
- hash: -387631044094105301
142
+ hash: -1855020977643402553
131
143
  required_rubygems_version: !ruby/object:Gem::Requirement
132
144
  none: false
133
145
  requirements:
@@ -136,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
136
148
  version: '0'
137
149
  segments:
138
150
  - 0
139
- hash: -387631044094105301
151
+ hash: -1855020977643402553
140
152
  requirements: []
141
153
  rubyforge_project: birddog
142
154
  rubygems_version: 1.8.10