rich-acts_as_revisable 0.9.8 → 1.0.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/README.rdoc +11 -12
- data/Rakefile +3 -3
- data/lib/acts_as_revisable/acts/common.rb +13 -35
- data/lib/acts_as_revisable/acts/deletable.rb +9 -5
- data/lib/acts_as_revisable/acts/revisable.rb +29 -36
- data/lib/acts_as_revisable/acts/revision.rb +7 -9
- data/lib/acts_as_revisable/base.rb +3 -1
- data/lib/acts_as_revisable/gem_spec_options.rb +6 -6
- data/lib/acts_as_revisable/options.rb +1 -1
- data/lib/acts_as_revisable/quoted_columns.rb +3 -7
- data/lib/acts_as_revisable/version.rb +4 -4
- data/lib/acts_as_revisable.rb +1 -5
- data/spec/associations_spec.rb +1 -1
- data/spec/branch_spec.rb +1 -1
- data/spec/find_spec.rb +4 -12
- data/spec/general_spec.rb +7 -1
- data/spec/options_spec.rb +5 -5
- data/spec/quoted_columns_spec.rb +1 -1
- data/spec/revert_spec.rb +1 -1
- data/spec/spec_helper.rb +14 -0
- metadata +6 -6
- data/lib/acts_as_revisable/acts/scoped_model.rb +0 -75
- data/lib/acts_as_revisable/clone_associations.rb +0 -36
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= acts_as_revisable
|
2
2
|
|
3
|
-
http://github.com/
|
3
|
+
http://github.com/rich/acts_as_revisable
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
@@ -11,7 +11,9 @@ This plugin wouldn't exist without Rick Olsen's acts_as_versioned. AAV has been
|
|
11
11
|
== FEATURES:
|
12
12
|
|
13
13
|
* Both the revisable and revision models must be explicitly defined.
|
14
|
-
Yes, this is a feature. The less magic needed the better. This allows you to build up your revision models just as you would any other.
|
14
|
+
Yes, this is a feature. The less magic needed the better. This allows you to build up your revision models just as you would any other.
|
15
|
+
|
16
|
+
If you absolutely need a generated revision model, you may pass ":generate_revision_class => true" to acts_as_revisable and it will generate the class at runtime for you. Think of this like scaffolding and not to be kept around for a real application.
|
15
17
|
|
16
18
|
* Numerous custom callbacks for both revisable and revision models.
|
17
19
|
* revisable models
|
@@ -22,6 +24,8 @@ This plugin wouldn't exist without Rick Olsen's acts_as_versioned. AAV has been
|
|
22
24
|
* before_changeset
|
23
25
|
* after_changeset
|
24
26
|
* after_branch_created
|
27
|
+
* before_revise_on_destroy (when :on_destroy => :revise is set)
|
28
|
+
* after_revise_on_destroy (when :on_destroy => :revise is set)
|
25
29
|
* revision models
|
26
30
|
* before_restore
|
27
31
|
* after_restore
|
@@ -33,7 +37,6 @@ This plugin wouldn't exist without Rick Olsen's acts_as_versioned. AAV has been
|
|
33
37
|
* Provides migration generators to add the revisable columns.
|
34
38
|
* Grouping several revisable actions into a single revision (changeset).
|
35
39
|
* Monitor all or just specified columns to trigger a revision.
|
36
|
-
* Clone all or specified associations to the revision model.
|
37
40
|
* Uses ActiveRecord's dirty attribute tracking.
|
38
41
|
* Several ways to find revisions including:
|
39
42
|
* revision number
|
@@ -72,7 +75,7 @@ Create the revision class:
|
|
72
75
|
|
73
76
|
class Session < ActiveRecord::Base
|
74
77
|
# we can accept the more standard hash syntax
|
75
|
-
acts_as_revision :revisable_class_name => "Project"
|
78
|
+
acts_as_revision :revisable_class_name => "Project"
|
76
79
|
end
|
77
80
|
|
78
81
|
Some example usage:
|
@@ -154,10 +157,6 @@ Changesets:
|
|
154
157
|
# our revision number has only incremented by one
|
155
158
|
@project.revision_number # => 3
|
156
159
|
|
157
|
-
Associations have been cloned:
|
158
|
-
|
159
|
-
@project.owner === @previous.owner # => true
|
160
|
-
|
161
160
|
Maybe we don't want to be able to branch from revisions:
|
162
161
|
|
163
162
|
class Session < ActiveRecord::Base
|
@@ -184,23 +183,23 @@ If the owner isn't set let's prevent reverting:
|
|
184
183
|
|
185
184
|
== REQUIREMENTS:
|
186
185
|
|
187
|
-
This plugin
|
186
|
+
This plugin requires Rails 2.3. Use version 0.9.8 of this plugin for Rails 2.1 and 2.2.
|
188
187
|
|
189
188
|
== INSTALL:
|
190
189
|
|
191
190
|
acts_as_revisable uses Rails' new ability to use gems as plugins. Installing AAR is as simple as installing a gem:
|
192
191
|
|
193
|
-
sudo gem install
|
192
|
+
sudo gem install rich-acts_as_revisable --source=http://gems.github.com
|
194
193
|
|
195
194
|
Once the gem is installed you'll want to activate it in your Rails app by adding the following line to config/environment.rb:
|
196
195
|
|
197
|
-
config.gem "
|
196
|
+
config.gem "rich-acts_as_revisable", :lib => "acts_as_revisable", :source => "http://gems.github.com"
|
198
197
|
|
199
198
|
== LICENSE:
|
200
199
|
|
201
200
|
(The MIT License)
|
202
201
|
|
203
|
-
Copyright (c)
|
202
|
+
Copyright (c) 2009 Rich Cavanaugh
|
204
203
|
|
205
204
|
Permission is hereby granted, free of charge, to any person obtaining
|
206
205
|
a copy of this software and associated documentation files (the
|
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ Rake::RDocTask.new do |rdoc|
|
|
14
14
|
end
|
15
15
|
|
16
16
|
spec = Gem::Specification.new do |s|
|
17
|
-
|
17
|
+
WithoutScope::ActsAsRevisable::GemSpecOptions::HASH.each do |key, value|
|
18
18
|
s.send("#{key.to_s}=",value)
|
19
19
|
end
|
20
20
|
end
|
@@ -25,7 +25,7 @@ end
|
|
25
25
|
|
26
26
|
desc "Generate the static gemspec required for github."
|
27
27
|
task :generate_gemspec do
|
28
|
-
options =
|
28
|
+
options = WithoutScope::ActsAsRevisable::GemSpecOptions::HASH.clone
|
29
29
|
options[:name] = "acts_as_revisable"
|
30
30
|
|
31
31
|
spec = ["Gem::Specification.new do |s|"]
|
@@ -39,6 +39,6 @@ end
|
|
39
39
|
|
40
40
|
desc "Install acts_as_revisable"
|
41
41
|
task :install => :repackage do
|
42
|
-
options =
|
42
|
+
options = WithoutScope::ActsAsRevisable::GemSpecOptions::HASH.clone
|
43
43
|
sh %{sudo gem install pkg/#{options[:name]}-#{spec.version} --no-rdoc --no-ri}
|
44
44
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module WithoutScope
|
2
2
|
module ActsAsRevisable
|
3
3
|
# This module is mixed into the revision and revisable classes.
|
4
4
|
#
|
@@ -18,17 +18,12 @@ module FatJam
|
|
18
18
|
base.class_inheritable_hash :revisable_current_states
|
19
19
|
base.revisable_current_states = {}
|
20
20
|
|
21
|
-
class << base
|
22
|
-
alias_method_chain :instantiate, :revisable
|
23
|
-
end
|
24
|
-
|
25
21
|
base.instance_eval do
|
26
22
|
define_callbacks :before_branch, :after_branch
|
27
23
|
has_many :branches, (revisable_options.revision_association_options || {}).merge({:class_name => base.class_name, :foreign_key => :revisable_branched_from_id})
|
28
24
|
|
29
25
|
belongs_to :branch_source, :class_name => base.class_name, :foreign_key => :revisable_branched_from_id
|
30
26
|
after_save :execute_blocks_after_save
|
31
|
-
disable_revisable_scope :branch_source, :branches
|
32
27
|
end
|
33
28
|
end
|
34
29
|
|
@@ -151,7 +146,11 @@ module FatJam
|
|
151
146
|
|
152
147
|
# Accessor for revisable_number just to make external API more pleasant.
|
153
148
|
def revision_number
|
154
|
-
self[:revisable_number]
|
149
|
+
self[:revisable_number] ||= 0
|
150
|
+
end
|
151
|
+
|
152
|
+
def revision_number=(value)
|
153
|
+
self[:revisable_number] = value
|
155
154
|
end
|
156
155
|
|
157
156
|
def diffs(what)
|
@@ -163,32 +162,11 @@ module FatJam
|
|
163
162
|
end
|
164
163
|
end
|
165
164
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
assoc = self.class.reflect_on_association(#{a.inspect})
|
172
|
-
models = [self.class]
|
173
|
-
|
174
|
-
if [:has_many, :has_one].member? assoc.macro
|
175
|
-
models << (assoc.options[:class_name] ? assoc.options[:class_name] : #{a.inspect}.to_s.singularize.camelize).constantize
|
176
|
-
end
|
177
|
-
|
178
|
-
begin
|
179
|
-
models.each {|m| m.scoped_model_enabled = false}
|
180
|
-
if associated = #{a.to_s}_without_open_scope(*args, &block)
|
181
|
-
associated.reload
|
182
|
-
end
|
183
|
-
ensure
|
184
|
-
models.each {|m| m.scoped_model_enabled = true}
|
185
|
-
end
|
186
|
-
end
|
187
|
-
EOT
|
188
|
-
alias_method_chain a, :open_scope
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
165
|
+
def deleted?
|
166
|
+
self.revisable_deleted_at.present?
|
167
|
+
end
|
168
|
+
|
169
|
+
module ClassMethods
|
192
170
|
# Returns true if the revision should clone the given column.
|
193
171
|
def revisable_should_clone_column?(col) #:nodoc:
|
194
172
|
return false if (REVISABLE_SYSTEM_COLUMNS + REVISABLE_UNREVISABLE_COLUMNS).member? col
|
@@ -198,12 +176,12 @@ module FatJam
|
|
198
176
|
# acts_as_revisable's override for instantiate so we can
|
199
177
|
# return the appropriate type of model based on whether
|
200
178
|
# or not the record is the current record.
|
201
|
-
def
|
179
|
+
def instantiate(record) #:nodoc:
|
202
180
|
is_current = columns_hash["revisable_is_current"].type_cast(
|
203
181
|
record["revisable_is_current"])
|
204
182
|
|
205
183
|
if (is_current && self == self.revisable_class) || (!is_current && self == self.revision_class)
|
206
|
-
return
|
184
|
+
return super(record)
|
207
185
|
end
|
208
186
|
|
209
187
|
object = if is_current
|
@@ -1,19 +1,19 @@
|
|
1
|
-
module
|
1
|
+
module WithoutScope
|
2
2
|
module ActsAsRevisable
|
3
3
|
module Deletable
|
4
4
|
def self.included(base)
|
5
5
|
base.instance_eval do
|
6
|
-
|
6
|
+
define_callbacks :before_revise_on_destroy, :after_revise_on_destroy
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def destroy
|
11
11
|
now = Time.now
|
12
12
|
|
13
13
|
prev = self.revisions.first
|
14
14
|
self.revisable_deleted_at = now
|
15
15
|
self.revisable_is_current = false
|
16
|
-
|
16
|
+
|
17
17
|
self.revisable_current_at = if prev
|
18
18
|
prev.update_attribute(:revisable_revised_at, now)
|
19
19
|
prev.revisable_revised_at + 1.second
|
@@ -22,7 +22,11 @@ module FatJam
|
|
22
22
|
end
|
23
23
|
|
24
24
|
self.revisable_revised_at = self.revisable_deleted_at
|
25
|
-
|
25
|
+
|
26
|
+
return false unless run_callbacks(:before_revise_on_destroy) { |r, o| r == false}
|
27
|
+
returning(self.save(:without_revision => true)) do
|
28
|
+
run_callbacks(:after_revise_on_destroy)
|
29
|
+
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module WithoutScope
|
2
2
|
module ActsAsRevisable
|
3
3
|
|
4
4
|
# This module is mixed into the revision classes.
|
@@ -18,8 +18,6 @@ module FatJam
|
|
18
18
|
base.send(:extend, ClassMethods)
|
19
19
|
|
20
20
|
class << base
|
21
|
-
alias_method_chain :find, :revisable
|
22
|
-
alias_method_chain :with_scope, :revisable
|
23
21
|
attr_accessor :revisable_revision_class, :revisable_columns
|
24
22
|
end
|
25
23
|
|
@@ -30,21 +28,24 @@ module FatJam
|
|
30
28
|
attr_accessor :revisable_new_params, :revisable_revision
|
31
29
|
|
32
30
|
define_callbacks :before_revise, :after_revise, :before_revert, :after_revert, :before_changeset, :after_changeset, :after_branch_created
|
33
|
-
|
34
|
-
alias_method_chain :save, :revisable
|
35
|
-
alias_method_chain :save!, :revisable
|
36
|
-
|
31
|
+
|
37
32
|
before_create :before_revisable_create
|
38
33
|
before_update :before_revisable_update
|
39
34
|
after_update :after_revisable_update
|
40
35
|
after_save :clear_revisable_shared_objects!, :unless => :is_reverting?
|
41
36
|
|
42
|
-
|
37
|
+
default_scope :conditions => {:revisable_is_current => true}
|
43
38
|
|
44
39
|
[:revisions, revisions_association_name.to_sym].each do |assoc|
|
45
40
|
has_many assoc, (revisable_options.revision_association_options || {}).merge({:class_name => revision_class_name, :foreign_key => :revisable_original_id, :order => "#{quoted_table_name}.#{connection.quote_column_name(:revisable_number)} DESC", :dependent => :destroy})
|
46
41
|
end
|
47
42
|
end
|
43
|
+
|
44
|
+
if !Object.const_defined?(base.revision_class_name) && base.revisable_options.generate_revision_class?
|
45
|
+
Object.const_set(base.revision_class_name, Class.new(ActiveRecord::Base)).class_eval do
|
46
|
+
acts_as_revision
|
47
|
+
end
|
48
|
+
end
|
48
49
|
end
|
49
50
|
|
50
51
|
# Finds a specific revision of self.
|
@@ -80,7 +81,7 @@ module FatJam
|
|
80
81
|
revisions.first
|
81
82
|
when Time
|
82
83
|
revisions.find(:first, :conditions => ["? >= ? and ? <= ?", :revisable_revised_at, by, :revisable_current_at, by])
|
83
|
-
when self
|
84
|
+
when self.revisable_number
|
84
85
|
self
|
85
86
|
else
|
86
87
|
revisions.find_by_revisable_number(by)
|
@@ -274,23 +275,23 @@ module FatJam
|
|
274
275
|
end
|
275
276
|
|
276
277
|
# acts_as_revisable's override for ActiveRecord::Base's #save!
|
277
|
-
def
|
278
|
+
def save!(*args) #:nodoc:
|
278
279
|
self.revisable_new_params ||= args.extract_options!
|
279
280
|
self.no_revision! if self.revisable_new_params.delete :without_revision
|
280
|
-
|
281
|
+
super
|
281
282
|
end
|
282
283
|
|
283
284
|
# acts_as_revisable's override for ActiveRecord::Base's #save
|
284
|
-
def
|
285
|
+
def save(*args) #:nodoc:
|
285
286
|
self.revisable_new_params ||= args.extract_options!
|
286
287
|
self.no_revision! if self.revisable_new_params.delete :without_revision
|
287
|
-
|
288
|
+
super(args)
|
288
289
|
end
|
289
290
|
|
290
291
|
# Set some defaults for a newly created +Revisable+ instance.
|
291
292
|
def before_revisable_create #:nodoc:
|
292
293
|
self[:revisable_is_current] = true
|
293
|
-
self
|
294
|
+
self.revision_number ||= 0
|
294
295
|
end
|
295
296
|
|
296
297
|
# Checks whether or not a +Revisable+ should be revised.
|
@@ -347,9 +348,9 @@ module FatJam
|
|
347
348
|
|
348
349
|
rev.revisable_original_id = self.id
|
349
350
|
|
350
|
-
new_revision_number = revisions.maximum(:revisable_number) + 1 rescue self.
|
351
|
-
rev.
|
352
|
-
self.
|
351
|
+
new_revision_number = revisions.maximum(:revisable_number) + 1 rescue self.revision_number
|
352
|
+
rev.revision_number = new_revision_number
|
353
|
+
self.revision_number = new_revision_number + 1
|
353
354
|
|
354
355
|
self.class.column_names.each do |col|
|
355
356
|
next unless self.class.revisable_should_clone_column? col
|
@@ -402,15 +403,15 @@ module FatJam
|
|
402
403
|
# with_scope(:with_revisions => true) do
|
403
404
|
# ...
|
404
405
|
# end
|
405
|
-
def
|
406
|
+
def with_scope(*args, &block) #:nodoc:
|
406
407
|
options = (args.grep(Hash).first || {})[:find]
|
407
408
|
|
408
409
|
if options && options.delete(:with_revisions)
|
409
|
-
|
410
|
-
|
410
|
+
with_exclusive_scope do
|
411
|
+
super(*args, &block)
|
411
412
|
end
|
412
413
|
else
|
413
|
-
|
414
|
+
super(*args, &block)
|
414
415
|
end
|
415
416
|
end
|
416
417
|
|
@@ -420,26 +421,18 @@ module FatJam
|
|
420
421
|
# ==== Example
|
421
422
|
#
|
422
423
|
# find(:all, :with_revisions => true)
|
423
|
-
def
|
424
|
+
def find(*args) #:nodoc:
|
424
425
|
options = args.grep(Hash).first
|
425
426
|
|
426
427
|
if options && options.delete(:with_revisions)
|
427
|
-
|
428
|
-
|
428
|
+
with_exclusive_scope do
|
429
|
+
super(*args)
|
429
430
|
end
|
430
431
|
else
|
431
|
-
|
432
|
+
super(*args)
|
432
433
|
end
|
433
434
|
end
|
434
|
-
|
435
|
-
# Equivalent to:
|
436
|
-
# find(..., :with_revisions => true)
|
437
|
-
def find_with_revisions(*args)
|
438
|
-
args << {} if args.grep(Hash).blank?
|
439
|
-
args.grep(Hash).first.update({:with_revisions => true})
|
440
|
-
find_with_revisable(*args)
|
441
|
-
end
|
442
|
-
|
435
|
+
|
443
436
|
# Returns the +revision_class_name+ as configured in
|
444
437
|
# +acts_as_revisable+.
|
445
438
|
def revision_class_name #:nodoc:
|
@@ -449,7 +442,7 @@ module FatJam
|
|
449
442
|
# Returns the actual +Revision+ class based on the
|
450
443
|
# #revision_class_name.
|
451
444
|
def revision_class #:nodoc:
|
452
|
-
self.revisable_revision_class ||= revision_class_name.constantize
|
445
|
+
self.revisable_revision_class ||= self.revision_class_name.constantize
|
453
446
|
end
|
454
447
|
|
455
448
|
# Returns the revisable_class which in this case is simply +self+.
|
@@ -460,7 +453,7 @@ module FatJam
|
|
460
453
|
# Returns the name of the association acts_as_revisable
|
461
454
|
# creates.
|
462
455
|
def revisions_association_name #:nodoc:
|
463
|
-
revision_class_name.pluralize.
|
456
|
+
revision_class_name.pluralize.underscore
|
464
457
|
end
|
465
458
|
|
466
459
|
# Returns an Array of the columns that are watched for changes.
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module FatJam
|
1
|
+
module WithoutScope
|
4
2
|
module ActsAsRevisable
|
5
3
|
# This module is mixed into the revision classes.
|
6
4
|
#
|
@@ -20,14 +18,14 @@ module FatJam
|
|
20
18
|
|
21
19
|
base.instance_eval do
|
22
20
|
set_table_name(revisable_class.table_name)
|
23
|
-
|
24
|
-
|
25
|
-
CloneAssociations.clone_associations(revisable_class, self)
|
26
|
-
|
21
|
+
default_scope :conditions => {:revisable_is_current => false}
|
22
|
+
|
27
23
|
define_callbacks :before_restore, :after_restore
|
28
24
|
before_create :revision_setup
|
29
25
|
after_create :grab_my_branches
|
30
26
|
|
27
|
+
named_scope :deleted, :conditions => ["? is not null", :revisable_deleted_at]
|
28
|
+
|
31
29
|
[:current_revision, revisable_association_name.to_sym].each do |a|
|
32
30
|
belongs_to a, :class_name => revisable_class_name, :foreign_key => :revisable_original_id
|
33
31
|
end
|
@@ -111,7 +109,7 @@ module FatJam
|
|
111
109
|
# Returns the actual +Revisable+ class based on the
|
112
110
|
# #revisable_class_name.
|
113
111
|
def revisable_class #:nodoc:
|
114
|
-
self.revisable_revisable_class ||= revisable_class_name.constantize
|
112
|
+
self.revisable_revisable_class ||= self.revisable_class_name.constantize
|
115
113
|
end
|
116
114
|
|
117
115
|
# Returns the revision_class which in this case is simply +self+.
|
@@ -126,7 +124,7 @@ module FatJam
|
|
126
124
|
# Returns the name of the association acts_as_revision
|
127
125
|
# creates.
|
128
126
|
def revisable_association_name #:nodoc:
|
129
|
-
revisable_class_name.
|
127
|
+
revisable_class_name.underscore
|
130
128
|
end
|
131
129
|
|
132
130
|
# Returns an array of the associations that should be cloned.
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'acts_as_revisable/options'
|
2
|
+
require 'acts_as_revisable/quoted_columns'
|
2
3
|
require 'acts_as_revisable/acts/common'
|
3
4
|
require 'acts_as_revisable/acts/revision'
|
4
5
|
require 'acts_as_revisable/acts/revisable'
|
5
6
|
require 'acts_as_revisable/acts/deletable'
|
6
7
|
|
7
|
-
module
|
8
|
+
module WithoutScope
|
8
9
|
# define the columns used internall by AAR
|
9
10
|
REVISABLE_SYSTEM_COLUMNS = %w(revisable_original_id revisable_branched_from_id revisable_number revisable_name revisable_type revisable_current_at revisable_revised_at revisable_deleted_at revisable_is_current)
|
10
11
|
|
@@ -44,6 +45,7 @@ module FatJam
|
|
44
45
|
self.revisable_options = Options.new(options, &block)
|
45
46
|
|
46
47
|
self.send(:include, Common)
|
48
|
+
self.send(:include, WithoutScope::QuotedColumnConditions)
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
@@ -1,14 +1,14 @@
|
|
1
|
-
module
|
1
|
+
module WithoutScope #:nodoc:
|
2
2
|
module ActsAsRevisable
|
3
3
|
class GemSpecOptions
|
4
4
|
HASH = {
|
5
|
-
:name => "
|
6
|
-
:version =>
|
5
|
+
:name => "rich-acts_as_revisable",
|
6
|
+
:version => WithoutScope::ActsAsRevisable::VERSION::STRING,
|
7
7
|
:summary => "acts_as_revisable enables revision tracking, querying, reverting and branching of ActiveRecord models. Inspired by acts_as_versioned.",
|
8
|
-
:email => "
|
9
|
-
:homepage => "http://github.com/
|
8
|
+
:email => "rich@withoutscope.com",
|
9
|
+
:homepage => "http://github.com/rich/acts_as_revisable",
|
10
10
|
:has_rdoc => true,
|
11
|
-
:authors => ["Rich Cavanaugh
|
11
|
+
:authors => ["Rich Cavanaugh", "Stephen Caudill"],
|
12
12
|
:files => %w( LICENSE README.rdoc Rakefile ) + Dir["{spec,lib,generators,rails}/**/*"],
|
13
13
|
:rdoc_options => ["--main", "README.rdoc"],
|
14
14
|
:extra_rdoc_files => ["README.rdoc", "LICENSE"]
|
@@ -10,17 +10,13 @@
|
|
10
10
|
# This is consistent with Rails and Ruby where symbols are used to
|
11
11
|
# represent methods. Only a symbol matching a column name will
|
12
12
|
# trigger this beavior.
|
13
|
-
module
|
13
|
+
module WithoutScope::QuotedColumnConditions
|
14
14
|
def self.included(base)
|
15
15
|
base.send(:extend, ClassMethods)
|
16
|
-
|
17
|
-
class << base
|
18
|
-
alias_method_chain :quote_bound_value, :quoted_column
|
19
|
-
end
|
20
16
|
end
|
21
17
|
|
22
18
|
module ClassMethods
|
23
|
-
def
|
19
|
+
def quote_bound_value(value)
|
24
20
|
if value.is_a?(Symbol) && column_names.member?(value.to_s)
|
25
21
|
# code borrowed from sanitize_sql_hash_for_conditions
|
26
22
|
attr = value.to_s
|
@@ -29,7 +25,7 @@ module FatJam::QuotedColumnConditions
|
|
29
25
|
return "#{table_name}.#{connection.quote_column_name(attr)}"
|
30
26
|
end
|
31
27
|
|
32
|
-
|
28
|
+
super(value)
|
33
29
|
end
|
34
30
|
end
|
35
31
|
end
|
data/lib/acts_as_revisable.rb
CHANGED
@@ -5,10 +5,6 @@ require 'activesupport' unless defined? ActiveSupport
|
|
5
5
|
require 'activerecord' unless defined? ActiveRecord
|
6
6
|
|
7
7
|
require 'acts_as_revisable/version.rb'
|
8
|
-
require 'acts_as_revisable/acts/scoped_model'
|
9
|
-
require 'acts_as_revisable/quoted_columns'
|
10
8
|
require 'acts_as_revisable/base'
|
11
9
|
|
12
|
-
ActiveRecord::Base.send(:include,
|
13
|
-
ActiveRecord::Base.send(:include, FatJam::QuotedColumnConditions)
|
14
|
-
ActiveRecord::Base.send(:include, FatJam::ActsAsRevisable)
|
10
|
+
ActiveRecord::Base.send(:include, WithoutScope::ActsAsRevisable)
|
data/spec/associations_spec.rb
CHANGED
data/spec/branch_spec.rb
CHANGED
data/spec/find_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe WithoutScope::ActsAsRevisable do
|
4
4
|
after(:each) do
|
5
5
|
cleanup_db
|
6
6
|
end
|
@@ -18,21 +18,13 @@ describe FatJam::ActsAsRevisable do
|
|
18
18
|
it "should accept the :with_revisions options" do
|
19
19
|
lambda { Project.find(:all, :with_revisions => true) }.should_not raise_error
|
20
20
|
end
|
21
|
-
|
22
|
-
it "should provide find_with_revisions" do
|
23
|
-
lambda { Project.find_with_revisions(:all) }.should_not raise_error
|
24
|
-
end
|
25
|
-
|
21
|
+
|
26
22
|
it "should find current and revisions with the :with_revisions option" do
|
27
23
|
Project.find(:all, :with_revisions => true).size.should == 2
|
28
24
|
end
|
29
|
-
|
30
|
-
it "should find current and revisions with the find_with_revisions method" do
|
31
|
-
Project.find_with_revisions(:all).size.should == 2
|
32
|
-
end
|
33
|
-
|
25
|
+
|
34
26
|
it "should find revisions with conditions" do
|
35
|
-
Project.
|
27
|
+
Project.find(:all, :conditions => {:name => "Rich"}, :with_revisions => true).should == [@project1.find_revision(:previous)]
|
36
28
|
end
|
37
29
|
end
|
38
30
|
end
|
data/spec/general_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe WithoutScope::ActsAsRevisable do
|
4
4
|
after(:each) do
|
5
5
|
cleanup_db
|
6
6
|
end
|
@@ -9,6 +9,12 @@ describe FatJam::ActsAsRevisable do
|
|
9
9
|
@project = Project.create(:name => "Rich", :notes => "this plugin's author")
|
10
10
|
end
|
11
11
|
|
12
|
+
describe "with auto-generated revision class" do
|
13
|
+
it "should have a revision class" do
|
14
|
+
Foo.revision_class.should == FooRevision
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
12
18
|
describe "without revisions" do
|
13
19
|
it "should have a revision_number of zero" do
|
14
20
|
@project.revision_number.should be_zero
|
data/spec/options_spec.rb
CHANGED
@@ -38,10 +38,10 @@ shared_examples_for "common Options usage" do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
describe
|
41
|
+
describe WithoutScope::ActsAsRevisable::Options do
|
42
42
|
describe "with hash options" do
|
43
43
|
before(:each) do
|
44
|
-
@options =
|
44
|
+
@options = WithoutScope::ActsAsRevisable::Options.new :one => 1, :yes => true, :no => false, :arr => [1,2,3]
|
45
45
|
end
|
46
46
|
|
47
47
|
it_should_behave_like "common Options usage"
|
@@ -49,7 +49,7 @@ describe FatJam::ActsAsRevisable::Options do
|
|
49
49
|
|
50
50
|
describe "with block options" do
|
51
51
|
before(:each) do
|
52
|
-
@options =
|
52
|
+
@options = WithoutScope::ActsAsRevisable::Options.new do
|
53
53
|
one 1
|
54
54
|
yes true
|
55
55
|
arr [1,2,3]
|
@@ -61,7 +61,7 @@ describe FatJam::ActsAsRevisable::Options do
|
|
61
61
|
|
62
62
|
describe "with both block and hash options" do
|
63
63
|
before(:each) do
|
64
|
-
@options =
|
64
|
+
@options = WithoutScope::ActsAsRevisable::Options.new(:yes => true, :arr => [1,2,3]) do
|
65
65
|
one 1
|
66
66
|
end
|
67
67
|
end
|
@@ -70,7 +70,7 @@ describe FatJam::ActsAsRevisable::Options do
|
|
70
70
|
|
71
71
|
describe "the block should override the hash" do
|
72
72
|
before(:each) do
|
73
|
-
@options =
|
73
|
+
@options = WithoutScope::ActsAsRevisable::Options.new(:yes => false, :one => 10, :arr => [1,2,3,4,5]) do
|
74
74
|
one 1
|
75
75
|
yes true
|
76
76
|
arr [1,2,3]
|
data/spec/quoted_columns_spec.rb
CHANGED
@@ -14,6 +14,6 @@ describe "the quoted_columns extension" do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should not quote strings any differently" do
|
17
|
-
Project.send(:quote_bound_value, "what").should ==
|
17
|
+
Project.send(:quote_bound_value, "what").should == ActiveRecord::Base.send(:quote_bound_value, "what")
|
18
18
|
end
|
19
19
|
end
|
data/spec/revert_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -36,6 +36,15 @@ def setup_db
|
|
36
36
|
t.datetime :revisable_current_at, :revisable_revised_at, :revisable_deleted_at
|
37
37
|
t.timestamps
|
38
38
|
end
|
39
|
+
|
40
|
+
create_table :foos do |t|
|
41
|
+
t.string :name, :revisable_name, :revisable_type
|
42
|
+
t.text :notes
|
43
|
+
t.boolean :revisable_is_current
|
44
|
+
t.integer :revisable_original_id, :revisable_branched_from_id, :revisable_number, :project_id
|
45
|
+
t.datetime :revisable_current_at, :revisable_revised_at, :revisable_deleted_at
|
46
|
+
t.timestamps
|
47
|
+
end
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
@@ -52,6 +61,7 @@ class Person < ActiveRecord::Base
|
|
52
61
|
|
53
62
|
acts_as_revisable do
|
54
63
|
revision_class_name "OldPerson"
|
64
|
+
on_delete :revise
|
55
65
|
end
|
56
66
|
end
|
57
67
|
|
@@ -76,4 +86,8 @@ class Session < ActiveRecord::Base
|
|
76
86
|
revisable_class_name "Project"
|
77
87
|
clone_associations :all
|
78
88
|
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Foo < ActiveRecord::Base
|
92
|
+
acts_as_revisable :generate_revision_class => true
|
79
93
|
end
|
metadata
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rich-acts_as_revisable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
- Rich Cavanaugh
|
8
|
-
- Stephen Caudill
|
7
|
+
- Rich Cavanaugh
|
8
|
+
- Stephen Caudill
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date:
|
13
|
+
date: 2009-04-01 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
17
17
|
description:
|
18
|
-
email:
|
18
|
+
email: rich@withoutscope.com
|
19
19
|
executables: []
|
20
20
|
|
21
21
|
extensions: []
|
@@ -56,7 +56,7 @@ files:
|
|
56
56
|
- generators/revisable_migration/templates/migration.rb
|
57
57
|
- rails/init.rb
|
58
58
|
has_rdoc: true
|
59
|
-
homepage: http://github.com/
|
59
|
+
homepage: http://github.com/rich/acts_as_revisable/tree/master
|
60
60
|
post_install_message:
|
61
61
|
rdoc_options:
|
62
62
|
- --main
|
@@ -1,75 +0,0 @@
|
|
1
|
-
module FatJam
|
2
|
-
module ActsAsScopedModel
|
3
|
-
def self.included(base)
|
4
|
-
base.send(:extend, ClassMethods)
|
5
|
-
end
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
SCOPED_METHODS = %w(construct_calculation_sql construct_finder_sql update_all delete_all destroy_all).freeze
|
9
|
-
|
10
|
-
def call_method_with_static_scope(meth, args)
|
11
|
-
return send(meth, *args) unless self.scoped_model_enabled?
|
12
|
-
|
13
|
-
with_scope(self.scoped_model_static_scope) do
|
14
|
-
send(meth, *args)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
SCOPED_METHODS.each do |m|
|
19
|
-
module_eval <<-EVAL
|
20
|
-
def #{m}_with_static_scope(*args)
|
21
|
-
call_method_with_static_scope(:#{m}_without_static_scope, args)
|
22
|
-
end
|
23
|
-
EVAL
|
24
|
-
end
|
25
|
-
|
26
|
-
def without_model_scope
|
27
|
-
return unless block_given?
|
28
|
-
|
29
|
-
begin
|
30
|
-
self.scoped_model_enabled = false
|
31
|
-
rv = yield
|
32
|
-
ensure
|
33
|
-
self.scoped_model_enabled = true
|
34
|
-
end
|
35
|
-
|
36
|
-
rv
|
37
|
-
end
|
38
|
-
|
39
|
-
def disable_model_scope!
|
40
|
-
self.scoped_model_disable_count += 1
|
41
|
-
end
|
42
|
-
|
43
|
-
def enable_model_scope!
|
44
|
-
self.scoped_model_disable_count -= 1
|
45
|
-
end
|
46
|
-
|
47
|
-
def scoped_model_enabled?
|
48
|
-
self.scoped_model_disable_count == 0
|
49
|
-
end
|
50
|
-
|
51
|
-
def scoped_model_enabled
|
52
|
-
self.scoped_model_enabled?
|
53
|
-
end
|
54
|
-
|
55
|
-
def scoped_model_enabled=(value)
|
56
|
-
if value == false
|
57
|
-
disable_model_scope!
|
58
|
-
else
|
59
|
-
enable_model_scope!
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def acts_as_scoped_model(*args)
|
64
|
-
class << self
|
65
|
-
attr_accessor :scoped_model_static_scope, :scoped_model_disable_count
|
66
|
-
SCOPED_METHODS.each do |m|
|
67
|
-
alias_method_chain m.to_sym, :static_scope
|
68
|
-
end
|
69
|
-
end
|
70
|
-
self.scoped_model_disable_count = 0
|
71
|
-
self.scoped_model_static_scope = args.extract_options!
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# This module encapsulates the methods used by ActsAsRevisable
|
2
|
-
# for cloning associations from one model to another.
|
3
|
-
module FatJam
|
4
|
-
module ActsAsRevisable
|
5
|
-
module CloneAssociations
|
6
|
-
class << self
|
7
|
-
def clone_associations(from, to)
|
8
|
-
return unless from.descends_from_active_record? && to.descends_from_active_record?
|
9
|
-
|
10
|
-
to.revision_cloned_associations.each do |key|
|
11
|
-
assoc = from.reflect_on_association(key)
|
12
|
-
meth = "clone_#{assoc.macro.to_s}_association"
|
13
|
-
meth = "clone_association" unless respond_to? meth
|
14
|
-
send(meth, assoc, to)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def clone_association(association, to)
|
19
|
-
options = association.options.clone
|
20
|
-
options[:foreign_key] ||= "revisable_original_id"
|
21
|
-
to.send(association.macro, association.name, options)
|
22
|
-
end
|
23
|
-
|
24
|
-
def clone_belongs_to_association(association, to)
|
25
|
-
to.send(association.macro, association.name, association.options.clone)
|
26
|
-
end
|
27
|
-
|
28
|
-
def clone_has_many_association(association, to)
|
29
|
-
options = association.options.clone
|
30
|
-
options[:association_foreign_key] ||= "revisable_original_id"
|
31
|
-
to.send(association.macro, association.name, options)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|