alvarobp-inverse_sortable 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.
@@ -0,0 +1,11 @@
1
+ benchmark/benchmark.rb
2
+ benchmark/schema.rb
3
+ init.rb
4
+ lib/inverse_sortable.rb
5
+ Manifest
6
+ Rakefile
7
+ README.rdoc
8
+ test/inverse_sortable_test.rb
9
+ test/schema.rb
10
+ test/test_helper.rb
11
+ TODO
@@ -0,0 +1,33 @@
1
+ = inverse_sortable
2
+
3
+ Sets negative timestamps on Active Record models for efficiently sort in reverse order.
4
+
5
+ == Install
6
+
7
+ sudo gem install alvarobp-inverse_sortable --source http://gems.github.com
8
+
9
+ Add to environment.rb:
10
+
11
+ config.gem "alvarobp-inverse_sortable", :lib => "inverse_sortable"
12
+
13
+ == Usage
14
+
15
+ As a very simple plugin, using it is simple. Just add an integer attribute called "created_at_inverse" to your model. Afterwards you can make that model inverse sortable, for example:
16
+
17
+ class Film < ActiveRecord::Base
18
+ acts_as_inverse_sortable
19
+ end
20
+
21
+ Therefore, you can get an inverse sorted array of Films with Film.find(:all, :order => 'created_at_inverse') working on an efficient way.
22
+
23
+ == Test
24
+
25
+ Just do
26
+
27
+ rake test
28
+
29
+ == Benchmarks
30
+
31
+ I ran some benchmarks to see how efficient is this method. Well, most of the times benchmarks showed that this method is more efficient than "ORDER BY created_at DESC" as the table grows.
32
+
33
+ Just in case you want to run these benchmarks, you will need a mysql database (maybe other engines as well) and configure it at the top of benchmark/benchmark.rb file.
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'echoe'
4
+
5
+ Echoe.new('inverse_sortable', '0.1.0') do |p|
6
+ p.description = "Sets negative timestamps on Active Record models for efficiently sort in reverse order."
7
+ p.url = "http://github.com/alvarobp/inverse_sortable"
8
+ p.author = "Alvaro Bautista Pino"
9
+ p.email = "alvarobp@gmail.com"
10
+ p.ignore_pattern = ["tmp/*", "script/*"]
11
+ p.development_dependencies = []
12
+ end
data/TODO ADDED
@@ -0,0 +1 @@
1
+ - Go deep in the fact that in Rails 2.3 on before_create record attributes information is not available.
@@ -0,0 +1,65 @@
1
+ require 'test/unit'
2
+
3
+ require 'rubygems'
4
+ require 'active_record'
5
+
6
+ ActiveRecord::Base.establish_connection({
7
+ :adapter => "mysql",
8
+ :database => "testing_dates",
9
+ :username => "root",
10
+ :password => "",
11
+ :host => "localhost"
12
+ })
13
+
14
+ load(File.dirname(__FILE__) + "/schema.rb")
15
+
16
+ class WithCreatedModel < ActiveRecord::Base
17
+ end
18
+
19
+ def add_rows(ntimes)
20
+ tdate = Time.now-100.days
21
+ ntimes.times do |n|
22
+ wcm = WithCreatedModel.create(:something => "Model #{n}")
23
+ tdate += (rand(5)+1).days
24
+ wcm.update_attribute(:created_at, tdate)
25
+ end
26
+ end
27
+
28
+ def do_benchmark
29
+ Benchmark.bm(10) do |x|
30
+ x.report("normal") {WithCreatedModel.find(:all, :order => "created_at DESC")}
31
+ x.report("inverse") {WithCreatedModel.find(:all, :order => "created_at_inverse")}
32
+ end
33
+ end
34
+
35
+ puts
36
+ puts
37
+ puts "-- Benchmark for 5000 rows --"
38
+ puts
39
+
40
+ add_rows(5000)
41
+ do_benchmark
42
+
43
+ puts
44
+ puts
45
+ puts "-- Benchmark for 10000 rows --"
46
+ puts
47
+
48
+ add_rows(5000)
49
+ do_benchmark
50
+
51
+ puts
52
+ puts
53
+ puts "-- Benchmark for 15000 rows --"
54
+ puts
55
+
56
+ add_rows(5000)
57
+ do_benchmark
58
+
59
+ puts
60
+ puts
61
+ puts "-- Benchmark for 20000 rows --"
62
+ puts
63
+
64
+ add_rows(5000)
65
+ do_benchmark
@@ -0,0 +1,13 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ begin
3
+ drop_table :with_created_models
4
+ rescue
5
+ end
6
+
7
+ create_table :with_created_models, :force => true do |t|
8
+ t.column :something, :string
9
+ t.column :created_at, :datetime
10
+ t.column :updated_at, :datetime
11
+ t.column :created_at_inverse, :integer
12
+ end
13
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'inverse_sortable'
@@ -0,0 +1,34 @@
1
+ module InverseSortable
2
+ def self.included(base)
3
+ super
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def acts_as_inverse_sortable
9
+ include InverseSortable::InstanceMethods
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+ def set_created_at_inverse
15
+ self.update_attribute(:created_at_inverse, -self.created_at.to_i)
16
+ end
17
+
18
+ def set_updated_at_inverse
19
+ self.updated_at_inverse = -Time.now.to_i
20
+ end
21
+
22
+ def after_create
23
+ set_created_at_inverse if self.respond_to?(:created_at_inverse)
24
+ super
25
+ end
26
+
27
+ def before_save
28
+ set_updated_at_inverse if self.respond_to?(:updated_at_inverse)
29
+ super
30
+ end
31
+ end
32
+ end
33
+
34
+ ActiveRecord::Base.send :include, InverseSortable
@@ -0,0 +1,40 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ class WithCreatedModel
4
+ acts_as_inverse_sortable
5
+ end
6
+
7
+ class WithUpdatedModel
8
+ acts_as_inverse_sortable
9
+ end
10
+
11
+ class WithBothModel
12
+ acts_as_inverse_sortable
13
+ end
14
+
15
+ class ActsAsInverseSortableTest < Test::Unit::TestCase
16
+ context "A model that acts as an inverse sortable" do
17
+ should "have the inverse of its created_at time when is created if created_at_inverse is available" do
18
+ with_created = WithCreatedModel.create(:something => "Testing")
19
+
20
+ assert_not_nil with_created.created_at_inverse
21
+ assert_equal -with_created.created_at.to_i, with_created.created_at_inverse
22
+ end
23
+
24
+ should "have the inverse of its updated_at time when is created if updated_at_inverse is available" do
25
+ with_updated = WithUpdatedModel.create(:something => "Testing")
26
+
27
+ assert_not_nil with_updated.updated_at_inverse
28
+ assert_equal -with_updated.updated_at.to_i, with_updated.updated_at_inverse
29
+ end
30
+
31
+ should "update its updated_at_inverse value at update" do
32
+ with_updated = WithUpdatedModel.create(:something => "Testing")
33
+ before_updated = with_updated.updated_at_inverse
34
+ sleep 1
35
+ with_updated.update_attribute(:something, "Testing update")
36
+
37
+ assert with_updated.updated_at_inverse < before_updated
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :with_created_models, :force => true do |t|
3
+ t.column :something, :string
4
+ t.column :created_at, :datetime
5
+ t.column :updated_at, :datetime
6
+ t.column :created_at_inverse, :integer
7
+ end
8
+
9
+ add_index :with_created_models, :created_at_inverse
10
+
11
+ create_table :with_updated_models, :force => true do |t|
12
+ t.column :something, :string
13
+ t.column :created_at, :datetime
14
+ t.column :updated_at, :datetime
15
+ t.column :updated_at_inverse, :integer
16
+ end
17
+
18
+ create_table :with_both_models, :force => true do |t|
19
+ t.column :something, :string
20
+ t.column :created_at, :datetime
21
+ t.column :updated_at, :datetime
22
+ t.column :created_at_inverse, :integer
23
+ t.column :updated_at_inverse, :integer
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ #$:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'test/unit'
4
+
5
+ require 'rubygems'
6
+ require 'active_record'
7
+ require 'shoulda'
8
+
9
+ require File.dirname(__FILE__) + '/../lib/inverse_sortable'
10
+
11
+ ActiveRecord::Base.establish_connection({
12
+ :adapter => "sqlite3",
13
+ :dbfile => "test/test.db"
14
+ })
15
+
16
+ class WithCreatedModel < ActiveRecord::Base
17
+ end
18
+
19
+ class WithUpdatedModel < ActiveRecord::Base
20
+ end
21
+
22
+ class WithBothModel < ActiveRecord::Base
23
+ end
24
+
25
+ load(File.dirname(__FILE__) + "/schema.rb")
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alvarobp-inverse_sortable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alvaro Bautista Pino
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-19 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Sets negative timestamps on Active Record models for efficiently sort in reverse order.
17
+ email: alvarobp@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - lib/inverse_sortable.rb
24
+ - README.rdoc
25
+ - TODO
26
+ files:
27
+ - benchmark/benchmark.rb
28
+ - benchmark/schema.rb
29
+ - init.rb
30
+ - lib/inverse_sortable.rb
31
+ - Manifest
32
+ - Rakefile
33
+ - README.rdoc
34
+ - test/inverse_sortable_test.rb
35
+ - test/schema.rb
36
+ - test/test_helper.rb
37
+ - TODO
38
+ has_rdoc: true
39
+ homepage: http://github.com/alvarobp/inverse_sortable
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "1.2"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project: inverse_sortable
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: Sets negative timestamps on Active Record models for efficiently sort in reverse order.
64
+ test_files:
65
+ - test/inverse_sortable_test.rb
66
+ - test/test_helper.rb