versioned 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +51 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/lib/version.rb +20 -0
- data/lib/versioned.rb +163 -0
- data/pkg/versioned-0.1.0.gem +0 -0
- data/test/between_test.rb +58 -0
- data/test/changes_test.rb +28 -0
- data/test/comparable_test.rb +35 -0
- data/test/creation_test.rb +79 -0
- data/test/latest_changes_test.rb +42 -0
- data/test/revert_test.rb +79 -0
- data/test/schema.rb +21 -0
- data/test/test_helper.rb +10 -0
- data/versioned.gemspec +61 -0
- metadata +78 -0
data/README.rdoc
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
= versioned
|
2
|
+
|
3
|
+
Simple versioning for MongoMapper
|
4
|
+
|
5
|
+
= installation
|
6
|
+
|
7
|
+
The versioned gem is hosted on gemcutter.org:
|
8
|
+
|
9
|
+
* gem install versioned
|
10
|
+
|
11
|
+
= usage
|
12
|
+
|
13
|
+
class Doc
|
14
|
+
include MongoMapper::Document
|
15
|
+
include Versioned
|
16
|
+
key :title, String
|
17
|
+
end
|
18
|
+
|
19
|
+
@doc = Doc.create(:title=>"v1")
|
20
|
+
@doc.title = "v2"
|
21
|
+
@doc.save
|
22
|
+
|
23
|
+
@doc.revert
|
24
|
+
|
25
|
+
puts @doc.title
|
26
|
+
=> v1
|
27
|
+
|
28
|
+
@doc.title = "v3"
|
29
|
+
@doc.save
|
30
|
+
@doc.version
|
31
|
+
=> 3
|
32
|
+
|
33
|
+
@doc.retrieve_version 2
|
34
|
+
puts @doc.title
|
35
|
+
=> "v2"
|
36
|
+
|
37
|
+
@doc = Doc.find(@doc.id)
|
38
|
+
@doc.title
|
39
|
+
=> "v3"
|
40
|
+
@doc.version
|
41
|
+
=> 3
|
42
|
+
|
43
|
+
== Note on Patches/Pull Requests
|
44
|
+
|
45
|
+
* Fork the project.
|
46
|
+
* Make your feature addition or bug fix.
|
47
|
+
* Add tests for it. This is important so I don't break it in a
|
48
|
+
future version unintentionally.
|
49
|
+
* Commit, do not mess with rakefile, version, or history.
|
50
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
51
|
+
* Send me a pull request. Bonus points for topic branches.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'jeweler'
|
8
|
+
Jeweler::Tasks.new do |g|
|
9
|
+
g.name = 'versioned'
|
10
|
+
g.summary = %(Versioning for MongoMapper)
|
11
|
+
g.description = %(Versioning for MongoMapper)
|
12
|
+
g.email = 'signalstatic@gmail.com'
|
13
|
+
g.homepage = 'http://github.com/twoism/versioned'
|
14
|
+
g.authors = %w(twoism toastyapps jacqui)
|
15
|
+
end
|
16
|
+
Jeweler::GemcutterTasks.new
|
17
|
+
rescue LoadError
|
18
|
+
puts 'Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com'
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::TestTask.new do |t|
|
22
|
+
t.libs = %w(test)
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/version.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
class Version
|
2
|
+
include MongoMapper::Document
|
3
|
+
include Comparable
|
4
|
+
|
5
|
+
key :number, Integer
|
6
|
+
key :versioned_type, String
|
7
|
+
key :versioned_id, ObjectId
|
8
|
+
key :changes, Hash
|
9
|
+
timestamps!
|
10
|
+
|
11
|
+
belongs_to :versioned, :polymorphic => true
|
12
|
+
def changes
|
13
|
+
read_attribute(:changes)
|
14
|
+
end
|
15
|
+
alias_attribute :version, :number
|
16
|
+
|
17
|
+
def <=>(other)
|
18
|
+
number <=> other.number
|
19
|
+
end
|
20
|
+
end
|
data/lib/versioned.rb
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'version'
|
2
|
+
|
3
|
+
module Versioned
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
base.class_eval do
|
7
|
+
versioned
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def versioned(options = {})
|
13
|
+
class_inheritable_accessor :version_only_columns
|
14
|
+
self.version_only_columns = Array(options[:only]).map(&:to_s).uniq if options[:only]
|
15
|
+
class_inheritable_accessor :version_except_columns
|
16
|
+
self.version_except_columns = Array(options[:except]).map(&:to_s).uniq if options[:except]
|
17
|
+
|
18
|
+
many :versions, :as => :versioned, :order => 'number ASC', :dependent => :delete_all do
|
19
|
+
def between(from, to)
|
20
|
+
from_number, to_number = number_at(from), number_at(to)
|
21
|
+
return [] if from_number.nil? || to_number.nil?
|
22
|
+
condition = (from_number == to_number) ? to_number : Range.new(*[from_number, to_number].sort)
|
23
|
+
if condition.is_a?(Range)
|
24
|
+
conditions = {'$gte' => condition.first, '$lte' => condition.last}
|
25
|
+
else
|
26
|
+
conditions = condition
|
27
|
+
end
|
28
|
+
find(:all,
|
29
|
+
:number => conditions,
|
30
|
+
:order => "number #{(from_number > to_number) ? 'DESC' : 'ASC'}"
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def at(value)
|
35
|
+
case value
|
36
|
+
when Version then value
|
37
|
+
when Numeric then find_by_number(value.floor)
|
38
|
+
when Symbol then respond_to?(value) ? send(value) : nil
|
39
|
+
when Date, Time then last(:created_at => {'$lte' => value.to_time})
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def number_at(value)
|
44
|
+
case value
|
45
|
+
when Version then value.number
|
46
|
+
when Numeric then value.floor
|
47
|
+
when Symbol, Date, Time then at(value).try(:number)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
after_create :create_initial_version
|
53
|
+
after_update :create_initial_version, :if => :needs_initial_version?
|
54
|
+
after_update :create_version, :if => :needs_version?
|
55
|
+
|
56
|
+
include InstanceMethods
|
57
|
+
alias_method_chain :reload, :versions
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module InstanceMethods
|
62
|
+
private
|
63
|
+
def versioned_columns
|
64
|
+
case
|
65
|
+
when version_only_columns then self.class.keys.keys & version_only_columns
|
66
|
+
when version_except_columns then self.class.keys.keys - version_except_columns
|
67
|
+
else self.class.keys.keys
|
68
|
+
end - %w(created_at created_on updated_at updated_on)
|
69
|
+
end
|
70
|
+
|
71
|
+
def needs_initial_version?
|
72
|
+
versions.empty?
|
73
|
+
end
|
74
|
+
|
75
|
+
def needs_version?
|
76
|
+
!(versioned_columns & changed).empty?
|
77
|
+
end
|
78
|
+
|
79
|
+
def reset_version(new_version = nil)
|
80
|
+
@last_version = nil if new_version.nil?
|
81
|
+
@version = new_version
|
82
|
+
end
|
83
|
+
|
84
|
+
def create_initial_version
|
85
|
+
versions.create(:changes => nil, :number => 1)
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_version
|
89
|
+
versions << Version.create(:changes => changes.slice(*versioned_columns), :number => (last_version + 1))
|
90
|
+
reset_version
|
91
|
+
end
|
92
|
+
|
93
|
+
public
|
94
|
+
def version
|
95
|
+
@version ||= last_version
|
96
|
+
end
|
97
|
+
|
98
|
+
def last_version
|
99
|
+
@last_version ||= versions.inject(1){|max, version| version.number > max ? version.number : max}
|
100
|
+
end
|
101
|
+
|
102
|
+
def reverted?
|
103
|
+
version != last_version
|
104
|
+
end
|
105
|
+
|
106
|
+
def reload_with_versions(*args)
|
107
|
+
reset_version
|
108
|
+
reload_without_versions(*args)
|
109
|
+
end
|
110
|
+
|
111
|
+
def changes_between(from, to)
|
112
|
+
from_number, to_number = versions.number_at(from), versions.number_at(to)
|
113
|
+
return {} if from_number == to_number
|
114
|
+
chain = versions.between(from_number, to_number)
|
115
|
+
return {} if chain.empty?
|
116
|
+
|
117
|
+
backward = chain.first > chain.last
|
118
|
+
backward ? chain.pop : chain.shift
|
119
|
+
|
120
|
+
chain.inject({}) do |changes, version|
|
121
|
+
version.changes.each do |attribute, change|
|
122
|
+
change.reverse! if backward
|
123
|
+
new_change = [changes.fetch(attribute, change).first, change.last]
|
124
|
+
changes.update(attribute => new_change)
|
125
|
+
end
|
126
|
+
changes
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def revert
|
131
|
+
revert_to self.version -1
|
132
|
+
end
|
133
|
+
|
134
|
+
def retrieve_version n
|
135
|
+
versions.find_by_number(n).changes.each do |n,v|
|
136
|
+
self.send("#{n.to_sym}=",v.first)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def revert_to(value)
|
141
|
+
to_number = versions.number_at(value)
|
142
|
+
changes = changes_between(version, to_number)
|
143
|
+
return version if changes.empty?
|
144
|
+
|
145
|
+
changes.each do |attribute, change|
|
146
|
+
write_attribute(attribute, change.last)
|
147
|
+
end
|
148
|
+
|
149
|
+
reset_version(to_number)
|
150
|
+
end
|
151
|
+
|
152
|
+
def revert_to!(value)
|
153
|
+
revert_to(value)
|
154
|
+
reset_version if saved = save
|
155
|
+
saved
|
156
|
+
end
|
157
|
+
|
158
|
+
def latest_changes
|
159
|
+
return {} if version.nil? || version == 1
|
160
|
+
versions.at(version).changes
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
Binary file
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BetweenTest < Test::Unit::TestCase
|
4
|
+
context 'The number of versions between' do
|
5
|
+
setup do
|
6
|
+
@user = User.create(:name => 'Steve Richert')
|
7
|
+
@version = @user.version
|
8
|
+
@valid = [@version, 0, 1_000_000, :first, :last, 1.day.since(@user.created_at), @user.versions.first]
|
9
|
+
@invalid = [nil, :bogus, 'bogus', Date.parse('0001-12-25')]
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'the current version and the current version' do
|
13
|
+
should 'equal one' do
|
14
|
+
assert_equal 1, @user.versions.between(@version, @version).size
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'the current version and a valid value' do
|
19
|
+
should 'not equal zero' do
|
20
|
+
@valid.each do |valid|
|
21
|
+
assert_not_equal 0, @user.versions.between(@version, valid).size
|
22
|
+
assert_not_equal 0, @user.versions.between(valid, @version).size
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'the current version and an invalid value' do
|
28
|
+
should 'equal zero' do
|
29
|
+
@invalid.each do |invalid|
|
30
|
+
assert_equal 0, @user.versions.between(@version, invalid).size
|
31
|
+
assert_equal 0, @user.versions.between(invalid, @version).size
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'two invalid values' do
|
37
|
+
should 'equal zero' do
|
38
|
+
@invalid.each do |first|
|
39
|
+
@invalid.each do |second|
|
40
|
+
assert_equal 0, @user.versions.between(first, second).size
|
41
|
+
assert_equal 0, @user.versions.between(second, first).size
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'a valid value and an invalid value' do
|
48
|
+
should 'equal zero' do
|
49
|
+
@valid.each do |valid|
|
50
|
+
@invalid.each do |invalid|
|
51
|
+
assert_equal 0, @user.versions.between(valid, invalid).size
|
52
|
+
assert_equal 0, @user.versions.between(invalid, valid).size
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ChangesTest < Test::Unit::TestCase
|
4
|
+
context "A version's changes" do
|
5
|
+
setup do
|
6
|
+
@user = User.create(:name => 'Steve Richert')
|
7
|
+
end
|
8
|
+
|
9
|
+
should "initially be blank" do
|
10
|
+
assert @user.versions.first.changes.blank?
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'contain all changed attributes' do
|
14
|
+
@user.name = 'Steve Jobs'
|
15
|
+
changes = @user.changes
|
16
|
+
@user.save
|
17
|
+
assert_equal changes, @user.versions.last.changes.slice(*changes.keys)
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'contain no more than the changed attributes and timestamps' do
|
21
|
+
timestamps = %w(created_at created_on updated_at updated_on)
|
22
|
+
@user.name = 'Steve Jobs'
|
23
|
+
changes = @user.changes
|
24
|
+
@user.save
|
25
|
+
assert_equal changes, @user.versions.last.changes.except(*timestamps)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ComparableTest < Test::Unit::TestCase
|
4
|
+
context 'A comparable version' do
|
5
|
+
setup do
|
6
|
+
@version_1 = Version.new(:number => 1)
|
7
|
+
@version_2 = Version.new(:number => 2)
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'equal itself' do
|
11
|
+
assert @version_1 == @version_1
|
12
|
+
assert @version_2 == @version_2
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with version number 1' do
|
16
|
+
should 'not equal a version with version number 2' do
|
17
|
+
assert @version_1 != @version_2
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'be less than a version with version number 2' do
|
21
|
+
assert @version_1 < @version_2
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with version number 2' do
|
26
|
+
should 'not equal a version with version number 1' do
|
27
|
+
assert @version_2 != @version_1
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'be greater than a version with version number 1' do
|
31
|
+
assert @version_2 > @version_1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CreationTest < Test::Unit::TestCase
|
4
|
+
context 'The number of versions' do
|
5
|
+
setup do
|
6
|
+
@name = 'Steve Richert'
|
7
|
+
@user = User.create(:name => @name)
|
8
|
+
@count = @user.versions.count
|
9
|
+
end
|
10
|
+
|
11
|
+
should 'initially equal one' do
|
12
|
+
assert_equal 1, @count
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'not increase when no changes are made in an update' do
|
16
|
+
@user.name = @name
|
17
|
+
assert_equal @count, @user.versions.count
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'not increase when no changes are made before a save' do
|
21
|
+
@user.save
|
22
|
+
assert_equal @count, @user.versions.count
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'not increase when reverting to the current version' do
|
26
|
+
@user.revert_to!(@user.version)
|
27
|
+
assert_equal @count, @user.versions.count
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'after an update' do
|
31
|
+
setup do
|
32
|
+
@initial_count = @count
|
33
|
+
@name = 'Steve Jobs'
|
34
|
+
@user.name = @name
|
35
|
+
@user.save
|
36
|
+
@count = @user.versions.count
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'increase by one' do
|
40
|
+
assert_equal @initial_count + 1, @count
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'increase by one when reverted' do
|
44
|
+
@user.revert_to!(:first)
|
45
|
+
assert_equal @count + 1, @user.versions.count
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'not increase until a revert is saved' do
|
49
|
+
@user.revert_to(:first)
|
50
|
+
assert_equal @count, @user.versions.count
|
51
|
+
@user.save
|
52
|
+
assert_not_equal @count, @user.versions.count
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
should "retrieve a specific version without reverting it" do
|
57
|
+
@user.name = "Hoge"
|
58
|
+
@user.save
|
59
|
+
version_count = @user.versions.size
|
60
|
+
@user.retrieve_version 2
|
61
|
+
assert_equal version_count, @user.versions.size
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'after multiple updates' do
|
65
|
+
setup do
|
66
|
+
@initial_count = @count
|
67
|
+
@new_name = 'Steve Jobs'
|
68
|
+
@user.name = @new_name
|
69
|
+
@user.name = @name
|
70
|
+
@count = @user.versions.count
|
71
|
+
end
|
72
|
+
|
73
|
+
should 'not increase when reverting to an identical version' do
|
74
|
+
@user.revert_to!(:first)
|
75
|
+
assert_equal @count, @user.versions.count
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class LatestChangesTest < Test::Unit::TestCase
|
4
|
+
context "A created model's last changes" do
|
5
|
+
setup do
|
6
|
+
@user = User.create(:name => 'Steve Richert')
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'be blank' do
|
10
|
+
assert @user.latest_changes.blank?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "An updated model's last changes" do
|
15
|
+
setup do
|
16
|
+
@user = User.create(:name => 'Steve Richert')
|
17
|
+
@previous_attributes = @user.attributes
|
18
|
+
@user.name = 'Steve Jobs'
|
19
|
+
@current_attributes = @user.attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'values of two-element arrays with unique values' do
|
23
|
+
@user.latest_changes.values.each do |value|
|
24
|
+
assert_kind_of Array, value
|
25
|
+
assert_equal 2, value.size
|
26
|
+
assert_equal value, value.uniq
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'begin with the previous attribute values' do
|
31
|
+
changes = @user.latest_changes.inject({}){|h,(k,v)| h.update(k => v.first) }
|
32
|
+
previous = @previous_attributes.slice(*@user.latest_changes.keys)
|
33
|
+
assert_equal previous, changes
|
34
|
+
end
|
35
|
+
|
36
|
+
should 'end with the current attribute values' do
|
37
|
+
changes = @user.latest_changes.inject({}){|h,(k,v)| h.update(k => v.last) }
|
38
|
+
current = @current_attributes.slice(*@user.latest_changes.keys)
|
39
|
+
assert_equal current, changes
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/revert_test.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class RevertTest < Test::Unit::TestCase
|
4
|
+
context 'A model reversion' do
|
5
|
+
setup do
|
6
|
+
@user, @attributes, @times = User.new, {}, {}
|
7
|
+
names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs']
|
8
|
+
time = names.size.hours.ago
|
9
|
+
names.each do |name|
|
10
|
+
@user.update_attributes({:name => name})
|
11
|
+
@attributes[@user.version] = @user.attributes
|
12
|
+
time += 1.hour
|
13
|
+
@user.versions.last.update_attributes({:created_at => time})
|
14
|
+
@times[@user.version] = time
|
15
|
+
end
|
16
|
+
@first_version, @last_version = @attributes.keys.min, @attributes.keys.max
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'do nothing for a non-existent version' do
|
20
|
+
attributes = @user.attributes
|
21
|
+
@user.revert_to!(nil)
|
22
|
+
assert_equal attributes, @user.attributes
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'return the new version number' do
|
26
|
+
new_version = @user.revert_to(@first_version)
|
27
|
+
assert_equal @first_version, new_version
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'change the version number when saved' do
|
31
|
+
current_version = @user.version
|
32
|
+
@user.revert_to!(@first_version)
|
33
|
+
assert_not_equal current_version, @user.version
|
34
|
+
end
|
35
|
+
|
36
|
+
should 'be able to target the first version' do
|
37
|
+
@user.revert_to(:first)
|
38
|
+
assert_equal @first_version, @user.version
|
39
|
+
end
|
40
|
+
|
41
|
+
should 'be able to target the last version' do
|
42
|
+
@user.revert_to(:last)
|
43
|
+
assert_equal @last_version, @user.version
|
44
|
+
end
|
45
|
+
|
46
|
+
should 'do nothing for a non-existent method name' do
|
47
|
+
current_version = @user.version
|
48
|
+
@user.revert_to(:bogus)
|
49
|
+
assert_equal current_version, @user.version
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'be able to target a version number' do
|
53
|
+
@user.revert_to(1)
|
54
|
+
assert 1, @user.version
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'be able to target a date and time' do
|
58
|
+
@times.each do |version, time|
|
59
|
+
@user.revert_to(time + 1.second)
|
60
|
+
assert_equal version, @user.version
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
should 'be able to target a version object' do
|
65
|
+
@user.versions.each do |version|
|
66
|
+
@user.revert_to(version)
|
67
|
+
assert_equal version.number, @user.version
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
should "correctly roll back the model's attributes" do
|
72
|
+
timestamps = %w(created_at created_on updated_at updated_on)
|
73
|
+
@attributes.each do |version, attributes|
|
74
|
+
@user.revert_to!(version)
|
75
|
+
assert_equal attributes.except(*timestamps), @user.attributes.except(*timestamps)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/test/schema.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MongoMapper.connection = Mongo::Connection.new('127.0.0.1')
|
2
|
+
MongoMapper.database = "testing_versioned"
|
3
|
+
|
4
|
+
class User
|
5
|
+
include MongoMapper::Document
|
6
|
+
include Versioned
|
7
|
+
key :first_name, String
|
8
|
+
key :last_name, String
|
9
|
+
timestamps!
|
10
|
+
|
11
|
+
def name
|
12
|
+
[first_name, last_name].compact.join(' ')
|
13
|
+
end
|
14
|
+
|
15
|
+
def name=(names)
|
16
|
+
self[:first_name], self[:last_name] = names.split(' ', 2)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
User.destroy_all
|
21
|
+
Version.destroy_all
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
$: << File.dirname(__FILE__)
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'shoulda'
|
7
|
+
require 'mongo_mapper'
|
8
|
+
require 'versioned'
|
9
|
+
require 'schema'
|
10
|
+
begin; require 'redgreen'; rescue LoadError; end
|
data/versioned.gemspec
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{versioned}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["twoism", "toastyapps", "jacqui"]
|
12
|
+
s.date = %q{2009-12-17}
|
13
|
+
s.description = %q{Versioning for MongoMapper}
|
14
|
+
s.email = %q{signalstatic@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"README.rdoc",
|
20
|
+
"Rakefile",
|
21
|
+
"VERSION",
|
22
|
+
"lib/version.rb",
|
23
|
+
"lib/versioned.rb",
|
24
|
+
"pkg/versioned-0.1.0.gem",
|
25
|
+
"test/between_test.rb",
|
26
|
+
"test/changes_test.rb",
|
27
|
+
"test/comparable_test.rb",
|
28
|
+
"test/creation_test.rb",
|
29
|
+
"test/latest_changes_test.rb",
|
30
|
+
"test/revert_test.rb",
|
31
|
+
"test/schema.rb",
|
32
|
+
"test/test_helper.rb",
|
33
|
+
"versioned.gemspec"
|
34
|
+
]
|
35
|
+
s.homepage = %q{http://github.com/twoism/versioned}
|
36
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
s.rubygems_version = %q{1.3.5}
|
39
|
+
s.summary = %q{Versioning for MongoMapper}
|
40
|
+
s.test_files = [
|
41
|
+
"test/between_test.rb",
|
42
|
+
"test/changes_test.rb",
|
43
|
+
"test/comparable_test.rb",
|
44
|
+
"test/creation_test.rb",
|
45
|
+
"test/latest_changes_test.rb",
|
46
|
+
"test/revert_test.rb",
|
47
|
+
"test/schema.rb",
|
48
|
+
"test/test_helper.rb"
|
49
|
+
]
|
50
|
+
|
51
|
+
if s.respond_to? :specification_version then
|
52
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
53
|
+
s.specification_version = 3
|
54
|
+
|
55
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
56
|
+
else
|
57
|
+
end
|
58
|
+
else
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: versioned
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- twoism
|
8
|
+
- toastyapps
|
9
|
+
- jacqui
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
|
14
|
+
date: 2009-12-17 00:00:00 -05:00
|
15
|
+
default_executable:
|
16
|
+
dependencies: []
|
17
|
+
|
18
|
+
description: Versioning for MongoMapper
|
19
|
+
email: signalstatic@gmail.com
|
20
|
+
executables: []
|
21
|
+
|
22
|
+
extensions: []
|
23
|
+
|
24
|
+
extra_rdoc_files:
|
25
|
+
- README.rdoc
|
26
|
+
files:
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- lib/version.rb
|
31
|
+
- lib/versioned.rb
|
32
|
+
- pkg/versioned-0.1.0.gem
|
33
|
+
- test/between_test.rb
|
34
|
+
- test/changes_test.rb
|
35
|
+
- test/comparable_test.rb
|
36
|
+
- test/creation_test.rb
|
37
|
+
- test/latest_changes_test.rb
|
38
|
+
- test/revert_test.rb
|
39
|
+
- test/schema.rb
|
40
|
+
- test/test_helper.rb
|
41
|
+
- versioned.gemspec
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/twoism/versioned
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options:
|
48
|
+
- --charset=UTF-8
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.3.5
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Versioning for MongoMapper
|
70
|
+
test_files:
|
71
|
+
- test/between_test.rb
|
72
|
+
- test/changes_test.rb
|
73
|
+
- test/comparable_test.rb
|
74
|
+
- test/creation_test.rb
|
75
|
+
- test/latest_changes_test.rb
|
76
|
+
- test/revert_test.rb
|
77
|
+
- test/schema.rb
|
78
|
+
- test/test_helper.rb
|