vestal_versions 0.8.3 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +20 -2
  2. data/README.rdoc +110 -8
  3. data/Rakefile +14 -3
  4. data/VERSION +1 -1
  5. data/lib/vestal_versions.rb +93 -143
  6. data/lib/vestal_versions/changes.rb +125 -0
  7. data/lib/vestal_versions/conditions.rb +69 -0
  8. data/lib/vestal_versions/configuration.rb +40 -0
  9. data/lib/vestal_versions/control.rb +175 -0
  10. data/lib/vestal_versions/creation.rb +85 -0
  11. data/lib/vestal_versions/options.rb +42 -0
  12. data/lib/vestal_versions/reload.rb +23 -0
  13. data/lib/vestal_versions/reset.rb +56 -0
  14. data/lib/vestal_versions/reversion.rb +69 -0
  15. data/lib/vestal_versions/tagging.rb +50 -0
  16. data/lib/vestal_versions/users.rb +57 -0
  17. data/lib/vestal_versions/version.rb +32 -0
  18. data/lib/vestal_versions/versioned.rb +30 -0
  19. data/lib/vestal_versions/versions.rb +74 -0
  20. data/rails/init.rb +1 -0
  21. data/rails_generators/vestal_versions/templates/initializer.rb +9 -0
  22. data/{generators/vestal_versions_migration → rails_generators/vestal_versions}/templates/migration.rb +9 -2
  23. data/rails_generators/vestal_versions/vestal_versions_generator.rb +10 -0
  24. data/test/changes_test.rb +154 -13
  25. data/test/conditions_test.rb +137 -0
  26. data/test/configuration_test.rb +39 -0
  27. data/test/control_test.rb +152 -0
  28. data/test/creation_test.rb +70 -30
  29. data/test/options_test.rb +52 -0
  30. data/test/reload_test.rb +19 -0
  31. data/test/reset_test.rb +107 -0
  32. data/test/{revert_test.rb → reversion_test.rb} +8 -22
  33. data/test/schema.rb +4 -1
  34. data/test/tagging_test.rb +38 -0
  35. data/test/test_helper.rb +2 -1
  36. data/test/users_test.rb +25 -0
  37. data/test/version_test.rb +43 -0
  38. data/test/versioned_test.rb +18 -0
  39. data/test/versions_test.rb +172 -0
  40. data/vestal_versions.gemspec +61 -21
  41. metadata +75 -15
  42. data/generators/vestal_versions_migration/vestal_versions_migration_generator.rb +0 -11
  43. data/init.rb +0 -1
  44. data/lib/version.rb +0 -14
  45. data/test/between_test.rb +0 -58
  46. data/test/comparable_test.rb +0 -35
  47. data/test/latest_changes_test.rb +0 -42
data/.gitignore CHANGED
@@ -1,4 +1,22 @@
1
+ ## MAC OS
1
2
  .DS_Store
2
- pkg
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
3
18
  rdoc
4
- test/*.db
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ *.db
@@ -4,9 +4,7 @@ Finally, DRY ActiveRecord versioning!
4
4
 
5
5
  <tt>acts_as_versioned</tt>[http://github.com/technoweenie/acts_as_versioned] by technoweenie[http://github.com/technoweenie] was a great start, but it failed to keep up with ActiveRecord's introduction of dirty objects in version 2.1. Additionally, each versioned model needs its own versions table that duplicates most of the original table's columns. The versions table is then populated with records that often duplicate most of the original record's attributes. All in all, not very DRY.
6
6
 
7
- <tt>simply_versioned</tt>[http://github.com/mmower/simply_versioned] by mmower[http://github.com/mmower] started to move in the right direction by removing a great deal of the duplication of acts_as_versioned. It requires only one versions table and no changes whatsoever to existing models. Its versions table stores all of the model attributes as a YAML hash in a single text column. But we could be DRYer!
8
-
9
- <tt>vestal_versions</tt>[http://github.com/laserlemon/vestal_versions] keeps in the spirit of consolidating to one versions table, polymorphically associated with its parent models. But it goes one step further by storing a serialized hash of _only_ the models' changes. Think modern version control systems. By traversing the record of changes, the models can be reverted to any point in time.
7
+ <tt>vestal_versions</tt>[http://github.com/laserlemon/vestal_versions] requires only one versions table (polymorphically associated with its parent models) and no changes whatsoever to existing tables. But it goes one step DRYer by storing a serialized hash of _only_ the models' changes. Think modern version control systems. By traversing the record of changes, the models can be reverted to any point in time.
10
8
 
11
9
  And that's just what <tt>vestal_versions</tt> does. Not only can a model be reverted to a previous version number but also to a date or time!
12
10
 
@@ -15,7 +13,9 @@ And that's just what <tt>vestal_versions</tt> does. Not only can a model be reve
15
13
  In <tt>environment.rb</tt>:
16
14
 
17
15
  Rails::Initializer.run do |config|
16
+ ...
18
17
  config.gem 'vestal_versions'
18
+ ...
19
19
  end
20
20
 
21
21
  At your application root, run:
@@ -24,7 +24,7 @@ At your application root, run:
24
24
 
25
25
  Next, generate and run the first and last versioning migration you'll ever need:
26
26
 
27
- $ script/generate vestal_versions_migration
27
+ $ script/generate vestal_versions
28
28
  $ rake db:migrate
29
29
 
30
30
  == Example
@@ -43,17 +43,17 @@ To version an ActiveRecord model, simply add <tt>versioned</tt> to your class li
43
43
 
44
44
  It's that easy! Now watch it in action...
45
45
 
46
- >> u = User.create(:first_name => 'Steve', :last_name => 'Richert')
46
+ >> u = User.create(:first_name => "Steve", :last_name => "Richert")
47
47
  => #<User first_name: "Steve", last_name: "Richert">
48
48
  >> u.version
49
49
  => 1
50
- >> u.update_attribute(:first_name, 'Stephen')
50
+ >> u.update_attribute(:first_name, "Stephen")
51
51
  => true
52
52
  >> u.name
53
53
  => "Stephen Richert"
54
54
  >> u.version
55
55
  => 2
56
- >> u.revert_to(:first)
56
+ >> u.revert_to(10.seconds.ago)
57
57
  => 1
58
58
  >> u.name
59
59
  => "Steve Richert"
@@ -63,7 +63,7 @@ It's that easy! Now watch it in action...
63
63
  => true
64
64
  >> u.version
65
65
  => 3
66
- >> u.update_attribute(:last_name, 'Jobs')
66
+ >> u.update_attribute(:last_name, "Jobs")
67
67
  => true
68
68
  >> u.name
69
69
  => "Steve Jobs"
@@ -75,3 +75,105 @@ It's that easy! Now watch it in action...
75
75
  => "Stephen Richert"
76
76
  >> u.version
77
77
  => 5
78
+
79
+ == Upgrading to 1.0
80
+
81
+ For the most part, version 1.0 of <tt>vestal_versions</tt> is backwards compatible, with just a few notable changes:
82
+
83
+ * The versions table has been beefed up. You'll need to add the following columns (and indexes, if you feel so inclined):
84
+
85
+ change_table :versions do |t|
86
+ t.belongs_to :user, :polymorphic => true
87
+ t.string :user_name
88
+ t.string :tag
89
+ end
90
+
91
+ change_table :versions do |t|
92
+ t.index [:user_id, :user_type]
93
+ t.index :user_name
94
+ t.index :tag
95
+ end
96
+
97
+ * When a model is created (or updated the first time after being versioned), an initial version record with a number of 1 is no longer created. These aren't used during reversion and so they end up just being dead weight. Feel free to scrap all your versions where <tt>number == 1</tt> after the upgrade if you'd like to free up some room in your database (but you don't have to).
98
+
99
+ * Models that have no version records in the database will return a <tt>@user.version</tt> of 1. In the past, this would have returned <tt>nil</tt> instead.
100
+
101
+ * <tt>Version</tt> has moved to <tt>VestalVersions::Version</tt> to make way for custom version classes.
102
+
103
+ * <tt>Version#version</tt> did not survive the move to <tt>VestalVersions::Version#version</tt>. That alias was dropped (too confusing). Use <tt>VestalVersions::Version#number</tt>.
104
+
105
+ == New to 1.0
106
+
107
+ There are a handful of exciting new additions in version 1.0 of <tt>vestal_versions</tt>. A lot has changed in the code: much better documentation, more modular organization of features, and a more exhaustive test suite. But there are also a number of new features that are available in this release of <tt>vestal_versions</tt>:
108
+
109
+ * The ability to completely skip versioning within a new <tt>skip_version</tt> block:
110
+
111
+ @user.version # => 1
112
+ @user.skip_version do
113
+ @user.update_attribute(:first_name, "Stephen")
114
+ @user.first_name = "Steve"
115
+ @user.save
116
+ @user.update_attributes(:last_name => "Jobs")
117
+ end
118
+ @user.version # => 1
119
+
120
+ Also available, are <tt>merge_version</tt> and <tt>append_version</tt> blocks. The <tt>merge_version</tt> block will compile the possibly multiple versions that would result from the updates inside the block into one summary version. The single resulting version is then tacked onto the version history as usual. The <tt>append_version</tt> block works similarly except that the resulting single version is combined with the most recent version in the history and saved.
121
+
122
+ * Version tagging. Any version can have a tag attached to it (must be unique within the scope of the versioned parent) and that tag can be used for reversion.
123
+
124
+ @user.name # => "Steve Richert"
125
+ @user.update_attribute(:last_name, "Jobs")
126
+ @user.name # => "Steve Jobs"
127
+ @user.tag_version("apple")
128
+ @user.update_attribute(:last_name, "Richert")
129
+ @user.name # => "Steve Richert"
130
+ @user.revert_to("apple")
131
+ @user.name # => "Steve Jobs"
132
+
133
+ So if you're not big on version numbers, you could just tag your versions and avoid the numbers altogether.
134
+
135
+ * Resetting. This is basically a hard revert. The new <tt>reset_to!</tt> instance method behaves just like the <tt>revert_to!</tt> method except that after the reversion, it will also scrap all the versions that came after that target version.
136
+
137
+ @user.name # => "Steve Richert"
138
+ @user.version # => 1
139
+ @user.versions.count # => 0
140
+ @user.update_attribute(:last_name, "Jobs")
141
+ @user.name # => "Steve Jobs"
142
+ @user.version # => 2
143
+ @user.versions.count # => 1
144
+ @user.reset_to!(1)
145
+ @user.name # => "Steve Richert"
146
+ @user.version # => 1
147
+ @user.versions.count # => 0
148
+
149
+ * Storing which user is responsible for a revision. Rather than introduce a lot of controller magic to guess what to store, you can simply update an additional attribute on your versioned model: <tt>updated_by</tt>.
150
+
151
+ @user.update_attributes(:last_name => "Jobs", :updated_by => "Tyler")
152
+ @user.versions.last.user # => "Tyler"
153
+
154
+ Instead of passing a simple string to the <tt>updated_by</tt> setter, you can pass a model instance, such as an ActiveRecord user or administrator. The association will be saved polymorphically alongside the version.
155
+
156
+ @user.update_attributes(:last_name => "Jobs", :updated_by => current_user)
157
+ @user.versions.last.user # => #<User first_name: "Steven", last_name: "Tyler">
158
+
159
+ * Global configuration. The new <tt>vestal_versions</tt> Rails generator also writes an initializer with instructions on how to set application-wide options for the <tt>versioned</tt> method.
160
+
161
+ * Conditional version creation. The <tt>versioned</tt> method now accepts <tt>:if</tt> and <tt>:unless</tt> options. Each expects a symbol representing an instance method or a proc that will be evaluated to determine whether or not to create a new version after an update. An array containing any combination of symbols and procs can also be given.
162
+
163
+ class User < ActiveRecord::Base
164
+ versioned :if => :really_create_a_version?
165
+ end
166
+
167
+ * Custom version classes. By passing a <tt>:class_name</tt> option to the <tt>versioned</tt> method, you can specify your own ActiveRecord version model. <tt>VestalVersions::Version</tt> is the default, but feel free to stray from that. I recommend that your custom model inherit from <tt>VestalVersions::Version</tt>, but that's up to you!
168
+
169
+ * A <tt>versioned?</tt> convenience class method. If your user model is versioned, <tt>User.versioned?</tt> will let you know.
170
+
171
+ == Thanks!
172
+
173
+ Thank you to all those who post {issues and suggestions}[http://github.com/laserlemon/vestal_versions/issues]. And special thanks to:
174
+
175
+ * splattael[http://github.com/splattael], who first bugged (and helped) me to write some tests for this thing
176
+ * snaury[http://github.com/snaury], who helped out early on with the <tt>between</tt> association method, the <tt>:dependent</tt> option and a conflict from using a method called <tt>changes</tt>
177
+ * sthapit[http://github.com/sthapit], who was responsible for the <tt>:only</tt> and <tt>:except</tt> options as well as showing me that I'm a dummy for storing a useless first version
178
+
179
+ To contribute to <tt>vestal_versions</tt>, please fork, hack away in the integration[http://github.com/laserlemon/vestal_versions/tree/integration] branch and send me a pull request. Remember your tests!
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
3
  require 'rake/testtask'
4
+ require 'rcov/rcovtask'
4
5
  require 'rake/rdoctask'
5
6
 
6
7
  begin
@@ -12,15 +13,18 @@ begin
12
13
  g.email = 'steve@laserlemon.com'
13
14
  g.homepage = 'http://github.com/laserlemon/vestal_versions'
14
15
  g.authors = %w(laserlemon)
15
- g.add_development_dependency 'thoughtbot-shoulda'
16
+ g.add_development_dependency 'activerecord'
17
+ g.add_development_dependency 'activesupport'
18
+ g.add_development_dependency 'shoulda'
19
+ g.add_development_dependency 'mocha'
16
20
  g.rubyforge_project = 'laser-lemon'
17
21
  end
22
+ Jeweler::GemcutterTasks.new
18
23
  Jeweler::RubyforgeTasks.new do |r|
19
24
  r.doc_task = 'rdoc'
20
25
  end
21
- Jeweler::GemcutterTasks.new
22
26
  rescue LoadError
23
- puts 'Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com'
27
+ puts 'Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler'
24
28
  end
25
29
 
26
30
  Rake::TestTask.new do |t|
@@ -28,12 +32,19 @@ Rake::TestTask.new do |t|
28
32
  t.pattern = 'test/**/*_test.rb'
29
33
  end
30
34
 
35
+ Rcov::RcovTask.new do |t|
36
+ t.libs = %w(test)
37
+ t.pattern = 'test/**/*_test.rb'
38
+ end
39
+
40
+ task :test => :check_dependencies
31
41
  task :default => :test
32
42
 
33
43
  Rake::RDocTask.new do |r|
34
44
  version = File.exist?('VERSION') ? File.read('VERSION') : nil
35
45
  r.rdoc_dir = 'rdoc'
36
46
  r.title = ['vestal_versions', version].compact.join(' ')
47
+ r.options << '--line-numbers' << '--inline-source'
37
48
  r.rdoc_files.include('README*')
38
49
  r.rdoc_files.include('lib/**/*.rb')
39
50
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.3
1
+ 1.0.0
@@ -1,149 +1,99 @@
1
- require 'version'
2
-
3
- module LaserLemon
4
- module VestalVersions
5
- def self.included(base)
6
- base.extend ClassMethods
7
- end
8
-
9
- module ClassMethods
10
- def versioned(options = {})
11
- class_inheritable_accessor :version_only_columns
12
- self.version_only_columns = Array(options[:only]).map(&:to_s).uniq if options[:only]
13
- class_inheritable_accessor :version_except_columns
14
- self.version_except_columns = Array(options[:except]).map(&:to_s).uniq if options[:except]
15
-
16
- has_many :versions, :as => :versioned, :order => 'versions.number ASC', :dependent => :delete_all do
17
- def between(from, to)
18
- from_number, to_number = number_at(from), number_at(to)
19
- return [] if from_number.nil? || to_number.nil?
20
- condition = (from_number == to_number) ? to_number : Range.new(*[from_number, to_number].sort)
21
- all(
22
- :conditions => {:number => condition},
23
- :order => "versions.number #{(from_number > to_number) ? 'DESC' : 'ASC'}"
24
- )
25
- end
26
-
27
- def at(value)
28
- case value
29
- when Version then value
30
- when Numeric then find_by_number(value.floor)
31
- when Symbol then respond_to?(value) ? send(value) : nil
32
- when Date, Time then last(:conditions => ['versions.created_at <= ?', value.to_time])
33
- end
34
- end
35
-
36
- def number_at(value)
37
- case value
38
- when Version then value.number
39
- when Numeric then value.floor
40
- when Symbol, Date, Time then at(value).try(:number)
41
- end
42
- end
43
- end
44
-
45
- after_create :create_initial_version
46
- after_update :create_initial_version, :if => :needs_initial_version?
47
- after_update :create_version, :if => :needs_version?
48
-
49
- include InstanceMethods
50
- alias_method_chain :reload, :versions
51
- end
1
+ # +vestal_versions+ keeps track of updates to ActiveRecord models, leveraging the introduction of
2
+ # dirty attributes in Rails 2.1. By storing only the updated attributes in a serialized column of a
3
+ # single version model, the history is kept DRY and no additional schema changes are necessary.
4
+ #
5
+ # Author:: Steve Richert
6
+ # Copyright:: Copyright (c) 2009 Steve Richert
7
+ # License:: MIT License (http://www.opensource.org/licenses/mit-license.php)
8
+ #
9
+ # To enable versioning on a model, simply use the +versioned+ method:
10
+ #
11
+ # class User < ActiveRecord::Base
12
+ # versioned
13
+ # end
14
+ #
15
+ # user = User.create(:name => "Steve Richert")
16
+ # user.version # => 1
17
+ # user.update_attribute(:name, "Steve Jobs")
18
+ # user.version # => 2
19
+ # user.revert_to(1)
20
+ # user.name # => "Steve Richert"
21
+ #
22
+ # See the +versioned+ documentation for more details.
23
+
24
+ Dir[File.join(File.dirname(__FILE__), 'vestal_versions', '*.rb')].each{|f| require f }
25
+
26
+ # The base module that gets included in ActiveRecord::Base. See the documentation for
27
+ # VestalVersions::ClassMethods for more useful information.
28
+ module VestalVersions
29
+ def self.included(base) # :nodoc:
30
+ base.class_eval do
31
+ extend ClassMethods
32
+ extend Versioned
52
33
  end
34
+ end
53
35
 
54
- module InstanceMethods
55
- private
56
- def versioned_columns
57
- case
58
- when version_only_columns then self.class.column_names & version_only_columns
59
- when version_except_columns then self.class.column_names - version_except_columns
60
- else self.class.column_names
61
- end - %w(created_at created_on updated_at updated_on)
62
- end
63
-
64
- def needs_initial_version?
65
- versions.empty?
66
- end
67
-
68
- def needs_version?
69
- !(versioned_columns & changed).empty?
70
- end
71
-
72
- def reset_version(new_version = nil)
73
- @last_version = nil if new_version.nil?
74
- @version = new_version
75
- end
76
-
77
- def create_initial_version
78
- versions.create(:changes => nil, :number => 1)
79
- end
80
-
81
- def create_version
82
- versions.create(:changes => changes.slice(*versioned_columns), :number => (last_version + 1))
83
- reset_version
84
- end
85
-
86
- public
87
- def version
88
- @version ||= last_version
89
- end
90
-
91
- def last_version
92
- @last_version ||= versions.maximum(:number)
93
- end
94
-
95
- def reverted?
96
- version != last_version
97
- end
98
-
99
- def reload_with_versions(*args)
100
- reset_version
101
- reload_without_versions(*args)
102
- end
103
-
104
- def changes_between(from, to)
105
- from_number, to_number = versions.number_at(from), versions.number_at(to)
106
- return {} if from_number == to_number
107
- chain = versions.between(from_number, to_number)
108
- return {} if chain.empty?
109
-
110
- backward = chain.first > chain.last
111
- backward ? chain.pop : chain.shift
112
-
113
- chain.inject({}) do |changes, version|
114
- version.changes.each do |attribute, change|
115
- change.reverse! if backward
116
- new_change = [changes.fetch(attribute, change).first, change.last]
117
- changes.update(attribute => new_change)
118
- end
119
- changes
120
- end
121
- end
122
-
123
- def revert_to(value)
124
- to_number = versions.number_at(value)
125
- changes = changes_between(version, to_number)
126
- return version if changes.empty?
127
-
128
- changes.each do |attribute, change|
129
- write_attribute(attribute, change.last)
130
- end
131
-
132
- reset_version(to_number)
133
- end
134
-
135
- def revert_to!(value)
136
- revert_to(value)
137
- reset_version if saved = save
138
- saved
139
- end
140
-
141
- def latest_changes
142
- return {} if version.nil? || version == 1
143
- versions.at(version).changes
144
- end
36
+ module ClassMethods
37
+ # +versioned+ associates an ActiveRecord model with many versions. When the object is updated,
38
+ # a new version containing the changes is created. There are several options available to the
39
+ # +versioned+ method, most of which are passed to the +has_many+ association itself:
40
+ # * <tt>:class_name</tt>: The class name of the version model to use for the association. By
41
+ # default, this is set to "VestalVersions::Version", representing the built-in version class.
42
+ # By specifying this option, you can override the version class, to include custom version
43
+ # behavior. It's recommended that a custom version inherit from VestalVersions::Version.
44
+ # * <tt>:dependent</tt>: Also common to +has_many+ associations, this describes the behavior of
45
+ # version records when the parent object is destroyed. This defaults to :delete_all, which
46
+ # will permanently remove all associated versions *without* triggering any destroy callbacks.
47
+ # Other options are :destroy which removes the associated versions *with* callbacks, or
48
+ # :nullify which leaves the version records in the database, but dissociates them from the
49
+ # parent object by setting the foreign key columns to +nil+ values.
50
+ # * <tt>:except</tt>: An update will trigger version creation as long as at least one column
51
+ # outside those specified here was updated. Also, upon version creation, the columns
52
+ # specified here will be excluded from the change history. This is useful when dealing with
53
+ # unimportant, constantly changing, or sensitive information. This option accepts a symbol,
54
+ # string or an array of either, representing column names to exclude. It is completely
55
+ # optional and defaults to +nil+, allowing all columns to be versioned. This option is also
56
+ # ignored if the +only+ option is used.
57
+ # * <tt>:extend</tt>: This option allows you to extend the +has_many+ association proxy with a
58
+ # module or an array of modules. Any methods defined in those modules become available on the
59
+ # +versions+ association. The VestalVersions::Versions module is essential to the
60
+ # functionality of +vestal_versions+ and so is prepended to any additional modules that you
61
+ # might specify here.
62
+ # * <tt>:if</tt>: Accepts a symbol, a proc or an array of either to be evaluated when the parent
63
+ # object is updated to determine whether a new version should be created. +to_proc+ is called
64
+ # on any symbols given and the resulting procs are called, passing in the object itself. If
65
+ # an array is given, all must be evaluate to +true+ in order for a version to be created.
66
+ # * <tt>:only</tt>: An update will trigger version creation as long as at least one updated
67
+ # column falls within those specified here. Also, upon version creation, only the columns
68
+ # specified here will be included in the change history. This option accepts a symbol, string
69
+ # or an array of either, representing column names to include. It is completely optional and
70
+ # defaults to +nil+, allowing all columns to be versioned. This option takes precedence over
71
+ # the +except+ option if both are specified.
72
+ # * <tt>:unless</tt>: Accepts a symbol, a proc or an array of either to be evaluated when the
73
+ # parent object is updated to determine whether version creation should be skipped. +to_proc+
74
+ # is called on any symbols given and the resulting procs are called, passing in the object
75
+ # itself. If an array is given and any element evaluates as +true+, the version creation will
76
+ # be skipped.
77
+ def versioned(options = {}, &block)
78
+ return if versioned?
79
+
80
+ include Options
81
+ include Changes
82
+ include Creation
83
+ include Users
84
+ include Reversion
85
+ include Reset
86
+ include Conditions
87
+ include Control
88
+ include Tagging
89
+ include Reload
90
+
91
+ prepare_versioned_options(options)
92
+ has_many :versions, options, &block
145
93
  end
146
94
  end
95
+
96
+ extend Configuration
147
97
  end
148
98
 
149
- ActiveRecord::Base.send(:include, LaserLemon::VestalVersions)
99
+ ActiveRecord::Base.send(:include, VestalVersions)