jsl-hashback 0.0.1.2 → 0.0.2.3
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/LICENSE +1 -1
- data/README.rdoc +84 -2
- data/hashback.gemspec +16 -4
- data/lib/hashback.rb +3 -1
- data/lib/hashback/backend.rb +8 -2
- data/lib/hashback/resource.rb +56 -0
- data/spec/hashback/backend_spec.rb +1 -0
- metadata +25 -9
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,7 +1,89 @@
|
|
1
1
|
= HashBack
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
HashBack is a simple Object-hash mapping (OHM) system for Ruby. It allows for serializable classes to be saved,
|
4
|
+
retrieved and deleted from any key-value store supported by {Moneta}[http://github.com/wycats/moneta/tree/master]
|
5
|
+
(a unified interface to key-value systems).
|
6
|
+
|
7
|
+
== Quick Start
|
8
|
+
|
9
|
+
HashBack is easy to use, so we can jump right in to code using the system.
|
10
|
+
|
11
|
+
First, install the gem:
|
12
|
+
|
13
|
+
sudo gem install jsl-hashback
|
14
|
+
|
15
|
+
Then, in your code you'll want to require 'hashback'. For this example, the object ids that we use will be
|
16
|
+
UUIDs created by the assaf-uuid gem, so we'll include that as well.
|
17
|
+
|
18
|
+
require 'hashback'
|
19
|
+
require 'uuid'
|
20
|
+
|
21
|
+
Below we create a simple class that is serializable to HashBack.
|
22
|
+
|
23
|
+
class Elephant
|
24
|
+
HashBack::Resource.setup(self, :uuid, 'Moneta::Memory')
|
25
|
+
|
26
|
+
attr_accessor :uuid, :name
|
27
|
+
|
28
|
+
def initialize(name)
|
29
|
+
@name = name
|
30
|
+
@uuid = UUID.new.generate
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
You can now start using this class to save, fetch and retrieve elephants as follows:
|
35
|
+
|
36
|
+
dumbo = Elephant.new('Dumbo')
|
37
|
+
dumbo.save
|
38
|
+
|
39
|
+
To bring Dumbo back as a new elephant:
|
40
|
+
|
41
|
+
new_dumbo = Elephant.fetch(dumbo.uuid)
|
42
|
+
|
43
|
+
When you're sick of Dumbo and want to get rid of him:
|
44
|
+
|
45
|
+
new_dumbo.destroy
|
46
|
+
|
47
|
+
Note that at this point the data is still available in the instance variables for Dumbo, but the persisted form of him is gone.
|
48
|
+
|
49
|
+
== Detailed usage
|
50
|
+
|
51
|
+
Generally, HashBack should work with any class that can be serialized. You can decide which key-value storage system
|
52
|
+
to use by passing an appropriate class name to HashBack::Resource.setup. See the Moneta documentation for available backends.
|
53
|
+
|
54
|
+
You can also pass options to HashBack::Resource which are given directly to the moneta backend during initialization as
|
55
|
+
follows:
|
56
|
+
|
57
|
+
require 'hashback'
|
58
|
+
|
59
|
+
class Foo
|
60
|
+
HashBack::Resource.setup(self, :id, 'Moneta::Memcache', :server => 'localhost:1978')
|
61
|
+
end
|
62
|
+
|
63
|
+
This initializes a class with a backend storage in a Tokyo Tyrant server. The serialized forms of objects that are
|
64
|
+
stored will be saved with keys like Foo-object_id. You probably want to use a different id method to customize the id
|
65
|
+
that will be used to store these objects.
|
66
|
+
|
67
|
+
== Discussion
|
68
|
+
|
69
|
+
Key-value databases are rapidly becoming more popular, and they clearly have several use cases that aren't well
|
70
|
+
addressed by existing RDBM systems. While adoptation of these key-value storage systems has been rapid, there don't
|
71
|
+
seem to be any systems that help to implement common patterns for accessing objects saved in these stores. Before
|
72
|
+
writing this program, I couldn't find any precedent for a concept of a OHM (Object Hash Mapping) system, so I put
|
73
|
+
together a lightweight implementation with methods for saving and accessing similar to popular ORM systems in Ruby.
|
74
|
+
|
75
|
+
== TODO
|
76
|
+
|
77
|
+
The following features are not present in the current library, but may be useful:
|
78
|
+
|
79
|
+
* A system of callbacks
|
80
|
+
* A system for associating objects, perhaps constrained to objects that have a 1 - 1 mapping (since it's not entirely
|
81
|
+
intuitive what the structures or algorithms would be for mainting integrity with higher levels of mapping between
|
82
|
+
objects).
|
83
|
+
|
84
|
+
== Feedback
|
85
|
+
|
86
|
+
Please write the author if you have any questions or feedbacks about this library.
|
5
87
|
|
6
88
|
== Author
|
7
89
|
|
data/hashback.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "hashback"
|
3
|
-
s.version = "0.0.
|
3
|
+
s.version = "0.0.2.3"
|
4
4
|
s.date = "2009-05-13"
|
5
5
|
s.summary = "Generic tool for writing namespaced key-value data to a variety of hash-type systems"
|
6
6
|
s.email = "justin@phq.org"
|
@@ -16,13 +16,25 @@ Gem::Specification.new do |s|
|
|
16
16
|
"README.rdoc",
|
17
17
|
"Rakefile",
|
18
18
|
"lib/hashback.rb",
|
19
|
-
"lib/hashback/backend.rb"
|
19
|
+
"lib/hashback/backend.rb",
|
20
|
+
"lib/hashback/resource.rb"
|
20
21
|
]
|
21
22
|
s.test_files = [
|
22
23
|
"spec/hashback/backend_spec.rb",
|
23
24
|
"spec/hashback_spec.rb",
|
24
25
|
"spec/spec_helper.rb"
|
25
26
|
]
|
26
|
-
|
27
|
-
s.
|
27
|
+
|
28
|
+
s.extra_rdoc_files = [ "README.rdoc" ]
|
29
|
+
|
30
|
+
s.rdoc_options += [
|
31
|
+
'--title', 'HashBack',
|
32
|
+
'--main', 'README.rdoc',
|
33
|
+
'--line-numbers',
|
34
|
+
'--inline-source'
|
35
|
+
]
|
36
|
+
|
37
|
+
s.add_dependency("wycats-moneta")
|
38
|
+
s.add_dependency("activesupport")
|
39
|
+
s.add_dependency("assaf-uuid")
|
28
40
|
end
|
data/lib/hashback.rb
CHANGED
data/lib/hashback/backend.rb
CHANGED
@@ -8,7 +8,7 @@ module HashBack
|
|
8
8
|
def initialize(namespace, moneta_klass, options = { })
|
9
9
|
@namespace = namespace
|
10
10
|
@options = options
|
11
|
-
@moneta
|
11
|
+
@moneta = initialize_moneta_klass(moneta_klass)
|
12
12
|
end
|
13
13
|
|
14
14
|
def [](key)
|
@@ -36,7 +36,13 @@ module HashBack
|
|
36
36
|
|
37
37
|
def load_moneta_klass(klass)
|
38
38
|
klass_const = klass.respond_to?(:constantize) ? klass.constantize : klass
|
39
|
-
klass_const.new(@options)
|
39
|
+
moneta = klass_const.new(@options)
|
40
|
+
|
41
|
+
# The options hash would have messed up default Hash initialization to return an empty hash
|
42
|
+
# when the key was not found. Revert this case by setting the default to nil if the object
|
43
|
+
# responds to this method.
|
44
|
+
moneta.default = nil if moneta.respond_to?(:default)
|
45
|
+
moneta
|
40
46
|
end
|
41
47
|
|
42
48
|
def require_klass(klass)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module HashBack
|
2
|
+
|
3
|
+
# HashBack::Resource is an Object-Hash Mapping (OHM) tool for Ruby. It is able to map Ruby objects
|
4
|
+
# to any of the backends supported by Moneta, a unified interface to key-value storage systems.
|
5
|
+
class Resource
|
6
|
+
|
7
|
+
# Configures the persistent backend for this object. Configuration options:
|
8
|
+
#
|
9
|
+
# * +source+ - the class to be persisted
|
10
|
+
# * +key_method+ - a symbol representing the method that will return a unique identifier
|
11
|
+
# for this object when called on the instance
|
12
|
+
# * +moneta_klass+ - a String representation or class constant of the Moneta class used to store this object
|
13
|
+
# * +moneta_options+ - an (optional) hash which is passed directly to the moneta backend for configuration
|
14
|
+
def self.setup(source, key_method_sym, moneta_klass, moneta_options = {})
|
15
|
+
source.__send__(:class_variable_set, :@@_backend, HashBack::Backend.new(source.to_s, moneta_klass, moneta_options))
|
16
|
+
source.__send__(:class_variable_set, :@@_key_method_sym, key_method_sym)
|
17
|
+
|
18
|
+
source.__send__(:include, InstanceMethods)
|
19
|
+
source.extend(ClassMethods)
|
20
|
+
end
|
21
|
+
|
22
|
+
module InstanceMethods
|
23
|
+
|
24
|
+
# Saves the serialized form of this object to the configured backend store.
|
25
|
+
def save
|
26
|
+
_hashback_backend[_hashback_id_key] = self
|
27
|
+
end
|
28
|
+
|
29
|
+
# Destroy the persisted copy of this object.
|
30
|
+
def destroy
|
31
|
+
_hashback_backend.delete(_hashback_id_key)
|
32
|
+
end
|
33
|
+
|
34
|
+
## Methods we try to hide, because we're just sneaky like that.
|
35
|
+
|
36
|
+
def _hashback_backend
|
37
|
+
self.class.__send__(:class_variable_get, :@@_backend)
|
38
|
+
end
|
39
|
+
|
40
|
+
def _hashback_id_key
|
41
|
+
self.__send__(self.class.__send__(:class_variable_get, :@@_key_method_sym))
|
42
|
+
end
|
43
|
+
|
44
|
+
private :_hashback_backend, :_hashback_id_key
|
45
|
+
end
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
|
49
|
+
# Fetches the object identified by +key+ from the storage backend.
|
50
|
+
def fetch(key)
|
51
|
+
backend = self.__send__(:class_variable_get, :@@_backend)
|
52
|
+
backend[key]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -3,6 +3,7 @@ require File.join(File.dirname(__FILE__), %w[ .. spec_helper ])
|
|
3
3
|
describe HashBack::Backend do
|
4
4
|
before do
|
5
5
|
@mock_moneta = mock('moneta')
|
6
|
+
@mock_moneta.stubs(:keys).returns(['keyname'])
|
6
7
|
@moneta_klass = "Moneta::Memory"
|
7
8
|
@b = HashBack::Backend.new('foo', @moneta_klass, { })
|
8
9
|
@b.instance_variable_set(:@moneta, @mock_moneta)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsl-hashback
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Leitgeb
|
@@ -18,9 +18,9 @@ dependencies:
|
|
18
18
|
version_requirement:
|
19
19
|
version_requirements: !ruby/object:Gem::Requirement
|
20
20
|
requirements:
|
21
|
-
- - "
|
21
|
+
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0
|
23
|
+
version: "0"
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activesupport
|
@@ -28,9 +28,19 @@ dependencies:
|
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: assaf-uuid
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
34
44
|
version:
|
35
45
|
description: Wrapper around Moneta that facilitates using the key-value store as a backend for applications requiring namespacing
|
36
46
|
email: justin@phq.org
|
@@ -38,8 +48,8 @@ executables: []
|
|
38
48
|
|
39
49
|
extensions: []
|
40
50
|
|
41
|
-
extra_rdoc_files:
|
42
|
-
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.rdoc
|
43
53
|
files:
|
44
54
|
- Rakefile
|
45
55
|
- hashback.gemspec
|
@@ -48,11 +58,17 @@ files:
|
|
48
58
|
- README.rdoc
|
49
59
|
- lib/hashback.rb
|
50
60
|
- lib/hashback/backend.rb
|
61
|
+
- lib/hashback/resource.rb
|
51
62
|
has_rdoc: true
|
52
63
|
homepage: http://github.com/jsl/hashback
|
53
64
|
post_install_message:
|
54
|
-
rdoc_options:
|
55
|
-
|
65
|
+
rdoc_options:
|
66
|
+
- --title
|
67
|
+
- HashBack
|
68
|
+
- --main
|
69
|
+
- README.rdoc
|
70
|
+
- --line-numbers
|
71
|
+
- --inline-source
|
56
72
|
require_paths:
|
57
73
|
- lib
|
58
74
|
required_ruby_version: !ruby/object:Gem::Requirement
|