has_versions 0.3.0 → 0.4.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.
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
-