rico 0.0.1 → 0.1.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/.rspec CHANGED
@@ -1 +1 @@
1
- --color
1
+ --tty --color --format nested
data/Guardfile ADDED
@@ -0,0 +1,5 @@
1
+ guard "rspec" do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1].split("/").last}_spec.rb" }
4
+ watch("spec/spec_helper.rb") { "spec" }
5
+ end
data/lib/rico/array.rb CHANGED
@@ -4,7 +4,7 @@ module Rico
4
4
  include Enumerable
5
5
  extend Forwardable
6
6
 
7
- def_delegators :members, :each, :[]
7
+ def_delegators :members, :each, :[], :length, :count
8
8
 
9
9
  public
10
10
 
@@ -14,7 +14,7 @@ module Rico
14
14
  #
15
15
  # Returns the result of the store operation
16
16
  def add(*items)
17
- mutate compute_add(items)
17
+ mutate build_map_add(items)
18
18
  end
19
19
 
20
20
  # Removes the requested items from the array and stores the object
@@ -23,14 +23,14 @@ module Rico
23
23
  #
24
24
  # Returns the result of the store operation
25
25
  def remove(*items)
26
- mutate compute_remove(items)
26
+ mutate build_map_remove(items)
27
27
  end
28
28
 
29
29
  # Obtains the items in the array
30
30
  #
31
31
  # Returns the data in the object as an array
32
32
  def members
33
- Array(data)
33
+ Array((data || {})["_values"])
34
34
  end
35
35
 
36
36
  # Tests whether or not an item exists in the array
@@ -42,16 +42,38 @@ module Rico
42
42
  members.include? item
43
43
  end
44
44
 
45
- # Returns the number of items in the array
45
+ # Resolve conflict between one or more RObject siblings
46
46
  #
47
- # Returns an Integer
48
- def length
49
- members.length
47
+ # robjects - array of RObjects to merge
48
+ #
49
+ # Returns a single RObject result or nil
50
+ def self.resolve(robject)
51
+ siblings = robject.siblings
52
+ values = siblings.map {|r| Array(r.data["_values"]) }
53
+ deletions = siblings.map {|r| Array(r.data["_deletes"]) }.flatten
54
+
55
+ result = []
56
+ values.each do |v|
57
+ result += (v - result)
58
+ end
59
+
60
+ result -= deletions
61
+
62
+ obj = Riak::RObject.new(robject.bucket, robject.key)
63
+ obj.data = { "_values" => result, "_deletes" => deletions }
64
+ obj
50
65
  end
51
- alias_method :count, :length
52
66
 
53
67
  protected
54
68
 
69
+ def build_map_add(items)
70
+ { "_type" => type_key, "_values" => compute_add(items) }
71
+ end
72
+
73
+ def build_map_remove(items)
74
+ { "_type" => type_key, "_values" => compute_remove(items), "_deletes" => items }
75
+ end
76
+
55
77
  def compute_add(items)
56
78
  members + items
57
79
  end
data/lib/rico/object.rb CHANGED
@@ -2,7 +2,7 @@ module Rico
2
2
  module Object
3
3
  extend Forwardable
4
4
 
5
- def_delegators :riak_object, :store, :delete
5
+ def_delegators :riak_object, :conflict?, :delete, :store
6
6
 
7
7
  # Initialize an object with a bucket and key
8
8
  #
@@ -26,7 +26,7 @@ module Rico
26
26
  def mutate(value)
27
27
  @data = value
28
28
  riak_object.data = value
29
- riak_object.store
29
+ store
30
30
  end
31
31
 
32
32
  # Determine whether an object exists or not
@@ -38,6 +38,11 @@ module Rico
38
38
 
39
39
  protected
40
40
 
41
+ def type_key
42
+ name = self.class.name.split("::").last
43
+ Rico::TYPES[name]
44
+ end
45
+
41
46
  def riak_object
42
47
  @riak_object ||= Rico.bucket(@bucket).get_or_new @key
43
48
  end
@@ -0,0 +1,18 @@
1
+ module Rico
2
+ class Resolver
3
+ def self.to_proc
4
+ @to_proc ||= lambda do |robject|
5
+ klasses = robject.siblings.map{|s| s.data && s.data["_type"] }.compact.uniq
6
+ return nil unless klasses.length == 1
7
+
8
+ klass_name = Rico::TYPES.invert[klasses.first]
9
+ return nil unless klass_name
10
+
11
+ klass = Rico.const_get(klass_name)
12
+ return nil unless klass.respond_to?(:resolve)
13
+
14
+ klass.resolve(robject.siblings)
15
+ end
16
+ end
17
+ end
18
+ end
data/lib/rico/value.rb CHANGED
@@ -20,12 +20,25 @@ module Rico
20
20
  #
21
21
  # Returns true if stored, false if not
22
22
  def setnx(value)
23
- if redis_object.exists?
23
+ if exists?
24
24
  false
25
25
  else
26
26
  set value
27
27
  true
28
28
  end
29
29
  end
30
+
31
+ # Resolve conflict between one or more RObject siblings
32
+ #
33
+ # This currently just returns the first sibling
34
+ #
35
+ # robjects - array of RObjects to resolve
36
+ #
37
+ # Returns a single RObject result or nil
38
+ def self.resolve(robject)
39
+ obj = Riak::RObject.new(robject.bucket, robject.key)
40
+ obj.data = robject.siblings.first.data
41
+ obj
42
+ end
30
43
  end
31
44
  end
data/lib/rico/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rico
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/rico.rb CHANGED
@@ -8,10 +8,20 @@ require "rico/set"
8
8
  require "rico/sorted_set"
9
9
  require "rico/value"
10
10
 
11
+ require "rico/resolver"
12
+
11
13
  require "rico/version"
12
14
 
13
15
  module Rico
14
16
 
17
+ TYPES = {
18
+ "Array" => "array",
19
+ "List" => "list",
20
+ "Set" => "set",
21
+ "SortedSet" => "sset",
22
+ "Value" => "value"
23
+ }
24
+
15
25
  def self.configure
16
26
  yield self if block_given?
17
27
  end
@@ -38,3 +48,5 @@ module Rico
38
48
  @riak = riak
39
49
  end
40
50
  end
51
+
52
+ Riak::RObject.on_conflict(&Rico::Resolver.to_proc)
data/rico.gemspec CHANGED
@@ -17,4 +17,5 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency "riak-client", "~> 1.1"
19
19
  gem.add_development_dependency "rspec", "~> 2.12"
20
+ gem.add_development_dependency "guard-rspec", "~> 2.3"
20
21
  end
data/spec/array_spec.rb CHANGED
@@ -133,6 +133,29 @@ describe Rico::Array do
133
133
  end
134
134
  end
135
135
 
136
+ describe ".resolve" do
137
+ it "properly resolves missing values" do
138
+ datas = [
139
+ { "_type" => "array", "_values" => [1,2,3] },
140
+ { "_type" => "array", "_values" => [1,2,3,4] }
141
+ ]
142
+ conflicted = RiakHelpers.build_conflicted_robject "array_resolve_simple", datas
143
+ result = Rico::Array.resolve(conflicted)
144
+ result.data["_values"].should eql [1,2,3,4]
145
+ end
146
+
147
+ it "properly deletes deleted values after resolve" do
148
+ datas = [
149
+ { "_type" => "array", "_values" => [1,2,3,4] },
150
+ { "_type" => "array", "_values" => [1,2,3], "_deletes" => [4] }
151
+ ]
152
+ conflicted = RiakHelpers.build_conflicted_robject "array_resolve_delete", datas
153
+ result = Rico::Array.resolve(conflicted)
154
+ result.data["_values"].should eql [1,2,3]
155
+ result.data["_deletes"].should eql [4]
156
+ end
157
+ end
158
+
136
159
  it "is enumerable" do
137
160
  a = Rico::Array.new RiakHelpers.bucket, "enumerable"
138
161
  a.add(3, 1, 4, 1, 5, 9)
@@ -0,0 +1,45 @@
1
+ require "spec_helper"
2
+
3
+ describe Rico::Resolver do
4
+ describe ".to_proc" do
5
+ it "returns nil for data without type" do
6
+ datas = [
7
+ { "a" => "b" },
8
+ { "c" => "d" },
9
+ { "f" => "e" }
10
+ ]
11
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_no_type", datas
12
+ Rico::Resolver.to_proc.call(conflicted).should eql nil
13
+ end
14
+
15
+ it "returns nil for data with conflicted types" do
16
+ datas = [
17
+ { "_type" => "array", "_values" => [1,2,3,4,1] },
18
+ { "_type" => "set", "_values" => [1,2,3,4] }
19
+ ]
20
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_conflicted_types", datas
21
+ Rico::Resolver.to_proc.call(conflicted).should eql nil
22
+ end
23
+
24
+ it "returns nil for data without a known rico class" do
25
+ datas = [
26
+ { "_type" => "unknown", "_values" => [1,2,3] },
27
+ { "_type" => "unknown", "_values" => [1,2,3,4] }
28
+ ]
29
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_unknown_type", datas
30
+ Rico::Resolver.to_proc.call(conflicted).should eql nil
31
+ end
32
+
33
+ it "returns the result of the resolve function on known types" do
34
+ datas = [
35
+ { "_type" => "array", "_values" => [1,2,3] },
36
+ { "_type" => "array", "_values" => [1,2,3,4] }
37
+ ]
38
+ conflicted = RiakHelpers.build_conflicted_robject "resolver_proc_no_resolve_function", datas
39
+
40
+ Rico::Array.stub(:resolve).and_return(conflicted.siblings.last)
41
+ Rico::Resolver.to_proc.call(conflicted).should eql conflicted.siblings.last
42
+ Rico::Array.unstub(:resolve)
43
+ end
44
+ end
45
+ end
data/spec/spec_helper.rb CHANGED
@@ -17,5 +17,30 @@ module RiakHelpers
17
17
  b.keys.each do |k|
18
18
  b.delete k
19
19
  end
20
+
21
+ a = Rico::Array.new bucket, "visual_array"
22
+ a.add 1,2,3,4,5,6
23
+ a.remove 6
24
+ end
25
+
26
+ def self.build_conflicted_robject(key, values)
27
+ bucket = Rico.bucket RiakHelpers.bucket
28
+ o = Riak::RObject.new bucket, key
29
+ siblings = values.map do |v|
30
+ x = Riak::RObject.new bucket, key
31
+ x.data = v
32
+ x
33
+ end
34
+
35
+ o = Riak::RObject.new bucket, key
36
+ o.siblings = siblings
37
+ o
38
+ end
39
+
40
+ def self.build_conflicted_rico_object(klass, key, values=["v1", "v2", "v3"])
41
+ o = build_conflicted_robject key, values
42
+ v = klass.new RiakHelpers.bucket, key
43
+ v.instance_variable_set("@riak_object", o)
44
+ v
20
45
  end
21
46
  end
data/spec/value_spec.rb CHANGED
@@ -42,6 +42,25 @@ describe Rico::Value do
42
42
  end
43
43
  end
44
44
 
45
+ describe "#setnx" do
46
+ it "writes the value, returns true if new" do
47
+ a = Rico::Value.new RiakHelpers.bucket, "setnx_new"
48
+ a.setnx("value").should eql true
49
+ b = Rico::Value.new RiakHelpers.bucket, "setnx_new"
50
+ b.get.should eql "value"
51
+ end
52
+
53
+ it "does nothing, returns false if the value exists" do
54
+ a = Rico::Value.new RiakHelpers.bucket, "setnx_exists"
55
+ a.set "value"
56
+ b = Rico::Value.new RiakHelpers.bucket, "setnx_exists"
57
+ b.setnx("other").should eql false
58
+ b.get.should eql "value"
59
+ c = Rico::Value.new RiakHelpers.bucket, "setnx_exists"
60
+ c.get.should eql "value"
61
+ end
62
+ end
63
+
45
64
  describe "#delete" do
46
65
  it "deletes an existing object" do
47
66
  a = Rico::Value.new RiakHelpers.bucket, "delete_existing"
@@ -52,4 +71,25 @@ describe Rico::Value do
52
71
  b.get.should eql nil
53
72
  end
54
73
  end
74
+
75
+ describe ".resolve" do
76
+ it "just returns the first sibling" do
77
+ datas = ["Tom", "Jerry"]
78
+ conflicted = RiakHelpers.build_conflicted_robject "value_resolve_simple", datas
79
+ result = Rico::Value.resolve(conflicted)
80
+ result.data.should eql "Tom"
81
+ end
82
+
83
+ it "properly deletes deleted values after resolve" do
84
+ datas = [
85
+ { "_type" => "array", "_values" => [1,2,3,4] },
86
+ { "_type" => "array", "_values" => [1,2,3], "_deletes" => [4] }
87
+ ]
88
+ conflicted = RiakHelpers.build_conflicted_robject "array_resolve_delete", datas
89
+ result = Rico::Array.resolve(conflicted)
90
+ result.data["_values"].should eql [1,2,3]
91
+ result.data["_deletes"].should eql [4]
92
+ end
93
+ end
94
+
55
95
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rico
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-09 00:00:00.000000000 Z
12
+ date: 2012-12-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: riak-client
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
45
  version: '2.12'
46
+ - !ruby/object:Gem::Dependency
47
+ name: guard-rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '2.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.3'
46
62
  description: Primative data types on Riak
47
63
  email:
48
64
  - jcoene@gmail.com
@@ -53,6 +69,7 @@ files:
53
69
  - .gitignore
54
70
  - .rspec
55
71
  - Gemfile
72
+ - Guardfile
56
73
  - LICENSE
57
74
  - README.md
58
75
  - Rakefile
@@ -61,6 +78,7 @@ files:
61
78
  - lib/rico/counter.rb
62
79
  - lib/rico/list.rb
63
80
  - lib/rico/object.rb
81
+ - lib/rico/resolver.rb
64
82
  - lib/rico/set.rb
65
83
  - lib/rico/sorted_set.rb
66
84
  - lib/rico/value.rb
@@ -68,6 +86,7 @@ files:
68
86
  - rico.gemspec
69
87
  - spec/array_spec.rb
70
88
  - spec/list_spec.rb
89
+ - spec/resolver_spec.rb
71
90
  - spec/rico_spec.rb
72
91
  - spec/set_spec.rb
73
92
  - spec/sorted_set_spec.rb
@@ -100,6 +119,7 @@ summary: Primative data types on Riak
100
119
  test_files:
101
120
  - spec/array_spec.rb
102
121
  - spec/list_spec.rb
122
+ - spec/resolver_spec.rb
103
123
  - spec/rico_spec.rb
104
124
  - spec/set_spec.rb
105
125
  - spec/sorted_set_spec.rb