active_reaper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ db/*
2
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1,3 @@
1
+ rvm_gemset_create_on_use_flag=1
2
+ rvm use ruby-1.9.2-p136@active_reaper
3
+ rvm wrapper ruby-1.9.2-p136@active_reaper textmate
data/CHANGELOG.md ADDED
@@ -0,0 +1,4 @@
1
+ # CHANGELOG #
2
+
3
+ ## 0.0.1 ##
4
+ * restructured as gem from specs
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in active_reaper.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,61 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ active_reaper (0.0.1)
5
+ activerecord
6
+ activesupport
7
+ rake
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activemodel (3.1.1)
13
+ activesupport (= 3.1.1)
14
+ builder (~> 3.0.0)
15
+ i18n (~> 0.6)
16
+ activerecord (3.1.1)
17
+ activemodel (= 3.1.1)
18
+ activesupport (= 3.1.1)
19
+ arel (~> 2.2.1)
20
+ tzinfo (~> 0.3.29)
21
+ activesupport (3.1.1)
22
+ multi_json (~> 1.0)
23
+ archive-tar-minitar (0.5.2)
24
+ arel (2.2.1)
25
+ builder (3.0.0)
26
+ columnize (0.3.4)
27
+ diff-lcs (1.1.3)
28
+ i18n (0.6.0)
29
+ linecache19 (0.5.12)
30
+ ruby_core_source (>= 0.1.4)
31
+ multi_json (1.0.3)
32
+ rake (0.9.2.2)
33
+ rspec (2.7.0)
34
+ rspec-core (~> 2.7.0)
35
+ rspec-expectations (~> 2.7.0)
36
+ rspec-mocks (~> 2.7.0)
37
+ rspec-core (2.7.1)
38
+ rspec-expectations (2.7.0)
39
+ diff-lcs (~> 1.1.2)
40
+ rspec-mocks (2.7.0)
41
+ ruby-debug-base19 (0.11.25)
42
+ columnize (>= 0.3.1)
43
+ linecache19 (>= 0.5.11)
44
+ ruby_core_source (>= 0.1.4)
45
+ ruby-debug19 (0.11.6)
46
+ columnize (>= 0.3.1)
47
+ linecache19 (>= 0.5.11)
48
+ ruby-debug-base19 (>= 0.11.19)
49
+ ruby_core_source (0.1.5)
50
+ archive-tar-minitar (>= 0.5.2)
51
+ sqlite3 (1.3.4)
52
+ tzinfo (0.3.31)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ active_reaper!
59
+ rspec (>= 2.6)
60
+ ruby-debug19
61
+ sqlite3
data/README.md ADDED
@@ -0,0 +1,68 @@
1
+ # README #
2
+
3
+ ## Description ##
4
+
5
+ Mark your ActiveRecord models for deletion after a certain period in a single line. Keep these kinds of specifications out of other files or rake tasks and in the models where they belong. A rake task iterates over all participating classes and finds objects/rows ready for deletion. Useful on Heroku where the rake task can be called from their free daily cron task. Ideal for objects common to social networking applications that can quickly build up over time (notifications, news feeds, private messages, etc).
6
+
7
+ ## How To Use ##
8
+
9
+ Within an ActiveRecord class make a call to the "reap" method with an argument to say when a row should be deleted. ActiveReaper will assume that you intend to base the time calculation on the datetime column 'created_at':
10
+
11
+ class PrivateMessage < ActiveRecord::Base
12
+ # delete private messages 30 days after they've been created
13
+ reap :after => 30.days
14
+ end
15
+
16
+ If you need the time calculation to be based off of another value, in can be the name of a column or an instance method:
17
+
18
+ class PrivateMessage < ActiveRecord::Base
19
+ # delete private messages 30 days after they've been read
20
+ reap :after => 30.days, :determined_by => :read_at
21
+ end
22
+
23
+ # == Schema Information
24
+ #
25
+ # Table name: private_messages
26
+ #
27
+ # id :integer(4) not null, primary key
28
+ # sweet_nothings :text
29
+ # read_at :datetime
30
+ # created_at :datetime
31
+ # updated_at :datetime
32
+
33
+ The default method used by ActiveReaper is to delete the expired rows using `ActiveRecord::Base.delete()`. If there are important callbacks or child models in a `has_many :dependent => :destroy` association that need to be taken care of, tell ActiveReaper to use `ActiveRecord::Base.destroy()` instead:
34
+
35
+ class Post < ActiveRecord::Base
36
+ has_many :comments, :dependent => :destroy
37
+
38
+ # delete posts after 3 months, and take all comments with them
39
+ reap :after => 3.months, :using => :destroy
40
+ end
41
+
42
+ If you want to place a guard on top of the expiration time. The guard can be the name of a column or an instance method (_NOTE: Strings in mysql have a truth value of false_):
43
+
44
+ class Post < ActiveRecord::Base
45
+ # delete posts after 1 week if it's been flagged
46
+ reap :after => 1.week, :if => :flagged
47
+ end
48
+
49
+ `unless` may also be used:
50
+
51
+ class PrivateMessage < ActiveRecord::Base
52
+ # delete private messages 30 days after they've been created, unless the user wants them saved
53
+ reap :after => 30.days, :unless => :saved
54
+ end
55
+
56
+ ## Running The Reap Task ##
57
+
58
+ Straightforward:
59
+
60
+ rake reap
61
+
62
+ ## Don't Fear The Reaper ##
63
+
64
+ Since the actual deleting of models gets performed in a rake task, performance may not _necessarily_ be an issue, but ActiveReaper is the fastest when using the delete method, and when both the arguments for 'determined\_by' and 'if/unless' are table columns. Using the destroy method is slower for obvious reasons, and if 'determined\_by' is given as an instance method, then every row has to be instantiated as an ActiveRecord object and evaluated to look for expired objects, making it the slowest strategy.
65
+
66
+ ## Author ##
67
+
68
+ Christopher Eberz; chris@chriseberz.com; @zortnac
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "active_reaper/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "active_reaper"
7
+ s.version = ActiveReaper::VERSION
8
+ s.authors = ["Chris Eberz"]
9
+ s.email = ["chris@chriseberz.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Your ActiveRecord models can cleanly mark themsleves for deletion after a specifc time.}
12
+ s.description = %q{Set ActiveRecord models to delete themselves after a fixed time, or when a certain criteria is met.}
13
+
14
+ s.rubyforge_project = "active_reaper"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib", "spec"]
20
+
21
+ s.add_development_dependency "rspec", ">= 2.6"
22
+ s.add_development_dependency "ruby-debug19"
23
+ s.add_development_dependency "sqlite3"
24
+
25
+ s.add_runtime_dependency "rake"
26
+ s.add_runtime_dependency "activerecord"
27
+ s.add_runtime_dependency "activesupport"
28
+ end
@@ -0,0 +1,113 @@
1
+ require "active_support"
2
+ require "active_record"
3
+
4
+ module ActiveReaper
5
+ REAPED_CLASSES = {}
6
+
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ def self.reap!
12
+ REAPED_CLASSES.each_pair do |klass, settings|
13
+ if settings[:determined_by_type] == :column && settings[:condition].nil?
14
+ ActiveReaper.reap_simply(klass, settings)
15
+ elsif settings[:determined_by_type] == :column && !settings[:condition].nil? && settings[:condition_type] == :column
16
+ ActiveReaper.reap_quickly(klass, settings)
17
+ elsif settings[:determined_by_type] == :column && !settings[:condition].nil? && settings[:condition_type] == :method
18
+ ActiveReaper.reap_conditionally(klass, settings)
19
+ elsif settings[:determined_by_type] == :method
20
+ ActiveReaper.reap_meticulously(klass, settings)
21
+ end
22
+ end
23
+ end
24
+
25
+ module ClassMethods
26
+ def reap(opts)
27
+ unless opts[:after].respond_to?(:ago)
28
+ raise ArgumentError.new("ActiveReaper: option for 'after' must be a FixNum (amount in seconds)")
29
+ end
30
+
31
+ unless [:delete, :destroy].include? (opts[:using] || :delete)
32
+ raise ArgumentError.new("ActiveReaper: option for 'using' must be either :delete or :destroy")
33
+ end
34
+
35
+ unless self.column_names.include?(opts[:determined_by].to_s) ||
36
+ self.instance_methods.include?(opts[:determined_by]) ||
37
+ (opts[:determined_by].nil? && self.column_names.include?('created_at'))
38
+ raise ArgumentError.new("ActiveReaper: option for 'determined_by' must be either a table column name or an instance method. If option is left blank, table must have a datetime 'created_at' column.")
39
+ end
40
+
41
+ unless (opts[:if].nil? && opts[:unless].nil?) || ( !!opts[:if] ^ !!opts[:unless])
42
+ raise ArgumentError.new("ActiveReaper: Pass only 'if' or 'unless' as a condition")
43
+ end
44
+
45
+ unless self.column_names.include?(opts[:if].to_s) || (opts[:if].to_s.last=='?' && self.column_names.include?(opts[:if].to_s.chop)) || self.instance_methods.include?(opts[:if]) || opts[:if].nil?
46
+ raise ArgumentError.new("ActiveReaper: option for 'if' or 'unless' must be either a table column name or an instance method.")
47
+ end
48
+
49
+ settings = {
50
+ :after => opts[:after],
51
+ :using => opts[:using] || :delete,
52
+ :determined_by => opts[:determined_by].nil? ? :created_at : opts[:determined_by],
53
+ :determined_by_type => self.column_names.include?(opts[:determined_by].to_s) ? :column : :method,
54
+ :condition => opts[:if].nil? ? opts[:unless] : opts[:if],
55
+ :condition_type => nil,
56
+ :truth_value => nil
57
+ }
58
+
59
+ if settings[:condition]
60
+ settings[:truth_value] = opts[:if].nil? ? false : true
61
+ settings[:condition_type] = self.column_names.include?(settings[:condition].to_s) ? :column : :method
62
+ end
63
+
64
+ REAPED_CLASSES[self] = settings
65
+ end
66
+ end
67
+
68
+ # run a simple delete_all or destroy_all; no conditions or method-based expiration
69
+ def self.reap_simply(klass, settings)
70
+ if settings[:using] == :delete
71
+ klass.where("#{settings[:determined_by]} < ?", settings[:after].ago.to_s(:db)).delete_all
72
+ else
73
+ klass.where("#{settings[:determined_by]} < ?", settings[:after].ago.to_s(:db)).destroy_all
74
+ end
75
+ end
76
+
77
+ # run a delete_all or destroy_all with the value of the column given as the condition made part of the query
78
+ def self.reap_quickly(klass, settings)
79
+ if settings[:using] == :delete
80
+ klass.where("#{settings[:determined_by]} < ?", settings[:after].ago.to_s(:db)).where(settings[:condition] => settings[:truth_value]).delete_all
81
+ else
82
+ klass.where("#{settings[:determined_by]} < ?", settings[:after].ago.to_s(:db)).where(settings[:condition] => settings[:truth_value]).destroy_all
83
+ end
84
+ end
85
+
86
+ # objects can be selected quickly, but have to be individually evaluated for the extra condition
87
+ def self.reap_conditionally(klass, settings)
88
+ klass.where("#{settings[:determined_by]} < ?", settings[:after].ago.to_s(:db)).each do |object|
89
+ if object.send(settings[:condition]) == settings[:truth_value]
90
+ if settings[:using] == :delete
91
+ klass.delete(object.id)
92
+ else
93
+ klass.destroy(object.id)
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ # All objects must be iterated over to see which have expired, and then may or may not require an extra condition
100
+ def self.reap_meticulously(klass, settings)
101
+ klass.all.each do |object|
102
+ if (object.send(settings[:determined_by]) < settings[:after].ago) && (settings[:condition].nil? || object.send(settings[:condition]) == settings[:truth_value])
103
+ if settings[:using] == :delete
104
+ klass.delete(object.id)
105
+ else
106
+ klass.destroy(object.id)
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ ::ActiveRecord::Base.send(:include, ActiveReaper)
@@ -0,0 +1,9 @@
1
+ require 'rails'
2
+
3
+ module ActiveReaper
4
+ class Railtie < Rails::Railtie
5
+ rake_tasks do
6
+ load "tasks/active_reaper.rake"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveReaper
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ require "active_reaper/version"
2
+ require "active_reaper/active_reaper"
3
+ require "active_reaper/railtie" if defined?(Rails)
File without changes
@@ -0,0 +1,201 @@
1
+ require 'spec_helper.rb'
2
+
3
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'posts'")
4
+ ActiveRecord::Base.connection.create_table(:posts) do |t|
5
+ t.string :title
6
+ t.string :content
7
+ t.boolean :flagged
8
+ t.timestamps
9
+ end
10
+ ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'comments'")
11
+ ActiveRecord::Base.connection.create_table(:comments) do |t|
12
+ t.belongs_to :post
13
+ t.string :content
14
+ end
15
+
16
+ class Post < ActiveRecord::Base
17
+ has_many :comments, :dependent => :destroy
18
+ end
19
+
20
+ class Comment < ActiveRecord::Base
21
+ belongs_to :post
22
+ end
23
+
24
+ describe ActiveReaper do
25
+ before do
26
+ ActiveRecord::Base.connection.increment_open_transactions
27
+ ActiveRecord::Base.connection.begin_db_transaction
28
+
29
+ @post_to_be_deleted = Post.create
30
+ @post_that_survives = Post.create
31
+ @comment = Comment.create(:post_id => @post_to_be_deleted.id)
32
+ end
33
+
34
+ describe "classes set to be reaped after an expiration date" do
35
+ before do
36
+ Post.class_eval do
37
+ reap :after => 10.days
38
+ end
39
+
40
+ @post_that_survives.update_attribute :created_at, 9.days.ago
41
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
42
+ end
43
+
44
+ it "should correctly delete only the instances that have expired" do
45
+ ActiveReaper.reap!
46
+ Post.exists?(@post_that_survives.id).should be_true
47
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
48
+ end
49
+ end
50
+
51
+ describe "classes set to be reaped after an expiration date, based on a field" do
52
+ before do
53
+ Post.class_eval do
54
+ reap :after => 10.days, :determined_by => :created_at
55
+ end
56
+
57
+ @post_that_survives.update_attribute :created_at, 9.days.ago
58
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
59
+ end
60
+
61
+ it "should correctly delete only the instances that have expired" do
62
+ ActiveReaper.reap!
63
+ Post.exists?(@post_that_survives.id).should be_true
64
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
65
+ end
66
+ end
67
+
68
+ describe "classes set to be reaped after an expiration date, based on a value returned by a method" do
69
+ before do
70
+ Post.class_eval do
71
+ def last_looked_at
72
+ created_at
73
+ end
74
+
75
+ reap :after => 10.days, :determined_by => :last_looked_at
76
+ end
77
+
78
+ @post_that_survives.update_attribute :created_at, 9.days.ago
79
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
80
+ end
81
+
82
+ it "should correctly delete only the instances that have expired" do
83
+ ActiveReaper.reap!
84
+ Post.exists?(@post_that_survives.id).should be_true
85
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
86
+ end
87
+ end
88
+
89
+ describe "classes set to be reaped using the default delete method" do
90
+ before do
91
+ Post.class_eval do
92
+ reap :after => 10.days, :determined_by => :created_at
93
+ end
94
+
95
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
96
+ end
97
+
98
+ it "should leave dependent models behind" do
99
+ ActiveReaper.reap!
100
+ Comment.exists?(@comment.id).should be_true
101
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
102
+ end
103
+ end
104
+
105
+ describe "classes set to be reaped using the optional destroy method" do
106
+ before do
107
+ Post.class_eval do
108
+ reap :after => 10.days, :determined_by => :created_at, :using => :destroy
109
+ end
110
+
111
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
112
+ end
113
+
114
+ it "should also delete dependent models" do
115
+ ActiveReaper.reap!
116
+ Comment.exists?(@comment.id).should_not be_true
117
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
118
+ end
119
+ end
120
+
121
+ describe "classes set to be reaped after an expiration date, with a condition based on a field" do
122
+ before do
123
+ Post.class_eval do
124
+ reap :after => 10.days, :determined_by => :created_at, :if => :flagged
125
+ end
126
+
127
+ @post_that_survives.update_attribute :created_at, 11.days.ago
128
+ @post_that_survives.update_attribute :flagged, false
129
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
130
+ @post_to_be_deleted.update_attribute :flagged, true
131
+ end
132
+
133
+ it "should correctly delete only the instances that have expired" do
134
+ ActiveReaper.reap!
135
+ Post.exists?(@post_that_survives.id).should be_true
136
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
137
+ end
138
+ end
139
+
140
+ describe "classes set to be reaped after an expiration date, with a condition based on a method" do
141
+ before do
142
+ Post.class_eval do
143
+ reap :after => 10.days, :determined_by => :created_at, :if => :flagged?
144
+ end
145
+
146
+ @post_that_survives.update_attribute :created_at, 11.days.ago
147
+ @post_that_survives.update_attribute :flagged, false
148
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
149
+ @post_to_be_deleted.update_attribute :flagged, true
150
+ end
151
+
152
+ it "should correctly delete only the instances that have expired" do
153
+ ActiveReaper.reap!
154
+ Post.exists?(@post_that_survives.id).should be_true
155
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
156
+ end
157
+ end
158
+
159
+ describe "classes set to be reaped after an expiration date, with a negative condition based on a field" do
160
+ before do
161
+ Post.class_eval do
162
+ reap :after => 10.days, :determined_by => :created_at, :unless => :flagged
163
+ end
164
+
165
+ @post_that_survives.update_attribute :created_at, 11.days.ago
166
+ @post_that_survives.update_attribute :flagged, true
167
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
168
+ @post_to_be_deleted.update_attribute :flagged, false
169
+ end
170
+
171
+ it "should correctly delete only the instances that have expired" do
172
+ ActiveReaper.reap!
173
+ Post.exists?(@post_that_survives.id).should be_true
174
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
175
+ end
176
+ end
177
+
178
+ describe "classes set to be reaped after an expiration date, with a negative condition based on a method" do
179
+ before do
180
+ Post.class_eval do
181
+ reap :after => 10.days, :determined_by => :created_at, :unless => :flagged?
182
+ end
183
+
184
+ @post_that_survives.update_attribute :created_at, 11.days.ago
185
+ @post_that_survives.update_attribute :flagged, true
186
+ @post_to_be_deleted.update_attribute :created_at, 11.days.ago
187
+ @post_to_be_deleted.update_attribute :flagged, false
188
+ end
189
+
190
+ it "should correctly delete only the instances that have expired" do
191
+ ActiveReaper.reap!
192
+ Post.exists?(@post_that_survives.id).should be_true
193
+ Post.exists?(@post_to_be_deleted.id).should_not be_true
194
+ end
195
+ end
196
+
197
+ after do
198
+ ActiveRecord::Base.connection.rollback_db_transaction
199
+ ActiveRecord::Base.connection.decrement_open_transactions
200
+ end
201
+ end
@@ -0,0 +1,8 @@
1
+ require 'active_reaper'
2
+
3
+ root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
4
+
5
+ ActiveRecord::Base.establish_connection(
6
+ :adapter => "sqlite3",
7
+ :database => "#{root}/db/activereaper.db"
8
+ )
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_reaper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Eberz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-11-15 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &2157213160 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '2.6'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2157213160
25
+ - !ruby/object:Gem::Dependency
26
+ name: ruby-debug19
27
+ requirement: &2157212740 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2157212740
36
+ - !ruby/object:Gem::Dependency
37
+ name: sqlite3
38
+ requirement: &2157212280 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2157212280
47
+ - !ruby/object:Gem::Dependency
48
+ name: rake
49
+ requirement: &2157211820 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *2157211820
58
+ - !ruby/object:Gem::Dependency
59
+ name: activerecord
60
+ requirement: &2157184760 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *2157184760
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: &2157184340 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *2157184340
80
+ description: Set ActiveRecord models to delete themselves after a fixed time, or when
81
+ a certain criteria is met.
82
+ email:
83
+ - chris@chriseberz.com
84
+ executables: []
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - .gitignore
89
+ - .rvmrc
90
+ - CHANGELOG.md
91
+ - Gemfile
92
+ - Gemfile.lock
93
+ - README.md
94
+ - Rakefile
95
+ - active_reaper.gemspec
96
+ - lib/active_reaper.rb
97
+ - lib/active_reaper/active_reaper.rb
98
+ - lib/active_reaper/railtie.rb
99
+ - lib/active_reaper/version.rb
100
+ - lib/tasks/active_reaper.rake
101
+ - spec/active_reaper_spec.rb
102
+ - spec/spec_helper.rb
103
+ homepage: ''
104
+ licenses: []
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ - spec
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ! '>='
114
+ - !ruby/object:Gem::Version
115
+ version: '0'
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ! '>='
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ requirements: []
123
+ rubyforge_project: active_reaper
124
+ rubygems_version: 1.8.10
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Your ActiveRecord models can cleanly mark themsleves for deletion after a
128
+ specifc time.
129
+ test_files:
130
+ - spec/active_reaper_spec.rb
131
+ - spec/spec_helper.rb