ropl 0.0.1 → 0.0.2
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/README.md +9 -2
- data/Rakefile +0 -1
- data/lib/ropl.rb +26 -2
- data/lib/ropl/composition.rb +36 -0
- data/lib/ropl/version.rb +1 -1
- data/ropl.gemspec +1 -1
- data/test/helper.rb +5 -0
- data/test/riak.yml +9 -0
- data/test/test_composition.rb +56 -0
- data/test/test_composition_story.rb +45 -0
- data/test/test_oop_story.rb +41 -0
- data/test/test_persisted_class.rb +74 -0
- metadata +19 -6
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
# Ropl
|
2
2
|
|
3
|
-
|
3
|
+
There are plenty of ORMs out there. With a K/V database like Riak,
|
4
|
+
having an ORM means an awkward fit, since Riak doesn't natively
|
5
|
+
have any way to represent a Relationship.
|
6
|
+
|
7
|
+
In a conversation with Nathan Aschbacher, it was pointed out that
|
8
|
+
all we really want in many cases is persistence. So here it is --
|
9
|
+
a stupidly simple Riak Object Persistence Layer. ROPL.
|
4
10
|
|
5
11
|
## Installation
|
6
12
|
|
@@ -18,7 +24,8 @@ Or install it yourself as:
|
|
18
24
|
|
19
25
|
## Usage
|
20
26
|
|
21
|
-
|
27
|
+
Take a look at test/test_composition_story.rb and test/test_oop_story.rb
|
28
|
+
The later is the preferred usage.
|
22
29
|
|
23
30
|
## Contributing
|
24
31
|
|
data/Rakefile
CHANGED
data/lib/ropl.rb
CHANGED
@@ -1,5 +1,29 @@
|
|
1
|
-
require
|
1
|
+
require 'riak'
|
2
|
+
require 'ropl/composition'
|
2
3
|
|
3
4
|
module Ropl
|
4
|
-
|
5
|
+
class Ropl
|
6
|
+
def initialize(riak_client)
|
7
|
+
@riak_client = riak_client
|
8
|
+
end
|
9
|
+
|
10
|
+
def post(object)
|
11
|
+
robject = Riak::RObject.new @riak_client.bucket(object.class.name)
|
12
|
+
robject.content_type = 'application/x-marshalled-ruby-object'
|
13
|
+
robject.raw_data = Marshal::dump(object)
|
14
|
+
robject.store
|
15
|
+
end
|
16
|
+
|
17
|
+
def put(object, key)
|
18
|
+
robject = Riak::RObject.new @riak_client.bucket(object.class.name), key.to_s
|
19
|
+
robject.content_type = 'application/x-marshalled-ruby-object'
|
20
|
+
robject.raw_data = Marshal::dump(object)
|
21
|
+
robject.store.key
|
22
|
+
end
|
23
|
+
|
24
|
+
def get(klass, key)
|
25
|
+
robject = @riak_client.bucket(klass.name).get(key.to_s)
|
26
|
+
Marshal::load(robject.raw_data)
|
27
|
+
end
|
28
|
+
end
|
5
29
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Ropl
|
2
|
+
module Composition
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :ropl, :key
|
10
|
+
|
11
|
+
def persist
|
12
|
+
ropl = self.class.class_variable_get :@@ropl_object
|
13
|
+
|
14
|
+
raise Error if ropl.nil?
|
15
|
+
|
16
|
+
if @key.nil?
|
17
|
+
@key = ropl.post self
|
18
|
+
else
|
19
|
+
ropl.put self, @key
|
20
|
+
end
|
21
|
+
@key
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
def ropl(riak_client)
|
26
|
+
self.ancestors[0].class_variable_set :@@ropl_object, Ropl.new(riak_client)
|
27
|
+
end
|
28
|
+
|
29
|
+
def retrieve(key)
|
30
|
+
ropl = self.ancestors[0].class_variable_get :@@ropl_object
|
31
|
+
raise Error if ropl.nil?
|
32
|
+
ropl.get self.ancestors[0], key
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/ropl/version.rb
CHANGED
data/ropl.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |gem|
|
|
6
6
|
gem.email = ["clr@port49.com"]
|
7
7
|
gem.description = %q{Riak Object Persistence Layer}
|
8
8
|
gem.summary = %q{Why bother with an ORM? Just store the object. This is OOP, after all.}
|
9
|
-
gem.homepage = ""
|
9
|
+
gem.homepage = "https://github.com/clr/ropl"
|
10
10
|
|
11
11
|
gem.add_dependency "riak-client", "~> 1.0.0"
|
12
12
|
|
data/test/helper.rb
ADDED
data/test/riak.yml
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.expand_path(File.join('..','helper'), __FILE__)
|
2
|
+
|
3
|
+
class CompositeClass
|
4
|
+
include Ropl::Composition
|
5
|
+
attr_accessor :attribute_one, :attribute_two
|
6
|
+
|
7
|
+
def initialize(attribute_one, attribute_two)
|
8
|
+
@attribute_one = attribute_one
|
9
|
+
@attribute_two = attribute_two
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestCompositeClass < Test::Unit::TestCase
|
14
|
+
def setup
|
15
|
+
riak_config = YAML.load(File.read(File.expand_path(File.join('..','riak.yml'), __FILE__)))[:test]
|
16
|
+
riak_client = Riak::Client.new riak_config
|
17
|
+
# set the persistence connection
|
18
|
+
CompositeClass.ropl riak_client
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_post
|
22
|
+
# create some object without specifying the key
|
23
|
+
composite_class = CompositeClass.new 'post data', 'other post data'
|
24
|
+
|
25
|
+
# save it
|
26
|
+
assert composite_class.persist
|
27
|
+
assert !composite_class.key.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_put
|
31
|
+
# create some object with a key
|
32
|
+
composite_class = CompositeClass.new 'put data', 'other put data'
|
33
|
+
|
34
|
+
# set the key
|
35
|
+
composite_class.key = 'put key'
|
36
|
+
|
37
|
+
# save it
|
38
|
+
response = composite_class.persist
|
39
|
+
assert 'put key', response
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_put_then_get
|
43
|
+
# create some object with a key
|
44
|
+
composite_class = CompositeClass.new 'put data', 'other put data'
|
45
|
+
composite_class.key = 'put key'
|
46
|
+
|
47
|
+
# save it
|
48
|
+
composite_class.persist
|
49
|
+
|
50
|
+
# get the object back
|
51
|
+
composite_class = CompositeClass.retrieve 'put key'
|
52
|
+
|
53
|
+
assert_equal 'put data', composite_class.attribute_one
|
54
|
+
assert_equal 'other put data', composite_class.attribute_two
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.expand_path(File.join('..','helper'), __FILE__)
|
2
|
+
|
3
|
+
class Animal
|
4
|
+
include Ropl::Composition
|
5
|
+
|
6
|
+
attr_accessor :type, :friends, :interests
|
7
|
+
end
|
8
|
+
|
9
|
+
class TestCompositionStory < Test::Unit::TestCase
|
10
|
+
def test_story
|
11
|
+
# set up Riak connection
|
12
|
+
riak_config = YAML.load(File.read(File.expand_path(File.join('..','riak.yml'), __FILE__)))[:test]
|
13
|
+
riak_client = Riak::Client.new riak_config
|
14
|
+
|
15
|
+
henry = Animal.new
|
16
|
+
henry.key = 'henry'
|
17
|
+
henry.type = :chicken
|
18
|
+
henry.friends = 12
|
19
|
+
henry.interests = ["walking in the woods", "eating berries"]
|
20
|
+
|
21
|
+
timothy = Animal.new
|
22
|
+
timothy.key = 'timothy'
|
23
|
+
timothy.type = :bovine
|
24
|
+
timothy.friends = 17
|
25
|
+
timothy.interests = ["walking in fields of grass", "eating berries", "hanging out with the family"]
|
26
|
+
|
27
|
+
# ... later on that evening,
|
28
|
+
# we decide that henry and timothy
|
29
|
+
# are worth keeping around
|
30
|
+
|
31
|
+
Animal.ropl riak_client
|
32
|
+
|
33
|
+
henry.persist
|
34
|
+
timothy.persist
|
35
|
+
|
36
|
+
# ... and then some time later,
|
37
|
+
# perhaps in a different context,
|
38
|
+
# we want to compare interests
|
39
|
+
|
40
|
+
henry = Animal.retrieve 'henry'
|
41
|
+
timothy = Animal.retrieve 'timothy'
|
42
|
+
|
43
|
+
assert_equal ["eating berries"], henry.interests & timothy.interests
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path(File.join('..','helper'), __FILE__)
|
2
|
+
|
3
|
+
class Animal
|
4
|
+
attr_accessor :type, :friends, :interests
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestOopStory < Test::Unit::TestCase
|
8
|
+
def test_story
|
9
|
+
# set up Riak connection and persistence object
|
10
|
+
riak_config = YAML.load(File.read(File.expand_path(File.join('..','riak.yml'), __FILE__)))[:test]
|
11
|
+
riak_client = Riak::Client.new riak_config
|
12
|
+
ropl = Ropl::Ropl.new riak_client
|
13
|
+
|
14
|
+
# go about your day
|
15
|
+
henry = Animal.new
|
16
|
+
henry.type = :chicken
|
17
|
+
henry.friends = 12
|
18
|
+
henry.interests = ["walking in the woods", "eating berries"]
|
19
|
+
|
20
|
+
timothy = Animal.new
|
21
|
+
timothy.type = :bovine
|
22
|
+
timothy.friends = 17
|
23
|
+
timothy.interests = ["walking in fields of grass", "eating berries", "hanging out with the family"]
|
24
|
+
|
25
|
+
# later on that evening,
|
26
|
+
# we decide that henry and timothy
|
27
|
+
# are worth keeping around
|
28
|
+
|
29
|
+
ropl.put henry, :henry
|
30
|
+
ropl.put timothy, :timothy
|
31
|
+
|
32
|
+
# then some time even later,
|
33
|
+
# perhaps in a different context,
|
34
|
+
# we want to compare interests
|
35
|
+
|
36
|
+
henry = ropl.get Animal, :henry
|
37
|
+
timothy = ropl.get Animal, :timothy
|
38
|
+
|
39
|
+
assert_equal ["eating berries"], henry.interests & timothy.interests
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path(File.join('..','helper'), __FILE__)
|
2
|
+
|
3
|
+
class PersistedClass
|
4
|
+
attr_accessor :attribute_one, :attribute_two
|
5
|
+
end
|
6
|
+
|
7
|
+
class TestPersistedClass < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
riak_config = YAML.load(File.read(File.expand_path(File.join('..','riak.yml'), __FILE__)))[:test]
|
10
|
+
riak_client = Riak::Client.new riak_config
|
11
|
+
@ropl = Ropl::Ropl.new riak_client
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_post
|
15
|
+
# create some object without a key
|
16
|
+
persisted_class = PersistedClass.new
|
17
|
+
persisted_class.attribute_one = 'post data'
|
18
|
+
persisted_class.attribute_two = 'other post data'
|
19
|
+
|
20
|
+
# save it
|
21
|
+
response = @ropl.post persisted_class
|
22
|
+
assert response
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_put
|
26
|
+
# create some object with a key
|
27
|
+
persisted_class = PersistedClass.new
|
28
|
+
persisted_class.attribute_one = 'put data'
|
29
|
+
persisted_class.attribute_two = 'other put data'
|
30
|
+
|
31
|
+
# save it
|
32
|
+
response = @ropl.put persisted_class, 'put key'
|
33
|
+
assert_equal 'put key', response
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_put_then_get
|
37
|
+
# create some object with a key
|
38
|
+
persisted_class = PersistedClass.new
|
39
|
+
persisted_class.attribute_one = 'put data'
|
40
|
+
persisted_class.attribute_two = 'other put data'
|
41
|
+
|
42
|
+
# save it
|
43
|
+
@ropl.put persisted_class, 'put key'
|
44
|
+
|
45
|
+
# get the object back
|
46
|
+
persisted_class = @ropl.get PersistedClass, 'put key'
|
47
|
+
assert_equal 'put data', persisted_class.attribute_one
|
48
|
+
assert_equal 'other put data', persisted_class.attribute_two
|
49
|
+
end
|
50
|
+
|
51
|
+
=begin
|
52
|
+
def test_a_thousand_ops
|
53
|
+
# create a thousand objects
|
54
|
+
objects = 1000.times.map do
|
55
|
+
random_ascii = lambda{|n| rand(n).times.map{rand(256).chr}.join}
|
56
|
+
|
57
|
+
# create some object with a key
|
58
|
+
persisted_class = PersistedClass.new
|
59
|
+
persisted_class.attribute_one = random_ascii.call(1000)
|
60
|
+
persisted_class.attribute_two = random_ascii.call(1000)
|
61
|
+
|
62
|
+
[persisted_class, random_ascii.call(20)]
|
63
|
+
end
|
64
|
+
|
65
|
+
# persist each object
|
66
|
+
start_time = Time.now
|
67
|
+
objects.each do |object|
|
68
|
+
# save it
|
69
|
+
@ropl.put *object
|
70
|
+
end
|
71
|
+
puts "\nOne thousand ops time elapsed: #{Time.now - start_time} seconds.\n"
|
72
|
+
end
|
73
|
+
=end
|
74
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ropl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: riak-client
|
16
|
-
requirement: &
|
16
|
+
requirement: &70098053914280 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,7 +21,7 @@ dependencies:
|
|
21
21
|
version: 1.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70098053914280
|
25
25
|
description: Riak Object Persistence Layer
|
26
26
|
email:
|
27
27
|
- clr@port49.com
|
@@ -35,9 +35,16 @@ files:
|
|
35
35
|
- README.md
|
36
36
|
- Rakefile
|
37
37
|
- lib/ropl.rb
|
38
|
+
- lib/ropl/composition.rb
|
38
39
|
- lib/ropl/version.rb
|
39
40
|
- ropl.gemspec
|
40
|
-
|
41
|
+
- test/helper.rb
|
42
|
+
- test/riak.yml
|
43
|
+
- test/test_composition.rb
|
44
|
+
- test/test_composition_story.rb
|
45
|
+
- test/test_oop_story.rb
|
46
|
+
- test/test_persisted_class.rb
|
47
|
+
homepage: https://github.com/clr/ropl
|
41
48
|
licenses: []
|
42
49
|
post_install_message:
|
43
50
|
rdoc_options: []
|
@@ -61,4 +68,10 @@ rubygems_version: 1.8.15
|
|
61
68
|
signing_key:
|
62
69
|
specification_version: 3
|
63
70
|
summary: Why bother with an ORM? Just store the object. This is OOP, after all.
|
64
|
-
test_files:
|
71
|
+
test_files:
|
72
|
+
- test/helper.rb
|
73
|
+
- test/riak.yml
|
74
|
+
- test/test_composition.rb
|
75
|
+
- test/test_composition_story.rb
|
76
|
+
- test/test_oop_story.rb
|
77
|
+
- test/test_persisted_class.rb
|