has_versions 0.4.9 → 0.5.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/Rakefile +7 -24
- data/has_versions.gemspec +5 -6
- data/lib/has_versions/attributes.rb +3 -3
- data/lib/has_versions/configuration.rb +0 -1
- data/lib/has_versions/reset.rb +10 -4
- data/lib/has_versions/version_methods/diff.rb +40 -0
- data/lib/has_versions/version_methods/log.rb +45 -0
- data/lib/has_versions/versioned.rb +9 -12
- data/lib/has_versions.rb +8 -9
- data/test/has_versions/attributes_test.rb +15 -10
- data/test/has_versions/configuration_test.rb +12 -0
- data/test/has_versions/reset_test.rb +29 -0
- data/test/has_versions/version_methods/diff_test.rb +68 -0
- data/test/has_versions/version_methods/log_test.rb +33 -0
- data/test/has_versions/versioned_test.rb +27 -0
- data/test/helper.rb +6 -0
- data/test/support/test_model.rb +21 -0
- data/test/support/test_version.rb +15 -0
- metadata +24 -96
- data/lib/has_versions/apply/simple.rb +0 -34
- data/lib/has_versions/apply.rb +0 -9
- data/lib/has_versions/diff/simple.rb +0 -27
- data/lib/has_versions/diff.rb +0 -7
- data/lib/has_versions/merge/always_conflicted.rb +0 -9
- data/lib/has_versions/merge/base.rb +0 -22
- data/lib/has_versions/merge/choose_first.rb +0 -9
- data/lib/has_versions/merge/diff3.rb +0 -66
- data/lib/has_versions/merge/fast_forward.rb +0 -34
- data/lib/has_versions/merge/merge_base.rb +0 -75
- data/lib/has_versions/merge/octopus.rb +0 -42
- data/lib/has_versions/merge/three_way.rb +0 -53
- data/lib/has_versions/merge.rb +0 -32
- data/lib/has_versions/reset/simple.rb +0 -19
- data/spec/has_versions/apply_spec.rb +0 -33
- data/spec/has_versions/configuration_spec.rb +0 -33
- data/spec/has_versions/diff_spec.rb +0 -40
- data/spec/has_versions/merge/diff3_spec.rb +0 -29
- data/spec/has_versions/merge/merge_base_spec.rb +0 -61
- data/spec/has_versions/merge/octopus_spec.rb +0 -74
- data/spec/has_versions/merge/three_way_spec.rb +0 -57
- data/spec/has_versions/reset_spec.rb +0 -40
- data/spec/has_versions/stage_spec.rb +0 -17
- data/spec/has_versions/versioned_spec.rb +0 -60
- data/spec/spec_helper.rb +0 -17
- data/spec/support/matchers/be_a_uuid.rb +0 -7
- data/spec/support/version.rb +0 -17
- data/test/test_helper.rb +0 -3
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe 'Configuration' do
|
4
|
-
subject do
|
5
|
-
HasVersions::Configuration.new do
|
6
|
-
type :baz, expected: Hash
|
7
|
-
attribute :foo
|
8
|
-
attribute :bar
|
9
|
-
attribute :baz, type: :baz
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should include specified attributes' do
|
14
|
-
subject.attributes.should include(:foo)
|
15
|
-
subject.attributes.should include(:bar)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should set options on attributes' do
|
19
|
-
subject.attributes[:baz].should include(type: :baz)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should allow indifferent access to attributes' do
|
23
|
-
subject.attributes.should include("foo")
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'should include specified types' do
|
27
|
-
subject.types.should include(:baz)
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'should propagate type options to typed attributes' do
|
31
|
-
subject.attributes[:baz].should include(expected: Hash)
|
32
|
-
end
|
33
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class DiffingVersion < Version; end
|
4
|
-
|
5
|
-
describe DiffingVersion do
|
6
|
-
class DiffingVersion
|
7
|
-
include HasVersions::Diff::Simple
|
8
|
-
|
9
|
-
def versioning_decode_value(key, value)
|
10
|
-
if key == 'name'
|
11
|
-
value.upcase
|
12
|
-
else
|
13
|
-
value
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def versioning_codable?(name)
|
18
|
-
true
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
let (:foo) { described_class.new(name: 'foo', argyle: 'socks') }
|
23
|
-
let (:foo2) { described_class.new(name: 'foo2', stripey: 'socks') }
|
24
|
-
|
25
|
-
it 'should return empty when diffed with itself' do
|
26
|
-
foo.diff(foo).should be_empty
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'should return a patch when diffed with another version' do
|
30
|
-
foo.diff(foo2).should include(name: ['FOO', 'FOO2'])
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should include patches for attributes added' do
|
34
|
-
foo.diff(foo2).should include(stripey: [nil, 'socks'])
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'should include patches for attributes deleted' do
|
38
|
-
foo.diff(foo2).should include(argyle: ['socks', nil])
|
39
|
-
end
|
40
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Merge" do
|
4
|
-
describe "Diff3" do
|
5
|
-
|
6
|
-
it 'should behave like a 3-way merge' do
|
7
|
-
extend HasVersions::Merge::Diff3
|
8
|
-
|
9
|
-
diff3('A','A','A').should == [true, 'A']
|
10
|
-
diff3('A','B','A').should == [true, 'B']
|
11
|
-
diff3('A','A','B').should == [true, 'B']
|
12
|
-
diff3('B','A','A').should == [true, 'A']
|
13
|
-
diff3('B','A','C').should == [false, ['A', 'C']]
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'should take multiple theirs' do
|
17
|
-
extend HasVersions::Merge::Diff3
|
18
|
-
|
19
|
-
diff3('A','A',*['A','A']).should == [true, 'A']
|
20
|
-
diff3('A','A',*['B','B']).should == [true, 'B']
|
21
|
-
diff3('A','A',*['B','B']).should == [true, 'B']
|
22
|
-
diff3('A','A',*['A','B']).should == [false, ['A','B']]
|
23
|
-
diff3('A','A',*['B','C']).should == [false, ['B','C']]
|
24
|
-
diff3('A','B',*['C','D']).should == [false, ['C','D','B']]
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should handle _missing values'
|
28
|
-
end
|
29
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Merge" do
|
4
|
-
describe "MergeBase" do
|
5
|
-
include HasVersions::Merge::MergeBase
|
6
|
-
|
7
|
-
it 'should find no bases for one version' do
|
8
|
-
v = MergingVersion.new
|
9
|
-
merge_bases([v]).should == []
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'should find merge base for a version and its parent' do
|
13
|
-
p1 = MergingVersion.new
|
14
|
-
v1 = MergingVersion.new
|
15
|
-
v1.parents = p1
|
16
|
-
merge_bases([v1, p1]).should == [p1]
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'should find merge base for versions with multiple ancestors' do
|
20
|
-
p1 = MergingVersion.new
|
21
|
-
p2 = MergingVersion.new
|
22
|
-
v1 = MergingVersion.new
|
23
|
-
v1.parents = p1
|
24
|
-
p1.parents = p2
|
25
|
-
merge_bases([v1, p1]).should == [p1]
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should find merge base for two versions with the same parent' do
|
29
|
-
p1 = MergingVersion.new
|
30
|
-
v1 = MergingVersion.new
|
31
|
-
v2 = MergingVersion.new
|
32
|
-
v1.parents = v2.parents = [p1]
|
33
|
-
merge_bases([v1, v2]).should == [p1]
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should find merge base for multiple versions with different parents' do
|
37
|
-
p1, p2, v1, v2, v3 = *5.times.collect { MergingVersion.new }
|
38
|
-
p2.parents = [p1]
|
39
|
-
v1.parents = [p1]
|
40
|
-
v2.parents = [p2]
|
41
|
-
v3.parents = [v2]
|
42
|
-
merge_bases([v1, v2, v3]).should == [p1]
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'should find no base for versions with no common ancestry' do
|
46
|
-
v1 = MergingVersion.new
|
47
|
-
v2 = MergingVersion.new
|
48
|
-
merge_bases([v1, v2]).should == []
|
49
|
-
end
|
50
|
-
|
51
|
-
#TODO this is broken
|
52
|
-
it 'should find multiple bases for versions with criss-cross ancestry' do
|
53
|
-
p1, p2, p3, v1, v2 = *5.times.collect { MergingVersion.new }
|
54
|
-
p2.parents = [p1]
|
55
|
-
p3.parents = [p1]
|
56
|
-
v1.parents = [p3, p2]
|
57
|
-
v2.parents = [p2, p3]
|
58
|
-
merge_bases([v1, v2]).should == [p2, p3]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe HasVersions::Merge::Octopus do
|
4
|
-
|
5
|
-
it 'should only accept 3+ versions' do
|
6
|
-
expect { merge([MergingVersion.new]) }.to raise_error(HasVersions::MergeFailed)
|
7
|
-
expect { merge([MergingVersion.new]*2) }.to raise_error(HasVersions::MergeFailed)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should merge identical versions' do
|
11
|
-
v1 = MergingVersion.new(name: 'foo1')
|
12
|
-
v2 = MergingVersion.new(name: 'foo1')
|
13
|
-
v3 = MergingVersion.new(name: 'foo1')
|
14
|
-
merge([v1, v2, v3]).resolution.snapshot.should include(name: 'foo1')
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'should merge many versions' do
|
18
|
-
v1 = MergingVersion.new(name: 'foo1')
|
19
|
-
v2 = MergingVersion.new(name: 'foo1')
|
20
|
-
v3 = MergingVersion.new(name: 'foo1')
|
21
|
-
v4 = MergingVersion.new(name: 'foo1')
|
22
|
-
v5 = MergingVersion.new(name: 'foo1')
|
23
|
-
v6 = MergingVersion.new(name: 'foo1')
|
24
|
-
merge([v1, v2, v3, v4, v5, v6]).resolution.snapshot.should include(name: 'foo1')
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should detect conflicts' do
|
28
|
-
v1 = MergingVersion.new(name: 'foo1')
|
29
|
-
v2 = MergingVersion.new(name: 'foo2')
|
30
|
-
v3 = MergingVersion.new(name: 'foo3')
|
31
|
-
merge([v1, v2, v3]).conflicts.should include(name: ['foo1', 'foo2', 'foo3'])
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'should merge ancestors cleanly' do
|
35
|
-
v1 = MergingVersion.new(name: 'foo1')
|
36
|
-
v2 = MergingVersion.new(name: 'foo2')
|
37
|
-
v3 = MergingVersion.new(name: 'foo3')
|
38
|
-
|
39
|
-
v3.parents = v2
|
40
|
-
v2.parents = v1
|
41
|
-
merge([v1, v2, v3]).conflicts.should be_empty
|
42
|
-
merge([v1, v2, v3]).resolution.snapshot.should include(name: 'foo3')
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'should merge missing attributes' do
|
46
|
-
v1 = MergingVersion.new(name: 'foo1')
|
47
|
-
v2 = MergingVersion.new(name: 'foo1', socks: 'stripey')
|
48
|
-
v3 = MergingVersion.new(hat: 'silly')
|
49
|
-
merge([v1, v2, v3]).resolution.snapshot.should include(name: 'foo1', socks: 'stripey', hat: 'silly')
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'should save the partial merge result' do
|
53
|
-
v1 = MergingVersion.new(name: 'foo1', socks: 'stripey')
|
54
|
-
v2 = MergingVersion.new(name: 'foo2', socks: 'argyle')
|
55
|
-
v3 = MergingVersion.new(name: 'foo3', socks: 'argyle')
|
56
|
-
p1 = MergingVersion.new(name: 'foo', socks: 'argyle')
|
57
|
-
v1.parents = v2.parents = v3.parents = p1
|
58
|
-
merge([v1, v2, v3]).conflicts.should include(name: ['foo1', 'foo2', 'foo3'])
|
59
|
-
merge([v1, v2, v3]).resolution.snapshot.should include(socks: 'stripey')
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'should set parents' do
|
63
|
-
v1 = MergingVersion.new(name: 'foo1', socks: 'stripey')
|
64
|
-
v2 = MergingVersion.new(name: 'foo2', socks: 'argyle')
|
65
|
-
v3 = MergingVersion.new(name: 'foo3', socks: 'argyle')
|
66
|
-
merge([v1, v2, v3]).resolution.parents.should == [v1, v2, v3]
|
67
|
-
end
|
68
|
-
|
69
|
-
def merge(versions, options={})
|
70
|
-
s = HasVersions::Merge::Octopus.new(versions, options)
|
71
|
-
s.merge
|
72
|
-
s
|
73
|
-
end
|
74
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe HasVersions::Merge::ThreeWay do
|
4
|
-
|
5
|
-
it 'should only accept 2 versions' do
|
6
|
-
expect { merge([MergingVersion.new]) }.to raise_error(HasVersions::MergeFailed)
|
7
|
-
expect { merge([MergingVersion.new]*3) }.to raise_error(HasVersions::MergeFailed)
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should merge identical versions' do
|
11
|
-
v1 = MergingVersion.new(name: 'foo1')
|
12
|
-
v2 = MergingVersion.new(name: 'foo1')
|
13
|
-
merge([v1, v2]).resolution.snapshot.should include(name: 'foo1')
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'should detect conflicts' do
|
17
|
-
v1 = MergingVersion.new(name: 'foo1')
|
18
|
-
v2 = MergingVersion.new(name: 'foo2')
|
19
|
-
merge([v1, v2]).conflicts.should include(name: ['foo1', 'foo2'])
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should merge ancestors cleanly' do
|
23
|
-
v1 = MergingVersion.new(name: 'foo1')
|
24
|
-
v2 = MergingVersion.new(name: 'foo2')
|
25
|
-
|
26
|
-
v2.parents = [v1]
|
27
|
-
merge([v1, v2]).conflicts.should be_empty
|
28
|
-
merge([v1, v2]).resolution.snapshot.should include(name: 'foo2')
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should merge missing attributes' do
|
32
|
-
v1 = MergingVersion.new(name: 'foo1')
|
33
|
-
v2 = MergingVersion.new(name: 'foo1', socks: 'stripey')
|
34
|
-
merge([v1, v2]).resolution.snapshot.should include(name: 'foo1', socks: 'stripey')
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'should save the partial merge result' do
|
38
|
-
v1 = MergingVersion.new(name: 'foo1', socks: 'stripey')
|
39
|
-
v2 = MergingVersion.new(name: 'foo2', socks: 'argyle')
|
40
|
-
p1 = MergingVersion.new(name: 'foo', socks: 'argyle')
|
41
|
-
v1.parents = v2.parents = p1
|
42
|
-
merge([v1, v2]).conflicts.should include(name: ['foo1', 'foo2'])
|
43
|
-
merge([v1, v2]).resolution.snapshot.should include(socks: 'stripey')
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'should set parents' do
|
47
|
-
v1 = MergingVersion.new(name: 'foo1', socks: 'stripey')
|
48
|
-
v2 = MergingVersion.new(name: 'foo2', socks: 'argyle')
|
49
|
-
merge([v1, v2]).resolution.parents.should == [v1, v2]
|
50
|
-
end
|
51
|
-
|
52
|
-
def merge(versions, options={})
|
53
|
-
s = HasVersions::Merge::ThreeWay.new(versions, options)
|
54
|
-
s.merge
|
55
|
-
s
|
56
|
-
end
|
57
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class ResetObjectVersion < Version; end
|
4
|
-
|
5
|
-
class ResetObject
|
6
|
-
include HasVersions::Versioned
|
7
|
-
|
8
|
-
include HasVersions::Reset::Simple
|
9
|
-
|
10
|
-
attr_accessor :name
|
11
|
-
attr_accessor :set
|
12
|
-
|
13
|
-
has_versions(ResetObjectVersion) do
|
14
|
-
attribute :name
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "Reset" do
|
19
|
-
describe "Simple" do
|
20
|
-
subject do
|
21
|
-
ResetObject.new.reset!(ResetObjectVersion.new(set: [1,2,3]))
|
22
|
-
end
|
23
|
-
|
24
|
-
its(:set) { should be_a(Set) }
|
25
|
-
end
|
26
|
-
|
27
|
-
describe "FromVersion" do
|
28
|
-
class ResetObject
|
29
|
-
extend HasVersions::Reset::FromVersion
|
30
|
-
end
|
31
|
-
|
32
|
-
subject do
|
33
|
-
ResetObject.from_version(ResetObjectVersion.new(name: 'foo'))
|
34
|
-
end
|
35
|
-
|
36
|
-
it { should be_a(ResetObject) }
|
37
|
-
|
38
|
-
its(:name) { should == 'foo' }
|
39
|
-
end
|
40
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class StagingObjectVersion < Version; end
|
4
|
-
|
5
|
-
# class StagingObject
|
6
|
-
# include HasVersions::Versioned
|
7
|
-
# include HasVersions::Stage
|
8
|
-
#
|
9
|
-
# attr_accessor :name
|
10
|
-
#
|
11
|
-
# has_versions(StagingObjectVersion) do
|
12
|
-
# attribute :name
|
13
|
-
# end
|
14
|
-
# end
|
15
|
-
#
|
16
|
-
# describe StagingObject do
|
17
|
-
# end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
class VersionedObject
|
4
|
-
include HasVersions::Versioned
|
5
|
-
|
6
|
-
attr_accessor :name
|
7
|
-
attr_accessor :time
|
8
|
-
attr_accessor :color
|
9
|
-
end
|
10
|
-
|
11
|
-
class VersionedObjectVersion < Version; end
|
12
|
-
|
13
|
-
describe VersionedObject do
|
14
|
-
it { should respond_to(:versioning_configuration) }
|
15
|
-
it { should respond_to(:version_class) }
|
16
|
-
|
17
|
-
it 'should not be versioned' do
|
18
|
-
described_class.is_versioned?.should be_false
|
19
|
-
end
|
20
|
-
|
21
|
-
context "configured" do
|
22
|
-
subject do
|
23
|
-
described_class.has_versions(VersionedObjectVersion) do
|
24
|
-
attribute :name
|
25
|
-
attribute :time
|
26
|
-
end
|
27
|
-
described_class.versioned_attribute(:color)
|
28
|
-
|
29
|
-
described_class
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should be versioned' do
|
33
|
-
subject.is_versioned?.should be_true
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should have attributes' do
|
37
|
-
subject.versioning_configuration.attributes.should == ["name", "time", "color"]
|
38
|
-
end
|
39
|
-
|
40
|
-
its(:version_class) { should be(VersionedObjectVersion) }
|
41
|
-
its(:versioning_configuration) { should be_a(HasVersions::Configuration) }
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "configured instance" do
|
45
|
-
subject do
|
46
|
-
v = VersionedObject.new
|
47
|
-
v.name = 'foo'
|
48
|
-
v.time = Time.parse("1970-01-01 2:43")
|
49
|
-
v
|
50
|
-
end
|
51
|
-
|
52
|
-
its(:versioned_attributes) { should include(name: 'foo') }
|
53
|
-
|
54
|
-
its(:to_version) { should be_a(VersionedObjectVersion) }
|
55
|
-
|
56
|
-
it 'should set attributes in to_version' do
|
57
|
-
subject.to_version.snapshot.should include(name: 'foo')
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
# $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
-
# $LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
-
|
4
|
-
# p "#{$LOAD_PATH.inspect}"
|
5
|
-
|
6
|
-
require 'rspec'
|
7
|
-
require 'has_versions'
|
8
|
-
|
9
|
-
# Requires supporting files with custom matchers and macros, etc,
|
10
|
-
# in ./support/ and its subdirectories.
|
11
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
|
12
|
-
require f
|
13
|
-
end
|
14
|
-
|
15
|
-
RSpec.configure do |config|
|
16
|
-
config.mock_with :rspec
|
17
|
-
end
|
data/spec/support/version.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
class Version
|
2
|
-
attr_accessor :snapshot
|
3
|
-
|
4
|
-
def initialize(snapshot=nil)
|
5
|
-
@snapshot = (snapshot || {}).with_indifferent_access
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
class MergingVersion < Version
|
10
|
-
def parents
|
11
|
-
@parents || []
|
12
|
-
end
|
13
|
-
|
14
|
-
def parents=(parents)
|
15
|
-
@parents = Array(parents)
|
16
|
-
end
|
17
|
-
end
|
data/test/test_helper.rb
DELETED