mrkurt-versioned 0.1.0 → 0.1.1

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/.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