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
data/Rakefile
CHANGED
@@ -1,29 +1,12 @@
|
|
1
1
|
require 'bundler/setup'
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
|
-
require '
|
5
|
-
require 'rspec/core/rake_task'
|
6
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
7
|
-
spec.pattern = FileList['spec/**/*_spec.rb']
|
8
|
-
end
|
9
|
-
|
10
|
-
# require 'cucumber/rake/task'
|
11
|
-
# Cucumber::Rake::Task.new(:features)
|
12
|
-
|
13
|
-
# require 'reek/rake/task'
|
14
|
-
# Reek::Rake::Task.new do |t|
|
15
|
-
# t.fail_on_error = true
|
16
|
-
# t.verbose = false
|
17
|
-
# t.source_files = 'lib/**/*.rb'
|
18
|
-
# end
|
4
|
+
require 'rake/testtask'
|
19
5
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
task :default => :spec
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << 'lib'
|
8
|
+
t.libs << 'test'
|
9
|
+
t.pattern = 'test/**/*_test.rb'
|
10
|
+
t.verbose = false
|
11
|
+
end
|
27
12
|
|
28
|
-
# require 'yard'
|
29
|
-
# YARD::Rake::YardocTask.new
|
data/has_versions.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
Gem::Specification.new do |s|
|
3
3
|
s.name = "has_versions"
|
4
|
-
s.version = '0.
|
4
|
+
s.version = '0.5.0'
|
5
5
|
|
6
6
|
s.platform = Gem::Platform::RUBY
|
7
7
|
s.authors = ["Grant Rodgers"]
|
@@ -23,9 +23,8 @@ Gem::Specification.new do |s|
|
|
23
23
|
]
|
24
24
|
s.licenses = ["MIT"]
|
25
25
|
|
26
|
-
s.add_runtime_dependency("i18n", [">= 0"])
|
27
|
-
s.add_runtime_dependency("activesupport",
|
28
|
-
s.
|
29
|
-
s.
|
30
|
-
s.add_development_dependency("yard", ["~> 0.6.0"])
|
26
|
+
# s.add_runtime_dependency("i18n", [">= 0"])
|
27
|
+
s.add_runtime_dependency("activesupport", "~> 3.2")
|
28
|
+
s.add_development_dependency("rake")
|
29
|
+
# s.add_runtime_dependency("simple_uuid", [">= 0"])
|
31
30
|
end
|
@@ -3,14 +3,14 @@ module HasVersions
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
module ClassMethods
|
6
|
-
def
|
6
|
+
def versioned_attributes
|
7
7
|
versioning_configuration.attributes
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
def versioned_attributes
|
12
|
-
self.class.
|
13
|
-
memo[attribute] = versioning_encode_value(attribute,
|
12
|
+
self.class.versioned_attributes.inject({}) do |memo, attribute|
|
13
|
+
memo[attribute] = versioning_encode_value(attribute, send(attribute))
|
14
14
|
memo
|
15
15
|
end
|
16
16
|
end
|
data/lib/has_versions/reset.rb
CHANGED
@@ -1,15 +1,21 @@
|
|
1
1
|
module HasVersions
|
2
2
|
module Reset
|
3
|
-
extend ActiveSupport::
|
3
|
+
extend ActiveSupport::Concern
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
module FromVersion
|
5
|
+
module ClassMethods
|
8
6
|
def from_version(version)
|
9
7
|
new.tap do |object|
|
10
8
|
object.reset!(version)
|
11
9
|
end
|
12
10
|
end
|
13
11
|
end
|
12
|
+
|
13
|
+
def reset!(version)
|
14
|
+
self.class.versioned_attributes.each do |attribute|
|
15
|
+
value = versioning_decode_value(attribute, version.snapshot[attribute])
|
16
|
+
send("#{attribute}=", value)
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end
|
14
20
|
end
|
15
21
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module HasVersions
|
2
|
+
module VersionMethods
|
3
|
+
module Diff
|
4
|
+
def diff(original = parent)
|
5
|
+
original_snapshot = original.nil? ? {} : original.decoded_snapshot
|
6
|
+
|
7
|
+
output = {}
|
8
|
+
decoded_snapshot.each do |attribute, new_value|
|
9
|
+
original_value = original_snapshot[attribute]
|
10
|
+
|
11
|
+
if original_value != new_value
|
12
|
+
output[attribute] = [original_value, new_value]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
output
|
17
|
+
end
|
18
|
+
|
19
|
+
def modified_attributes
|
20
|
+
diff.keys
|
21
|
+
end
|
22
|
+
|
23
|
+
def different_attributes
|
24
|
+
modified_attributes.select do |attribute|
|
25
|
+
target.send(attribute) != decoded_snapshot[attribute]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def decoded_snapshot
|
30
|
+
@decoded_snapshot ||= begin
|
31
|
+
decoded = {}
|
32
|
+
target.class.versioned_attributes.each do |attribute|
|
33
|
+
decoded[attribute] = target.versioning_decode_value(attribute, snapshot[attribute])
|
34
|
+
end
|
35
|
+
decoded
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module HasVersions
|
2
|
+
module VersionMethods
|
3
|
+
class LogCollection
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(version)
|
7
|
+
@version = version
|
8
|
+
end
|
9
|
+
|
10
|
+
def walk
|
11
|
+
walker = Walker.new(@version)
|
12
|
+
while v = walker.next
|
13
|
+
yield v
|
14
|
+
end
|
15
|
+
end
|
16
|
+
alias_method :each, :walk
|
17
|
+
|
18
|
+
def all
|
19
|
+
all = []
|
20
|
+
walk { |v| all << v }
|
21
|
+
all
|
22
|
+
end
|
23
|
+
alias_method :to_a, :all
|
24
|
+
|
25
|
+
class Walker
|
26
|
+
attr_accessor :current_version
|
27
|
+
def initialize(version)
|
28
|
+
self.current_version = version
|
29
|
+
end
|
30
|
+
|
31
|
+
def next
|
32
|
+
version = self.current_version
|
33
|
+
self.current_version = version.try(:parent)
|
34
|
+
version
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Log
|
40
|
+
def log
|
41
|
+
@log ||= LogCollection.new(self)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -7,33 +7,30 @@ module HasVersions
|
|
7
7
|
class_attribute :version_class
|
8
8
|
|
9
9
|
include HasVersions::Attributes
|
10
|
-
include HasVersions::Reset
|
11
|
-
include HasVersions::Diff::Simple
|
12
|
-
extend HasVersions::Reset::FromVersion
|
10
|
+
include HasVersions::Reset
|
13
11
|
end
|
14
12
|
|
15
13
|
module ClassMethods
|
16
14
|
def has_versions(version_class, &block)
|
17
15
|
self.versioning_configuration = HasVersions::Configuration.new(&block)
|
18
16
|
self.version_class = version_class
|
17
|
+
version_class.class_eval do
|
18
|
+
include HasVersions::VersionMethods::Diff
|
19
|
+
include HasVersions::VersionMethods::Log
|
20
|
+
end
|
19
21
|
end
|
20
22
|
|
21
23
|
def versioned_attribute(name)
|
22
24
|
self.versioning_configuration ||= HasVersions::Configuration.new
|
23
25
|
versioning_configuration.attribute(name)
|
24
26
|
end
|
25
|
-
|
26
|
-
def is_versioned?
|
27
|
-
!versioning_configuration.blank?
|
28
|
-
end
|
29
27
|
end
|
30
28
|
|
31
|
-
# generates a version from the current object
|
32
29
|
def to_version
|
33
|
-
version_class.new
|
34
|
-
|
35
|
-
|
36
|
-
|
30
|
+
version = version_class.new
|
31
|
+
version.snapshot = versioned_attributes
|
32
|
+
version.target = self
|
33
|
+
version
|
37
34
|
end
|
38
35
|
end
|
39
36
|
end
|
data/lib/has_versions.rb
CHANGED
@@ -3,16 +3,10 @@ require 'active_support/all'
|
|
3
3
|
module HasVersions
|
4
4
|
extend ActiveSupport::Autoload
|
5
5
|
|
6
|
-
autoload :Configuration
|
7
|
-
autoload :Versioned
|
8
6
|
autoload :Attributes
|
9
|
-
|
10
|
-
autoload :Stage
|
11
|
-
|
12
|
-
autoload :Apply
|
13
|
-
autoload :Diff
|
14
|
-
autoload :Merge
|
7
|
+
autoload :Configuration
|
15
8
|
autoload :Reset
|
9
|
+
autoload :Versioned
|
16
10
|
|
17
11
|
module Orm
|
18
12
|
extend ActiveSupport::Autoload
|
@@ -20,7 +14,12 @@ module HasVersions
|
|
20
14
|
autoload :CassandraObject
|
21
15
|
end
|
22
16
|
|
23
|
-
|
17
|
+
module VersionMethods
|
18
|
+
extend ActiveSupport::Autoload
|
19
|
+
|
20
|
+
autoload :Diff
|
21
|
+
autoload :Log
|
22
|
+
end
|
24
23
|
end
|
25
24
|
|
26
25
|
ActiveSupport.on_load :cassandra_object do
|
@@ -1,20 +1,25 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
class HasVersions::AttributesTest < MiniTest::Spec
|
4
|
-
class VersionedObject
|
5
|
-
include HasVersions::Versioned
|
1
|
+
require 'helper'
|
6
2
|
|
3
|
+
class HasVersions::AttributesTest < MiniTest::Unit::TestCase
|
4
|
+
class VersionedModel < TestModel
|
7
5
|
attr_accessor :name
|
8
|
-
attr_accessor :
|
6
|
+
attr_accessor :weight
|
9
7
|
attr_accessor :color
|
10
8
|
|
11
9
|
has_versions(Class.new) do
|
12
10
|
attribute :name
|
13
|
-
attribute :
|
11
|
+
attribute :weight
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
17
|
-
def
|
18
|
-
assert_equal ['name', '
|
15
|
+
def test_class_versioned_attributes
|
16
|
+
assert_equal ['name', 'weight'], VersionedModel.versioned_attributes
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_instance_versioned_attributes
|
20
|
+
record = VersionedModel.new(name: 'joe', weight: 142.0, color: 'green')
|
21
|
+
expected = {'name' => 'joe', 'weight' => '142.0'}
|
22
|
+
|
23
|
+
assert_equal expected, record.versioned_attributes
|
19
24
|
end
|
20
|
-
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HasVersions::ConfigurationTest < MiniTest::Unit::TestCase
|
4
|
+
def test_configuration
|
5
|
+
configuration = HasVersions::Configuration.new do
|
6
|
+
attribute :foo
|
7
|
+
attribute :bar
|
8
|
+
end
|
9
|
+
|
10
|
+
assert_equal %w(foo bar), configuration.attributes
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HasVersions::ResetTest < MiniTest::Unit::TestCase
|
4
|
+
class ResetModel < TestModel
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :color
|
7
|
+
|
8
|
+
has_versions(TestVersion) do
|
9
|
+
attribute :name
|
10
|
+
end
|
11
|
+
|
12
|
+
def versioning_decode_value(name, value)
|
13
|
+
"hello, #{value}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_from_version
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_reset
|
21
|
+
reset_model = ResetModel.new(name: "bob", color: "green")
|
22
|
+
version = TestVersion.new(snapshot: {name: "joe", color: "blue"})
|
23
|
+
|
24
|
+
reset_model.reset!(version)
|
25
|
+
|
26
|
+
assert_equal "hello, joe", reset_model.name
|
27
|
+
assert_equal "green", reset_model.color
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HasVersions::VersionMethods::DiffTest < MiniTest::Unit::TestCase
|
4
|
+
class DiffModel < TestModel
|
5
|
+
attr_accessor :name
|
6
|
+
attr_accessor :color
|
7
|
+
attr_accessor :weight
|
8
|
+
|
9
|
+
has_versions(TestVersion) do
|
10
|
+
attribute :name
|
11
|
+
attribute :weight
|
12
|
+
end
|
13
|
+
|
14
|
+
def versioning_decode_value(name, value)
|
15
|
+
"decoded: #{value}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_diff_with_parent
|
20
|
+
target = DiffModel.new
|
21
|
+
parent = TestVersion.new(target: target, snapshot: {name: 'foo', color: 'green', weight: '4.3'})
|
22
|
+
child = TestVersion.new(target: target, parent: parent, snapshot: {name: 'bar', color: 'orange', weight: '4.3'})
|
23
|
+
|
24
|
+
diff = child.diff
|
25
|
+
|
26
|
+
assert_equal({'name' => ['decoded: foo', 'decoded: bar']}, diff)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_diff_with_parameter
|
30
|
+
target = DiffModel.new
|
31
|
+
this_version = TestVersion.new(target: target, snapshot: {name: 'foo', color: 'green', weight: '4.3'})
|
32
|
+
other_version = TestVersion.new(target: target, snapshot: {name: 'bar', color: 'orange', weight: '4.3'})
|
33
|
+
|
34
|
+
diff = this_version.diff(other_version)
|
35
|
+
|
36
|
+
assert_equal({'name' => ['decoded: bar', 'decoded: foo']}, diff)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_diff_with_nil
|
40
|
+
target = DiffModel.new
|
41
|
+
version = TestVersion.new(target: target, snapshot: {name: 'bar', color: 'orange', weight: '4.3'})
|
42
|
+
|
43
|
+
diff = version.diff
|
44
|
+
|
45
|
+
assert_equal({'name' => [nil, 'decoded: bar'], 'weight' => [nil, 'decoded: 4.3']}, diff)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_modified_attributes
|
49
|
+
target = DiffModel.new
|
50
|
+
version = TestVersion.new(target: target, snapshot: {'name' => 'joe', 'weight' => '129'})
|
51
|
+
|
52
|
+
assert_equal version.snapshot.keys, version.modified_attributes
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_different_attributes
|
56
|
+
target = DiffModel.new(name: 'decoded: sam', color: 'decoded: green', weight: 'decoded: 129')
|
57
|
+
version = TestVersion.new(target: target, snapshot: {'name' => 'joe', 'weight' => '129'})
|
58
|
+
|
59
|
+
assert_equal ['name'], version.different_attributes
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_decoded_snapshot
|
63
|
+
target = DiffModel.new
|
64
|
+
version = TestVersion.new(target: target, snapshot: {name: 'foo', color: 'green', weight: '4.3'})
|
65
|
+
|
66
|
+
assert_equal({"name" => "decoded: foo", "weight" => "decoded: 4.3"}, version.decoded_snapshot)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HasVersions::VersionMethods::LogTest < MiniTest::Unit::TestCase
|
4
|
+
class LogVersion < TestVersion
|
5
|
+
include HasVersions::VersionMethods::Log
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_walk
|
9
|
+
grandparent = LogVersion.new
|
10
|
+
parent = LogVersion.new parent: grandparent
|
11
|
+
child = LogVersion.new parent: parent
|
12
|
+
|
13
|
+
ancestors = []
|
14
|
+
child.log.walk do |v|
|
15
|
+
ancestors << v
|
16
|
+
end
|
17
|
+
|
18
|
+
assert_equal [child, parent, grandparent], ancestors
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_all
|
22
|
+
grandparent = LogVersion.new
|
23
|
+
parent = LogVersion.new parent: grandparent
|
24
|
+
child = LogVersion.new parent: parent
|
25
|
+
|
26
|
+
assert_equal [child, parent, grandparent], child.log.all
|
27
|
+
assert_equal [child, parent, grandparent], child.log.to_a
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_is_enumerable
|
31
|
+
assert LogVersion.new.log.respond_to?(:collect)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class HasVersions::VersionedTest < MiniTest::Unit::TestCase
|
4
|
+
def test_versioned_attribute
|
5
|
+
versioned_model = Class.new(TestModel) do
|
6
|
+
versioned_attribute 'hello'
|
7
|
+
end
|
8
|
+
|
9
|
+
assert_equal ['hello'], versioned_model.versioned_attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_to_version
|
13
|
+
record = Class.new(TestModel) do
|
14
|
+
attr_accessor :name
|
15
|
+
|
16
|
+
has_versions(TestVersion) do
|
17
|
+
attribute :name
|
18
|
+
end
|
19
|
+
end.new(name: 'wee')
|
20
|
+
|
21
|
+
version = record.to_version
|
22
|
+
|
23
|
+
assert_kind_of TestVersion, version
|
24
|
+
assert_equal record, version.target
|
25
|
+
assert_equal record.versioned_attributes, version.snapshot
|
26
|
+
end
|
27
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
class TestModel
|
2
|
+
include HasVersions::Versioned
|
3
|
+
|
4
|
+
def initialize(attributes = {})
|
5
|
+
attributes.each do |key, value|
|
6
|
+
send("#{key}=", value)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def versioning_encode_value(name, value)
|
11
|
+
value.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def versioning_decode_value(name, value)
|
15
|
+
value
|
16
|
+
end
|
17
|
+
|
18
|
+
def versioning_codable?(name)
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class TestVersion
|
2
|
+
attr_reader :snapshot
|
3
|
+
attr_accessor :parent
|
4
|
+
attr_accessor :target
|
5
|
+
|
6
|
+
def initialize(attributes = {})
|
7
|
+
attributes.each do |key, value|
|
8
|
+
send("#{key}=", value)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def snapshot=(hash)
|
13
|
+
@snapshot = hash.stringify_keys
|
14
|
+
end
|
15
|
+
end
|