kb-acts_as_revisable 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,18 @@
1
+ module WithoutScope #:nodoc:
2
+ module ActsAsRevisable
3
+ class GemSpecOptions
4
+ HASH = {
5
+ :name => "rich-acts_as_revisable",
6
+ :version => WithoutScope::ActsAsRevisable::VERSION::STRING,
7
+ :summary => "acts_as_revisable enables revision tracking, querying, reverting and branching of ActiveRecord models. Inspired by acts_as_versioned.",
8
+ :email => "rich@withoutscope.com",
9
+ :homepage => "http://github.com/rich/acts_as_revisable",
10
+ :has_rdoc => true,
11
+ :authors => ["Rich Cavanaugh", "Stephen Caudill"],
12
+ :files => %w( LICENSE README.rdoc Rakefile ) + Dir["{spec,lib,generators,rails}/**/*"],
13
+ :rdoc_options => ["--main", "README.rdoc"],
14
+ :extra_rdoc_files => ["README.rdoc", "LICENSE"]
15
+ }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module WithoutScope
2
+ module ActsAsRevisable
3
+ # This class provides for a flexible method of setting
4
+ # options and querying them. This is especially useful
5
+ # for giving users flexibility when using your plugin.
6
+ class Options
7
+ def initialize(*options, &block)
8
+ @options = options.extract_options!
9
+ instance_eval(&block) if block_given?
10
+ end
11
+
12
+ def method_missing(key, *args)
13
+ return (@options[key.to_s.gsub(/\?$/, '').to_sym].eql?(true)) if key.to_s.match(/\?$/)
14
+ if args.blank?
15
+ @options[key.to_sym]
16
+ else
17
+ @options[key.to_sym] = args.size == 1 ? args.first : args
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ # This module is more about the pretty than anything else. This allows
2
+ # you to use symbols for column names in a conditions hash.
3
+ #
4
+ # User.find(:all, :conditions => ["? = ?", :name, "sam"])
5
+ #
6
+ # Would generate:
7
+ #
8
+ # select * from users where "users"."name" = 'sam'
9
+ #
10
+ # This is consistent with Rails and Ruby where symbols are used to
11
+ # represent methods. Only a symbol matching a column name will
12
+ # trigger this beavior.
13
+ module WithoutScope::QuotedColumnConditions
14
+ def self.included(base)
15
+ base.send(:extend, ClassMethods)
16
+ end
17
+
18
+ module ClassMethods
19
+ def quote_bound_value(value)
20
+ if value.is_a?(Symbol) && column_names.member?(value.to_s)
21
+ # code borrowed from sanitize_sql_hash_for_conditions
22
+ attr = value.to_s
23
+ table_name = quoted_table_name
24
+
25
+ return "#{table_name}.#{connection.quote_column_name(attr)}"
26
+ end
27
+
28
+ super(value)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ module WithoutScope #:nodoc:
2
+ module ActsAsRevisable
3
+ module VERSION #:nodoc:
4
+ MAJOR = 1
5
+ MINOR = 0
6
+ TINY = 3
7
+
8
+ STRING = [MAJOR, MINOR, TINY].join('.')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'activesupport' unless defined? ActiveSupport
5
+ require 'activerecord' unless defined? ActiveRecord
6
+
7
+ require 'acts_as_revisable/version.rb'
8
+ require 'acts_as_revisable/base'
9
+
10
+ ActiveRecord::Base.send(:include, WithoutScope::ActsAsRevisable)
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'acts_as_revisable'
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe WithoutScope::ActsAsRevisable do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ before(:each) do
9
+ @project = Project.create(:name => "Rich", :notes => "this plugin's author")
10
+ @project.update_attribute(:name, "one")
11
+ @project.update_attribute(:name, "two")
12
+ @project.update_attribute(:name, "three")
13
+ end
14
+
15
+ it "should have a pretty named association" do
16
+ lambda { @project.sessions }.should_not raise_error
17
+ end
18
+
19
+ it "should return all the revisions" do
20
+ @project.revisions.size.should == 3
21
+ end
22
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ class Project
4
+ validates_presence_of :name
5
+ end
6
+
7
+ describe WithoutScope::ActsAsRevisable, "with branching" do
8
+ after(:each) do
9
+ cleanup_db
10
+ end
11
+
12
+ before(:each) do
13
+ @project = Project.create(:name => "Rich", :notes => "a note")
14
+ @project.update_attribute(:name, "Sam")
15
+ end
16
+
17
+ it "should allow for branch creation" do
18
+ @project.should == @project.branch.branch_source
19
+ end
20
+
21
+ it "should branch without saving" do
22
+ @project.branch.should be_new_record
23
+ end
24
+
25
+ it "should branch and save" do
26
+ @project.branch!.should_not be_new_record
27
+ end
28
+
29
+ it "should not raise an error for a valid branch" do
30
+ lambda { @project.branch!(:name => "A New User") }.should_not raise_error
31
+ end
32
+
33
+ it "should raise an error for invalid records" do
34
+ lambda { @project.branch!(:name => nil) }.should raise_error
35
+ end
36
+
37
+ it "should not save an invalid record" do
38
+ @branch = @project.branch(:name => nil)
39
+ @branch.save.should be_false
40
+ @branch.should be_new_record
41
+ end
42
+ end
@@ -0,0 +1,16 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe WithoutScope::ActsAsRevisable::Deletable do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ before(:each) do
9
+ @person = Person.create(:name => "Rich", :notes => "a note")
10
+ @person.update_attribute(:name, "Sam")
11
+ end
12
+
13
+ it "should store a revision on destroy" do
14
+ lambda{ @person.destroy }.should change(OldPerson, :count).from(1).to(2)
15
+ end
16
+ end
data/spec/find_spec.rb ADDED
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe WithoutScope::ActsAsRevisable do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ describe "with a single revision" do
9
+ before(:each) do
10
+ @project1 = Project.create(:name => "Rich", :notes => "a note")
11
+ @project1.update_attribute(:name, "Sam")
12
+ end
13
+
14
+ it "should just find the current revision by default" do
15
+ Project.find(:first).name.should == "Sam"
16
+ end
17
+
18
+ it "should accept the :with_revisions options" do
19
+ lambda { Project.find(:all, :with_revisions => true) }.should_not raise_error
20
+ end
21
+
22
+ it "should find current and revisions with the :with_revisions option" do
23
+ Project.find(:all, :with_revisions => true).size.should == 2
24
+ end
25
+
26
+ it "should find revisions with conditions" do
27
+ Project.find(:all, :conditions => {:name => "Rich"}, :with_revisions => true).should == [@project1.find_revision(:previous)]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,79 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe WithoutScope::ActsAsRevisable do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ before(:each) do
9
+ @project = Project.create(:name => "Rich", :notes => "this plugin's author")
10
+ end
11
+
12
+ describe "with auto-generated revision class" do
13
+ it "should have a revision class" do
14
+ Foo.revision_class.should == FooRevision
15
+ end
16
+ end
17
+
18
+ describe "without revisions" do
19
+ it "should have a revision_number of zero" do
20
+ @project.revision_number.should be_zero
21
+ end
22
+
23
+ it "should be the current revision" do
24
+ @project.revisable_is_current.should be_true
25
+ end
26
+
27
+ it "should respond to current_revision? positively" do
28
+ @project.current_revision?.should be_true
29
+ end
30
+
31
+ it "should not have any revisions in the generic association" do
32
+ @project.revisions.should be_empty
33
+ end
34
+
35
+ it "should not have any revisions in the pretty named association" do
36
+ @project.sessions.should be_empty
37
+ end
38
+ end
39
+
40
+ describe "with revisions" do
41
+ before(:each) do
42
+ @project.update_attribute(:name, "Stephen")
43
+ end
44
+
45
+ it "should have a revision_number of one" do
46
+ @project.revision_number.should == 1
47
+ end
48
+
49
+ it "should have a single revision in the generic association" do
50
+ @project.revisions.size.should == 1
51
+ end
52
+
53
+ it "should have a single revision in the pretty named association" do
54
+ @project.sessions.size.should == 1
55
+ end
56
+
57
+ it "should return an instance of the revision class" do
58
+ @project.revisions.first.should be_an_instance_of(Session)
59
+ end
60
+
61
+ it "should have the original revision's data" do
62
+ @project.revisions.first.name.should == "Rich"
63
+ end
64
+ end
65
+
66
+ describe "with excluded columns modified" do
67
+ before(:each) do
68
+ @project.update_attribute(:unimportant, "a new value")
69
+ end
70
+
71
+ it "should maintain the revision_number at zero" do
72
+ @project.revision_number.should be_zero
73
+ end
74
+
75
+ it "should not have any revisions" do
76
+ @project.revisions.should be_empty
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,83 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ shared_examples_for "common Options usage" do
4
+ it "should return a set value" do
5
+ @options.one.should == 1
6
+ end
7
+
8
+ it "should return nil for an unset value" do
9
+ @options.two.should be_nil
10
+ end
11
+
12
+ it "should return false for unset query option" do
13
+ @options.should_not be_unset_value
14
+ end
15
+
16
+ it "should return true for a query option set to true" do
17
+ @options.should be_yes
18
+ end
19
+
20
+ it "should return false for a query option set to false" do
21
+ @options.should_not be_no
22
+ end
23
+
24
+ it "should return false for a query on a non-boolean value" do
25
+ @options.should_not be_one
26
+ end
27
+
28
+ it "should return an array when passed one" do
29
+ @options.arr.should be_a_kind_of(Array)
30
+ end
31
+
32
+ it "should not return an array when not passed one" do
33
+ @options.one.should_not be_a_kind_of(Array)
34
+ end
35
+
36
+ it "should have the right number of elements in an array" do
37
+ @options.arr.size.should == 3
38
+ end
39
+ end
40
+
41
+ describe WithoutScope::ActsAsRevisable::Options do
42
+ describe "with hash options" do
43
+ before(:each) do
44
+ @options = WithoutScope::ActsAsRevisable::Options.new :one => 1, :yes => true, :no => false, :arr => [1,2,3]
45
+ end
46
+
47
+ it_should_behave_like "common Options usage"
48
+ end
49
+
50
+ describe "with block options" do
51
+ before(:each) do
52
+ @options = WithoutScope::ActsAsRevisable::Options.new do
53
+ one 1
54
+ yes true
55
+ arr [1,2,3]
56
+ end
57
+ end
58
+
59
+ it_should_behave_like "common Options usage"
60
+ end
61
+
62
+ describe "with both block and hash options" do
63
+ before(:each) do
64
+ @options = WithoutScope::ActsAsRevisable::Options.new(:yes => true, :arr => [1,2,3]) do
65
+ one 1
66
+ end
67
+ end
68
+
69
+ it_should_behave_like "common Options usage"
70
+
71
+ describe "the block should override the hash" do
72
+ before(:each) do
73
+ @options = WithoutScope::ActsAsRevisable::Options.new(:yes => false, :one => 10, :arr => [1,2,3,4,5]) do
74
+ one 1
75
+ yes true
76
+ arr [1,2,3]
77
+ end
78
+ end
79
+
80
+ it_should_behave_like "common Options usage"
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,19 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe "the quoted_columns extension" do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ it "should quote symbols matching column names as columns" do
9
+ Project.send(:quote_bound_value, :name).should == %q{"projects"."name"}
10
+ end
11
+
12
+ it "should not quote symbols that don't match column names" do
13
+ Project.send(:quote_bound_value, :whatever).should == "'#{:whatever.to_yaml}'"
14
+ end
15
+
16
+ it "should not quote strings any differently" do
17
+ Project.send(:quote_bound_value, "what").should == ActiveRecord::Base.send(:quote_bound_value, "what")
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe WithoutScope::ActsAsRevisable, "with reverting" do
4
+ after(:each) do
5
+ cleanup_db
6
+ end
7
+
8
+ before(:each) do
9
+ @project = Project.create(:name => "Rich", :notes => "a note")
10
+ @project.update_attribute(:name, "Sam")
11
+ end
12
+
13
+ it "should let you revert to previous versions" do
14
+ @project.revert_to!(:first)
15
+ @project.name.should == "Rich"
16
+ end
17
+
18
+ it "should accept the :without_revision hash option" do
19
+ lambda { @project.revert_to!(:first, :without_revision => true) }.should_not raise_error
20
+ @project.name.should == "Rich"
21
+ end
22
+
23
+ it "should support the revert_to_without_revision method" do
24
+ lambda { @project.revert_to_without_revision(:first).save }.should_not raise_error
25
+ @project.name.should == "Rich"
26
+ end
27
+
28
+ it "should support the revert_to_without_revision! method" do
29
+ lambda { @project.revert_to_without_revision!(:first) }.should_not raise_error
30
+ @project.name.should == "Rich"
31
+ end
32
+
33
+ it "should let you revert to previous versions without a new revision" do
34
+ @project.revert_to!(:first, :without_revision => true)
35
+ @project.revisions.size.should == 1
36
+ end
37
+
38
+ it "should support the revert_to method" do
39
+ lambda{ @project.revert_to(:first) }.should_not raise_error
40
+ @project.should be_changed
41
+ end
42
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,93 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ if ENV['EDGE_RAILS_PATH']
10
+ edge_path = File.expand_path(ENV['EDGE_RAILS_PATH'])
11
+ require File.join(edge_path, 'activesupport', 'lib', 'active_support')
12
+ require File.join(edge_path, 'activerecord', 'lib', 'active_record')
13
+ end
14
+
15
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
16
+ require 'acts_as_revisable'
17
+
18
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
19
+
20
+ def setup_db
21
+ ActiveRecord::Schema.define(:version => 1) do
22
+ create_table :people do |t|
23
+ t.string :name, :revisable_name, :revisable_type
24
+ t.text :notes
25
+ t.boolean :revisable_is_current
26
+ t.integer :revisable_original_id, :revisable_branched_from_id, :revisable_number, :project_id
27
+ t.datetime :revisable_current_at, :revisable_revised_at, :revisable_deleted_at
28
+ t.timestamps
29
+ end
30
+
31
+ create_table :projects do |t|
32
+ t.string :name, :unimportant, :revisable_name, :revisable_type
33
+ t.text :notes
34
+ t.boolean :revisable_is_current
35
+ t.integer :revisable_original_id, :revisable_branched_from_id, :revisable_number
36
+ t.datetime :revisable_current_at, :revisable_revised_at, :revisable_deleted_at
37
+ t.timestamps
38
+ end
39
+
40
+ create_table :foos do |t|
41
+ t.string :name, :revisable_name, :revisable_type
42
+ t.text :notes
43
+ t.boolean :revisable_is_current
44
+ t.integer :revisable_original_id, :revisable_branched_from_id, :revisable_number, :project_id
45
+ t.datetime :revisable_current_at, :revisable_revised_at, :revisable_deleted_at
46
+ t.timestamps
47
+ end
48
+ end
49
+ end
50
+
51
+ setup_db
52
+
53
+ def cleanup_db
54
+ ActiveRecord::Base.connection.tables.each do |table|
55
+ ActiveRecord::Base.connection.execute("delete from #{table}")
56
+ end
57
+ end
58
+
59
+ class Person < ActiveRecord::Base
60
+ belongs_to :project
61
+
62
+ acts_as_revisable do
63
+ revision_class_name "OldPerson"
64
+ on_delete :revise
65
+ end
66
+ end
67
+
68
+ class OldPerson < ActiveRecord::Base
69
+ acts_as_revision do
70
+ revisable_class_name "Person"
71
+ clone_associations :all
72
+ end
73
+ end
74
+
75
+ class Project < ActiveRecord::Base
76
+ has_many :people
77
+
78
+ acts_as_revisable do
79
+ revision_class_name "Session"
80
+ except :unimportant
81
+ end
82
+ end
83
+
84
+ class Session < ActiveRecord::Base
85
+ acts_as_revision do
86
+ revisable_class_name "Project"
87
+ clone_associations :all
88
+ end
89
+ end
90
+
91
+ class Foo < ActiveRecord::Base
92
+ acts_as_revisable :generate_revision_class => true
93
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kb-acts_as_revisable
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Rich Cavanaugh
8
+ - Stephen Caudill
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-05-16 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description:
18
+ email: rich@withoutscope.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - README.rdoc
25
+ - LICENSE
26
+ files:
27
+ - LICENSE
28
+ - README.rdoc
29
+ - Rakefile
30
+ - spec/associations_spec.rb
31
+ - spec/branch_spec.rb
32
+ - spec/deletable_spec.rb
33
+ - spec/find_spec.rb
34
+ - spec/general_spec.rb
35
+ - spec/options_spec.rb
36
+ - spec/quoted_columns_spec.rb
37
+ - spec/revert_spec.rb
38
+ - spec/spec.opts
39
+ - spec/spec_helper.rb
40
+ - lib/acts_as_revisable
41
+ - lib/acts_as_revisable/acts
42
+ - lib/acts_as_revisable/acts/common.rb
43
+ - lib/acts_as_revisable/acts/deletable.rb
44
+ - lib/acts_as_revisable/acts/revisable.rb
45
+ - lib/acts_as_revisable/acts/revision.rb
46
+ - lib/acts_as_revisable/base.rb
47
+ - lib/acts_as_revisable/gem_spec_options.rb
48
+ - lib/acts_as_revisable/options.rb
49
+ - lib/acts_as_revisable/quoted_columns.rb
50
+ - lib/acts_as_revisable/version.rb
51
+ - lib/acts_as_revisable.rb
52
+ - generators/revisable_migration
53
+ - generators/revisable_migration/revisable_migration_generator.rb
54
+ - generators/revisable_migration/templates
55
+ - generators/revisable_migration/templates/migration.rb
56
+ - rails/init.rb
57
+ has_rdoc: true
58
+ homepage: http://github.com/rich/acts_as_revisable
59
+ post_install_message:
60
+ rdoc_options:
61
+ - --main
62
+ - README.rdoc
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.2.0
81
+ signing_key:
82
+ specification_version: 2
83
+ summary: acts_as_revisable enables revision tracking, querying, reverting and branching of ActiveRecord models. Inspired by acts_as_versioned.
84
+ test_files: []
85
+