cohort_scope 0.0.7 → 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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/cohort_scope.gemspec +10 -2
- data/lib/cohort_scope.rb +9 -124
- data/lib/cohort_scope/big_cohort.rb +21 -0
- data/lib/cohort_scope/cohort.rb +81 -0
- data/lib/cohort_scope/strict_cohort.rb +13 -0
- data/test/helper.rb +40 -4
- data/test/test_cohort.rb +44 -0
- data/test/test_cohort_scope.rb +6 -13
- metadata +23 -4
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ begin
|
|
13
13
|
gem.add_dependency "activesupport", ">=3.0.0.beta4"
|
14
14
|
gem.add_dependency "activerecord", ">=3.0.0.beta4"
|
15
15
|
gem.add_development_dependency "shoulda", ">= 2.10.3"
|
16
|
-
|
16
|
+
gem.add_development_dependency 'sqlite3-ruby'
|
17
17
|
end
|
18
18
|
Jeweler::GemcutterTasks.new
|
19
19
|
rescue LoadError
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/cohort_scope.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cohort_scope}
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Seamus Abshere", "Andy Rossmeissl", "Derek Kastner"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-10-15}
|
13
13
|
s.description = %q{Provides big_cohort, which widens by finding the constraint that eliminates the most records and removing it. Also provides strict_cohort, which widens by eliminating constraints in order.}
|
14
14
|
s.email = %q{seamus@abshere.net}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,7 +25,11 @@ Gem::Specification.new do |s|
|
|
25
25
|
"VERSION",
|
26
26
|
"cohort_scope.gemspec",
|
27
27
|
"lib/cohort_scope.rb",
|
28
|
+
"lib/cohort_scope/big_cohort.rb",
|
29
|
+
"lib/cohort_scope/cohort.rb",
|
30
|
+
"lib/cohort_scope/strict_cohort.rb",
|
28
31
|
"test/helper.rb",
|
32
|
+
"test/test_cohort.rb",
|
29
33
|
"test/test_cohort_scope.rb"
|
30
34
|
]
|
31
35
|
s.homepage = %q{http://github.com/seamusabshere/cohort_scope}
|
@@ -35,6 +39,7 @@ Gem::Specification.new do |s|
|
|
35
39
|
s.summary = %q{Provides cohorts (in the form of ActiveRecord scopes) that dynamically widen until they contain a certain number of records.}
|
36
40
|
s.test_files = [
|
37
41
|
"test/helper.rb",
|
42
|
+
"test/test_cohort.rb",
|
38
43
|
"test/test_cohort_scope.rb"
|
39
44
|
]
|
40
45
|
|
@@ -46,15 +51,18 @@ Gem::Specification.new do |s|
|
|
46
51
|
s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0.beta4"])
|
47
52
|
s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0.beta4"])
|
48
53
|
s.add_development_dependency(%q<shoulda>, [">= 2.10.3"])
|
54
|
+
s.add_development_dependency(%q<sqlite3-ruby>, [">= 0"])
|
49
55
|
else
|
50
56
|
s.add_dependency(%q<activesupport>, [">= 3.0.0.beta4"])
|
51
57
|
s.add_dependency(%q<activerecord>, [">= 3.0.0.beta4"])
|
52
58
|
s.add_dependency(%q<shoulda>, [">= 2.10.3"])
|
59
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
53
60
|
end
|
54
61
|
else
|
55
62
|
s.add_dependency(%q<activesupport>, [">= 3.0.0.beta4"])
|
56
63
|
s.add_dependency(%q<activerecord>, [">= 3.0.0.beta4"])
|
57
64
|
s.add_dependency(%q<shoulda>, [">= 2.10.3"])
|
65
|
+
s.add_dependency(%q<sqlite3-ruby>, [">= 0"])
|
58
66
|
end
|
59
67
|
end
|
60
68
|
|
data/lib/cohort_scope.rb
CHANGED
@@ -1,28 +1,12 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'active_support'
|
3
3
|
require 'active_support/version'
|
4
|
-
%w{
|
5
|
-
active_support/core_ext/module/delegation
|
6
|
-
}.each do |active_support_3_requirement|
|
7
|
-
require active_support_3_requirement
|
8
|
-
end if ActiveSupport::VERSION::MAJOR == 3
|
9
4
|
|
10
|
-
module
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
def inspect_count_only?
|
16
|
-
@inspect_count_only == true
|
17
|
-
end
|
18
|
-
def as_json(*)
|
19
|
-
inspect_count_only? ? { :members => count } : super
|
20
|
-
end
|
21
|
-
def inspect
|
22
|
-
inspect_count_only? ? "<Massive ActiveRecord scope with #{count} members>" : super
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
5
|
+
require 'active_support/core_ext/module/delegation' if ActiveSupport::VERSION::MAJOR == 3
|
6
|
+
|
7
|
+
require 'cohort_scope/cohort'
|
8
|
+
require 'cohort_scope/big_cohort'
|
9
|
+
require 'cohort_scope/strict_cohort'
|
26
10
|
|
27
11
|
module CohortScope
|
28
12
|
def self.extended(klass)
|
@@ -31,9 +15,9 @@ module CohortScope
|
|
31
15
|
|
32
16
|
# Find the biggest scope possible by removing constraints <b>in any order</b>.
|
33
17
|
# Returns an empty scope if it can't meet the minimum scope size.
|
34
|
-
def big_cohort(constraints = {}, custom_minimum_cohort_size =
|
18
|
+
def big_cohort(constraints = {}, custom_minimum_cohort_size = self.minimum_cohort_size)
|
35
19
|
raise ArgumentError, "You can't give a big_cohort an OrderedHash; do you want strict_cohort?" if constraints.is_a?(ActiveSupport::OrderedHash)
|
36
|
-
|
20
|
+
BigCohort.create self, constraints, custom_minimum_cohort_size
|
37
21
|
end
|
38
22
|
|
39
23
|
# Find the first acceptable scope by removing constraints <b>in strict order</b>, starting with the last constraint.
|
@@ -52,107 +36,8 @@ module CohortScope
|
|
52
36
|
#
|
53
37
|
# If the original constraints don't meet the minimum scope size, then the only constraint that can be removed is birthdate.
|
54
38
|
# In other words, this would never return a scope that was constrained on birthdate but not on favorite_color.
|
55
|
-
def strict_cohort(constraints, custom_minimum_cohort_size =
|
39
|
+
def strict_cohort(constraints, custom_minimum_cohort_size = self.minimum_cohort_size)
|
56
40
|
raise ArgumentError, "You need to give strict_cohort an OrderedHash" unless constraints.is_a?(ActiveSupport::OrderedHash)
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
protected
|
61
|
-
|
62
|
-
# Recursively look for a scope that meets the constraints and is at least <tt>minimum_cohort_size</tt>.
|
63
|
-
def _cohort_scope(constraints, custom_minimum_cohort_size)
|
64
|
-
raise RuntimeError, "You need to set #{name}.minimum_cohort_size = X" unless minimum_cohort_size.present?
|
65
|
-
|
66
|
-
if constraints.values.none? # failing base case
|
67
|
-
empty_cohort = scoped.where '1 = 2'
|
68
|
-
empty_cohort.inspect_count_only!
|
69
|
-
return empty_cohort
|
70
|
-
end
|
71
|
-
|
72
|
-
this_hash = _cohort_constraints constraints
|
73
|
-
this_count = scoped.where(this_hash).count
|
74
|
-
|
75
|
-
if this_count >= (custom_minimum_cohort_size || minimum_cohort_size) # successful base case
|
76
|
-
cohort = scoped.where this_hash
|
77
|
-
else
|
78
|
-
cohort = _cohort_scope _cohort_reduce_constraints(constraints), custom_minimum_cohort_size
|
79
|
-
end
|
80
|
-
cohort.inspect_count_only!
|
81
|
-
cohort
|
82
|
-
end
|
83
|
-
|
84
|
-
# Sanitize constraints by
|
85
|
-
# * removing nil constraints (so constraints like "X IS NULL" are impossible, sorry)
|
86
|
-
# * converting ActiveRecord::Base objects into integer foreign key constraints
|
87
|
-
def _cohort_constraints(constraints)
|
88
|
-
new_hash = constraints.is_a?(ActiveSupport::OrderedHash) ? ActiveSupport::OrderedHash.new : Hash.new
|
89
|
-
conditions = constraints.inject(new_hash) do |memo, tuple|
|
90
|
-
k, v = tuple
|
91
|
-
if v.kind_of?(ActiveRecord::Base)
|
92
|
-
condition = { _cohort_association_primary_key(k) => v.to_param }
|
93
|
-
elsif !v.nil?
|
94
|
-
condition = { k => v }
|
95
|
-
end
|
96
|
-
memo.merge! condition if condition.is_a? Hash
|
97
|
-
memo
|
98
|
-
end
|
99
|
-
conditions
|
100
|
-
end
|
101
|
-
|
102
|
-
# Convert constraints that are provided as ActiveRecord::Base objects into their corresponding integer primary keys.
|
103
|
-
#
|
104
|
-
# Only works for <tt>belongs_to</tt> relationships.
|
105
|
-
#
|
106
|
-
# For example, :car => <#Car> might get translated into :car_id => 44.
|
107
|
-
def _cohort_association_primary_key(name)
|
108
|
-
@_cohort_association_primary_keys ||= {}
|
109
|
-
return @_cohort_association_primary_keys[name] if @_cohort_association_primary_keys.has_key? name
|
110
|
-
a = reflect_on_association name
|
111
|
-
raise "can't use cohort scope on :through associations (#{self.name} #{name})" if a.options.has_key? :through
|
112
|
-
if !a.primary_key_name.blank?
|
113
|
-
@_cohort_association_primary_keys[name] = a.primary_key_name
|
114
|
-
else
|
115
|
-
raise "we need some other way to find primary key"
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# Choose how to reduce constraints based on whether we're looking for a big cohort or a strict cohort.
|
120
|
-
def _cohort_reduce_constraints(constraints)
|
121
|
-
case constraints
|
122
|
-
when ActiveSupport::OrderedHash
|
123
|
-
_cohort_reduce_constraints_in_order constraints
|
124
|
-
when Hash
|
125
|
-
_cohort_reduce_constraints_seeking_maximum_count constraints
|
126
|
-
else
|
127
|
-
raise "what did you pass me? #{constraints}"
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
# (Used by <tt>big_cohort</tt>)
|
132
|
-
#
|
133
|
-
# Reduce constraints by removing them one by one and counting the results.
|
134
|
-
#
|
135
|
-
# The constraint whose removal leads to the highest record count is removed from the overall constraint set.
|
136
|
-
def _cohort_reduce_constraints_seeking_maximum_count(constraints)
|
137
|
-
highest_count_after_removal = nil
|
138
|
-
losing_key = nil
|
139
|
-
constraints.keys.each do |key|
|
140
|
-
test_constraints = constraints.except(key)
|
141
|
-
count_after_removal = scoped.where(_cohort_constraints(test_constraints)).count
|
142
|
-
if highest_count_after_removal.nil? or count_after_removal > highest_count_after_removal
|
143
|
-
highest_count_after_removal = count_after_removal
|
144
|
-
losing_key = key
|
145
|
-
end
|
146
|
-
end
|
147
|
-
constraints.except losing_key
|
148
|
-
end
|
149
|
-
|
150
|
-
# (Used by <tt>strict_cohort</tt>)
|
151
|
-
#
|
152
|
-
# Reduce constraints by removing the least important one.
|
153
|
-
def _cohort_reduce_constraints_in_order(constraints)
|
154
|
-
reduced_constraints = constraints.dup
|
155
|
-
reduced_constraints.delete constraints.keys.last
|
156
|
-
reduced_constraints
|
41
|
+
StrictCohort.create self, constraints, custom_minimum_cohort_size
|
157
42
|
end
|
158
43
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CohortScope
|
2
|
+
class BigCohort < Cohort
|
3
|
+
|
4
|
+
# Reduce constraints by removing them one by one and counting the results.
|
5
|
+
#
|
6
|
+
# The constraint whose removal leads to the highest record count is removed from the overall constraint set.
|
7
|
+
def self.reduce_constraints(model, constraints)
|
8
|
+
highest_count_after_removal = nil
|
9
|
+
losing_key = nil
|
10
|
+
constraints.keys.each do |key|
|
11
|
+
test_constraints = constraints.except(key)
|
12
|
+
count_after_removal = model.scoped.where(sanitize_constraints(model, test_constraints)).count
|
13
|
+
if highest_count_after_removal.nil? or count_after_removal > highest_count_after_removal
|
14
|
+
highest_count_after_removal = count_after_removal
|
15
|
+
losing_key = key
|
16
|
+
end
|
17
|
+
end
|
18
|
+
constraints.except losing_key
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module CohortScope
|
4
|
+
class Cohort < Delegator
|
5
|
+
|
6
|
+
class << self
|
7
|
+
# Recursively look for a scope that meets the constraints and is at least <tt>minimum_cohort_size</tt>.
|
8
|
+
def create(model, constraints, custom_minimum_cohort_size)
|
9
|
+
raise RuntimeError, "You need to set #{name}.minimum_cohort_size = X" unless model.minimum_cohort_size.present?
|
10
|
+
|
11
|
+
if constraints.values.none? # failing base case
|
12
|
+
empty_cohort = model.scoped.where '1 = 2'
|
13
|
+
return new(empty_cohort)
|
14
|
+
end
|
15
|
+
|
16
|
+
constraint_hash = sanitize_constraints model, constraints
|
17
|
+
constrained_scope = model.scoped.where(constraint_hash)
|
18
|
+
|
19
|
+
if constrained_scope.count >= custom_minimum_cohort_size
|
20
|
+
new constrained_scope
|
21
|
+
else
|
22
|
+
reduced_constraints = reduce_constraints(model, constraints)
|
23
|
+
create(model, reduced_constraints, custom_minimum_cohort_size)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Sanitize constraints by
|
28
|
+
# * removing nil constraints (so constraints like "X IS NULL" are impossible, sorry)
|
29
|
+
# * converting ActiveRecord::Base objects into integer foreign key constraints
|
30
|
+
def sanitize_constraints(model, constraints)
|
31
|
+
new_hash = constraints.is_a?(ActiveSupport::OrderedHash) ? ActiveSupport::OrderedHash.new : Hash.new
|
32
|
+
conditions = constraints.inject(new_hash) do |memo, tuple|
|
33
|
+
k, v = tuple
|
34
|
+
if v.kind_of?(ActiveRecord::Base)
|
35
|
+
primary_key = association_primary_key(model, k)
|
36
|
+
param = v.respond_to?(primary_key) ? v.send(primary_key) : v.to_param
|
37
|
+
condition = { primary_key => param }
|
38
|
+
elsif !v.nil?
|
39
|
+
condition = { k => v }
|
40
|
+
end
|
41
|
+
memo.merge! condition if condition.is_a? Hash
|
42
|
+
memo
|
43
|
+
end
|
44
|
+
conditions
|
45
|
+
end
|
46
|
+
|
47
|
+
# Convert constraints that are provided as ActiveRecord::Base objects into their corresponding integer primary keys.
|
48
|
+
#
|
49
|
+
# Only works for <tt>belongs_to</tt> relationships.
|
50
|
+
#
|
51
|
+
# For example, :car => <#Car> might get translated into :car_id => 44.
|
52
|
+
def association_primary_key(model, name)
|
53
|
+
@_cohort_association_primary_keys ||= {}
|
54
|
+
return @_cohort_association_primary_keys[name] if @_cohort_association_primary_keys.has_key? name
|
55
|
+
a = model.reflect_on_association name
|
56
|
+
raise "there is no association #{name.inspect} on #{model}" if a.nil?
|
57
|
+
raise "can't use cohort scope on :through associations (#{self.name} #{name})" if a.options.has_key? :through
|
58
|
+
if !a.primary_key_name.blank?
|
59
|
+
@_cohort_association_primary_keys[name] = a.primary_key_name
|
60
|
+
else
|
61
|
+
raise "we need some other way to find primary key"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def initialize(obj)
|
67
|
+
@_ch_obj = obj
|
68
|
+
end
|
69
|
+
def __getobj__
|
70
|
+
@_ch_obj
|
71
|
+
end
|
72
|
+
|
73
|
+
def as_json(*)
|
74
|
+
{ :members => count }
|
75
|
+
end
|
76
|
+
|
77
|
+
def inspect
|
78
|
+
"<Massive ActiveRecord scope with #{count} members>"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CohortScope
|
2
|
+
class StrictCohort < Cohort
|
3
|
+
|
4
|
+
# (Used by <tt>strict_cohort</tt>)
|
5
|
+
#
|
6
|
+
# Reduce constraints by removing the least important one.
|
7
|
+
def self.reduce_constraints(model, constraints)
|
8
|
+
reduced_constraints = constraints.dup
|
9
|
+
reduced_constraints.delete constraints.keys.last
|
10
|
+
reduced_constraints
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/test/helper.rb
CHANGED
@@ -18,10 +18,8 @@ ActiveSupport::Notifications.subscribe do |*args|
|
|
18
18
|
end
|
19
19
|
|
20
20
|
ActiveRecord::Base.establish_connection(
|
21
|
-
'adapter' => '
|
22
|
-
'database' => '
|
23
|
-
'username' => 'root',
|
24
|
-
'password' => 'password'
|
21
|
+
'adapter' => 'sqlite3',
|
22
|
+
'database' => ':memory:'
|
25
23
|
)
|
26
24
|
|
27
25
|
ActiveRecord::Schema.define(:version => 20090819143429) do
|
@@ -30,6 +28,19 @@ ActiveRecord::Schema.define(:version => 20090819143429) do
|
|
30
28
|
t.string 'favorite_color'
|
31
29
|
t.integer 'teeth'
|
32
30
|
end
|
31
|
+
create_table 'houses', :force => true do |t|
|
32
|
+
t.string 'period'
|
33
|
+
t.string 'address'
|
34
|
+
t.integer 'storeys'
|
35
|
+
end
|
36
|
+
create_table 'styles', :force => true do |t|
|
37
|
+
t.string 'period'
|
38
|
+
t.string 'name'
|
39
|
+
end
|
40
|
+
create_table 'residents', :force => true do |t|
|
41
|
+
t.integer 'house_id'
|
42
|
+
t.string 'name'
|
43
|
+
end
|
33
44
|
end
|
34
45
|
|
35
46
|
class Citizen < ActiveRecord::Base
|
@@ -54,3 +65,28 @@ end
|
|
54
65
|
].each do |birthdate, favorite_color, teeth|
|
55
66
|
Citizen.create! :birthdate => birthdate, :favorite_color => favorite_color, :teeth => teeth
|
56
67
|
end
|
68
|
+
|
69
|
+
class Style < ActiveRecord::Base
|
70
|
+
extend CohortScope
|
71
|
+
self.minimum_cohort_size = 3
|
72
|
+
has_many :houses
|
73
|
+
end
|
74
|
+
class House < ActiveRecord::Base
|
75
|
+
belongs_to :style, :foreign_key => 'period', :primary_key => 'period'
|
76
|
+
has_one :resident
|
77
|
+
end
|
78
|
+
class Resident < ActiveRecord::Base
|
79
|
+
has_one :house
|
80
|
+
end
|
81
|
+
|
82
|
+
Style.create! :period => 'arts and crafts', :name => 'classical revival'
|
83
|
+
Style.create! :period => 'arts and crafts', :name => 'gothic'
|
84
|
+
Style.create! :period => 'arts and crafts', :name => 'art deco'
|
85
|
+
Style.create! :period => 'victorian', :name => 'stick-eastlake'
|
86
|
+
Style.create! :period => 'victorian', :name => 'queen anne'
|
87
|
+
h1 = House.create! :period => 'arts and crafts', :address => '123 Maple', :storeys => 1
|
88
|
+
h2 = House.create! :period => 'arts and crafts', :address => '223 Walnut', :storeys => 2
|
89
|
+
h3 = House.create! :period => 'victorian', :address => '323 Pine', :storeys => 2
|
90
|
+
Resident.create! :house => h1, :name => 'Bob'
|
91
|
+
Resident.create! :house => h2, :name => 'Rob'
|
92
|
+
Resident.create! :house => h3, :name => 'Gob'
|
data/test/test_cohort.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestCohortScope < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
Citizen.minimum_cohort_size = 3
|
6
|
+
@date_range = (Date.parse('1980-01-01')..Date.parse('1990-01-01'))
|
7
|
+
end
|
8
|
+
|
9
|
+
def style
|
10
|
+
@style ||= Style.find_by_period 'arts and crafts'
|
11
|
+
end
|
12
|
+
|
13
|
+
context '.sanitize_constraints' do
|
14
|
+
should 'remove nil constraints' do
|
15
|
+
constraints = CohortScope::Cohort.sanitize_constraints Style, :eh => :tu, :bru => :te, :caesar => nil
|
16
|
+
assert_does_not_contain constraints.keys, :caesar
|
17
|
+
end
|
18
|
+
should 'keep normal constraints' do
|
19
|
+
constraints = CohortScope::Cohort.sanitize_constraints Style, :eh => :tu, :bru => :te, :caesar => nil
|
20
|
+
assert_equal :tu, constraints[:eh]
|
21
|
+
end
|
22
|
+
should 'include constraints that are models' do
|
23
|
+
gob = Resident.find_by_name 'Gob'
|
24
|
+
constraints = CohortScope::Cohort.sanitize_constraints House, :resident => gob
|
25
|
+
assert_equal gob.house_id, constraints[:house_id]
|
26
|
+
end
|
27
|
+
should 'include constraints that are models not related by primary key' do
|
28
|
+
constraints = CohortScope::Cohort.sanitize_constraints House, :style => style
|
29
|
+
assert_equal 'arts and crafts', constraints['period']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context '.association_primary_key' do
|
34
|
+
should 'include constraints that are models related by a primary key' do
|
35
|
+
gob = Resident.find_by_name('Gob')
|
36
|
+
key = CohortScope::Cohort.association_primary_key Resident, :house
|
37
|
+
assert_equal 'resident_id', key
|
38
|
+
end
|
39
|
+
should 'include constraints that are models related by a non-primary key' do
|
40
|
+
key = CohortScope::Cohort.association_primary_key House, :style
|
41
|
+
assert_equal 'period', key
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/test/test_cohort_scope.rb
CHANGED
@@ -26,6 +26,12 @@ class TestCohortScope < Test::Unit::TestCase
|
|
26
26
|
assert_equal "<Massive ActiveRecord scope with 9 members>", cohort.inspect
|
27
27
|
end
|
28
28
|
|
29
|
+
should "retain the scope's original behavior" do
|
30
|
+
cohort = Citizen.big_cohort :birthdate => @date_range, :favorite_color => 'heliotrope'
|
31
|
+
assert_kind_of Citizen, cohort.last
|
32
|
+
assert_kind_of Citizen, cohort.where(:teeth => 31).first
|
33
|
+
end
|
34
|
+
|
29
35
|
should "raise if no minimum_cohort_size is specified" do
|
30
36
|
Citizen.minimum_cohort_size = nil
|
31
37
|
assert_raises(RuntimeError) {
|
@@ -59,11 +65,6 @@ class TestCohortScope < Test::Unit::TestCase
|
|
59
65
|
Citizen.big_cohort ActiveSupport::OrderedHash.new
|
60
66
|
}
|
61
67
|
end
|
62
|
-
|
63
|
-
should "result in a relation that has inspect_count_only set" do
|
64
|
-
cohort = Citizen.big_cohort :favorite_color => 'heliotrope'
|
65
|
-
assert cohort.inspect_count_only?
|
66
|
-
end
|
67
68
|
end
|
68
69
|
|
69
70
|
context "strict_cohort" do
|
@@ -104,13 +105,5 @@ class TestCohortScope < Test::Unit::TestCase
|
|
104
105
|
cohort = Citizen.strict_cohort birthdate_matters_most
|
105
106
|
assert_equal 9, cohort.count
|
106
107
|
end
|
107
|
-
|
108
|
-
should "result in a relation that has inspect_count_only set" do
|
109
|
-
ordered_attributes = ActiveSupport::OrderedHash.new
|
110
|
-
ordered_attributes[:favorite_color] = 'heliotrope'
|
111
|
-
|
112
|
-
cohort = Citizen.strict_cohort ordered_attributes
|
113
|
-
assert cohort.inspect_count_only?
|
114
|
-
end
|
115
108
|
end
|
116
109
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cohort_scope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 0.0.7
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Seamus Abshere
|
@@ -17,7 +17,7 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2010-
|
20
|
+
date: 2010-10-15 00:00:00 -04:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
@@ -70,6 +70,20 @@ dependencies:
|
|
70
70
|
version: 2.10.3
|
71
71
|
type: :development
|
72
72
|
version_requirements: *id003
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: sqlite3-ruby
|
75
|
+
prerelease: false
|
76
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
hash: 3
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
type: :development
|
86
|
+
version_requirements: *id004
|
73
87
|
description: Provides big_cohort, which widens by finding the constraint that eliminates the most records and removing it. Also provides strict_cohort, which widens by eliminating constraints in order.
|
74
88
|
email: seamus@abshere.net
|
75
89
|
executables: []
|
@@ -88,7 +102,11 @@ files:
|
|
88
102
|
- VERSION
|
89
103
|
- cohort_scope.gemspec
|
90
104
|
- lib/cohort_scope.rb
|
105
|
+
- lib/cohort_scope/big_cohort.rb
|
106
|
+
- lib/cohort_scope/cohort.rb
|
107
|
+
- lib/cohort_scope/strict_cohort.rb
|
91
108
|
- test/helper.rb
|
109
|
+
- test/test_cohort.rb
|
92
110
|
- test/test_cohort_scope.rb
|
93
111
|
has_rdoc: true
|
94
112
|
homepage: http://github.com/seamusabshere/cohort_scope
|
@@ -126,4 +144,5 @@ specification_version: 3
|
|
126
144
|
summary: Provides cohorts (in the form of ActiveRecord scopes) that dynamically widen until they contain a certain number of records.
|
127
145
|
test_files:
|
128
146
|
- test/helper.rb
|
147
|
+
- test/test_cohort.rb
|
129
148
|
- test/test_cohort_scope.rb
|