birddog 0.0.4 → 0.0.5

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.
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