Commit 4001b435cc8e42f14a80853eae274b6472b95a21

Authored by Rodrigo Souto
1 parent 8042c0ea

rails3: update acts_as_versioned to a rails3 compatible version

Showing 28 changed files with 513 additions and 1240 deletions   Show diff stats
vendor/plugins/acts_as_versioned/.document 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +README.rdoc
  2 +lib/**/*.rb
  3 +bin/*
  4 +features/**/*.feature
  5 +LICENSE
vendor/plugins/acts_as_versioned/.rvmrc 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +rvm --create use 1.9.2@acts_as_versioned
vendor/plugins/acts_as_versioned/CHANGELOG
@@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
1 -*GIT* (version numbers are overrated)  
2 -  
3 -* (16 Jun 2008) Backwards Compatibility is overrated (big updates for rails 2.1)  
4 -  
5 - * Use ActiveRecord 2.1's dirty attribute checking instead [Asa Calow]  
6 - * Remove last traces of #non_versioned_fields  
7 - * Remove AR::Base.find_version and AR::Base.find_versions, rely on AR association proxies and named_scope  
8 - * Remove #versions_count, rely on AR association counter caching.  
9 - * Remove #versioned_attributes, basically the same as AR::Base.versioned_columns  
10 -  
11 -* (5 Oct 2006) Allow customization of #versions association options [Dan Peterson]  
12 -  
13 -*0.5.1*  
14 -  
15 -* (8 Aug 2006) Versioned models now belong to the unversioned model. @article_version.article.class => Article [Aslak Hellesoy]  
16 -  
17 -*0.5* # do versions even matter for plugins?  
18 -  
19 -* (21 Apr 2006) Added without_locking and without_revision methods.  
20 -  
21 - Foo.without_revision do  
22 - @foo.update_attributes ...  
23 - end  
24 -  
25 -*0.4*  
26 -  
27 -* (28 March 2006) Rename non_versioned_fields to non_versioned_columns (old one is kept for compatibility).  
28 -* (28 March 2006) Made explicit documentation note that string column names are required for non_versioned_columns.  
29 -  
30 -*0.3.1*  
31 -  
32 -* (7 Jan 2006) explicitly set :foreign_key option for the versioned model's belongs_to assocation for STI [Caged]  
33 -* (7 Jan 2006) added tests to prove has_many :through joins work  
34 -  
35 -*0.3*  
36 -  
37 -* (2 Jan 2006) added ability to share a mixin with versioned class  
38 -* (2 Jan 2006) changed the dynamic version model to MyModel::Version  
39 -  
40 -*0.2.4*  
41 -  
42 -* (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig]  
43 -  
44 -*0.2.3*  
45 -  
46 -* (12 Nov 2005) fixed bug with old behavior of #blank? [Michael Schuerig]  
47 -* (12 Nov 2005) updated tests to use ActiveRecord Schema  
48 -  
49 -*0.2.2*  
50 -  
51 -* (3 Nov 2005) added documentation note to #acts_as_versioned [Martin Jul]  
52 -  
53 -*0.2.1*  
54 -  
55 -* (6 Oct 2005) renamed dirty? to changed? to keep it uniform. it was aliased to keep it backwards compatible.  
56 -  
57 -*0.2*  
58 -  
59 -* (6 Oct 2005) added find_versions and find_version class methods.  
60 -  
61 -* (6 Oct 2005) removed transaction from create_versioned_table().  
62 - this way you can specify your own transaction around a group of operations.  
63 -  
64 -* (30 Sep 2005) fixed bug where find_versions() would order by 'version' twice. (found by Joe Clark)  
65 -  
66 -* (26 Sep 2005) added :sequence_name option to acts_as_versioned to set the sequence name on the versioned model  
67 -  
68 -*0.1.3* (18 Sep 2005)  
69 -  
70 -* First RubyForge release  
71 -  
72 -*0.1.2*  
73 -  
74 -* check if module is already included when acts_as_versioned is called  
75 -  
76 -*0.1.1*  
77 -  
78 -* Adding tests and rdocs  
79 -  
80 -*0.1*  
81 -  
82 -* Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974  
83 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/Gemfile 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +source 'http://rubygems.org'
  2 +
  3 +group :development do
  4 + gem 'rails', '~> 3.1.0'
  5 + gem 'sqlite3'
  6 + gem 'echoe'
  7 +end
vendor/plugins/acts_as_versioned/Gemfile.lock 0 → 100644
@@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
  1 +GEM
  2 + remote: http://rubygems.org/
  3 + specs:
  4 + actionmailer (3.1.4)
  5 + actionpack (= 3.1.4)
  6 + mail (~> 2.3.0)
  7 + actionpack (3.1.4)
  8 + activemodel (= 3.1.4)
  9 + activesupport (= 3.1.4)
  10 + builder (~> 3.0.0)
  11 + erubis (~> 2.7.0)
  12 + i18n (~> 0.6)
  13 + rack (~> 1.3.6)
  14 + rack-cache (~> 1.1)
  15 + rack-mount (~> 0.8.2)
  16 + rack-test (~> 0.6.1)
  17 + sprockets (~> 2.0.3)
  18 + activemodel (3.1.4)
  19 + activesupport (= 3.1.4)
  20 + builder (~> 3.0.0)
  21 + i18n (~> 0.6)
  22 + activerecord (3.1.4)
  23 + activemodel (= 3.1.4)
  24 + activesupport (= 3.1.4)
  25 + arel (~> 2.2.3)
  26 + tzinfo (~> 0.3.29)
  27 + activeresource (3.1.4)
  28 + activemodel (= 3.1.4)
  29 + activesupport (= 3.1.4)
  30 + activesupport (3.1.4)
  31 + multi_json (~> 1.0)
  32 + allison (2.0.3)
  33 + arel (2.2.3)
  34 + builder (3.0.0)
  35 + echoe (4.6.3)
  36 + allison (>= 2.0.3)
  37 + gemcutter (>= 0.7.0)
  38 + rake (>= 0.9.2)
  39 + rdoc (>= 3.6.1)
  40 + rubyforge (>= 2.0.4)
  41 + erubis (2.7.0)
  42 + gemcutter (0.7.1)
  43 + hike (1.2.1)
  44 + i18n (0.6.0)
  45 + json (1.6.6)
  46 + json_pure (1.7.7)
  47 + mail (2.3.3)
  48 + i18n (>= 0.4.0)
  49 + mime-types (~> 1.16)
  50 + treetop (~> 1.4.8)
  51 + mime-types (1.18)
  52 + multi_json (1.2.0)
  53 + polyglot (0.3.3)
  54 + rack (1.3.6)
  55 + rack-cache (1.2)
  56 + rack (>= 0.4)
  57 + rack-mount (0.8.3)
  58 + rack (>= 1.0.0)
  59 + rack-ssl (1.3.2)
  60 + rack
  61 + rack-test (0.6.1)
  62 + rack (>= 1.0)
  63 + rails (3.1.4)
  64 + actionmailer (= 3.1.4)
  65 + actionpack (= 3.1.4)
  66 + activerecord (= 3.1.4)
  67 + activeresource (= 3.1.4)
  68 + activesupport (= 3.1.4)
  69 + bundler (~> 1.0)
  70 + railties (= 3.1.4)
  71 + railties (3.1.4)
  72 + actionpack (= 3.1.4)
  73 + activesupport (= 3.1.4)
  74 + rack-ssl (~> 1.3.2)
  75 + rake (>= 0.8.7)
  76 + rdoc (~> 3.4)
  77 + thor (~> 0.14.6)
  78 + rake (0.9.2.2)
  79 + rdoc (3.12)
  80 + json (~> 1.4)
  81 + rubyforge (2.0.4)
  82 + json_pure (>= 1.1.7)
  83 + sprockets (2.0.3)
  84 + hike (~> 1.2)
  85 + rack (~> 1.0)
  86 + tilt (~> 1.1, != 1.3.0)
  87 + sqlite3 (1.3.5)
  88 + thor (0.14.6)
  89 + tilt (1.3.3)
  90 + treetop (1.4.10)
  91 + polyglot
  92 + polyglot (>= 0.3.1)
  93 + tzinfo (0.3.33)
  94 +
  95 +PLATFORMS
  96 + ruby
  97 +
  98 +DEPENDENCIES
  99 + echoe
  100 + rails (~> 3.1.0)
  101 + sqlite3
vendor/plugins/acts_as_versioned/Manifest 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +Gemfile
  2 +Gemfile.lock
  3 +MIT-LICENSE
  4 +Manifest
  5 +README.md
  6 +RUNNING_UNIT_TESTS
  7 +Rakefile
  8 +acts_as_versioned.gemspec
  9 +acts_as_versioned_plugin.sqlite3.db
  10 +init.rb
  11 +lib/acts_as_versioned.rb
vendor/plugins/acts_as_versioned/README
@@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
1 -= acts_as_versioned  
2 -  
3 -This library adds simple versioning to an ActiveRecord module. ActiveRecord is required.  
4 -  
5 -== Resources  
6 -  
7 -Install  
8 -  
9 -* gem install acts_as_versioned  
10 -  
11 -Rubyforge project  
12 -  
13 -* http://rubyforge.org/projects/ar-versioned  
14 -  
15 -RDocs  
16 -  
17 -* http://ar-versioned.rubyforge.org  
18 -  
19 -Subversion  
20 -  
21 -* http://techno-weenie.net/svn/projects/acts_as_versioned  
22 -  
23 -Collaboa  
24 -  
25 -* http://collaboa.techno-weenie.net/repository/browse/acts_as_versioned  
26 -  
27 -Special thanks to Dreamer on ##rubyonrails for help in early testing. His ServerSideWiki (http://serversidewiki.com)  
28 -was the first project to use acts_as_versioned <em>in the wild</em>.  
29 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/README.md 0 → 100644
@@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
  1 +## About ##
  2 +=====
  3 +
  4 +acts_as_versioned is a gem for Rails 3.1 & 3.2 to enable easy versioning of models. As a versioned model is updated revisions are kept in a seperate table, providing a record of what changed.
  5 +
  6 +## Getting Started ##
  7 +=====
  8 +
  9 +In your Gemfile simply include:
  10 +
  11 + gem 'acts_as_versioned', :git => 'https://github.com/jwhitehorn/acts_as_versioned.git'
  12 +
  13 +The next time you run `bundle install` you'll be all set to start using acts_as_versioned.
  14 +
  15 +## Usage ##
  16 +=====
  17 +
  18 +#### Versioning a Model ####
  19 +By default acts_as_versioned is unobtrusive. You will need to explicitly state which models to version. To do so, add the line `acts_as_versioned` to your model, like so:
  20 +
  21 + class MyModel < ActiveRecord::Base
  22 + acts_as_versioned
  23 + #...
  24 + end
  25 +
  26 +Next we need to create a migration to setup our versioning tables:
  27 +
  28 + bundle exec rails generate migration AddVersioningToMyModel
  29 +
  30 +Once that is completed, edit the generated migration. acts_as_versioned patches your model to add a `create_versioned_table` and `drop_versioned_table` method. A migration for `MyModel` (assuming MyModel already existed) might look like:
  31 +
  32 + class AddVersioningToMyModel < ActiveRecord::Migration
  33 + def self.up
  34 + MyModel.create_versioned_table
  35 + end
  36 +
  37 + def self.down
  38 + MyModel.drop_versioned_table
  39 + end
  40 + end
  41 +
  42 +Execute your migration:
  43 +
  44 + bundle exec rake db:migrate
  45 +
  46 +And you're finished! Without any addition work, `MyModel` is being versioned.
  47 +
  48 +#### Excluding attributes from versioning ####
  49 +
  50 +Sometime you want to exclude an attribute of a model from being versioned. That can be accomplished with the `:except` paramter to `acts_as_versioned`:
  51 +
  52 + class MyMode < ActiveRecord::Base
  53 + acts_as_versioned :except => :some_attr_i_dont_want_versioned
  54 +
  55 + end
  56 +
  57 +
  58 +#### Revisions ####
  59 +
  60 +Recording a history of changes to a model is only useful if you can do something with that data. With acts_as_versioned there are several ways you can interact with a model's revisions.
  61 +
  62 +##### Version Number #####
  63 +To determine what the current version number for a model is:
  64 +
  65 + model.version
  66 +
  67 +The `version` attribute is available for both the actual model, and also any revisions of a model. Thusly, the following is valid:
  68 +
  69 + model.versions.last.version
  70 +
  71 +##### Revisions List #####
  72 +As alluded to above, you can get an array of revisions of a model via the `versions` attribute:
  73 +
  74 + model.versions
  75 +
  76 +The returned objects are of a type `MyModel::Version` where `MyModel` is the model you are working with. These objects have identical fields to `MyModel`. So, if `MyModel` had a `name` attribute, you could also say:
  77 +
  78 + model.versions.last.name
  79 +
  80 +##### Reverting to a Revision #####
  81 +To revert a model to an older revision, simply call `revert_to` with the version number you desire to rever to:
  82 +
  83 + model.revert_to(version_number)
  84 +
  85 +##### Saving Without Revisions #####
  86 +Occasionally you might need to save a model without necessary creating revisions. To do so, use the `save_without_revision` method:
  87 +
  88 + model.save_without_revision
  89 +
  90 +
  91 +#### Migrations ####
  92 +Adding a field to your model does not automatically add it to the versioning table. So, when you add new fields, be sure to add them to both:
  93 +
  94 + class AddNewFieldToMyModel < ActiveRecord::Migration
  95 + def change
  96 + add_column :my_models, :new_field_, :string
  97 + add_column :my_model_versions, :new_field_, :string
  98 + end
  99 + end
  100 +
  101 +#### Version Class ####
  102 +As has been stated, the versioned data is stored seperately from the main class. This also implies that `model.versions` returns an area of object of a class _other_ than `MyModel` (where `model` is an instance of `MyModel`, keeping with our working example). The instances returned are actually of type `MyModel::Version`. With this, comes the fact that any methods, associations, etc. defined on `MyModel` are not present on `MyModel::Version`.
  103 +
  104 +While this sounds obvious, it can some times be unexpected. Especially when acts_as_versioned make it so easy to grab historical records from a live record. A common scenario where this can come up is associations.
  105 +
  106 +Say `MyModel` belongs to `TheMan`. Also, assume that you want to find out where (in the past) a particular instance of `MyModel` was updated in regards to it's association to `TheMan`. You could write that as:
  107 +
  108 + model.versions.keep_if { |m| m.the_man != current_man }.last
  109 +
  110 +However, this will not work. This is because `MyModel::Version` does _not_ belong to `TheMan`. You could compare ids here, or you could patch `MyModel::Version` to belong to `TheMan` like:
  111 +
  112 + class MyModel
  113 + acts_as_versioned
  114 + belongs_to :the_men
  115 + #some stuff
  116 +
  117 + class Version
  118 + belongs_to :the_men
  119 + end
  120 + end
0 \ No newline at end of file 121 \ No newline at end of file
vendor/plugins/acts_as_versioned/Rakefile
1 -require 'rubygems'  
2 -  
3 -require 'rake/rdoctask'  
4 -require 'rake/packagetask'  
5 -require 'rake/gempackagetask'  
6 -require 'rake/testtask'  
7 -require 'rake/contrib/rubyforgepublisher'  
8 -  
9 -PKG_NAME = 'acts_as_versioned'  
10 -PKG_VERSION = '0.3.1'  
11 -PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"  
12 -PROD_HOST = "technoweenie@bidwell.textdrive.com"  
13 -RUBY_FORGE_PROJECT = 'ar-versioned'  
14 -RUBY_FORGE_USER = 'technoweenie'  
15 -  
16 -desc 'Default: run unit tests.'  
17 -task :default => :test  
18 -  
19 -desc 'Test the calculations plugin.'  
20 -Rake::TestTask.new(:test) do |t|  
21 - t.libs << 'lib'  
22 - t.pattern = 'test/**/*_test.rb'  
23 - t.verbose = true  
24 -end  
25 -  
26 -desc 'Generate documentation for the calculations plugin.'  
27 -Rake::RDocTask.new(:rdoc) do |rdoc|  
28 - rdoc.rdoc_dir = 'rdoc'  
29 - rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models"  
30 - rdoc.options << '--line-numbers --inline-source'  
31 - rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS')  
32 - rdoc.rdoc_files.include('lib/**/*.rb')  
33 -end  
34 -  
35 -spec = Gem::Specification.new do |s|  
36 - s.name = PKG_NAME  
37 - s.version = PKG_VERSION  
38 - s.platform = Gem::Platform::RUBY  
39 - s.summary = "Simple versioning with active record models"  
40 - s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS)  
41 - s.files.delete "acts_as_versioned_plugin.sqlite.db"  
42 - s.files.delete "acts_as_versioned_plugin.sqlite3.db"  
43 - s.files.delete "test/debug.log"  
44 - s.require_path = 'lib'  
45 - s.autorequire = 'acts_as_versioned'  
46 - s.has_rdoc = true  
47 - s.test_files = Dir['test/**/*_test.rb']  
48 - s.add_dependency 'activerecord', '>= 1.10.1'  
49 - s.add_dependency 'activesupport', '>= 1.1.1'  
50 - s.author = "Rick Olson"  
51 - s.email = "technoweenie@gmail.com"  
52 - s.homepage = "http://techno-weenie.net"  
53 -end  
54 -  
55 -Rake::GemPackageTask.new(spec) do |pkg|  
56 - pkg.need_tar = true  
57 -end  
58 -  
59 -desc "Publish the API documentation"  
60 -task :pdoc => [:rdoc] do  
61 - Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload  
62 -end  
63 -  
64 -desc 'Publish the gem and API docs'  
65 -task :publish => [:pdoc, :rubyforge_upload]  
66 -  
67 -desc "Publish the release files to RubyForge."  
68 -task :rubyforge_upload => :package do  
69 - files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" }  
70 -  
71 - if RUBY_FORGE_PROJECT then  
72 - require 'net/http'  
73 - require 'open-uri'  
74 -  
75 - project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/"  
76 - project_data = open(project_uri) { |data| data.read }  
77 - group_id = project_data[/[?&]group_id=(\d+)/, 1]  
78 - raise "Couldn't get group id" unless group_id  
79 -  
80 - # This echos password to shell which is a bit sucky  
81 - if ENV["RUBY_FORGE_PASSWORD"]  
82 - password = ENV["RUBY_FORGE_PASSWORD"]  
83 - else  
84 - print "#{RUBY_FORGE_USER}@rubyforge.org's password: "  
85 - password = STDIN.gets.chomp  
86 - end  
87 -  
88 - login_response = Net::HTTP.start("rubyforge.org", 80) do |http|  
89 - data = [  
90 - "login=1",  
91 - "form_loginname=#{RUBY_FORGE_USER}",  
92 - "form_pw=#{password}"  
93 - ].join("&")  
94 - http.post("/account/login.php", data)  
95 - end  
96 -  
97 - cookie = login_response["set-cookie"]  
98 - raise "Login failed" unless cookie  
99 - headers = { "Cookie" => cookie }  
100 -  
101 - release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}"  
102 - release_data = open(release_uri, headers) { |data| data.read }  
103 - package_id = release_data[/[?&]package_id=(\d+)/, 1]  
104 - raise "Couldn't get package id" unless package_id  
105 -  
106 - first_file = true  
107 - release_id = ""  
108 -  
109 - files.each do |filename|  
110 - basename = File.basename(filename)  
111 - file_ext = File.extname(filename)  
112 - file_data = File.open(filename, "rb") { |file| file.read }  
113 -  
114 - puts "Releasing #{basename}..."  
115 -  
116 - release_response = Net::HTTP.start("rubyforge.org", 80) do |http|  
117 - release_date = Time.now.strftime("%Y-%m-%d %H:%M")  
118 - type_map = {  
119 - ".zip" => "3000",  
120 - ".tgz" => "3110",  
121 - ".gz" => "3110",  
122 - ".gem" => "1400"  
123 - }; type_map.default = "9999"  
124 - type = type_map[file_ext]  
125 - boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor"  
126 -  
127 - query_hash = if first_file then  
128 - {  
129 - "group_id" => group_id,  
130 - "package_id" => package_id,  
131 - "release_name" => PKG_FILE_NAME,  
132 - "release_date" => release_date,  
133 - "type_id" => type,  
134 - "processor_id" => "8000", # Any  
135 - "release_notes" => "",  
136 - "release_changes" => "",  
137 - "preformatted" => "1",  
138 - "submit" => "1"  
139 - }  
140 - else  
141 - {  
142 - "group_id" => group_id,  
143 - "release_id" => release_id,  
144 - "package_id" => package_id,  
145 - "step2" => "1",  
146 - "type_id" => type,  
147 - "processor_id" => "8000", # Any  
148 - "submit" => "Add This File"  
149 - }  
150 - end  
151 -  
152 - query = "?" + query_hash.map do |(name, value)|  
153 - [name, URI.encode(value)].join("=")  
154 - end.join("&")  
155 -  
156 - data = [  
157 - "--" + boundary,  
158 - "Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"",  
159 - "Content-Type: application/octet-stream",  
160 - "Content-Transfer-Encoding: binary",  
161 - "", file_data, ""  
162 - ].join("\x0D\x0A")  
163 -  
164 - release_headers = headers.merge(  
165 - "Content-Type" => "multipart/form-data; boundary=#{boundary}"  
166 - )  
167 -  
168 - target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php"  
169 - http.post(target + query, data, release_headers)  
170 - end  
171 -  
172 - if first_file then  
173 - release_id = release_response.body[/release_id=(\d+)/, 1]  
174 - raise("Couldn't get release id") unless release_id  
175 - end  
176 -  
177 - first_file = false  
178 - end  
179 - end  
180 -end  
181 \ No newline at end of file 1 \ No newline at end of file
  2 +require 'rubygems'
  3 +require 'rake'
  4 +require 'echoe'
  5 +
  6 +Echoe.new('acts_as_versioned', '3.2.1') do |p|
  7 + p.description = "Active Record model versioning"
  8 + p.url = "http://github.com/jwhitehorn/acts_as_versioned"
  9 + p.author = "Jason Whitehorn"
  10 + p.email = "jason.whitehorn@gmail.com"
  11 + p.dependencies = ['activerecord']
  12 +end
  13 +
  14 +Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
182 \ No newline at end of file 15 \ No newline at end of file
vendor/plugins/acts_as_versioned/VERSION.yml
@@ -1,4 +0,0 @@ @@ -1,4 +0,0 @@
1 ----  
2 -:patch: 2  
3 -:major: 0  
4 -:minor: 5  
vendor/plugins/acts_as_versioned/acts_as_versioned.gemspec
1 # -*- encoding: utf-8 -*- 1 # -*- encoding: utf-8 -*-
2 2
3 Gem::Specification.new do |s| 3 Gem::Specification.new do |s|
4 - s.name = %q{acts_as_versioned}  
5 - s.version = "0.5.2" 4 + s.name = "acts_as_versioned"
  5 + s.version = "3.2.1"
6 6
7 - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=  
8 - s.authors = ["technoweenie"]  
9 - s.date = %q{2009-01-20}  
10 - s.description = %q{TODO}  
11 - s.email = %q{technoweenie@bidwell.textdrive.com}  
12 - s.files = ["VERSION.yml", "lib/acts_as_versioned.rb", "test/abstract_unit.rb", "test/database.yml", "test/fixtures", "test/fixtures/authors.yml", "test/fixtures/landmark.rb", "test/fixtures/landmark_versions.yml", "test/fixtures/landmarks.yml", "test/fixtures/locked_pages.yml", "test/fixtures/locked_pages_revisions.yml", "test/fixtures/migrations", "test/fixtures/migrations/1_add_versioned_tables.rb", "test/fixtures/page.rb", "test/fixtures/page_versions.yml", "test/fixtures/pages.yml", "test/fixtures/widget.rb", "test/migration_test.rb", "test/schema.rb", "test/versioned_test.rb"]  
13 - s.has_rdoc = true  
14 - s.homepage = %q{http://github.com/technoweenie/acts_as_versioned}  
15 - s.rdoc_options = ["--inline-source", "--charset=UTF-8"] 7 + s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
  8 + s.authors = ["Jason Whitehorn"]
  9 + s.date = "2013-05-03"
  10 + s.description = "Active Record model versioning"
  11 + s.email = "jason.whitehorn@gmail.com"
  12 + s.extra_rdoc_files = ["README.md", "lib/acts_as_versioned.rb"]
  13 + s.files = ["Gemfile", "Gemfile.lock", "MIT-LICENSE", "Manifest", "README.md", "RUNNING_UNIT_TESTS", "Rakefile", "acts_as_versioned.gemspec", "acts_as_versioned_plugin.sqlite3.db", "init.rb", "lib/acts_as_versioned.rb"]
  14 + s.homepage = "http://github.com/jwhitehorn/acts_as_versioned"
  15 + s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Acts_as_versioned", "--main", "README.md"]
16 s.require_paths = ["lib"] 16 s.require_paths = ["lib"]
17 - s.rubygems_version = %q{1.3.1}  
18 - s.summary = %q{TODO} 17 + s.rubyforge_project = "acts_as_versioned"
  18 + s.rubygems_version = "1.8.25"
  19 + s.summary = "Active Record model versioning"
19 20
20 if s.respond_to? :specification_version then 21 if s.respond_to? :specification_version then
21 - current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION  
22 - s.specification_version = 2 22 + s.specification_version = 3
23 23
24 - if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then 24 + if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
  25 + s.add_runtime_dependency(%q<activerecord>, [">= 0"])
25 else 26 else
  27 + s.add_dependency(%q<activerecord>, [">= 0"])
26 end 28 end
27 else 29 else
  30 + s.add_dependency(%q<activerecord>, [">= 0"])
28 end 31 end
29 end 32 end
vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21 +require 'active_support/concern'
21 22
22 module ActiveRecord #:nodoc: 23 module ActiveRecord #:nodoc:
23 module Acts #:nodoc: 24 module Acts #:nodoc:
@@ -66,203 +67,206 @@ module ActiveRecord #:nodoc: @@ -66,203 +67,206 @@ module ActiveRecord #:nodoc:
66 # 67 #
67 # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options 68 # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options
68 module Versioned 69 module Versioned
  70 + VERSION = "0.6.0"
69 CALLBACKS = [:set_new_version, :save_version, :save_version?] 71 CALLBACKS = [:set_new_version, :save_version, :save_version?]
70 - def self.included(base) # :nodoc:  
71 - base.extend ClassMethods  
72 - end  
73 72
74 - module ClassMethods  
75 - # == Configuration options  
76 - #  
77 - # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)  
78 - # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)  
79 - # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example)  
80 - # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type)  
81 - # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)  
82 - # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model.  
83 - # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited  
84 - # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved.  
85 - # For finer control, pass either a Proc or modify Model#version_condition_met?  
86 - #  
87 - # acts_as_versioned :if => Proc.new { |auction| !auction.expired? }  
88 - #  
89 - # or...  
90 - #  
91 - # class Auction  
92 - # def version_condition_met? # totally bypasses the <tt>:if</tt> option  
93 - # !expired?  
94 - # end  
95 - # end  
96 - #  
97 - # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes  
98 - # either a symbol or array of symbols.  
99 - #  
100 - # * <tt>extend</tt> - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block  
101 - # to create an anonymous mixin:  
102 - #  
103 - # class Auction  
104 - # acts_as_versioned do  
105 - # def started?  
106 - # !started_at.nil?  
107 - # end  
108 - # end  
109 - # end  
110 - #  
111 - # or...  
112 - #  
113 - # module AuctionExtension  
114 - # def started?  
115 - # !started_at.nil?  
116 - # end  
117 - # end  
118 - # class Auction  
119 - # acts_as_versioned :extend => AuctionExtension  
120 - # end  
121 - #  
122 - # Example code:  
123 - #  
124 - # @auction = Auction.find(1)  
125 - # @auction.started?  
126 - # @auction.versions.first.started?  
127 - #  
128 - # == Database Schema  
129 - #  
130 - # The model that you're versioning needs to have a 'version' attribute. The model is versioned  
131 - # into a table called #{model}_versions where the model name is singlular. The _versions table should  
132 - # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.  
133 - #  
134 - # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance,  
135 - # then that field is reflected in the versioned model as 'versioned_type' by default.  
136 - #  
137 - # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table  
138 - # method, perfect for a migration. It will also create the version column if the main model does not already have it.  
139 - #  
140 - # class AddVersions < ActiveRecord::Migration  
141 - # def self.up  
142 - # # create_versioned_table takes the same options hash  
143 - # # that create_table does  
144 - # Post.create_versioned_table  
145 - # end  
146 - #  
147 - # def self.down  
148 - # Post.drop_versioned_table  
149 - # end  
150 - # end  
151 - #  
152 - # == Changing What Fields Are Versioned  
153 - #  
154 - # By default, acts_as_versioned will version all but these fields:  
155 - #  
156 - # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]  
157 - #  
158 - # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols.  
159 - #  
160 - # class Post < ActiveRecord::Base  
161 - # acts_as_versioned  
162 - # self.non_versioned_columns << 'comments_count'  
163 - # end  
164 - #  
165 - def acts_as_versioned(options = {}, &extension)  
166 - # don't allow multiple calls  
167 - return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods)  
168 -  
169 - send :include, ActiveRecord::Acts::Versioned::ActMethods  
170 -  
171 - cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,  
172 - :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns,  
173 - :version_association_options, :version_if_changed  
174 -  
175 - self.versioned_class_name = options[:class_name] || "Version"  
176 - self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key  
177 - self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}"  
178 - self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"  
179 - self.version_column = options[:version_column] || 'version'  
180 - self.version_sequence_name = options[:sequence_name]  
181 - self.max_version_limit = options[:limit].to_i  
182 - self.version_condition = options[:if] || true  
183 - self.non_versioned_columns = [self.primary_key, inheritance_column, self.version_column, 'lock_version', versioned_inheritance_column] + options[:non_versioned_columns].to_a.map(&:to_s)  
184 - self.version_association_options = {  
185 - :class_name => "#{self.to_s}::#{versioned_class_name}",  
186 - :foreign_key => versioned_foreign_key,  
187 - :dependent => :delete_all  
188 - }.merge(options[:association_options] || {})  
189 -  
190 - if block_given?  
191 - extension_module_name = "#{versioned_class_name}Extension"  
192 - silence_warnings do  
193 - self.const_set(extension_module_name, Module.new(&extension))  
194 - end  
195 -  
196 - options[:extend] = self.const_get(extension_module_name) 73 + # == Configuration options
  74 + #
  75 + # * <tt>class_name</tt> - versioned model class name (default: PageVersion in the above example)
  76 + # * <tt>table_name</tt> - versioned model table name (default: page_versions in the above example)
  77 + # * <tt>foreign_key</tt> - foreign key used to relate the versioned model to the original model (default: page_id in the above example)
  78 + # * <tt>inheritance_column</tt> - name of the column to save the model's inheritance_column value for STI. (default: versioned_type)
  79 + # * <tt>version_column</tt> - name of the column in the model that keeps the version number (default: version)
  80 + # * <tt>sequence_name</tt> - name of the custom sequence to be used by the versioned model.
  81 + # * <tt>limit</tt> - number of revisions to keep, defaults to unlimited
  82 + # * <tt>if</tt> - symbol of method to check before saving a new version. If this method returns false, a new version is not saved.
  83 + # For finer control, pass either a Proc or modify Model#version_condition_met?
  84 + #
  85 + # acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
  86 + #
  87 + # or...
  88 + #
  89 + # class Auction
  90 + # def version_condition_met? # totally bypasses the <tt>:if</tt> option
  91 + # !expired?
  92 + # end
  93 + # end
  94 + #
  95 + # * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes
  96 + # either a symbol or array of symbols.
  97 + #
  98 + # * <tt>extend</tt> - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block
  99 + # to create an anonymous mixin:
  100 + #
  101 + # class Auction
  102 + # acts_as_versioned do
  103 + # def started?
  104 + # !started_at.nil?
  105 + # end
  106 + # end
  107 + # end
  108 + #
  109 + # or...
  110 + #
  111 + # module AuctionExtension
  112 + # def started?
  113 + # !started_at.nil?
  114 + # end
  115 + # end
  116 + # class Auction
  117 + # acts_as_versioned :extend => AuctionExtension
  118 + # end
  119 + #
  120 + # Example code:
  121 + #
  122 + # @auction = Auction.find(1)
  123 + # @auction.started?
  124 + # @auction.versions.first.started?
  125 + #
  126 + # == Database Schema
  127 + #
  128 + # The model that you're versioning needs to have a 'version' attribute. The model is versioned
  129 + # into a table called #{model}_versions where the model name is singlular. The _versions table should
  130 + # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
  131 + #
  132 + # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance,
  133 + # then that field is reflected in the versioned model as 'versioned_type' by default.
  134 + #
  135 + # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table
  136 + # method, perfect for a migration. It will also create the version column if the main model does not already have it.
  137 + #
  138 + # class AddVersions < ActiveRecord::Migration
  139 + # def self.up
  140 + # # create_versioned_table takes the same options hash
  141 + # # that create_table does
  142 + # Post.create_versioned_table
  143 + # end
  144 + #
  145 + # def self.down
  146 + # Post.drop_versioned_table
  147 + # end
  148 + # end
  149 + #
  150 + # == Changing What Fields Are Versioned
  151 + #
  152 + # By default, acts_as_versioned will version all but these fields:
  153 + #
  154 + # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
  155 + #
  156 + # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols.
  157 + #
  158 + # class Post < ActiveRecord::Base
  159 + # acts_as_versioned
  160 + # self.non_versioned_columns << 'comments_count'
  161 + # end
  162 + #
  163 + def acts_as_versioned(options = {}, &extension)
  164 + # don't allow multiple calls
  165 + return if self.included_modules.include?(ActiveRecord::Acts::Versioned::Behaviors)
  166 +
  167 + cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,
  168 + :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns,
  169 + :version_association_options, :version_if_changed, :version_except_columns
  170 +
  171 + self.versioned_class_name = options[:class_name] || "Version"
  172 + self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key
  173 + self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}"
  174 + self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
  175 + self.version_column = options[:version_column] || 'version'
  176 + self.version_sequence_name = options[:sequence_name]
  177 + self.max_version_limit = options[:limit].to_i
  178 + self.version_condition = options[:if] || true
  179 + self.version_except_columns = [options[:except]].flatten.map(&:to_s) #these columns are kept in _versioned, but changing them does not excplitly cause a version change
  180 + self.non_versioned_columns = [self.primary_key, inheritance_column, self.version_column, 'lock_version', versioned_inheritance_column] #these columns are excluded from _versions, and changing them does not cause a version change
  181 + self.version_association_options = {
  182 + :class_name => "#{self.to_s}::#{versioned_class_name}",
  183 + :foreign_key => versioned_foreign_key,
  184 + :dependent => :delete_all
  185 + }.merge(options[:association_options] || {})
  186 +
  187 + if block_given?
  188 + extension_module_name = "#{versioned_class_name}Extension"
  189 + silence_warnings do
  190 + self.const_set(extension_module_name, Module.new(&extension))
197 end 191 end
198 192
199 - class_eval <<-CLASS_METHODS  
200 - has_many :versions, version_association_options do  
201 - # finds earliest version of this record  
202 - def earliest  
203 - @earliest ||= find(:first, :order => '#{version_column}')  
204 - end 193 + options[:extend] = self.const_get(extension_module_name)
  194 + end
205 195
206 - # find latest version of this record  
207 - def latest  
208 - @latest ||= find(:first, :order => '#{version_column} desc')  
209 - end  
210 - end  
211 - before_save :set_new_version  
212 - after_save :save_version  
213 - after_save :clear_old_versions  
214 -  
215 - unless options[:if_changed].nil?  
216 - self.track_altered_attributes = true  
217 - options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)  
218 - self.version_if_changed = options[:if_changed].map(&:to_s)  
219 - end 196 + unless options[:if_changed].nil?
  197 + self.track_altered_attributes = true
  198 + options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)
  199 + self.version_if_changed = options[:if_changed].map(&:to_s)
  200 + end
220 201
221 - include options[:extend] if options[:extend].is_a?(Module)  
222 - CLASS_METHODS 202 + include options[:extend] if options[:extend].is_a?(Module)
223 203
224 - # create the dynamic versioned model  
225 - const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do  
226 - def self.reloadable? ; false ; end  
227 - # find first version before the given version  
228 - def self.before(version)  
229 - find :first, :order => 'version desc',  
230 - :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version]  
231 - end 204 + include ActiveRecord::Acts::Versioned::Behaviors
232 205
233 - # find first version after the given version.  
234 - def self.after(version)  
235 - find :first, :order => 'version',  
236 - :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version]  
237 - end 206 + #
  207 + # Create the dynamic versioned model
  208 + #
  209 + const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do
  210 + def self.reloadable?;
  211 + false;
  212 + end
238 213
239 - def previous  
240 - self.class.before(self)  
241 - end 214 + # find first version before the given version
  215 + def self.before(version)
  216 + where(["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version]).
  217 + order('version DESC').
  218 + first
  219 + end
242 220
243 - def next  
244 - self.class.after(self)  
245 - end 221 + # find first version after the given version.
  222 + def self.after(version)
  223 + where(["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version]).
  224 + order('version ASC').
  225 + first
  226 + end
246 227
247 - def versions_count  
248 - page.version  
249 - end 228 + # finds earliest version of this record
  229 + def self.earliest
  230 + order("#{original_class.version_column}").first
  231 + end
  232 +
  233 + # find latest version of this record
  234 + def self.latest
  235 + order("#{original_class.version_column} desc").first
  236 + end
  237 +
  238 + def previous
  239 + self.class.before(self)
  240 + end
  241 +
  242 + def next
  243 + self.class.after(self)
250 end 244 end
251 245
252 - versioned_class.cattr_accessor :original_class  
253 - versioned_class.original_class = self  
254 - versioned_class.set_table_name versioned_table_name  
255 - versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,  
256 - :class_name => "::#{self.to_s}",  
257 - :foreign_key => versioned_foreign_key  
258 - versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module)  
259 - versioned_class.set_sequence_name version_sequence_name if version_sequence_name 246 + def versions_count
  247 + page.version
  248 + end
260 end 249 end
  250 +
  251 + versioned_class.cattr_accessor :original_class
  252 + versioned_class.original_class = self
  253 + versioned_class.table_name = versioned_table_name
  254 + versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
  255 + :class_name => "::#{self.to_s}",
  256 + :foreign_key => versioned_foreign_key
  257 + versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module)
  258 + versioned_class.set_sequence_name version_sequence_name if version_sequence_name
261 end 259 end
262 260
263 - module ActMethods  
264 - def self.included(base) # :nodoc:  
265 - base.extend ClassMethods 261 + module Behaviors
  262 + extend ActiveSupport::Concern
  263 +
  264 + included do
  265 + has_many :versions, self.version_association_options
  266 +
  267 + before_save :set_new_version
  268 + after_save :save_version
  269 + after_save :clear_old_versions
266 end 270 end
267 271
268 # Saves a version of the model in the versioned table. This is called in the after_save callback by default 272 # Saves a version of the model in the versioned table. This is called in the after_save callback by default
@@ -292,7 +296,7 @@ module ActiveRecord #:nodoc: @@ -292,7 +296,7 @@ module ActiveRecord #:nodoc:
292 if version.is_a?(self.class.versioned_class) 296 if version.is_a?(self.class.versioned_class)
293 return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record? 297 return false unless version.send(self.class.versioned_foreign_key) == id and !version.new_record?
294 else 298 else
295 - return false unless version = versions.send("find_by_#{self.class.version_column}", version) 299 + return false unless version = versions.where(self.class.version_column => version).first
296 end 300 end
297 self.clone_versioned_model(version, self) 301 self.clone_versioned_model(version, self)
298 send("#{self.class.version_column}=", version.send(self.class.version_column)) 302 send("#{self.class.version_column}=", version.send(self.class.version_column))
@@ -320,23 +324,33 @@ module ActiveRecord #:nodoc: @@ -320,23 +324,33 @@ module ActiveRecord #:nodoc:
320 end 324 end
321 end 325 end
322 end 326 end
323 - 327 +
324 def altered? 328 def altered?
325 - track_altered_attributes ? (version_if_changed - changed).length < version_if_changed.length : changed? 329 + changed.map { |c| self.class.versioned_columns.map(&:name).include?(c) & !self.class.version_except_columns.include?(c) }.any?
326 end 330 end
327 331
328 # Clones a model. Used when saving a new version or reverting a model's version. 332 # Clones a model. Used when saving a new version or reverting a model's version.
329 def clone_versioned_model(orig_model, new_model) 333 def clone_versioned_model(orig_model, new_model)
330 self.class.versioned_columns.each do |col| 334 self.class.versioned_columns.each do |col|
331 - new_model.send("#{col.name}=", orig_model.send(col.name)) if orig_model.has_attribute?(col.name) 335 + next unless orig_model.has_attribute?(col.name)
  336 + define_method(new_model, col.name.to_sym)
  337 + new_model.send("#{col.name.to_sym}=", orig_model.send(col.name))
332 end 338 end
333 339
334 if orig_model.is_a?(self.class.versioned_class) 340 if orig_model.is_a?(self.class.versioned_class)
335 new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] 341 new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column]
336 elsif new_model.is_a?(self.class.versioned_class) 342 elsif new_model.is_a?(self.class.versioned_class)
337 - new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column] 343 + sym = self.class.versioned_inheritance_column.to_sym
  344 + define_method new_model, sym
  345 + new_model.send("#{sym}=", orig_model[orig_model.class.inheritance_column]) if orig_model[orig_model.class.inheritance_column]
338 end 346 end
339 end 347 end
  348 +
  349 + def define_method(object, method)
  350 + return if object.methods.include? method
  351 + metaclass = class << object; self; end
  352 + metaclass.send :attr_accessor, method
  353 + end
340 354
341 # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>. 355 # Checks whether a new version shall be saved or not. Calls <tt>version_condition_met?</tt> and <tt>changed?</tt>.
342 def save_version? 356 def save_version?
@@ -347,12 +361,12 @@ module ActiveRecord #:nodoc: @@ -347,12 +361,12 @@ module ActiveRecord #:nodoc:
347 # custom version condition checking. 361 # custom version condition checking.
348 def version_condition_met? 362 def version_condition_met?
349 case 363 case
350 - when version_condition.is_a?(Symbol)  
351 - send(version_condition)  
352 - when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)  
353 - version_condition.call(self)  
354 - else  
355 - version_condition 364 + when version_condition.is_a?(Symbol)
  365 + send(version_condition)
  366 + when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1)
  367 + version_condition.call(self)
  368 + else
  369 + version_condition
356 end 370 end
357 end 371 end
358 372
@@ -376,19 +390,23 @@ module ActiveRecord #:nodoc: @@ -376,19 +390,23 @@ module ActiveRecord #:nodoc:
376 self.class.without_locking(&block) 390 self.class.without_locking(&block)
377 end 391 end
378 392
379 - def empty_callback() end #:nodoc: 393 + def empty_callback()
  394 + end
  395 +
  396 + #:nodoc:
380 397
381 protected 398 protected
382 - # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.  
383 - def set_new_version  
384 - @saving_version = new_record? || save_version?  
385 - self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?)  
386 - end 399 + # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version.
  400 + def set_new_version
  401 + @saving_version = new_record? || save_version?
  402 + self.send("#{self.class.version_column}=", next_version) if new_record? || (!locking_enabled? && save_version?)
  403 + end
  404 +
  405 + # Gets the next available version for the current record, or 1 for a new record
  406 + def next_version
  407 + (new_record? ? 0 : versions.calculate(:maximum, version_column).to_i) + 1
  408 + end
387 409
388 - # Gets the next available version for the current record, or 1 for a new record  
389 - def next_version  
390 - (new_record? ? 0 : versions.calculate(:max, version_column).to_i) + 1  
391 - end  
392 410
393 module ClassMethods 411 module ClassMethods
394 # Returns an array of columns that are versioned. See non_versioned_columns 412 # Returns an array of columns that are versioned. See non_versioned_columns
@@ -410,28 +428,28 @@ module ActiveRecord #:nodoc: @@ -410,28 +428,28 @@ module ActiveRecord #:nodoc:
410 end 428 end
411 429
412 return if connection.table_exists?(versioned_table_name) 430 return if connection.table_exists?(versioned_table_name)
413 - 431 +
414 self.connection.create_table(versioned_table_name, create_table_options) do |t| 432 self.connection.create_table(versioned_table_name, create_table_options) do |t|
415 t.column versioned_foreign_key, :integer 433 t.column versioned_foreign_key, :integer
416 t.column version_column, :integer 434 t.column version_column, :integer
417 end 435 end
418 436
419 - self.versioned_columns.each do |col|  
420 - self.connection.add_column versioned_table_name, col.name, col.type,  
421 - :limit => col.limit,  
422 - :default => col.default,  
423 - :scale => col.scale,  
424 - :precision => col.precision 437 + self.versioned_columns.each do |col|
  438 + self.connection.add_column versioned_table_name, col.name, col.type,
  439 + :limit => col.limit,
  440 + :default => col.default,
  441 + :scale => col.scale,
  442 + :precision => col.precision
425 end 443 end
426 444
427 if type_col = self.columns_hash[inheritance_column] 445 if type_col = self.columns_hash[inheritance_column]
428 - self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type,  
429 - :limit => type_col.limit,  
430 - :default => type_col.default,  
431 - :scale => type_col.scale,  
432 - :precision => type_col.precision 446 + self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type,
  447 + :limit => type_col.limit,
  448 + :default => type_col.default,
  449 + :scale => type_col.scale,
  450 + :precision => type_col.precision
433 end 451 end
434 - 452 +
435 self.connection.add_index versioned_table_name, versioned_foreign_key 453 self.connection.add_index versioned_table_name, versioned_foreign_key
436 end 454 end
437 455
@@ -447,7 +465,7 @@ module ActiveRecord #:nodoc: @@ -447,7 +465,7 @@ module ActiveRecord #:nodoc:
447 # end 465 # end
448 # 466 #
449 def without_revision(&block) 467 def without_revision(&block)
450 - class_eval do 468 + class_eval do
451 CALLBACKS.each do |attr_name| 469 CALLBACKS.each do |attr_name|
452 alias_method "orig_#{attr_name}".to_sym, attr_name 470 alias_method "orig_#{attr_name}".to_sym, attr_name
453 alias_method attr_name, :empty_callback 471 alias_method attr_name, :empty_callback
@@ -455,7 +473,7 @@ module ActiveRecord #:nodoc: @@ -455,7 +473,7 @@ module ActiveRecord #:nodoc:
455 end 473 end
456 block.call 474 block.call
457 ensure 475 ensure
458 - class_eval do 476 + class_eval do
459 CALLBACKS.each do |attr_name| 477 CALLBACKS.each do |attr_name|
460 alias_method attr_name, "orig_#{attr_name}".to_sym 478 alias_method attr_name, "orig_#{attr_name}".to_sym
461 end 479 end
@@ -483,4 +501,4 @@ module ActiveRecord #:nodoc: @@ -483,4 +501,4 @@ module ActiveRecord #:nodoc:
483 end 501 end
484 end 502 end
485 503
486 -ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned 504 +ActiveRecord::Base.extend ActiveRecord::Acts::Versioned
vendor/plugins/acts_as_versioned/test/abstract_unit.rb
@@ -1,48 +0,0 @@ @@ -1,48 +0,0 @@
1 -$:.unshift(File.dirname(__FILE__) + '/../../../rails/activesupport/lib')  
2 -$:.unshift(File.dirname(__FILE__) + '/../../../rails/activerecord/lib')  
3 -$:.unshift(File.dirname(__FILE__) + '/../lib')  
4 -require 'test/unit'  
5 -begin  
6 - require 'active_support'  
7 - require 'active_record'  
8 - require 'active_record/fixtures'  
9 -rescue LoadError  
10 - require 'rubygems'  
11 - retry  
12 -end  
13 -  
14 -begin  
15 - require 'ruby-debug'  
16 - Debugger.start  
17 -rescue LoadError  
18 -end  
19 -  
20 -require 'acts_as_versioned'  
21 -  
22 -config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))  
23 -ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")  
24 -ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']}  
25 -ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])  
26 -  
27 -load(File.dirname(__FILE__) + "/schema.rb")  
28 -  
29 -# set up custom sequence on widget_versions for DBs that support sequences  
30 -if ENV['DB'] == 'postgresql'  
31 - ActiveRecord::Base.connection.execute "DROP SEQUENCE widgets_seq;" rescue nil  
32 - ActiveRecord::Base.connection.remove_column :widget_versions, :id  
33 - ActiveRecord::Base.connection.execute "CREATE SEQUENCE widgets_seq START 101;"  
34 - ActiveRecord::Base.connection.execute "ALTER TABLE widget_versions ADD COLUMN id INTEGER PRIMARY KEY DEFAULT nextval('widgets_seq');"  
35 -end  
36 -  
37 -Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"  
38 -$:.unshift(Test::Unit::TestCase.fixture_path)  
39 -  
40 -class Test::Unit::TestCase #:nodoc:  
41 - # Turn off transactional fixtures if you're working with MyISAM tables in MySQL  
42 - self.use_transactional_fixtures = true  
43 -  
44 - # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)  
45 - self.use_instantiated_fixtures = false  
46 -  
47 - # Add more helper methods to be used by all tests here...  
48 -end  
49 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/test/database.yml
@@ -1,18 +0,0 @@ @@ -1,18 +0,0 @@
1 -sqlite:  
2 - :adapter: sqlite  
3 - :dbfile: acts_as_versioned_plugin.sqlite.db  
4 -sqlite3:  
5 - :adapter: sqlite3  
6 - :dbfile: acts_as_versioned_plugin.sqlite3.db  
7 -postgresql:  
8 - :adapter: postgresql  
9 - :username: postgres  
10 - :password: postgres  
11 - :database: acts_as_versioned_plugin_test  
12 - :min_messages: ERROR  
13 -mysql:  
14 - :adapter: mysql  
15 - :host: localhost  
16 - :username: rails  
17 - :password:  
18 - :database: acts_as_versioned_plugin_test  
19 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/test/fixtures/authors.yml
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -caged:  
2 - id: 1  
3 - name: caged  
4 -mly:  
5 - id: 2  
6 - name: mly  
7 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/test/fixtures/landmark.rb
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -class Landmark < ActiveRecord::Base  
2 - acts_as_versioned :if_changed => [ :name, :longitude, :latitude ]  
3 -end  
vendor/plugins/acts_as_versioned/test/fixtures/landmark_versions.yml
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -washington:  
2 - id: 1  
3 - landmark_id: 1  
4 - version: 1  
5 - name: Washington, D.C.  
6 - latitude: 38.895  
7 - longitude: -77.036667  
vendor/plugins/acts_as_versioned/test/fixtures/landmarks.yml
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -washington:  
2 - id: 1  
3 - name: Washington, D.C.  
4 - latitude: 38.895  
5 - longitude: -77.036667  
6 - doesnt_trigger_version: This is not important  
7 - version: 1  
vendor/plugins/acts_as_versioned/test/fixtures/locked_pages.yml
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -welcome:  
2 - id: 1  
3 - title: Welcome to the weblog  
4 - lock_version: 24  
5 - type: LockedPage  
6 -thinking:  
7 - id: 2  
8 - title: So I was thinking  
9 - lock_version: 24  
10 - type: SpecialLockedPage  
vendor/plugins/acts_as_versioned/test/fixtures/locked_pages_revisions.yml
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -welcome_1:  
2 - id: 1  
3 - page_id: 1  
4 - title: Welcome to the weblg  
5 - lock_version: 23  
6 - version_type: LockedPage  
7 -  
8 -welcome_2:  
9 - id: 2  
10 - page_id: 1  
11 - title: Welcome to the weblog  
12 - lock_version: 24  
13 - version_type: LockedPage  
14 -  
15 -thinking_1:  
16 - id: 3  
17 - page_id: 2  
18 - title: So I was thinking!!!  
19 - lock_version: 23  
20 - version_type: SpecialLockedPage  
21 -  
22 -thinking_2:  
23 - id: 4  
24 - page_id: 2  
25 - title: So I was thinking  
26 - lock_version: 24  
27 - version_type: SpecialLockedPage  
vendor/plugins/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb
@@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
1 -class AddVersionedTables < ActiveRecord::Migration  
2 - def self.up  
3 - create_table("things") do |t|  
4 - t.column :title, :text  
5 - t.column :price, :decimal, :precision => 7, :scale => 2  
6 - t.column :type, :string  
7 - end  
8 - Thing.create_versioned_table  
9 - end  
10 -  
11 - def self.down  
12 - Thing.drop_versioned_table  
13 - drop_table "things" rescue nil  
14 - end  
15 -end  
16 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/test/fixtures/page.rb
@@ -1,43 +0,0 @@ @@ -1,43 +0,0 @@
1 -class Page < ActiveRecord::Base  
2 - belongs_to :author  
3 - has_many :authors, :through => :versions, :order => 'name'  
4 - belongs_to :revisor, :class_name => 'Author'  
5 - has_many :revisors, :class_name => 'Author', :through => :versions, :order => 'name'  
6 - acts_as_versioned :if => :feeling_good? do  
7 - def self.included(base)  
8 - base.cattr_accessor :feeling_good  
9 - base.feeling_good = true  
10 - base.belongs_to :author  
11 - base.belongs_to :revisor, :class_name => 'Author'  
12 - end  
13 -  
14 - def feeling_good?  
15 - @@feeling_good == true  
16 - end  
17 - end  
18 -end  
19 -  
20 -module LockedPageExtension  
21 - def hello_world  
22 - 'hello_world'  
23 - end  
24 -end  
25 -  
26 -class LockedPage < ActiveRecord::Base  
27 - acts_as_versioned \  
28 - :inheritance_column => :version_type,  
29 - :foreign_key => :page_id,  
30 - :table_name => :locked_pages_revisions,  
31 - :class_name => 'LockedPageRevision',  
32 - :version_column => :lock_version,  
33 - :limit => 2,  
34 - :if_changed => :title,  
35 - :extend => LockedPageExtension  
36 -end  
37 -  
38 -class SpecialLockedPage < LockedPage  
39 -end  
40 -  
41 -class Author < ActiveRecord::Base  
42 - has_many :pages  
43 -end  
44 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml
@@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
1 -welcome_2:  
2 - id: 1  
3 - page_id: 1  
4 - title: Welcome to the weblog  
5 - body: Such a lovely day  
6 - version: 24  
7 - author_id: 1  
8 - revisor_id: 1  
9 -welcome_1:  
10 - id: 2  
11 - page_id: 1  
12 - title: Welcome to the weblg  
13 - body: Such a lovely day  
14 - version: 23  
15 - author_id: 2  
16 - revisor_id: 2  
vendor/plugins/acts_as_versioned/test/fixtures/pages.yml
@@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
1 -welcome:  
2 - id: 1  
3 - title: Welcome to the weblog  
4 - body: Such a lovely day  
5 - version: 24  
6 - author_id: 1  
7 - revisor_id: 1  
8 - created_on: "2008-01-01 00:00:00"  
9 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/test/fixtures/widget.rb
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -class Widget < ActiveRecord::Base  
2 - acts_as_versioned :sequence_name => 'widgets_seq', :association_options => {  
3 - :dependent => :nullify, :order => 'version desc'  
4 - }  
5 - non_versioned_columns << 'foo'  
6 -end  
7 \ No newline at end of file 0 \ No newline at end of file
vendor/plugins/acts_as_versioned/test/migration_test.rb
@@ -1,46 +0,0 @@ @@ -1,46 +0,0 @@
1 -require File.join(File.dirname(__FILE__), 'abstract_unit')  
2 -  
3 -if ActiveRecord::Base.connection.supports_migrations?  
4 - class Thing < ActiveRecord::Base  
5 - attr_accessor :version  
6 - acts_as_versioned  
7 - end  
8 -  
9 - class MigrationTest < Test::Unit::TestCase  
10 - self.use_transactional_fixtures = false  
11 - def teardown  
12 - if ActiveRecord::Base.connection.respond_to?(:initialize_schema_information)  
13 - ActiveRecord::Base.connection.initialize_schema_information  
14 - ActiveRecord::Base.connection.update "UPDATE schema_info SET version = 0"  
15 - else  
16 - ActiveRecord::Base.connection.initialize_schema_migrations_table  
17 - ActiveRecord::Base.connection.assume_migrated_upto_version(0)  
18 - end  
19 -  
20 - Thing.connection.drop_table "things" rescue nil  
21 - Thing.connection.drop_table "thing_versions" rescue nil  
22 - Thing.reset_column_information  
23 - end  
24 -  
25 - def test_versioned_migration  
26 - assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }  
27 - # take 'er up  
28 - ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/')  
29 - t = Thing.create :title => 'blah blah', :price => 123.45, :type => 'Thing'  
30 - assert_equal 1, t.versions.size  
31 -  
32 - # check that the price column has remembered its value correctly  
33 - assert_equal t.price, t.versions.first.price  
34 - assert_equal t.title, t.versions.first.title  
35 - assert_equal t[:type], t.versions.first[:type]  
36 -  
37 - # make sure that the precision of the price column has been preserved  
38 - assert_equal 7, Thing::Version.columns.find{|c| c.name == "price"}.precision  
39 - assert_equal 2, Thing::Version.columns.find{|c| c.name == "price"}.scale  
40 -  
41 - # now lets take 'er back down  
42 - ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/')  
43 - assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' }  
44 - end  
45 - end  
46 -end  
vendor/plugins/acts_as_versioned/test/schema.rb
@@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
1 -ActiveRecord::Schema.define(:version => 0) do  
2 - create_table :pages, :force => true do |t|  
3 - t.column :version, :integer  
4 - t.column :title, :string, :limit => 255  
5 - t.column :body, :text  
6 - t.column :created_on, :datetime  
7 - t.column :updated_on, :datetime  
8 - t.column :author_id, :integer  
9 - t.column :revisor_id, :integer  
10 - end  
11 -  
12 - create_table :page_versions, :force => true do |t|  
13 - t.column :page_id, :integer  
14 - t.column :version, :integer  
15 - t.column :title, :string, :limit => 255  
16 - t.column :body, :text  
17 - t.column :created_on, :datetime  
18 - t.column :updated_on, :datetime  
19 - t.column :author_id, :integer  
20 - t.column :revisor_id, :integer  
21 - end  
22 -  
23 - add_index :page_versions, [:page_id, :version], :unique => true  
24 -  
25 - create_table :authors, :force => true do |t|  
26 - t.column :page_id, :integer  
27 - t.column :name, :string  
28 - end  
29 -  
30 - create_table :locked_pages, :force => true do |t|  
31 - t.column :lock_version, :integer  
32 - t.column :title, :string, :limit => 255  
33 - t.column :body, :text  
34 - t.column :type, :string, :limit => 255  
35 - end  
36 -  
37 - create_table :locked_pages_revisions, :force => true do |t|  
38 - t.column :page_id, :integer  
39 - t.column :lock_version, :integer  
40 - t.column :title, :string, :limit => 255  
41 - t.column :body, :text  
42 - t.column :version_type, :string, :limit => 255  
43 - t.column :updated_at, :datetime  
44 - end  
45 -  
46 - add_index :locked_pages_revisions, [:page_id, :lock_version], :unique => true  
47 -  
48 - create_table :widgets, :force => true do |t|  
49 - t.column :name, :string, :limit => 50  
50 - t.column :foo, :string  
51 - t.column :version, :integer  
52 - t.column :updated_at, :datetime  
53 - end  
54 -  
55 - create_table :widget_versions, :force => true do |t|  
56 - t.column :widget_id, :integer  
57 - t.column :name, :string, :limit => 50  
58 - t.column :version, :integer  
59 - t.column :updated_at, :datetime  
60 - end  
61 -  
62 - add_index :widget_versions, [:widget_id, :version], :unique => true  
63 -  
64 - create_table :landmarks, :force => true do |t|  
65 - t.column :name, :string  
66 - t.column :latitude, :float  
67 - t.column :longitude, :float  
68 - t.column :doesnt_trigger_version,:string  
69 - t.column :version, :integer  
70 - end  
71 -  
72 - create_table :landmark_versions, :force => true do |t|  
73 - t.column :landmark_id, :integer  
74 - t.column :name, :string  
75 - t.column :latitude, :float  
76 - t.column :longitude, :float  
77 - t.column :doesnt_trigger_version,:string  
78 - t.column :version, :integer  
79 - end  
80 -  
81 - add_index :landmark_versions, [:landmark_id, :version], :unique => true  
82 -end  
vendor/plugins/acts_as_versioned/test/versioned_test.rb
@@ -1,370 +0,0 @@ @@ -1,370 +0,0 @@
1 -require File.join(File.dirname(__FILE__), 'abstract_unit')  
2 -require File.join(File.dirname(__FILE__), 'fixtures/page')  
3 -require File.join(File.dirname(__FILE__), 'fixtures/widget')  
4 -  
5 -class VersionedTest < Test::Unit::TestCase  
6 - fixtures :pages, :page_versions, :locked_pages, :locked_pages_revisions, :authors, :landmarks, :landmark_versions  
7 - set_fixture_class :page_versions => Page::Version  
8 -  
9 - def test_saves_versioned_copy  
10 - p = Page.create! :title => 'first title', :body => 'first body'  
11 - assert !p.new_record?  
12 - assert_equal 1, p.versions.size  
13 - assert_equal 1, p.version  
14 - assert_instance_of Page.versioned_class, p.versions.first  
15 - end  
16 -  
17 - def test_saves_without_revision  
18 - p = pages(:welcome)  
19 - old_versions = p.versions.count  
20 -  
21 - p.save_without_revision  
22 -  
23 - p.without_revision do  
24 - p.update_attributes :title => 'changed'  
25 - end  
26 -  
27 - assert_equal old_versions, p.versions.count  
28 - end  
29 -  
30 - def test_rollback_with_version_number  
31 - p = pages(:welcome)  
32 - assert_equal 24, p.version  
33 - assert_equal 'Welcome to the weblog', p.title  
34 -  
35 - assert p.revert_to!(23), "Couldn't revert to 23"  
36 - assert_equal 23, p.version  
37 - assert_equal 'Welcome to the weblg', p.title  
38 - end  
39 -  
40 - def test_versioned_class_name  
41 - assert_equal 'Version', Page.versioned_class_name  
42 - assert_equal 'LockedPageRevision', LockedPage.versioned_class_name  
43 - end  
44 -  
45 - def test_versioned_class  
46 - assert_equal Page::Version, Page.versioned_class  
47 - assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class  
48 - end  
49 -  
50 - def test_special_methods  
51 - assert_nothing_raised { pages(:welcome).feeling_good? }  
52 - assert_nothing_raised { pages(:welcome).versions.first.feeling_good? }  
53 - assert_nothing_raised { locked_pages(:welcome).hello_world }  
54 - assert_nothing_raised { locked_pages(:welcome).versions.first.hello_world }  
55 - end  
56 -  
57 - def test_rollback_with_version_class  
58 - p = pages(:welcome)  
59 - assert_equal 24, p.version  
60 - assert_equal 'Welcome to the weblog', p.title  
61 -  
62 - assert p.revert_to!(p.versions.find_by_version(23)), "Couldn't revert to 23"  
63 - assert_equal 23, p.version  
64 - assert_equal 'Welcome to the weblg', p.title  
65 - end  
66 -  
67 - def test_rollback_fails_with_invalid_revision  
68 - p = locked_pages(:welcome)  
69 - assert !p.revert_to!(locked_pages(:thinking))  
70 - end  
71 -  
72 - def test_saves_versioned_copy_with_options  
73 - p = LockedPage.create! :title => 'first title'  
74 - assert !p.new_record?  
75 - assert_equal 1, p.versions.size  
76 - assert_instance_of LockedPage.versioned_class, p.versions.first  
77 - end  
78 -  
79 - def test_rollback_with_version_number_with_options  
80 - p = locked_pages(:welcome)  
81 - assert_equal 'Welcome to the weblog', p.title  
82 - assert_equal 'LockedPage', p.versions.first.version_type  
83 -  
84 - assert p.revert_to!(p.versions.first.lock_version), "Couldn't revert to 23"  
85 - assert_equal 'Welcome to the weblg', p.title  
86 - assert_equal 'LockedPage', p.versions.first.version_type  
87 - end  
88 -  
89 - def test_rollback_with_version_class_with_options  
90 - p = locked_pages(:welcome)  
91 - assert_equal 'Welcome to the weblog', p.title  
92 - assert_equal 'LockedPage', p.versions.first.version_type  
93 -  
94 - assert p.revert_to!(p.versions.first), "Couldn't revert to 1"  
95 - assert_equal 'Welcome to the weblg', p.title  
96 - assert_equal 'LockedPage', p.versions.first.version_type  
97 - end  
98 -  
99 - def test_saves_versioned_copy_with_sti  
100 - p = SpecialLockedPage.create! :title => 'first title'  
101 - assert !p.new_record?  
102 - assert_equal 1, p.versions.size  
103 - assert_instance_of LockedPage.versioned_class, p.versions.first  
104 - assert_equal 'SpecialLockedPage', p.versions.first.version_type  
105 - end  
106 -  
107 - def test_rollback_with_version_number_with_sti  
108 - p = locked_pages(:thinking)  
109 - assert_equal 'So I was thinking', p.title  
110 -  
111 - assert p.revert_to!(p.versions.first.lock_version), "Couldn't revert to 1"  
112 - assert_equal 'So I was thinking!!!', p.title  
113 - assert_equal 'SpecialLockedPage', p.versions.first.version_type  
114 - end  
115 -  
116 - def test_lock_version_works_with_versioning  
117 - p = locked_pages(:thinking)  
118 - p2 = LockedPage.find(p.id)  
119 -  
120 - p.title = 'fresh title'  
121 - p.save  
122 - assert_equal 2, p.versions.size # limit!  
123 -  
124 - assert_raises(ActiveRecord::StaleObjectError) do  
125 - p2.title = 'stale title'  
126 - p2.save  
127 - end  
128 - end  
129 -  
130 - def test_version_if_condition  
131 - p = Page.create! :title => "title"  
132 - assert_equal 1, p.version  
133 -  
134 - Page.feeling_good = false  
135 - p.save  
136 - assert_equal 1, p.version  
137 - Page.feeling_good = true  
138 - end  
139 -  
140 - def test_version_if_condition2  
141 - # set new if condition  
142 - Page.class_eval do  
143 - def new_feeling_good() title[0..0] == 'a'; end  
144 - alias_method :old_feeling_good, :feeling_good?  
145 - alias_method :feeling_good?, :new_feeling_good  
146 - end  
147 -  
148 - p = Page.create! :title => "title"  
149 - assert_equal 1, p.version # version does not increment  
150 - assert_equal 1, p.versions.count  
151 -  
152 - p.update_attributes(:title => 'new title')  
153 - assert_equal 1, p.version # version does not increment  
154 - assert_equal 1, p.versions.count  
155 -  
156 - p.update_attributes(:title => 'a title')  
157 - assert_equal 2, p.version  
158 - assert_equal 2, p.versions.count  
159 -  
160 - # reset original if condition  
161 - Page.class_eval { alias_method :feeling_good?, :old_feeling_good }  
162 - end  
163 -  
164 - def test_version_if_condition_with_block  
165 - # set new if condition  
166 - old_condition = Page.version_condition  
167 - Page.version_condition = Proc.new { |page| page.title[0..0] == 'b' }  
168 -  
169 - p = Page.create! :title => "title"  
170 - assert_equal 1, p.version # version does not increment  
171 - assert_equal 1, p.versions.count  
172 -  
173 - p.update_attributes(:title => 'a title')  
174 - assert_equal 1, p.version # version does not increment  
175 - assert_equal 1, p.versions.count  
176 -  
177 - p.update_attributes(:title => 'b title')  
178 - assert_equal 2, p.version  
179 - assert_equal 2, p.versions.count  
180 -  
181 - # reset original if condition  
182 - Page.version_condition = old_condition  
183 - end  
184 -  
185 - def test_version_no_limit  
186 - p = Page.create! :title => "title", :body => 'first body'  
187 - p.save  
188 - p.save  
189 - 5.times do |i|  
190 - p.title = "title#{i}"  
191 - p.save  
192 - assert_equal "title#{i}", p.title  
193 - assert_equal (i+2), p.version  
194 - end  
195 - end  
196 -  
197 - def test_version_max_limit  
198 - p = LockedPage.create! :title => "title"  
199 - p.update_attributes(:title => "title1")  
200 - p.update_attributes(:title => "title2")  
201 - 5.times do |i|  
202 - p.title = "title#{i}"  
203 - p.save  
204 - assert_equal "title#{i}", p.title  
205 - assert_equal (i+4), p.lock_version  
206 - assert p.versions(true).size <= 2, "locked version can only store 2 versions"  
207 - end  
208 - end  
209 -  
210 - def test_track_altered_attributes_default_value  
211 - assert !Page.track_altered_attributes  
212 - assert LockedPage.track_altered_attributes  
213 - assert SpecialLockedPage.track_altered_attributes  
214 - end  
215 -  
216 - def test_track_altered_attributes  
217 - p = LockedPage.create! :title => "title"  
218 - assert_equal 1, p.lock_version  
219 - assert_equal 1, p.versions(true).size  
220 -  
221 - p.body = 'whoa'  
222 - assert !p.save_version?  
223 - p.save  
224 - assert_equal 2, p.lock_version # still increments version because of optimistic locking  
225 - assert_equal 1, p.versions(true).size  
226 -  
227 - p.title = 'updated title'  
228 - assert p.save_version?  
229 - p.save  
230 - assert_equal 3, p.lock_version  
231 - assert_equal 1, p.versions(true).size # version 1 deleted  
232 -  
233 - p.title = 'updated title!'  
234 - assert p.save_version?  
235 - p.save  
236 - assert_equal 4, p.lock_version  
237 - assert_equal 2, p.versions(true).size # version 1 deleted  
238 - end  
239 -  
240 - def test_find_versions  
241 - assert_equal 1, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%weblog%']).size  
242 - end  
243 -  
244 - def test_find_version  
245 - assert_equal page_versions(:welcome_1), pages(:welcome).versions.find_by_version(23)  
246 - end  
247 -  
248 - def test_with_sequence  
249 - assert_equal 'widgets_seq', Widget.versioned_class.sequence_name  
250 - 3.times { Widget.create! :name => 'new widget' }  
251 - assert_equal 3, Widget.count  
252 - assert_equal 3, Widget.versioned_class.count  
253 - end  
254 -  
255 - def test_has_many_through  
256 - assert_equal [authors(:caged), authors(:mly)], pages(:welcome).authors  
257 - end  
258 -  
259 - def test_has_many_through_with_custom_association  
260 - assert_equal [authors(:caged), authors(:mly)], pages(:welcome).revisors  
261 - end  
262 -  
263 - def test_referential_integrity  
264 - pages(:welcome).destroy  
265 - assert_equal 0, Page.count  
266 - assert_equal 0, Page::Version.count  
267 - end  
268 -  
269 - def test_association_options  
270 - association = Page.reflect_on_association(:versions)  
271 - options = association.options  
272 - assert_equal :delete_all, options[:dependent]  
273 -  
274 - association = Widget.reflect_on_association(:versions)  
275 - options = association.options  
276 - assert_equal :nullify, options[:dependent]  
277 - assert_equal 'version desc', options[:order]  
278 - assert_equal 'widget_id', options[:foreign_key]  
279 -  
280 - widget = Widget.create! :name => 'new widget'  
281 - assert_equal 1, Widget.count  
282 - assert_equal 1, Widget.versioned_class.count  
283 - widget.destroy  
284 - assert_equal 0, Widget.count  
285 - assert_equal 1, Widget.versioned_class.count  
286 - end  
287 -  
288 - def test_versioned_records_should_belong_to_parent  
289 - page = pages(:welcome)  
290 - page_version = page.versions.last  
291 - assert_equal page, page_version.page  
292 - end  
293 -  
294 - def test_unaltered_attributes  
295 - landmarks(:washington).attributes = landmarks(:washington).attributes.except("id")  
296 - assert !landmarks(:washington).changed?  
297 - end  
298 -  
299 - def test_unchanged_string_attributes  
300 - landmarks(:washington).attributes = landmarks(:washington).attributes.except("id").inject({}) { |params, (key, value)| params.update(key => value.to_s) }  
301 - assert !landmarks(:washington).changed?  
302 - end  
303 -  
304 - def test_should_find_earliest_version  
305 - assert_equal page_versions(:welcome_1), pages(:welcome).versions.earliest  
306 - end  
307 -  
308 - def test_should_find_latest_version  
309 - assert_equal page_versions(:welcome_2), pages(:welcome).versions.latest  
310 - end  
311 -  
312 - def test_should_find_previous_version  
313 - assert_equal page_versions(:welcome_1), page_versions(:welcome_2).previous  
314 - assert_equal page_versions(:welcome_1), pages(:welcome).versions.before(page_versions(:welcome_2))  
315 - end  
316 -  
317 - def test_should_find_next_version  
318 - assert_equal page_versions(:welcome_2), page_versions(:welcome_1).next  
319 - assert_equal page_versions(:welcome_2), pages(:welcome).versions.after(page_versions(:welcome_1))  
320 - end  
321 -  
322 - def test_should_find_version_count  
323 - assert_equal 2, pages(:welcome).versions.size  
324 - end  
325 -  
326 - def test_if_changed_creates_version_if_a_listed_column_is_changed  
327 - landmarks(:washington).name = "Washington"  
328 - assert landmarks(:washington).changed?  
329 - assert landmarks(:washington).altered?  
330 - end  
331 -  
332 - def test_if_changed_creates_version_if_all_listed_columns_are_changed  
333 - landmarks(:washington).name = "Washington"  
334 - landmarks(:washington).latitude = 1.0  
335 - landmarks(:washington).longitude = 1.0  
336 - assert landmarks(:washington).changed?  
337 - assert landmarks(:washington).altered?  
338 - end  
339 -  
340 - def test_if_changed_does_not_create_new_version_if_unlisted_column_is_changed  
341 - landmarks(:washington).doesnt_trigger_version = "This should not trigger version"  
342 - assert landmarks(:washington).changed?  
343 - assert !landmarks(:washington).altered?  
344 - end  
345 -  
346 - def test_without_locking_temporarily_disables_optimistic_locking  
347 - enabled1 = false  
348 - block_called = false  
349 -  
350 - ActiveRecord::Base.lock_optimistically = true  
351 - LockedPage.without_locking do  
352 - enabled1 = ActiveRecord::Base.lock_optimistically  
353 - block_called = true  
354 - end  
355 - enabled2 = ActiveRecord::Base.lock_optimistically  
356 -  
357 - assert block_called  
358 - assert !enabled1  
359 - assert enabled2  
360 - end  
361 -  
362 - def test_without_locking_reverts_optimistic_locking_settings_if_block_raises_exception  
363 - assert_raises(RuntimeError) do  
364 - LockedPage.without_locking do  
365 - raise RuntimeError, "oh noes"  
366 - end  
367 - end  
368 - assert ActiveRecord::Base.lock_optimistically  
369 - end  
370 -end  
371 \ No newline at end of file 0 \ No newline at end of file