has_versions 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +1 -37
  2. data/Gemfile.lock +17 -45
  3. data/Rakefile +16 -16
  4. data/has_versions.gemspec +6 -6
  5. data/lib/has_versions/apply/simple.rb +1 -1
  6. data/lib/has_versions/attributes.rb +2 -26
  7. data/lib/has_versions/configuration.rb +3 -16
  8. data/lib/has_versions/diff/simple.rb +1 -1
  9. data/lib/has_versions/merge/always_conflicted.rb +9 -0
  10. data/lib/has_versions/merge/base.rb +22 -0
  11. data/lib/has_versions/merge/choose_first.rb +9 -0
  12. data/lib/has_versions/merge/diff3.rb +66 -0
  13. data/lib/has_versions/merge/fast_forward.rb +34 -0
  14. data/lib/has_versions/merge/merge_base.rb +75 -0
  15. data/lib/has_versions/merge/octopus.rb +42 -0
  16. data/lib/has_versions/merge/three_way.rb +53 -0
  17. data/lib/has_versions/merge.rb +16 -45
  18. data/lib/has_versions/orm/cassandra_object.rb +15 -0
  19. data/lib/has_versions/reset/simple.rb +2 -2
  20. data/lib/has_versions/version.rb +1 -1
  21. data/lib/has_versions/versioned.rb +1 -5
  22. data/lib/has_versions/versioning_key.rb +0 -1
  23. data/lib/has_versions.rb +10 -0
  24. data/spec/has_versions/apply_spec.rb +5 -5
  25. data/spec/has_versions/configuration_spec.rb +7 -7
  26. data/spec/has_versions/diff_spec.rb +4 -4
  27. data/spec/has_versions/merge/diff3_spec.rb +29 -0
  28. data/spec/has_versions/merge/merge_base_spec.rb +61 -0
  29. data/spec/has_versions/merge/octopus_spec.rb +74 -0
  30. data/spec/has_versions/merge/three_way_spec.rb +57 -0
  31. data/spec/has_versions/reset_spec.rb +1 -2
  32. data/spec/has_versions/stage_spec.rb +14 -15
  33. data/spec/has_versions/versioned_spec.rb +4 -4
  34. data/spec/has_versions/versioning_key_spec.rb +1 -1
  35. data/spec/spec_helper.rb +7 -8
  36. data/spec/support/matchers/be_a_uuid.rb +0 -1
  37. data/spec/support/version.rb +10 -0
  38. metadata +34 -69
  39. data/lib/has_versions/merge/stupid.rb +0 -44
  40. data/lib/has_versions/stage.rb +0 -121
  41. data/spec/has_versions/merge_spec.rb +0 -67
  42. data/spec/support/matchers/have_key.rb +0 -25
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has_versions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-03-16 00:00:00.000000000 -07:00
13
- default_executable:
12
+ date: 2011-10-10 00:00:00.000000000Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: i18n
17
- requirement: &17221640 !ruby/object:Gem::Requirement
16
+ requirement: &70120472609720 !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
19
  - - ! '>='
@@ -22,21 +21,21 @@ dependencies:
22
21
  version: '0'
23
22
  type: :runtime
24
23
  prerelease: false
25
- version_requirements: *17221640
24
+ version_requirements: *70120472609720
26
25
  - !ruby/object:Gem::Dependency
27
26
  name: activesupport
28
- requirement: &17220920 !ruby/object:Gem::Requirement
27
+ requirement: &70120472608780 !ruby/object:Gem::Requirement
29
28
  none: false
30
29
  requirements:
31
30
  - - ~>
32
31
  - !ruby/object:Gem::Version
33
- version: '3'
32
+ version: '3.0'
34
33
  type: :runtime
35
34
  prerelease: false
36
- version_requirements: *17220920
35
+ version_requirements: *70120472608780
37
36
  - !ruby/object:Gem::Dependency
38
37
  name: simple_uuid
39
- requirement: &17220260 !ruby/object:Gem::Requirement
38
+ requirement: &70120472607900 !ruby/object:Gem::Requirement
40
39
  none: false
41
40
  requirements:
42
41
  - - ! '>='
@@ -44,21 +43,21 @@ dependencies:
44
43
  version: '0'
45
44
  type: :runtime
46
45
  prerelease: false
47
- version_requirements: *17220260
46
+ version_requirements: *70120472607900
48
47
  - !ruby/object:Gem::Dependency
49
48
  name: rspec
50
- requirement: &17219620 !ruby/object:Gem::Requirement
49
+ requirement: &70120472607200 !ruby/object:Gem::Requirement
51
50
  none: false
52
51
  requirements:
53
52
  - - ~>
54
53
  - !ruby/object:Gem::Version
55
- version: '2'
54
+ version: '2.0'
56
55
  type: :development
57
56
  prerelease: false
58
- version_requirements: *17219620
57
+ version_requirements: *70120472607200
59
58
  - !ruby/object:Gem::Dependency
60
59
  name: yard
61
- requirement: &17219060 !ruby/object:Gem::Requirement
60
+ requirement: &70120472606420 !ruby/object:Gem::Requirement
62
61
  none: false
63
62
  requirements:
64
63
  - - ~>
@@ -66,21 +65,10 @@ dependencies:
66
65
  version: 0.6.0
67
66
  type: :development
68
67
  prerelease: false
69
- version_requirements: *17219060
70
- - !ruby/object:Gem::Dependency
71
- name: cucumber
72
- requirement: &17218360 !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
- type: :development
79
- prerelease: false
80
- version_requirements: *17218360
68
+ version_requirements: *70120472606420
81
69
  - !ruby/object:Gem::Dependency
82
70
  name: bundler
83
- requirement: &17217740 !ruby/object:Gem::Requirement
71
+ requirement: &70120472605360 !ruby/object:Gem::Requirement
84
72
  none: false
85
73
  requirements:
86
74
  - - ~>
@@ -88,40 +76,7 @@ dependencies:
88
76
  version: 1.0.0
89
77
  type: :development
90
78
  prerelease: false
91
- version_requirements: *17217740
92
- - !ruby/object:Gem::Dependency
93
- name: simplecov
94
- requirement: &17217060 !ruby/object:Gem::Requirement
95
- none: false
96
- requirements:
97
- - - ! '>='
98
- - !ruby/object:Gem::Version
99
- version: 0.3.8
100
- type: :development
101
- prerelease: false
102
- version_requirements: *17217060
103
- - !ruby/object:Gem::Dependency
104
- name: reek
105
- requirement: &17216340 !ruby/object:Gem::Requirement
106
- none: false
107
- requirements:
108
- - - ~>
109
- - !ruby/object:Gem::Version
110
- version: 1.2.8
111
- type: :development
112
- prerelease: false
113
- version_requirements: *17216340
114
- - !ruby/object:Gem::Dependency
115
- name: roodi
116
- requirement: &17215620 !ruby/object:Gem::Requirement
117
- none: false
118
- requirements:
119
- - - ~>
120
- - !ruby/object:Gem::Version
121
- version: 2.1.0
122
- type: :development
123
- prerelease: false
124
- version_requirements: *17215620
79
+ version_requirements: *70120472605360
125
80
  description: ActiveModel versioning
126
81
  email:
127
82
  - grantr@gmail.com
@@ -152,10 +107,17 @@ files:
152
107
  - lib/has_versions/diff.rb
153
108
  - lib/has_versions/diff/simple.rb
154
109
  - lib/has_versions/merge.rb
155
- - lib/has_versions/merge/stupid.rb
110
+ - lib/has_versions/merge/always_conflicted.rb
111
+ - lib/has_versions/merge/base.rb
112
+ - lib/has_versions/merge/choose_first.rb
113
+ - lib/has_versions/merge/diff3.rb
114
+ - lib/has_versions/merge/fast_forward.rb
115
+ - lib/has_versions/merge/merge_base.rb
116
+ - lib/has_versions/merge/octopus.rb
117
+ - lib/has_versions/merge/three_way.rb
118
+ - lib/has_versions/orm/cassandra_object.rb
156
119
  - lib/has_versions/reset.rb
157
120
  - lib/has_versions/reset/simple.rb
158
- - lib/has_versions/stage.rb
159
121
  - lib/has_versions/version.rb
160
122
  - lib/has_versions/versioned.rb
161
123
  - lib/has_versions/versioning_key.rb
@@ -163,16 +125,17 @@ files:
163
125
  - spec/has_versions/apply_spec.rb
164
126
  - spec/has_versions/configuration_spec.rb
165
127
  - spec/has_versions/diff_spec.rb
166
- - spec/has_versions/merge_spec.rb
128
+ - spec/has_versions/merge/diff3_spec.rb
129
+ - spec/has_versions/merge/merge_base_spec.rb
130
+ - spec/has_versions/merge/octopus_spec.rb
131
+ - spec/has_versions/merge/three_way_spec.rb
167
132
  - spec/has_versions/reset_spec.rb
168
133
  - spec/has_versions/stage_spec.rb
169
134
  - spec/has_versions/versioned_spec.rb
170
135
  - spec/has_versions/versioning_key_spec.rb
171
136
  - spec/spec_helper.rb
172
137
  - spec/support/matchers/be_a_uuid.rb
173
- - spec/support/matchers/have_key.rb
174
138
  - spec/support/version.rb
175
- has_rdoc: true
176
139
  homepage: ''
177
140
  licenses:
178
141
  - MIT
@@ -194,7 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
194
157
  version: '0'
195
158
  requirements: []
196
159
  rubyforge_project: has_versions
197
- rubygems_version: 1.6.0
160
+ rubygems_version: 1.8.10
198
161
  signing_key:
199
162
  specification_version: 3
200
163
  summary: ActiveModel versioning
@@ -205,12 +168,14 @@ test_files:
205
168
  - spec/has_versions/apply_spec.rb
206
169
  - spec/has_versions/configuration_spec.rb
207
170
  - spec/has_versions/diff_spec.rb
208
- - spec/has_versions/merge_spec.rb
171
+ - spec/has_versions/merge/diff3_spec.rb
172
+ - spec/has_versions/merge/merge_base_spec.rb
173
+ - spec/has_versions/merge/octopus_spec.rb
174
+ - spec/has_versions/merge/three_way_spec.rb
209
175
  - spec/has_versions/reset_spec.rb
210
176
  - spec/has_versions/stage_spec.rb
211
177
  - spec/has_versions/versioned_spec.rb
212
178
  - spec/has_versions/versioning_key_spec.rb
213
179
  - spec/spec_helper.rb
214
180
  - spec/support/matchers/be_a_uuid.rb
215
- - spec/support/matchers/have_key.rb
216
181
  - spec/support/version.rb
@@ -1,44 +0,0 @@
1
- module HasVersions
2
- module Merge
3
-
4
- # takes a list of versions and attempts to merge them with the current version.
5
- # returns the merged version if successful
6
- # raises MergeConflict if failed
7
- #
8
- # Doesn't attempt to determine common ancestry. The merge base is always the current version (self).
9
- # Since there is no ancestry, conflict resolution is conservative. Any conflicting values generate a conflict.
10
- #
11
- # In general merging more than 1 version will generate a conflict.
12
- module Stupid
13
- include Diff3
14
-
15
- def merge(*versions)
16
- merged_version = self.class.new
17
- merged_version.snapshot = snapshot.dup
18
-
19
- # get the full list of attributes in each version and the merge base (self)
20
- attributes = (versions.collect { |v| v.snapshot.keys }.flatten + snapshot.keys).uniq
21
- conflicts = HashWithIndifferentAccess.new
22
-
23
- # do 3-way merge on each attribute
24
- attributes.each do |key|
25
- theirs = versions.collect { |v| v.snapshot[key] }
26
- clean, result = diff3(snapshot[key], snapshot[key], *theirs)
27
-
28
- if clean
29
- puts "clean: #{result.inspect}"
30
- merged_version.snapshot[key] = result
31
- else
32
- conflicts[key] = result
33
- end
34
- end
35
-
36
- # raise if conflicts is not empty
37
- raise MergeConflict.new(conflicts, merged_version), conflicts.inspect unless conflicts.empty?
38
- merged_version
39
- end
40
-
41
- end
42
-
43
- end
44
- end
@@ -1,121 +0,0 @@
1
- #TODO this should move to a contrib gem
2
- module HasVersions
3
- module Stage
4
- # stage versions onto an object, returning true or false if there are conflicts.
5
- # extends the object and each versioned attribute with methods to retrieve status, conflicts, and original value.
6
- # extends the object with a resolution and conflicted/modified attribute lists
7
- #
8
- #TODO should this be part of the plugin?
9
-
10
- def stage(*versions)
11
- original = to_version
12
-
13
- # try merging
14
- begin
15
- merge_result = original.merge(*versions)
16
- conflicts = HashWithIndifferentAccess.new
17
- # if merge fails, get the conflicts and result
18
- rescue MergeConflict => e
19
- conflicts = e.conflicts
20
- merge_result = e.result
21
- end
22
-
23
- reset!(merge_result)
24
-
25
- stage_extend_self(versions, conflicts, original, merge_result)
26
- stage_extend_attributes(conflicts, original)
27
-
28
- conflicts.empty?
29
- end
30
- # devang also wants an api that is similar to the old one, with pending objects, and old values in the attributes.
31
- # we can implement something that attaches a non-updated object in pending, with all the old apis
32
-
33
- private
34
-
35
- def stage_extend_self(staged, conflicts, original, merge_result)
36
- # extend self with StagedAttribute and set conflicts and original
37
- self.extend(StagedAttribute)
38
- self.conflicts = conflicts
39
- self.original = self.class.new.reset!(original) #TODO should this be a clone or new? should it inherit the key or id or other attributes?
40
-
41
- # extend self with Staged and set the proper values
42
- self.extend(Staged)
43
- self.staged = staged
44
- self.resolution = merge_result
45
- # modified attributes is the conflicted keys plus the modified keys
46
- self.modified_attributes = (conflicts.keys + original.diff(merge_result).keys).uniq
47
- end
48
-
49
- def stage_extend_attributes(conflicts, original)
50
- # for each attribute, extend with StagedAttribute and set proper values
51
- versioned_attributes.each do |key, value|
52
- v.extend(StagedAttribute)
53
- v.conflicts = conflicts[key] || []
54
- v.original = original.snapshot[key]
55
- end
56
- end
57
-
58
- end
59
-
60
- # included in attributes of staged objects
61
- module StagedAttribute
62
-
63
- def conflicted?
64
- !@conflicts.empty?
65
- end
66
-
67
- def modified?
68
- @original != self
69
- end
70
-
71
- def conflicts
72
- @conflicts
73
- end
74
-
75
- def conflicts=(conflicts)
76
- @conflicts = conflicts
77
- end
78
-
79
- def original
80
- @original
81
- end
82
-
83
- def original=(original)
84
- @original = original
85
- end
86
- end
87
-
88
- # included in staged objects
89
- # TODO maybe this should be included in the class up front
90
- module Staged
91
-
92
- def staged
93
- @staged
94
- end
95
-
96
- def staged=(staged)
97
- @staged = staged
98
- end
99
-
100
- def resolution
101
- @resolution
102
- end
103
-
104
- def resolution=(resolution)
105
- @resolution = resolution
106
- end
107
-
108
- def modified_attributes
109
- @modified_attributes
110
- end
111
-
112
- def modified_attributes=(modified_attributes)
113
- @modified_attributes = modified_attributes
114
- end
115
-
116
- def conflicted_attributes
117
- @conflicts.keys
118
- end
119
- end
120
-
121
- end
@@ -1,67 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
-
3
- class MergingVersion < Version; end
4
-
5
- describe "Merge" do
6
- describe "Diff3" do
7
-
8
- it 'should behave like a 3-way merge' do
9
- extend HasVersions::Merge::Diff3
10
-
11
- diff3('A','A','A').should == [true, 'A']
12
- diff3('A','B','A').should == [true, 'B']
13
- diff3('A','A','B').should == [true, 'B']
14
- diff3('B','A','A').should == [true, 'A']
15
- diff3('B','A','C').should == [false, ['A', 'C']]
16
- end
17
-
18
- it 'should take multiple theirs' do
19
- extend HasVersions::Merge::Diff3
20
-
21
- diff3('A','A',*['A','A']).should == [true, 'A']
22
- diff3('A','A',*['B','B']).should == [true, 'B']
23
- diff3('A','A',*['B','B']).should == [true, 'B']
24
- diff3('A','A',*['A','B']).should == [false, ['A','B']]
25
- diff3('A','A',*['B','C']).should == [false, ['B','C']]
26
- diff3('A','B',*['C','D']).should == [false, ['C','D','B']]
27
- end
28
- end
29
-
30
- describe "Stupid" do
31
- class MergingVersion
32
- include HasVersions::Merge::Stupid
33
- end
34
-
35
- let (:foo1) { MergingVersion.new(name: 'foo1') }
36
- let (:foo2) { MergingVersion.new(name: 'foo2') }
37
- let (:foo3) { MergingVersion.new(name: 'foo3') }
38
- let (:socks) { MergingVersion.new(stripey: 'socks') }
39
-
40
- it 'should merge a version into another' do
41
- foo1.merge(foo2).snapshot.should have_key(:name).with_value('foo2')
42
- end
43
-
44
- it 'should merge non-conflicting versions' # but it doesn't, because it can't merge more than one version (when ours == base)
45
-
46
- it 'should raise when versions conflict' do
47
- expect { foo1.merge(foo2, foo3) }.to raise_error(HasVersions::MergeConflict)
48
- end
49
-
50
- it 'should put the conflicts in the MergeConflict exception' do
51
- begin
52
- foo1.merge(foo2, foo3)
53
- rescue HasVersions::MergeConflict => e
54
- e.conflicts.should have_key(:name).with_value(['foo2', 'foo3'])
55
- end
56
- end
57
-
58
- it 'should put the merge result in the MergeConflict exception' do
59
- begin
60
- foo1.merge(foo2, foo3)
61
- rescue HasVersions::MergeConflict => e
62
- e.result.snapshot.should have_key(:name).with_value('foo1')
63
- end
64
- end
65
- end
66
- end
67
-
@@ -1,25 +0,0 @@
1
- require 'rspec/expectations'
2
-
3
- RSpec::Matchers.define :have_key do |first|
4
- match do |actual|
5
- if @second
6
- actual.has_key?(first) && actual[first] == @second
7
- else
8
- actual.has_key?(first)
9
- end
10
- end
11
-
12
- chain :with_value do |second|
13
- @second = second
14
- end
15
-
16
- failure_message_for_should do |actual|
17
- if @second
18
- %(expected #{actual.inspect} to have key "#{first.inspect}" with value #{@second.inspect})
19
- else
20
- %(expected #{actual.inspect} to have key "#{first.inspect}")
21
- end
22
- end
23
-
24
- end
25
-