mrkurt-versioned 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.1.1
data/lib/version.rb CHANGED
@@ -17,4 +17,20 @@ class Version
17
17
  def <=>(other)
18
18
  number <=> other.number
19
19
  end
20
+
21
+ def previous
22
+ find_related(:first, :number => {:$lt => number}, :order => 'number.desc')
23
+ end
24
+
25
+ def next
26
+ find_related(:first, :number => {:$gt => number}, :order => 'number.asc')
27
+ end
28
+
29
+ protected
30
+
31
+ def find_related(*args)
32
+ options = args.extract_options!
33
+ params = options.merge(:versioned_id => versioned_id, :versioned_type => versioned_type)
34
+ self.class.find(args.first, params)
35
+ end
20
36
  end
data/lib/versioned.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'version'
2
2
 
3
3
  module Versioned
4
+ class StaleDocumentError < MongoMapper::MongoMapperError; end
4
5
  def self.included(base)
5
6
  base.extend ClassMethods
6
7
  base.class_eval do
@@ -8,7 +9,58 @@ module Versioned
8
9
  end
9
10
  end
10
11
 
12
+ module LockingInstanceMethods
13
+ private
14
+ #new? isn't working
15
+ def is_new_document?
16
+ (read_attribute(self.version_lock_key).blank? && changes[self.version_lock_key.to_s].blank?) ||
17
+ (changes[self.version_lock_key.to_s] && changes[self.version_lock_key.to_s].first.blank?)
18
+ end
19
+ def prep_lock_version
20
+ old = read_attribute(self.version_lock_key)
21
+ if !is_new_document? || old.blank?
22
+ v = (Time.now.to_f * 1000).ceil.to_s
23
+ write_attribute self.version_lock_key, v
24
+ end
25
+
26
+ old
27
+ end
28
+
29
+ def save_to_collection(options = {})
30
+ current_version = prep_lock_version
31
+ if is_new_document?
32
+ collection.insert(to_mongo, :safe => true)
33
+ else
34
+ selector = { :_id => read_attribute(:_id), self.version_lock_key => current_version }
35
+ #can't upsert, safe must be true for this to work
36
+ result = collection.update(selector, to_mongo, :upsert => false, :safe => true)
37
+
38
+ if result.is_a?(Array) && result[0][0]['updatedExisting'] == false
39
+ write_attribute self.version_lock_key, current_version
40
+ raise StaleDocumentError.new
41
+ elsif !result.is_a?(Array)
42
+ #wtf?
43
+ write_attribute self.version_lock_key, current_version
44
+ raise "Unexpected result from mongo"
45
+ end
46
+
47
+ selector[:_id]
48
+ end
49
+ end
50
+ end
11
51
  module ClassMethods
52
+ def locking!(options = {})
53
+ include(LockingInstanceMethods)
54
+ class_inheritable_accessor :version_lock_key
55
+ self.version_lock_key = options[:key] || :lock_version
56
+ key self.version_lock_key, Integer
57
+
58
+ if self.respond_to?(:version_use_key)
59
+ self.version_use_key = self.version_lock_key
60
+ (self.version_except_columns ||= []) << self.version_lock_key.to_s #don't version the lock key
61
+ end
62
+ end
63
+
12
64
  def versioned(options = {})
13
65
  class_inheritable_accessor :version_only_columns
14
66
  self.version_only_columns = Array(options[:only]).map(&:to_s).uniq if options[:only]
@@ -59,6 +111,7 @@ module Versioned
59
111
  include InstanceMethods
60
112
  alias_method_chain :reload, :versions
61
113
  end
114
+
62
115
  end
63
116
 
64
117
  module InstanceMethods
@@ -137,7 +190,7 @@ module Versioned
137
190
  end
138
191
 
139
192
  def revert
140
- revert_to self.version -1
193
+ revert_to self.versions.at(self.version).previous
141
194
  end
142
195
 
143
196
  def retrieve_version n
@@ -165,7 +218,7 @@ module Versioned
165
218
  end
166
219
 
167
220
  def latest_changes
168
- return {} if version.nil? || version == 1
221
+ return {} if version.nil?
169
222
  versions.at(version).changes
170
223
  end
171
224
  end
@@ -0,0 +1,67 @@
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{mrkurt-versioned}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["twoism", "toastyapps", "jacqui", "mrkurt"]
12
+ s.date = %q{2010-01-16}
13
+ s.description = %q{Versioning for MongoMapper}
14
+ s.email = %q{mrkurt@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "lib/version.rb",
24
+ "lib/versioned.rb",
25
+ "mrkurt-versioned.gemspec",
26
+ "pkg/versioned-0.1.0.gem",
27
+ "test/between_test.rb",
28
+ "test/changes_test.rb",
29
+ "test/comparable_test.rb",
30
+ "test/creation_test.rb",
31
+ "test/latest_changes_test.rb",
32
+ "test/lock_test.rb",
33
+ "test/revert_test.rb",
34
+ "test/schema.rb",
35
+ "test/specified_version_key_test.rb",
36
+ "test/test_helper.rb",
37
+ "versioned.gemspec"
38
+ ]
39
+ s.homepage = %q{http://github.com/mrkurt/versioned}
40
+ s.rdoc_options = ["--charset=UTF-8"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = %q{1.3.5}
43
+ s.summary = %q{Versioning for MongoMapper}
44
+ s.test_files = [
45
+ "test/test_helper.rb",
46
+ "test/between_test.rb",
47
+ "test/comparable_test.rb",
48
+ "test/revert_test.rb",
49
+ "test/creation_test.rb",
50
+ "test/latest_changes_test.rb",
51
+ "test/specified_version_key_test.rb",
52
+ "test/schema.rb",
53
+ "test/lock_test.rb",
54
+ "test/changes_test.rb"
55
+ ]
56
+
57
+ if s.respond_to? :specification_version then
58
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
+ s.specification_version = 3
60
+
61
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
62
+ else
63
+ end
64
+ else
65
+ end
66
+ end
67
+
data/test/lock_test.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'test_helper'
2
+
3
+ class LockTest < Test::Unit::TestCase
4
+ context 'An unversioned model with locks' do
5
+ setup do
6
+ @user = UnversionedLockableUser.create(:name => 'Kurt')
7
+ end
8
+
9
+ should 'have a lock_version field' do
10
+ assert_not_nil @user.lock_version
11
+ end
12
+
13
+ should 'save just fine when no conflicts' do
14
+ @user.name = 'Bob'
15
+ assert @user.save
16
+ end
17
+
18
+ should 'save just fine when given the proper lock version' do
19
+ u = UnversionedLockableUser.find(@user.id)
20
+ @user.update_attributes(:name => 'Bill')
21
+
22
+ assert u.update_attributes(:name => 'Jose', :lock_version => @user.lock_version)
23
+ end
24
+
25
+ should 'not save when given the wrong version' do
26
+ assert_raise Versioned::StaleDocumentError do
27
+ @user.update_attributes(:name => 'Bob', :lock_version => 1111)
28
+ end
29
+
30
+ # lock_version should match what we passed in
31
+ assert_equal 1111, @user.lock_version
32
+ end
33
+ end
34
+ context 'A versioned model with locks' do
35
+ setup do
36
+ @user = LockableUser.create(:name => 'Kurt', :required_field => 'woo!')
37
+ end
38
+
39
+ should 'have a lock_version field' do
40
+ assert_not_nil @user.lock_version
41
+ assert_equal @user.version, @user.lock_version
42
+ end
43
+
44
+ should 'save just fine when no conflicts' do
45
+ @user.name = 'Bob'
46
+ assert @user.save
47
+ end
48
+
49
+ should 'save just fine when given the proper lock version' do
50
+ u = LockableUser.find(@user.id)
51
+ @user.update_attributes(:name => 'Bill')
52
+
53
+ assert u.update_attributes(:name => 'Jose', :lock_version => @user.lock_version)
54
+ end
55
+
56
+ should 'not save when given the wrong version' do
57
+ assert_raise Versioned::StaleDocumentError do
58
+ @user.update_attributes(:name => 'Bob', :lock_version => 1111)
59
+ end
60
+
61
+ # lock_version should match what we passed in
62
+ assert_equal 1111, @user.lock_version
63
+ end
64
+
65
+ should 'be revertable with the lock version' do
66
+ v = @user.lock_version
67
+ name = @user.name
68
+ @user.update_attributes(:name => "Schlub")
69
+
70
+ assert_not_equal v, @user.lock_version
71
+
72
+ @user.revert_to(v)
73
+
74
+ assert_equal name, @user.name
75
+ assert_not_equal v, @user.lock_version #shouldn't have reverted version
76
+ end
77
+
78
+ should 'accept a specified version on create' do
79
+ u = LockableUser.create(:name => 'Burt', :required_field => 'woo!', :lock_version => 1111)
80
+ assert_equal 1111, u.lock_version
81
+ end
82
+
83
+ should "have same lock_version when validation fails" do
84
+ @user.required_field = nil
85
+ v = @user.lock_version
86
+ result = @user.save
87
+ assert !result
88
+ assert_equal v, @user.lock_version
89
+ end
90
+ end
91
+ end
data/test/schema.rb CHANGED
@@ -32,5 +32,24 @@ class Loser
32
32
  end
33
33
  end
34
34
 
35
+ class LockableUser
36
+ include MongoMapper::Document
37
+ include Versioned
38
+ locking!
39
+
40
+ key :name, String
41
+ key :required_field, String
42
+ validates_presence_of :required_field
43
+ end
44
+
45
+ class UnversionedLockableUser
46
+ include MongoMapper::Document
47
+ extend Versioned::ClassMethods
48
+ locking!
49
+
50
+ key :name, String
51
+ end
52
+
35
53
  User.destroy_all
54
+ Loser.destroy_all
36
55
  Version.destroy_all
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class SpecifiedVersionKey < Test::Unit::TestCase
4
- context 'A specified version key' do
4
+ context 'A model with a specified version key' do
5
5
  setup do
6
6
  @name = "Blah"
7
7
  @loser = Loser.create(:name => @name)
@@ -38,7 +38,8 @@ class SpecifiedVersionKey < Test::Unit::TestCase
38
38
  end
39
39
 
40
40
  should 'revert properly' do
41
- @loser.revert_to!(@initial_version)
41
+ @loser.revert
42
+ @loser.save!
42
43
  assert_equal @initial_name, @loser.name
43
44
  assert_equal @count + 1, @loser.versions.count
44
45
  assert_not_equal @version, @loser.version
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mrkurt-versioned
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - twoism
@@ -12,7 +12,7 @@ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
14
 
15
- date: 2010-01-09 00:00:00 -06:00
15
+ date: 2010-01-16 00:00:00 -06:00
16
16
  default_executable:
17
17
  dependencies: []
18
18
 
@@ -25,17 +25,20 @@ extensions: []
25
25
  extra_rdoc_files:
26
26
  - README.rdoc
27
27
  files:
28
+ - .gitignore
28
29
  - README.rdoc
29
30
  - Rakefile
30
31
  - VERSION
31
32
  - lib/version.rb
32
33
  - lib/versioned.rb
34
+ - mrkurt-versioned.gemspec
33
35
  - pkg/versioned-0.1.0.gem
34
36
  - test/between_test.rb
35
37
  - test/changes_test.rb
36
38
  - test/comparable_test.rb
37
39
  - test/creation_test.rb
38
40
  - test/latest_changes_test.rb
41
+ - test/lock_test.rb
39
42
  - test/revert_test.rb
40
43
  - test/schema.rb
41
44
  - test/specified_version_key_test.rb
@@ -78,4 +81,5 @@ test_files:
78
81
  - test/latest_changes_test.rb
79
82
  - test/specified_version_key_test.rb
80
83
  - test/schema.rb
84
+ - test/lock_test.rb
81
85
  - test/changes_test.rb