pacecar 1.4.4 → 1.4.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.
Files changed (5) hide show
  1. data/MIT-LICENSE +20 -22
  2. data/README.md +277 -0
  3. data/lib/pacecar/ranking.rb +33 -6
  4. metadata +6 -9
  5. data/README.rdoc +0 -242
data/MIT-LICENSE CHANGED
@@ -1,22 +1,20 @@
1
- Copyright (c) 2008, Matt Jankowski & thoughtbot, inc.
2
-
3
- Permission is hereby granted, free of charge, to any person
4
- obtaining a copy of this software and associated documentation
5
- files (the "Software"), to deal in the Software without
6
- restriction, including without limitation the rights to use,
7
- copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- copies of the Software, and to permit persons to whom the
9
- Software is furnished to do so, subject to the following
10
- conditions:
11
-
12
- The above copyright notice and this permission notice shall be
13
- included in all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
- OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2008, Matt Jankowski & thoughtbot, inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,277 @@
1
+ Pacecar
2
+ =======
3
+
4
+ Pacecar adds scope methods and other common functionality to ActiveRecord classes via database column introspection.
5
+
6
+ Pacecar automatically includes the Pacecar::Helpers module into all ActiveRecord::Base classes.
7
+
8
+ To get all Pacecar functionality, you need to "include Pacecar" in your class.
9
+
10
+ class User < ActiveRecord::Base
11
+ include Pacecar
12
+ end
13
+
14
+ To get some subset (for example, only the state functionality), you can do something like "include Pacecar::State" to get only the module(s) you want.
15
+
16
+ class Post < ActiveRecord::Base
17
+ include Pacecar::State
18
+ end
19
+
20
+ Pacecar supports mysql, postgres and sqlite database drivers.
21
+
22
+ Installation
23
+ ------------
24
+
25
+ For rails 3, just include in your Gemfile
26
+
27
+ gem 'pacecar'
28
+
29
+ For prior rails versions, there is a rails2 branch to use:
30
+
31
+ gem 'pacecar', :git => 'git://github.com/thoughtbot/pacecar.git', :branch => 'rails2'
32
+
33
+ Usage
34
+ -----
35
+
36
+ Assuming a database schema...
37
+
38
+ class CreateSchema < ActiveRecord::Migration
39
+ def self.up
40
+ create_table :users, :force => true do |t|
41
+ t.boolean :admin, :default => false, :null => false
42
+ t.datetime :approved_at
43
+ t.datetime :rejected_at
44
+ t.string :first_name
45
+ t.string :last_name
46
+ t.text :description
47
+ t.timestamps
48
+ end
49
+ create_table :posts, :force => true do |t|
50
+ t.string :owner_type
51
+ t.integer :owner_id
52
+ t.string :publication_state
53
+ t.string :post_type
54
+ t.timestamps
55
+ end
56
+ create_table :comments, :force => true do |t|
57
+ t.integer :user_id
58
+ t.text :description
59
+ t.integer :rating
60
+ t.timestamps
61
+ end
62
+ end
63
+ end
64
+
65
+ And some basic model declarations...
66
+
67
+ class User < ActiveRecord::Base
68
+ include Pacecar
69
+ has_many :posts, :as => :owner
70
+ has_many :comments
71
+ has_many :articles
72
+ has_ranking :comments
73
+ has_recent_records :comments
74
+ has_recent_records :articles, :comments
75
+ has_calculated_records :comments, :on => :rating
76
+ end
77
+
78
+ class Post < ActiveRecord::Base
79
+ include Pacecar
80
+ PUBLICATION_STATES = %w(Draft Submitted Rejected Accepted)
81
+ TYPES = %w(Free Open Private Anonymous PostModern)
82
+ belongs_to :owner, :polymorphic => true
83
+ has_state :publication_state
84
+ has_state :post_type, :with => TYPES
85
+ has_polymorph :owner
86
+ end
87
+
88
+ class Comment < ActiveRecord::Base
89
+ include Pacecar
90
+ belongs_to :user
91
+ end
92
+
93
+ class Article < ActiveRecord::Base
94
+ belongs_to :user
95
+ end
96
+
97
+ All columns
98
+ -----------
99
+
100
+ Records where approved_at is not null, or where it is null...
101
+
102
+ User.approved_at_present
103
+ User.approved_at_missing
104
+
105
+ Records where first_name is not null, or where it is null...
106
+
107
+ User.first_name_present
108
+ User.first_name_missing
109
+
110
+ Records ordered by first_name (default to 'asc', can specify to override)...
111
+
112
+ User.by_first_name
113
+ User.by_first_name(:asc)
114
+ User.by_first_name(:desc)
115
+
116
+ Records where an attribute matches a search term (column LIKE "%term%")...
117
+
118
+ User.first_name_matches('John')
119
+
120
+ Records where an attribute starts or ends with a search term...
121
+
122
+ User.first_name_starts_with('A')
123
+ User.first_name_ends_with('a')
124
+
125
+ Records where an attribute matches exactly a term...
126
+
127
+ User.first_name_equals('John')
128
+
129
+ Records where any non-state text or string column matches term...
130
+
131
+ User.search_for('test')
132
+
133
+ Records where any of a list of columns match the term...
134
+
135
+ User.search_for 'test', :on => [:first_name, :last_name]
136
+
137
+ Records where all of a list of columns match the term...
138
+
139
+ User.search_for 'test', :on => [:first_name, :last_name], :require => :all
140
+
141
+ Boolean columns
142
+ ---------------
143
+
144
+ Records that are all admins or non-admins...
145
+
146
+ User.admin
147
+ User.not_admin
148
+
149
+ The "balance" (count of true minus false for column in question)...
150
+
151
+ User.admin_balance
152
+
153
+ Datetime columns
154
+ ----------------
155
+
156
+ Records approved before or after certain times...
157
+
158
+ User.approved_at_before(5.days.ago)
159
+ User.approved_at_after(4.weeks.ago)
160
+
161
+ Records with approved_at in the past or future...
162
+
163
+ User.approved_at_in_past
164
+ User.approved_at_in_future
165
+
166
+ Records with approved_at inside or outside of two times...
167
+
168
+ User.approved_at_inside(10.days.ago, 1.day.ago)
169
+ User.approved_at_outside(2.days.ago, 1.day.ago)
170
+
171
+ Records with certain year, month or day...
172
+
173
+ User.approved_at_in_year(2000)
174
+ User.approved_at_in_month(01)
175
+ User.approved_at_in_day(01)
176
+
177
+ Records with a duration (time delta between two columns) of, over or under a certain number of days...
178
+
179
+ User.with_duration_of(14, :approved_at, :rejected_at)
180
+ User.with_duration_over(14, :approved_at, :rejected_at)
181
+ User.with_duration_under(14, :approved_at, :rejected_at)
182
+
183
+ Polymorphic relationships
184
+ -------------------------
185
+
186
+ Records which have an owner_type of User...
187
+
188
+ Post.for_owner_type(User)
189
+
190
+ Associations
191
+ ------------
192
+
193
+ Records with the most and least associated records...
194
+
195
+ User.maximum_comments
196
+ User.minimum_comments
197
+
198
+ Records with associated records since a certain time...
199
+
200
+ User.recent_comments_since(2.days.ago)
201
+ User.recent_comments_and_posts_since(3.days.ago)
202
+ User.recent_comments_or_posts_since(4.days.ago)
203
+
204
+ Records with highest and lowest association column average...
205
+
206
+ User.by_comments_highest_rating_average
207
+ User.by_comments_lowest_rating_average
208
+
209
+ Records with highest and lowest association column total...
210
+
211
+ User.by_comments_highest_rating_total
212
+ User.by_comments_lowest_rating_total
213
+
214
+ State columns
215
+ -------------
216
+
217
+ Records which are in a particular state, or not in a state...
218
+
219
+ Post.publication_state_draft
220
+ Post.post_type_not_open
221
+
222
+ Query methods on instances to check state...
223
+
224
+ Post.first.publication_state_draft?
225
+ Post.last.post_type_not_open?
226
+
227
+ Numeric columns
228
+ ---------------
229
+
230
+ Records which are greater than or less than a certain value...
231
+
232
+ User.age_greater_than(21)
233
+ User.age_greater_than_or_equal_to(21)
234
+ User.age_less_than(21)
235
+ User.age_less_than_or_equal_to(21)
236
+
237
+ Limits
238
+ ------
239
+
240
+ First x records...
241
+
242
+ User.limited(10)
243
+
244
+ Named scopes
245
+ ------------
246
+
247
+ Because these are all scope, you can combine them.
248
+
249
+ To get all users that have a first_name set, who are admins and approved more than 2 weeks ago, ordered by their first name...
250
+
251
+ User.first_name_present.admin.approved_at_before(2.weeks.ago).by_first_name
252
+
253
+ To get the top 10 commenters...
254
+
255
+ User.maximim_comments.limited(10)
256
+
257
+ Supported Databases
258
+ -------------------
259
+
260
+ * MySQL
261
+ * SQLite
262
+
263
+ Credits
264
+ -------
265
+
266
+ ![thoughtbot](http://thoughtbot.com/images/tm/logo.png)
267
+
268
+ Pacecar is maintained and funded by [thoughtbot, inc](http://thoughtbot.com/community)
269
+
270
+ Thank you to all [the contributors](https://github.com/thoughtbot/pacecar/contributors)!
271
+
272
+ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
273
+
274
+ License
275
+ -------
276
+
277
+ Pacecar is Copyright © 2008-2011 thoughtbot. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
@@ -11,14 +11,41 @@ module Pacecar
11
11
  define_ranking_scope association, :minimum, :asc
12
12
  end
13
13
 
14
+ def has_calculated_records(*names)
15
+ opts = names.extract_options!
16
+ names.each do |association_name|
17
+ *columns = opts[:on] || []
18
+ columns.flatten.each do |column|
19
+ define_calculated_scope association_name, column, :average, :avg
20
+ define_calculated_scope association_name, column, :total, :sum
21
+ define_calculated_scope association_name, column, :count, :count
22
+ end
23
+ end
24
+ end
25
+
14
26
  protected
15
27
 
16
- def define_ranking_scope(association, name, direction)
17
- scope "#{name}_#{association}",
18
- :select => "#{quoted_table_name}.*, count(#{reflections[association].quoted_table_name}.#{connection.quote_column_name reflections[association].primary_key_name}) as #{association}_count",
19
- :joins => "inner join #{association} on #{association}.#{reflections[association].primary_key_name} = #{quoted_table_name}.#{connection.quote_column_name primary_key}",
20
- :group => safe_column_names.collect { |name| "#{quoted_table_name}.#{connection.quote_column_name(name)}" }.join(', '),
21
- :order => "#{association}_count #{direction}"
28
+ def define_ranking_scope(association, direction_name, direction)
29
+ scope "#{direction_name}_#{association}", {
30
+ :select => "#{quoted_table_name}.*, count(#{reflections[association].quoted_table_name}.#{connection.quote_column_name reflections[association].primary_key_name}) as #{association}_count",
31
+ :order => "#{association}_count #{direction}"
32
+ }.merge(association_group_and_join(association))
33
+ end
34
+
35
+ def define_calculated_scope(association_name, column, function_name, function_method)
36
+ { 'highest' => 'desc', 'lowest' => 'asc' }.each do |direction_name, direction|
37
+ scope "by_#{association_name}_#{direction_name}_#{column}_#{function_name}".to_sym, {
38
+ :select => "#{quoted_table_name}.*, #{function_method}(#{connection.quote_table_name(association_name)}.#{connection.quote_column_name column}) as #{association_name}_#{column}_#{function_name}",
39
+ :order => "#{association_name}_#{column}_#{function_name} #{direction}"
40
+ }.merge(association_group_and_join(association_name))
41
+ end
42
+ end
43
+
44
+ def association_group_and_join(association_name)
45
+ {
46
+ :joins => "inner join #{connection.quote_table_name(association_name)} on #{connection.quote_table_name(association_name)}.#{connection.quote_column_name reflections[association_name].primary_key_name} = #{quoted_table_name}.#{connection.quote_column_name primary_key}",
47
+ :group => safe_column_names.collect { |column_name| "#{quoted_table_name}.#{connection.quote_column_name(column_name)}" }.join(', ')
48
+ }
22
49
  end
23
50
 
24
51
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pacecar
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
7
  - 4
9
- - 4
10
- version: 1.4.4
8
+ - 5
9
+ version: 1.4.5
11
10
  platform: ruby
12
11
  authors:
13
12
  - Matt Jankowski
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-12-11 00:00:00 -05:00
17
+ date: 2011-01-20 00:00:00 -05:00
19
18
  default_executable:
20
19
  dependencies: []
21
20
 
@@ -25,11 +24,11 @@ executables: []
25
24
 
26
25
  extensions: []
27
26
 
28
- extra_rdoc_files:
29
- - README.rdoc
27
+ extra_rdoc_files: []
28
+
30
29
  files:
31
30
  - init.rb
32
- - README.rdoc
31
+ - README.md
33
32
  - MIT-LICENSE
34
33
  - lib/pacecar/associations.rb
35
34
  - lib/pacecar/boolean.rb
@@ -59,7 +58,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
59
58
  requirements:
60
59
  - - ">="
61
60
  - !ruby/object:Gem::Version
62
- hash: 3
63
61
  segments:
64
62
  - 0
65
63
  version: "0"
@@ -68,7 +66,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
68
66
  requirements:
69
67
  - - ">="
70
68
  - !ruby/object:Gem::Version
71
- hash: 3
72
69
  segments:
73
70
  - 0
74
71
  version: "0"
data/README.rdoc DELETED
@@ -1,242 +0,0 @@
1
- == Pacecar
2
-
3
- Pacecar adds scope methods and other common functionality to ActiveRecord classes via database column introspection.
4
-
5
- Pacecar automatically includes the Pacecar::Helpers module into all ActiveRecord::Base classes.
6
-
7
- To get all Pacecar functionality, you need to "include Pacecar" in your class.
8
-
9
- class User < ActiveRecord::Base
10
- include Pacecar
11
- end
12
-
13
- To get some subset (for example, only the state functionality), you can do something like "include Pacecar::State" to get only the module(s) you want.
14
-
15
- class Post < ActiveRecord::Base
16
- include Pacecar::State
17
- end
18
-
19
- Pacecar supports mysql, postgres and sqlite database drivers.
20
-
21
-
22
- == Installation
23
-
24
- For rails 3, just include in your Gemfile
25
-
26
- gem 'pacecar'
27
-
28
- For prior rails versions, there is a rails2 branch to use:
29
-
30
- gem 'pacecar', :git => 'git://github.com/thoughtbot/pacecar.git', :branch => 'rails2'
31
-
32
-
33
- == Usage
34
-
35
- Assuming a database schema...
36
-
37
- class CreateSchema < ActiveRecord::Migration
38
- def self.up
39
- create_table :users, :force => true do |t|
40
- t.boolean :admin, :default => false, :null => false
41
- t.datetime :approved_at
42
- t.datetime :rejected_at
43
- t.string :first_name
44
- t.string :last_name
45
- t.text :description
46
- t.timestamps
47
- end
48
- create_table :posts, :force => true do |t|
49
- t.string :owner_type
50
- t.integer :owner_id
51
- t.string :publication_state
52
- t.string :post_type
53
- t.timestamps
54
- end
55
- create_table :comments, :force => true do |t|
56
- t.integer :user_id
57
- t.text :description
58
- t.timestamps
59
- end
60
- end
61
- end
62
-
63
- And some basic model declarations...
64
-
65
- class User < ActiveRecord::Base
66
- include Pacecar
67
- has_many :posts, :as => :owner
68
- has_many :comments
69
- has_many :articles
70
- has_ranking :comments
71
- has_recent_records :comments
72
- has_recent_records :articles, :comments
73
- end
74
-
75
- class Post < ActiveRecord::Base
76
- include Pacecar
77
- PUBLICATION_STATES = %w(Draft Submitted Rejected Accepted)
78
- TYPES = %w(Free Open Private Anonymous PostModern)
79
- belongs_to :owner, :polymorphic => true
80
- has_state :publication_state
81
- has_state :post_type, :with => TYPES
82
- has_polymorph :owner
83
- end
84
-
85
- class Comment < ActiveRecord::Base
86
- include Pacecar
87
- belongs_to :user
88
- end
89
-
90
- class Article < ActiveRecord::Base
91
- belongs_to :user
92
- end
93
-
94
- = All columns
95
-
96
- Records where approved_at is not null, or where it is null...
97
-
98
- User.approved_at_present
99
- User.approved_at_missing
100
-
101
- Records where first_name is not null, or where it is null...
102
-
103
- User.first_name_present
104
- User.first_name_missing
105
-
106
- Records ordered by first_name (default to 'asc', can specify to override)...
107
-
108
- User.by_first_name
109
- User.by_first_name(:asc)
110
- User.by_first_name(:desc)
111
-
112
- Records where an attribute matches a search term (column LIKE "%term%")...
113
-
114
- User.first_name_matches('John')
115
-
116
- Records where an attribute starts or ends with a search term...
117
-
118
- User.first_name_starts_with('A')
119
- User.first_name_ends_with('a')
120
-
121
- Records where an attribute matches exactly a term...
122
-
123
- User.first_name_equals('John')
124
-
125
- Records where any non-state text or string column matches term...
126
-
127
- User.search_for('test')
128
-
129
- Records where any of a list of columns match the term...
130
-
131
- User.search_for 'test', :on => [:first_name, :last_name]
132
-
133
- Records where all of a list of columns match the term...
134
-
135
- User.search_for 'test', :on => [:first_name, :last_name], :require => :all
136
-
137
- = Boolean columns
138
-
139
- Records that are all admins or non-admins...
140
-
141
- User.admin
142
- User.not_admin
143
-
144
- The "balance" (count of true minus false for column in question)...
145
-
146
- User.admin_balance
147
-
148
- = Datetime columns
149
-
150
- Records approved before or after certain times...
151
-
152
- User.approved_at_before(5.days.ago)
153
- User.approved_at_after(4.weeks.ago)
154
-
155
- Records with approved_at in the past or future...
156
-
157
- User.approved_at_in_past
158
- User.approved_at_in_future
159
-
160
- Records with approved_at inside or outside of two times...
161
-
162
- User.approved_at_inside(10.days.ago, 1.day.ago)
163
- User.approved_at_outside(2.days.ago, 1.day.ago)
164
-
165
- Records with certain year, month or day...
166
-
167
- User.approved_at_in_year(2000)
168
- User.approved_at_in_month(01)
169
- User.approved_at_in_day(01)
170
-
171
- Records with a duration (time delta between two columns) of, over or under a certain number of days...
172
-
173
- User.with_duration_of(14, :approved_at, :rejected_at)
174
- User.with_duration_over(14, :approved_at, :rejected_at)
175
- User.with_duration_under(14, :approved_at, :rejected_at)
176
-
177
- = Polymorphic relationships
178
-
179
- Records which have an owner_type of User...
180
-
181
- Post.for_owner_type(User)
182
-
183
- = Associations
184
-
185
- Records with the most and least associated records...
186
-
187
- User.maximum_comments
188
- User.minimum_comments
189
-
190
- Records with associated records since a certain time...
191
-
192
- User.recent_comments_since(2.days.ago)
193
- User.recent_comments_and_posts_since(3.days.ago)
194
- User.recent_comments_or_posts_since(4.days.ago)
195
-
196
- = State columns
197
-
198
- Records which are in a particular state, or not in a state...
199
-
200
- Post.publication_state_draft
201
- Post.post_type_not_open
202
-
203
- Query methods on instances to check state...
204
-
205
- Post.first.publication_state_draft?
206
- Post.last.post_type_not_open?
207
-
208
- = Numeric columns
209
-
210
- Records which are greater than or less than a certain value...
211
-
212
- User.age_greater_than(21)
213
- User.age_greater_than_or_equal_to(21)
214
- User.age_less_than(21)
215
- User.age_less_than_or_equal_to(21)
216
-
217
- = Limits
218
-
219
- First x records...
220
-
221
- User.limited(10)
222
-
223
- = Named scopes
224
-
225
- Because these are all scope, you can combine them.
226
-
227
- To get all users that have a first_name set, who are admins and approved more than 2 weeks ago, ordered by their first name...
228
-
229
- User.first_name_present.admin.approved_at_before(2.weeks.ago).by_first_name
230
-
231
- To get the top 10 commenters...
232
-
233
- User.maximim_comments.limited(10)
234
-
235
- = Supported Databases
236
-
237
- * MySQL
238
- * SQLite
239
-
240
- = License
241
-
242
- Pacecar is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.