ar_after_timestamps 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ *.gem
@@ -0,0 +1,58 @@
1
+ # after_timestamps
2
+
3
+ ## Summary
4
+
5
+ Plugin for Ruby on Rails that gives you a way to add a callback to the ActiveRecord callback chain that will be executed right after the record's timestamp columns are set, but before the record is actually saved to the database. This is useful if you want to do something with the timestamps, such as defaulting another time column to created_at, or rolling back a timestamp by a certain amount.
6
+
7
+ ## Example
8
+
9
+ Let's say you have a migration like this:
10
+
11
+ class AddFoo < ActiveRecord::Migration
12
+ def self.up
13
+ create_table :foo {|t| t.timestamps }
14
+ end
15
+ def self.down
16
+ drop_table :foo
17
+ end
18
+ end
19
+
20
+ And a model like this:
21
+
22
+ class Foo < ActiveRecord::Base
23
+ after_timestamps_on_create :roll_back_created_at_by_two_hours
24
+ after_timestamps_on_update :roll_back_updated_at_by_two_hours
25
+
26
+ private
27
+ def roll_back_created_at_by_two_hours
28
+ self.created_at -= 2.hours
29
+ end
30
+
31
+ def roll_back_updated_at_by_two_hours
32
+ self.updated_at -= 2.hours
33
+ end
34
+ end
35
+
36
+ Now if you say
37
+
38
+ Foo.create!
39
+
40
+ `created_at` and `updated_at` will be set, but 2 hours will be subtracted from them before they're put into the database.
41
+
42
+ ## Installation
43
+
44
+ 1. Run `gem install after_timestamps` (probably as root)
45
+ 2. Add `config.gem 'after_timestamps'` to environment.rb
46
+ 3. Optionally run `rake gems:build`
47
+
48
+ ## Support
49
+
50
+ If you find any bugs with this plugin, feel free to:
51
+
52
+ * file a bug report in the [Issues area on Github](http://github.com/mcmire/after_timestamps/issues)
53
+ * fork the [project on Github](http://github.com/mcmire/after_timestamps) and send me a pull request
54
+ * email me (*firstname* dot *lastname* at gmail dot com)
55
+
56
+ ## Author/License
57
+
58
+ (c) 2008-2010 Elliot Winkler. Released under the MIT license.
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require File.dirname(__FILE__) + "/lib/mcmire/ar_after_timestamps"
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.version = Mcmire::ARAfterTimestamps::VERSION
10
+ gem.name = "ar_after_timestamps"
11
+ gem.summary = %Q{Rails gem that provides an AR callback right after timestamps are set and before the record is saved}
12
+ gem.description = %Q{Gem that plugs into Ruby on Rails that gives you a way to add a callback to the ActiveRecord callback chain that will be executed right after the record's timestamp columns are set, but before the record is actually saved to the database. This is useful if you want to do something with the timestamps, such as defaulting another time column to created_at, or rolling back a timestamp by a certain amount.}
13
+ gem.authors = ["Elliot Winkler"]
14
+ gem.email = "elliot.winkler@gmail.com"
15
+ gem.homepage = "http://github.com/mcmire/ar_after_timestamps"
16
+ gem.add_dependency "activerecord", "< 3.0"
17
+ gem.add_development_dependency "mcmire-protest", "~> 0.2.4"
18
+ gem.add_development_dependency "mcmire-matchy", "~> 0.4.1"
19
+ gem.add_development_dependency "mcmire-mocha", "~> 0.9.8"
20
+ gem.add_development_dependency "mocha-protest-integration"
21
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
22
+ end
23
+ Jeweler::GemcutterTasks.new
24
+ rescue LoadError
25
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
26
+ end
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << File.dirname(__FILE__) << 'lib' << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = true
33
+ end
34
+
35
+ begin
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/*_test.rb'
40
+ test.verbose = true
41
+ end
42
+ rescue LoadError
43
+ task :rcov do
44
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
45
+ end
46
+ end
47
+
48
+ task :test => :check_dependencies
49
+
50
+ task :default => :test
51
+
52
+ begin
53
+ require 'yard'
54
+ YARD::Rake::YardocTask.new
55
+ rescue LoadError
56
+ task :yardoc do
57
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
58
+ end
59
+ end
@@ -0,0 +1,63 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ar_after_timestamps}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Elliot Winkler"]
12
+ s.date = %q{2010-01-09}
13
+ s.description = %q{Gem that plugs into Ruby on Rails that gives you a way to add a callback to the ActiveRecord callback chain that will be executed right after the record's timestamp columns are set, but before the record is actually saved to the database. This is useful if you want to do something with the timestamps, such as defaulting another time column to created_at, or rolling back a timestamp by a certain amount.}
14
+ s.email = %q{elliot.winkler@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.md",
21
+ "Rakefile",
22
+ "ar_after_timestamps.gemspec",
23
+ "lib/mcmire/ar_after_timestamps.rb",
24
+ "rails/init.rb",
25
+ "test/ar_after_timestamps_test.rb",
26
+ "test/helper.rb"
27
+ ]
28
+ s.homepage = %q{http://github.com/mcmire/ar_after_timestamps}
29
+ s.rdoc_options = ["--charset=UTF-8"]
30
+ s.require_paths = ["lib"]
31
+ s.rubygems_version = %q{1.3.5}
32
+ s.summary = %q{Rails gem that provides an AR callback right after timestamps are set and before the record is saved}
33
+ s.test_files = [
34
+ "test/ar_after_timestamps_test.rb",
35
+ "test/helper.rb"
36
+ ]
37
+
38
+ if s.respond_to? :specification_version then
39
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
40
+ s.specification_version = 3
41
+
42
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
43
+ s.add_runtime_dependency(%q<activerecord>, ["< 3.0"])
44
+ s.add_development_dependency(%q<mcmire-protest>, ["~> 0.2.4"])
45
+ s.add_development_dependency(%q<mcmire-matchy>, ["~> 0.4.1"])
46
+ s.add_development_dependency(%q<mcmire-mocha>, ["~> 0.9.8"])
47
+ s.add_development_dependency(%q<mocha-protest-integration>, [">= 0"])
48
+ else
49
+ s.add_dependency(%q<activerecord>, ["< 3.0"])
50
+ s.add_dependency(%q<mcmire-protest>, ["~> 0.2.4"])
51
+ s.add_dependency(%q<mcmire-matchy>, ["~> 0.4.1"])
52
+ s.add_dependency(%q<mcmire-mocha>, ["~> 0.9.8"])
53
+ s.add_dependency(%q<mocha-protest-integration>, [">= 0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<activerecord>, ["< 3.0"])
57
+ s.add_dependency(%q<mcmire-protest>, ["~> 0.2.4"])
58
+ s.add_dependency(%q<mcmire-matchy>, ["~> 0.4.1"])
59
+ s.add_dependency(%q<mcmire-mocha>, ["~> 0.9.8"])
60
+ s.add_dependency(%q<mocha-protest-integration>, [">= 0"])
61
+ end
62
+ end
63
+
@@ -0,0 +1,101 @@
1
+ module Mcmire
2
+ # You probably know that every time a record is created, its created_at field
3
+ # is automatically filled in. And every time a record is updated, its updated_at
4
+ # field is filled in. This "magic" happens because of ActiveRecord's
5
+ # Timestamp module, which is mixed in when ActiveRecord::Base is require()'d.
6
+ #
7
+ # Unfortunately, if you want to adjust these times for any reason before the
8
+ # record is actually saved to the database, there isn't a built-in way to do
9
+ # this. So, what we have to end up doing is inserting another method into the
10
+ # ActiveRecord callback chain. However, doing so can be kind of tricky if you
11
+ # don't know what's going on behind the scenes. This is because ActiveRecord
12
+ # starts out with a set of standard methods in AR::Base and then several modules
13
+ # are mixed in that override some of those methods.
14
+ #
15
+ # The methods that we are concerned about are the ones that are called when
16
+ # you say `some_record.save`:
17
+ #
18
+ # save
19
+ # |
20
+ # create_or_update
21
+ # / \
22
+ # create update
23
+ #
24
+ # The modules which are mixed into AR::Base that we are concerned about are
25
+ # AR::Timestamp and AR::Callbacks. Both use alias_method_chain to override
26
+ # the methods, so you will see that below. Anyway, when AR::Timestamp is mixed
27
+ # in this is what the call tree like:
28
+ #
29
+ # save
30
+ # |
31
+ # create_or_update
32
+ # ......./ \.......
33
+ # / \
34
+ # create(_with_timestamps) update(_with_timestamps)
35
+ # | |
36
+ # create_without_timestamps update_without_timestamps
37
+ #
38
+ # (The parentheses are there to indicate the effects of alias_method_chain.)
39
+ #
40
+ # And when AR::Callbacks is mixed in, the tree changes again:
41
+ #
42
+ # save
43
+ # |
44
+ # create_or_update(_with_callbacks)
45
+ # |
46
+ # before_save
47
+ # |
48
+ # create_or_update_without_callbacks
49
+ # ............/ ^ | ^ \..........
50
+ # v | | | v
51
+ # create(_with_callbacks) | | | update(_with_callbacks)
52
+ # | | | | |
53
+ # before_create | | | before_update
54
+ # | | | | |
55
+ # create_without_callbacks | | | update_without_callbacks
56
+ # | | | | |
57
+ # create_without_timestamps / | \ update_without_timestamps
58
+ # | / | \ |
59
+ # after_create .......´ | '....... after_update
60
+ # |
61
+ # v
62
+ # after_save
63
+ #
64
+ # As you can see, when the before_save callback is fired, the timestamps
65
+ # haven't been set yet. Even at before_create/before_update, the timestamps
66
+ # still haven't been set yet. Of course, by the time after_create/after_update,
67
+ # it's too late to adjust the timestamps, since the record has already been
68
+ # saved.
69
+ #
70
+ # That's why we need to insert a custom callback in the chain. We do this by
71
+ # simply alias_method_chain()'ing create_without_timestamps and
72
+ # update_without_timestamps to do what we want.
73
+ #
74
+ module ARAfterTimestamps
75
+ VERSION = "0.2.0"
76
+
77
+ def self.included(klass)
78
+ klass.class_eval do
79
+ alias_method_chain :create_without_timestamps, :after_timestamps
80
+ alias_method_chain :update_without_timestamps, :after_timestamps
81
+ define_callbacks :after_timestamps_on_create, :after_timestamps_on_update
82
+ end
83
+ end
84
+
85
+ def after_timestamps_on_create() end
86
+ def after_timestamps_on_update() end
87
+
88
+ private
89
+ # Override create_with_timestamps to call the after_timestamps_on_create callback
90
+ def create_without_timestamps_with_after_timestamps
91
+ return false if callback(:after_timestamps_on_create) == false
92
+ create_without_timestamps_without_after_timestamps
93
+ end
94
+
95
+ # Same thing, only for update_with_timestamps
96
+ def update_without_timestamps_with_after_timestamps
97
+ return false if callback(:after_timestamps_on_update) == false
98
+ update_without_timestamps_without_after_timestamps
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,7 @@
1
+ require 'active_record'
2
+
3
+ require 'mcmire/ar_after_timestamps'
4
+
5
+ ActiveRecord::Base.class_eval do
6
+ include Mcmire::ARAfterTimestamps
7
+ end
@@ -0,0 +1,61 @@
1
+ require 'helper'
2
+
3
+ ActiveRecord::Base.establish_connection(
4
+ "adapter" => "sqlite3",
5
+ "database" => ":memory:"
6
+ )
7
+
8
+ ActiveRecord::Migration.suppress_messages do
9
+ ActiveRecord::Schema.define do
10
+ create_table :posts do |t|
11
+ t.timestamps
12
+ t.datetime :posted_at, :null => false
13
+ t.string :formatted_created_at
14
+ t.integer :timestamp
15
+ end
16
+ end
17
+ end
18
+
19
+ class Post < ActiveRecord::Base
20
+ after_timestamps_on_create :set_posted_at_to_created_at
21
+ after_timestamps_on_create {|post| post.formatted_created_at = post.created_at.strftime("%b/%Y-%d %D %H%M..%S") }
22
+ after_timestamps_on_update :rollback_created_at
23
+ after_timestamps_on_update {|post| post.timestamp = post.created_at.to_i }
24
+
25
+ def set_posted_at_to_created_at
26
+ self.posted_at = self.created_at
27
+ end
28
+ def rollback_created_at
29
+ self.posted_at -= 2.days
30
+ end
31
+ end
32
+
33
+ Protest.context("ar_after_timestamps") do
34
+ test "after_timestamps_on_create symbol is called on create" do
35
+ Time.stubs(:now).returns(Time.local(2009))
36
+ post = Post.new
37
+ post.save!
38
+ post.posted_at.should == Time.local(2009)
39
+ end
40
+
41
+ test "after_timestamps_on_create proc is called on create" do
42
+ Time.stubs(:now).returns(Time.local(2009))
43
+ post = Post.new
44
+ post.save!
45
+ post.formatted_created_at.should == "Jan/2009-01 01/01/09 0000..00"
46
+ end
47
+
48
+ test "after_timestamps_on_update symbol is called on update" do
49
+ Time.stubs(:now).returns(Time.local(2009))
50
+ post = Post.create!
51
+ post.save!
52
+ post.posted_at.should == Time.local(2008, 12, 30)
53
+ end
54
+
55
+ test "after_timestamp_on_update proc is called on update" do
56
+ Time.stubs(:now).returns(Time.local(2009))
57
+ post = Post.create!
58
+ post.save!
59
+ post.timestamp.should == 1230789600
60
+ end
61
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+
3
+ gem 'mcmire-protest'
4
+ require 'protest'
5
+ gem 'mcmire-matchy'
6
+ require 'matchy'
7
+ gem 'mcmire-mocha'
8
+ require 'mocha'
9
+ require 'mocha-protest-integration'
10
+
11
+ require 'rails/init'
metadata ADDED
@@ -0,0 +1,112 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ar_after_timestamps
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Elliot Winkler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-09 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activerecord
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - <
22
+ - !ruby/object:Gem::Version
23
+ version: "3.0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: mcmire-protest
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 0.2.4
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: mcmire-matchy
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.4.1
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: mcmire-mocha
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.8
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: mocha-protest-integration
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ description: Gem that plugs into Ruby on Rails that gives you a way to add a callback to the ActiveRecord callback chain that will be executed right after the record's timestamp columns are set, but before the record is actually saved to the database. This is useful if you want to do something with the timestamps, such as defaulting another time column to created_at, or rolling back a timestamp by a certain amount.
66
+ email: elliot.winkler@gmail.com
67
+ executables: []
68
+
69
+ extensions: []
70
+
71
+ extra_rdoc_files:
72
+ - README.md
73
+ files:
74
+ - .gitignore
75
+ - README.md
76
+ - Rakefile
77
+ - ar_after_timestamps.gemspec
78
+ - lib/mcmire/ar_after_timestamps.rb
79
+ - rails/init.rb
80
+ - test/ar_after_timestamps_test.rb
81
+ - test/helper.rb
82
+ has_rdoc: true
83
+ homepage: http://github.com/mcmire/ar_after_timestamps
84
+ licenses: []
85
+
86
+ post_install_message:
87
+ rdoc_options:
88
+ - --charset=UTF-8
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: "0"
102
+ version:
103
+ requirements: []
104
+
105
+ rubyforge_project:
106
+ rubygems_version: 1.3.5
107
+ signing_key:
108
+ specification_version: 3
109
+ summary: Rails gem that provides an AR callback right after timestamps are set and before the record is saved
110
+ test_files:
111
+ - test/ar_after_timestamps_test.rb
112
+ - test/helper.rb