dm-is-versioned 0.9.11 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{History.txt → History.rdoc} +4 -0
- data/Manifest.txt +2 -2
- data/{README.txt → README.rdoc} +0 -0
- data/Rakefile +2 -3
- data/lib/dm-is-versioned.rb +4 -9
- data/lib/dm-is-versioned/is/version.rb +1 -1
- data/lib/dm-is-versioned/is/versioned.rb +45 -39
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +8 -4
- data/spec/versioned_spec.rb +51 -112
- data/tasks/install.rb +1 -1
- data/tasks/spec.rb +4 -4
- metadata +14 -21
data/Manifest.txt
CHANGED
data/{README.txt → README.rdoc}
RENAMED
File without changes
|
data/Rakefile
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require 'rubygems'
|
3
2
|
|
4
3
|
ROOT = Pathname(__FILE__).dirname.expand_path
|
5
4
|
JRUBY = RUBY_PLATFORM =~ /java/
|
@@ -14,10 +13,10 @@ GEM_NAME = 'dm-is-versioned'
|
|
14
13
|
GEM_VERSION = DataMapper::Is::Versioned::VERSION
|
15
14
|
GEM_DEPENDENCIES = [['dm-core', GEM_VERSION]]
|
16
15
|
GEM_CLEAN = %w[ log pkg coverage ]
|
17
|
-
GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.
|
16
|
+
GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.rdoc LICENSE TODO History.rdoc ] }
|
18
17
|
|
19
18
|
PROJECT_NAME = 'datamapper'
|
20
|
-
PROJECT_URL = "http://github.com/
|
19
|
+
PROJECT_URL = "http://github.com/datamapper/dm-more/tree/master/#{GEM_NAME}"
|
21
20
|
PROJECT_DESCRIPTION = PROJECT_SUMMARY = 'DataMapper plugin enabling simple versioning of models'
|
22
21
|
|
23
22
|
[ ROOT, ROOT.parent ].each do |dir|
|
data/lib/dm-is-versioned.rb
CHANGED
@@ -1,14 +1,9 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
gem 'dm-core', '0.9.11'
|
5
|
-
require 'dm-core'
|
6
|
-
|
7
|
-
require Pathname(__FILE__).dirname.expand_path / 'dm-is-versioned' / 'is' / 'versioned.rb'
|
1
|
+
require 'dm-is-versioned/is/versioned'
|
2
|
+
require 'dm-is-versioned/is/version'
|
8
3
|
|
9
4
|
# Include the plugin in Resource
|
10
5
|
module DataMapper
|
11
6
|
module Model
|
12
7
|
include DataMapper::Is::Versioned
|
13
|
-
end
|
14
|
-
end
|
8
|
+
end
|
9
|
+
end
|
@@ -45,54 +45,62 @@ module DataMapper
|
|
45
45
|
#
|
46
46
|
# TODO: enable replacing a current version with an old version.
|
47
47
|
module Versioned
|
48
|
-
|
49
48
|
def is_versioned(options = {})
|
50
|
-
on = options[:on]
|
51
|
-
|
52
|
-
class << self; self end.class_eval do
|
53
|
-
define_method :const_missing do |name|
|
54
|
-
storage_name = Extlib::Inflection.tableize(self.name + "Version")
|
55
|
-
model = DataMapper::Model.new(storage_name)
|
56
|
-
|
57
|
-
if name == :Version
|
58
|
-
properties.each do |property|
|
59
|
-
options = property.options
|
60
|
-
options[:key] = true if property.name == on || options[:serial] == true
|
61
|
-
options[:serial] = false
|
62
|
-
model.property property.name, property.type, options
|
63
|
-
end
|
49
|
+
@on = on = options[:on]
|
64
50
|
|
65
|
-
|
66
|
-
else
|
67
|
-
super(name)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
self.after_class_method :auto_migrate! do
|
51
|
+
after_class_method :auto_migrate! do |retval|
|
73
52
|
self::Version.auto_migrate!
|
74
53
|
end
|
75
54
|
|
76
|
-
|
55
|
+
after_class_method :auto_upgrade! do |retval|
|
77
56
|
self::Version.auto_upgrade!
|
78
57
|
end
|
79
58
|
|
80
|
-
|
81
|
-
|
59
|
+
properties.each do |property|
|
60
|
+
name = property.name
|
61
|
+
before "#{name}=".to_sym do
|
62
|
+
unless (value = property.get(self)).nil? || pending_version_attributes.key?(name)
|
63
|
+
pending_version_attributes[name] = value
|
64
|
+
end
|
65
|
+
end
|
82
66
|
end
|
83
67
|
|
84
|
-
|
85
|
-
if
|
86
|
-
|
87
|
-
|
68
|
+
after :update do |retval|
|
69
|
+
if retval && pending_version_attributes.key?(on)
|
70
|
+
model::Version.create(attributes.merge(pending_version_attributes))
|
71
|
+
pending_version_attributes.clear
|
88
72
|
end
|
89
73
|
|
90
|
-
|
74
|
+
retval
|
91
75
|
end
|
92
76
|
|
93
|
-
|
77
|
+
extend ClassMethods
|
78
|
+
include InstanceMethods
|
94
79
|
end
|
95
80
|
|
81
|
+
module ClassMethods
|
82
|
+
def const_missing(name)
|
83
|
+
if name == :Version
|
84
|
+
model = DataMapper::Model.new
|
85
|
+
|
86
|
+
properties.each do |property|
|
87
|
+
type = property.type
|
88
|
+
type = Class if type == DataMapper::Types::Discriminator
|
89
|
+
|
90
|
+
options = property.options.merge(
|
91
|
+
:key => property.name == @on,
|
92
|
+
:serial => false
|
93
|
+
)
|
94
|
+
|
95
|
+
model.property(property.name, type, options)
|
96
|
+
end
|
97
|
+
|
98
|
+
const_set(name, model)
|
99
|
+
else
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end # ClassMethods
|
96
104
|
|
97
105
|
module InstanceMethods
|
98
106
|
##
|
@@ -114,14 +122,12 @@ module DataMapper
|
|
114
122
|
# --
|
115
123
|
# @return <Collection>
|
116
124
|
def versions
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
version.all(query)
|
125
|
+
version_model = model.const_get(:Version)
|
126
|
+
query = model.key.zip(key).map { |p, v| [ p.name, v ] }.to_hash
|
127
|
+
query.merge(:order => version_model.key.map { |k| k.name.desc })
|
128
|
+
version_model.all(query)
|
122
129
|
end
|
123
|
-
end
|
124
|
-
|
130
|
+
end # InstanceMethods
|
125
131
|
end # Versioned
|
126
132
|
end # Is
|
127
133
|
end # DataMapper
|
data/spec/spec.opts
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
require 'pathname'
|
2
1
|
require 'rubygems'
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
# Use local dm-core if running from a typical dev checkout.
|
4
|
+
lib = File.join('..', '..', 'dm-core', 'lib')
|
5
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib)
|
6
|
+
require 'dm-core'
|
6
7
|
|
7
|
-
|
8
|
+
# Support running specs with 'rake spec' and 'spec'
|
9
|
+
$LOAD_PATH.unshift('lib') unless $LOAD_PATH.include?('lib')
|
10
|
+
|
11
|
+
require 'dm-is-versioned'
|
8
12
|
|
9
13
|
def load_driver(name, default_uri)
|
10
14
|
return false if ENV['ADAPTER'] != name.to_s
|
data/spec/versioned_spec.rb
CHANGED
@@ -1,184 +1,123 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
class Story
|
4
4
|
include DataMapper::Resource
|
5
5
|
|
6
|
-
property :id,
|
7
|
-
property :title,
|
6
|
+
property :id, Serial
|
7
|
+
property :title, String
|
8
8
|
property :updated_at, DateTime
|
9
|
+
property :type, Discriminator
|
9
10
|
|
10
11
|
before :save do
|
11
12
|
# For the sake of testing, make sure the updated_at is always unique
|
12
|
-
|
13
|
-
|
13
|
+
if dirty?
|
14
|
+
time = self.updated_at ? self.updated_at + 1 : Time.now
|
15
|
+
self.updated_at = time
|
16
|
+
end
|
14
17
|
end
|
15
18
|
|
16
19
|
is_versioned :on => :updated_at
|
17
|
-
|
18
20
|
end
|
19
21
|
|
20
22
|
if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
|
21
|
-
describe 'DataMapper' do
|
22
|
-
describe "#auto_migrate!" do
|
23
|
-
before do
|
24
|
-
# I *think* AutoMigrator breaks toplevel auto_migrate
|
25
|
-
# into two calls to reduce redundancy, so auto_migrate!
|
26
|
-
# never actually gets called on decendents after a
|
27
|
-
# DataMapper.auto_migrate! call.
|
28
|
-
Story::Version.should_receive(:auto_migrate_down!)
|
29
|
-
Story::Version.should_receive(:auto_migrate_up!)
|
30
|
-
end
|
31
|
-
it "should get called on a versioned inner class" do
|
32
|
-
DataMapper.auto_migrate!
|
33
|
-
end
|
34
|
-
end # #auto_migrate!
|
35
|
-
|
36
|
-
describe "#auto_upgrade!" do
|
37
|
-
before do
|
38
|
-
# AutoMigrator collects all descendents, triggering once
|
39
|
-
# but triggers a second time after Story gets upgraded.
|
40
|
-
# Since it's non-destructive, shouldn't matter that it
|
41
|
-
# gets called twice though.
|
42
|
-
Story::Version.should_receive(:auto_upgrade!).twice
|
43
|
-
end
|
44
|
-
it "should get called on a versioned inner class" do
|
45
|
-
DataMapper.auto_upgrade!
|
46
|
-
end
|
47
|
-
end # #auto_upgrade!
|
48
|
-
end
|
49
|
-
|
50
23
|
describe 'DataMapper::Is::Versioned' do
|
51
|
-
describe
|
52
|
-
it
|
53
|
-
Story::Version.should be_a_kind_of(
|
24
|
+
describe 'inner class' do
|
25
|
+
it 'should be present' do
|
26
|
+
Story::Version.should be_a_kind_of(DataMapper::Model)
|
54
27
|
end
|
55
28
|
|
56
|
-
it
|
57
|
-
Story::Version.storage_name.should ==
|
29
|
+
it 'should have a default storage name' do
|
30
|
+
Story::Version.storage_name.should == 'story_versions'
|
58
31
|
end
|
59
32
|
|
60
|
-
|
61
|
-
|
62
|
-
Story::Version.properties.should
|
33
|
+
Story.properties.each do |property|
|
34
|
+
it "should have its parent's property #{property.name}" do
|
35
|
+
Story::Version.properties.should include(property)
|
63
36
|
end
|
64
37
|
end
|
65
|
-
end
|
38
|
+
end
|
66
39
|
|
67
|
-
describe
|
68
|
-
before do
|
69
|
-
Story::Version.should_receive(:auto_migrate!)
|
70
|
-
end
|
71
|
-
it "should get called on the inner class" do
|
40
|
+
describe '#create' do
|
41
|
+
before :all do
|
72
42
|
Story.auto_migrate!
|
43
|
+
Story.create(:title => 'A Very Interesting Article')
|
73
44
|
end
|
74
|
-
end # #auto_migrate!
|
75
|
-
|
76
|
-
describe "#auto_upgrade!" do
|
77
|
-
before do
|
78
|
-
Story::Version.should_receive(:auto_upgrade!)
|
79
|
-
end
|
80
|
-
it "should get called on the inner class" do
|
81
|
-
Story.auto_upgrade!
|
82
|
-
end
|
83
|
-
end # #auto_upgrade!
|
84
45
|
|
85
|
-
|
86
|
-
before do
|
87
|
-
Story.auto_migrate!
|
88
|
-
Story.create(:title => "A Very Interesting Article")
|
89
|
-
end
|
90
|
-
it "should not create a versioned copy" do
|
46
|
+
it 'should not create a versioned copy' do
|
91
47
|
Story::Version.all.size.should == 0
|
92
48
|
end
|
93
|
-
end
|
49
|
+
end
|
94
50
|
|
95
|
-
describe
|
96
|
-
before do
|
51
|
+
describe '#save' do
|
52
|
+
before :all do
|
97
53
|
Story.auto_migrate!
|
98
54
|
end
|
99
55
|
|
100
|
-
describe
|
101
|
-
before do
|
102
|
-
@story = Story.new(:title =>
|
56
|
+
describe '(with new resource)' do
|
57
|
+
before :all do
|
58
|
+
@story = Story.new(:title => 'A Story')
|
103
59
|
@story.save
|
104
60
|
end
|
105
|
-
|
61
|
+
|
62
|
+
it 'should not create a versioned copy' do
|
106
63
|
Story::Version.all.size.should == 0
|
107
64
|
end
|
108
65
|
end
|
109
66
|
|
110
|
-
describe
|
111
|
-
before do
|
112
|
-
@story = Story.create(:title =>
|
67
|
+
describe '(with a clean existing resource)' do
|
68
|
+
before :all do
|
69
|
+
@story = Story.create(:title => 'A Story')
|
113
70
|
@story.save
|
114
71
|
end
|
115
72
|
|
116
|
-
it
|
73
|
+
it 'should not create a versioned copy' do
|
117
74
|
Story::Version.all.size.should == 0
|
118
75
|
end
|
119
76
|
end
|
120
77
|
|
121
|
-
describe
|
122
|
-
before do
|
123
|
-
@story = Story.create(:title =>
|
124
|
-
@story.title =
|
125
|
-
@story.title =
|
78
|
+
describe '(with a dirty existing resource)' do
|
79
|
+
before :all do
|
80
|
+
@story = Story.create(:title => 'A Story')
|
81
|
+
@story.title = 'An Inner Update'
|
82
|
+
@story.title = 'An Updated Story'
|
126
83
|
@story.save
|
127
84
|
end
|
128
85
|
|
129
|
-
it
|
86
|
+
it 'should create a versioned copy' do
|
130
87
|
Story::Version.all.size.should == 1
|
131
88
|
end
|
132
89
|
|
133
|
-
it
|
90
|
+
it 'should not have the same value for the versioned field' do
|
134
91
|
@story.updated_at.should_not == Story::Version.first.updated_at
|
135
92
|
end
|
136
93
|
|
137
|
-
it
|
94
|
+
it 'should save the original value, not the inner update' do
|
138
95
|
# changes to the story between saves shouldn't be updated.
|
139
|
-
@story.versions.last.title.should ==
|
96
|
+
@story.versions.last.title.should == 'A Story'
|
140
97
|
end
|
141
98
|
end
|
99
|
+
end
|
142
100
|
|
143
|
-
|
144
|
-
|
145
|
-
describe "#pending_version_attributes" do
|
146
|
-
before do
|
147
|
-
@story = Story.create(:title => "A Story")
|
148
|
-
end
|
149
|
-
|
150
|
-
it "should be updated when a property changes" do
|
151
|
-
@story.title = "A New Title"
|
152
|
-
@story.pending_version_attributes[:title].should == "A Story"
|
153
|
-
end
|
154
|
-
|
155
|
-
it "should be cleared when a resource is saved" do
|
156
|
-
@story.title = "A New Title"
|
157
|
-
@story.save
|
158
|
-
@story.pending_version_attributes.should be_empty
|
159
|
-
end
|
160
|
-
end # #pending_version_attributes
|
161
|
-
|
162
|
-
describe "#versions" do
|
163
|
-
before do
|
101
|
+
describe '#versions' do
|
102
|
+
before :all do
|
164
103
|
Story.auto_migrate!
|
165
|
-
@story = Story.create(:title =>
|
104
|
+
@story = Story.create(:title => 'A Story')
|
166
105
|
end
|
167
106
|
|
168
|
-
it
|
107
|
+
it 'should return an empty array when there are no versions' do
|
169
108
|
@story.versions.should == []
|
170
109
|
end
|
171
110
|
|
172
|
-
it
|
111
|
+
it 'should return a collection when there are versions' do
|
173
112
|
@story.versions.should == Story::Version.all(:id => @story.id)
|
174
113
|
end
|
175
114
|
|
176
115
|
it "should not return another object's versions" do
|
177
|
-
@story2 = Story.create(:title =>
|
178
|
-
@story2.title =
|
116
|
+
@story2 = Story.create(:title => 'A Different Story')
|
117
|
+
@story2.title = 'A Different Title'
|
179
118
|
@story2.save
|
180
119
|
@story.versions.should == Story::Version.all(:id => @story.id)
|
181
120
|
end
|
182
|
-
end
|
121
|
+
end
|
183
122
|
end
|
184
123
|
end
|
data/tasks/install.rb
CHANGED
@@ -4,7 +4,7 @@ end
|
|
4
4
|
|
5
5
|
desc "Install #{GEM_NAME} #{GEM_VERSION}"
|
6
6
|
task :install => [ :package ] do
|
7
|
-
sudo_gem "install
|
7
|
+
sudo_gem "install pkg/#{GEM_NAME}-#{GEM_VERSION} --no-update-sources"
|
8
8
|
end
|
9
9
|
|
10
10
|
desc "Uninstall #{GEM_NAME} #{GEM_VERSION}"
|
data/tasks/spec.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
begin
|
2
|
-
gem 'rspec', '~>1.2'
|
3
|
-
require 'spec'
|
4
2
|
require 'spec/rake/spectask'
|
5
3
|
|
6
4
|
task :default => [ :spec ]
|
@@ -8,16 +6,18 @@ begin
|
|
8
6
|
desc 'Run specifications'
|
9
7
|
Spec::Rake::SpecTask.new(:spec) do |t|
|
10
8
|
t.spec_opts << '--options' << 'spec/spec.opts' if File.exists?('spec/spec.opts')
|
11
|
-
t.
|
9
|
+
t.libs << 'lib' << 'spec' # needed for CI rake spec task, duplicated in spec_helper
|
12
10
|
|
13
11
|
begin
|
14
|
-
|
12
|
+
require 'rcov'
|
15
13
|
t.rcov = JRUBY ? false : (ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true)
|
16
14
|
t.rcov_opts << '--exclude' << 'spec'
|
17
15
|
t.rcov_opts << '--text-summary'
|
18
16
|
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
19
17
|
rescue LoadError
|
20
18
|
# rcov not installed
|
19
|
+
rescue SyntaxError
|
20
|
+
# rcov syntax invalid
|
21
21
|
end
|
22
22
|
end
|
23
23
|
rescue LoadError
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dm-is-versioned
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernerd Schaefer
|
@@ -9,19 +9,10 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-09-16 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
name: dm-core
|
17
|
-
type: :runtime
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - "="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.9.11
|
24
|
-
version:
|
14
|
+
dependencies: []
|
15
|
+
|
25
16
|
description: DataMapper plugin enabling simple versioning of models
|
26
17
|
email:
|
27
18
|
- bernerd [a] wieck [d] com
|
@@ -30,15 +21,15 @@ executables: []
|
|
30
21
|
extensions: []
|
31
22
|
|
32
23
|
extra_rdoc_files:
|
33
|
-
- README.
|
24
|
+
- README.rdoc
|
34
25
|
- LICENSE
|
35
26
|
- TODO
|
36
|
-
- History.
|
27
|
+
- History.rdoc
|
37
28
|
files:
|
38
|
-
- History.
|
29
|
+
- History.rdoc
|
39
30
|
- LICENSE
|
40
31
|
- Manifest.txt
|
41
|
-
- README.
|
32
|
+
- README.rdoc
|
42
33
|
- Rakefile
|
43
34
|
- TODO
|
44
35
|
- lib/dm-is-versioned.rb
|
@@ -50,11 +41,13 @@ files:
|
|
50
41
|
- tasks/install.rb
|
51
42
|
- tasks/spec.rb
|
52
43
|
has_rdoc: true
|
53
|
-
homepage: http://github.com/
|
44
|
+
homepage: http://github.com/datamapper/dm-more/tree/master/dm-is-versioned
|
45
|
+
licenses: []
|
46
|
+
|
54
47
|
post_install_message:
|
55
48
|
rdoc_options:
|
56
49
|
- --main
|
57
|
-
- README.
|
50
|
+
- README.rdoc
|
58
51
|
require_paths:
|
59
52
|
- lib
|
60
53
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -72,9 +65,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
65
|
requirements: []
|
73
66
|
|
74
67
|
rubyforge_project: datamapper
|
75
|
-
rubygems_version: 1.3.
|
68
|
+
rubygems_version: 1.3.5
|
76
69
|
signing_key:
|
77
|
-
specification_version:
|
70
|
+
specification_version: 3
|
78
71
|
summary: DataMapper plugin enabling simple versioning of models
|
79
72
|
test_files: []
|
80
73
|
|