blombo 0.1
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/CHANGELOG +2 -0
- data/Manifest +7 -0
- data/README +95 -0
- data/Rakefile +9 -0
- data/blombo.gemspec +33 -0
- data/lib/blombo.rb +129 -0
- data/test/test_all.rb +101 -0
- data/test/test_helper.rb +4 -0
- metadata +73 -0
data/CHANGELOG
ADDED
data/Manifest
ADDED
data/README
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
|
|
2
|
+
Blombo
|
|
3
|
+
-------
|
|
4
|
+
|
|
5
|
+
Tread redis-server like a deep ruby hash.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Example usage
|
|
9
|
+
-------------
|
|
10
|
+
|
|
11
|
+
Blombo.redis = Redis.new
|
|
12
|
+
$blombo = Blombo.new('ServerApp')
|
|
13
|
+
|
|
14
|
+
$blombo.servers.status['web1'] = 'ok'
|
|
15
|
+
$blombo.servers.status['web2'] = 'down'
|
|
16
|
+
|
|
17
|
+
$blombo.servers.status[:web1]
|
|
18
|
+
#=> "ok"
|
|
19
|
+
|
|
20
|
+
$blombo.servers.status[:web3]
|
|
21
|
+
#=> nil
|
|
22
|
+
|
|
23
|
+
This creates a Redis Hash with the key 'blombo:ServerApp:servers:status',
|
|
24
|
+
and two fields ('web1', 'web2'), with two associated values.
|
|
25
|
+
|
|
26
|
+
You can store any Ruby objects as values, they will be automaticallly
|
|
27
|
+
Marshalled. (Strings are stored as-is). Blombo does not cache anything but
|
|
28
|
+
goes back to redis to get data whenever it is requested with a lookup[key].
|
|
29
|
+
|
|
30
|
+
Ruby's Enumerable is included along with each() so you can enjoy the usual
|
|
31
|
+
range of ruby hash methods:
|
|
32
|
+
|
|
33
|
+
$blombo.server.status
|
|
34
|
+
#=> #<Blombo:0x9ab0d84 @name="ServerApp:server:status" ...>
|
|
35
|
+
|
|
36
|
+
$blombo.servers.status.exists
|
|
37
|
+
=> true
|
|
38
|
+
|
|
39
|
+
$blombo.servers.status.keys
|
|
40
|
+
#=> ['web1', 'web2']
|
|
41
|
+
|
|
42
|
+
$blombo.servers.status.type
|
|
43
|
+
#=> 'hash'
|
|
44
|
+
|
|
45
|
+
$blombo.servers.status.select {|server, status| status == 'ok' }
|
|
46
|
+
#=> [["web1", "ok"]]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
Blombo only saves the object back into redis if the []= method is used.
|
|
50
|
+
Assignment must always be used to save to db. This means you should
|
|
51
|
+
maintain ruby objects like arrays carefully:
|
|
52
|
+
|
|
53
|
+
$blombo.servers[:list] = ["web1"]
|
|
54
|
+
$blombo.servers[:list] << "web2"
|
|
55
|
+
$blombo.servers[:list]
|
|
56
|
+
#=> ["web1"] #oops
|
|
57
|
+
|
|
58
|
+
$blombo.servers[:list] += ["web2"]
|
|
59
|
+
$blombo.servers[:list]
|
|
60
|
+
#=> ["web1", "web2"] #ahh!
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
Other Redis types
|
|
64
|
+
-----------------
|
|
65
|
+
|
|
66
|
+
What if I don't want a Redis hash? Thats OK - Blombo passes through redis
|
|
67
|
+
commands curried with the key as the first parameter:
|
|
68
|
+
|
|
69
|
+
This: $blombo.joblist.rpush('job1')
|
|
70
|
+
Equals: $redis.rpush('blombo:ServerApp:joblist', 'job1')
|
|
71
|
+
|
|
72
|
+
Then I can pop it off the list:
|
|
73
|
+
|
|
74
|
+
$blombo.joblist.type
|
|
75
|
+
#=> "list"
|
|
76
|
+
|
|
77
|
+
$blombo.joblist.llen
|
|
78
|
+
#=> 1
|
|
79
|
+
|
|
80
|
+
$blombo.joblist.lpop
|
|
81
|
+
#=> "job1"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
Contact the author
|
|
89
|
+
------------------
|
|
90
|
+
|
|
91
|
+
Andrew Snow <andrew@modulus.org>
|
|
92
|
+
Andys^ on irc.freenode.net
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
Blombo never forgets.
|
data/Rakefile
ADDED
data/blombo.gemspec
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = "blombo"
|
|
5
|
+
s.version = "0.1"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Andrew Snow"]
|
|
9
|
+
s.date = "2012-02-10"
|
|
10
|
+
s.description = "Blombo: Treat redis-server like a deep ruby hash"
|
|
11
|
+
s.email = "andrew@modulus.org"
|
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "README", "lib/blombo.rb"]
|
|
13
|
+
s.files = ["CHANGELOG", "README", "Rakefile", "lib/blombo.rb", "test/test_all.rb", "test/test_helper.rb", "Manifest", "blombo.gemspec"]
|
|
14
|
+
s.homepage = "http://github.com/andys/blombo"
|
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Blombo", "--main", "README"]
|
|
16
|
+
s.require_paths = ["lib"]
|
|
17
|
+
s.rubyforge_project = "blombo"
|
|
18
|
+
s.rubygems_version = "1.8.10"
|
|
19
|
+
s.summary = "Blombo: Treat redis-server like a deep ruby hash"
|
|
20
|
+
s.test_files = ["test/test_all.rb"]
|
|
21
|
+
|
|
22
|
+
if s.respond_to? :specification_version then
|
|
23
|
+
s.specification_version = 3
|
|
24
|
+
|
|
25
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
26
|
+
s.add_runtime_dependency(%q<redis>, [">= 0"])
|
|
27
|
+
else
|
|
28
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
s.add_dependency(%q<redis>, [">= 0"])
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/blombo.rb
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
|
|
2
|
+
class Blombo
|
|
3
|
+
|
|
4
|
+
include Enumerable
|
|
5
|
+
include Comparable
|
|
6
|
+
attr_reader :blombo_parent
|
|
7
|
+
|
|
8
|
+
class << self
|
|
9
|
+
attr_accessor :redis
|
|
10
|
+
def is_marshalled?(str)
|
|
11
|
+
Marshal.dump(nil)[0,2] == str[0,2] # Marshall stores its version info in first 2 bytes
|
|
12
|
+
end
|
|
13
|
+
def to_redis_val(obj)
|
|
14
|
+
if Integer===obj || String===obj && obj !~ /^\d+$/ && !is_marshalled?(obj)
|
|
15
|
+
obj.to_s
|
|
16
|
+
else
|
|
17
|
+
Marshal.dump(obj)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
def from_redis_val(str)
|
|
21
|
+
if(is_marshalled?(str))
|
|
22
|
+
Marshal.load(str)
|
|
23
|
+
elsif(str =~ /^\d+$/)
|
|
24
|
+
str.to_i
|
|
25
|
+
else
|
|
26
|
+
str
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def redis
|
|
32
|
+
self.class.redis
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def initialize(name, blombo_parent=nil)
|
|
36
|
+
@name = name
|
|
37
|
+
@blombo_parent = blombo_parent
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def <=>(other)
|
|
41
|
+
@name <=> other.blombo_name
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def blombo_key
|
|
45
|
+
"blombo:#{@name}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def blombo_name
|
|
49
|
+
@name
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def []=(key, val)
|
|
53
|
+
redis.hset(blombo_key, key.to_s, self.class.to_redis_val(val))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def defined?(key)
|
|
57
|
+
redis.exists(key.to_s)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def [](key)
|
|
61
|
+
if(val = redis.hget(blombo_key, key.to_s))
|
|
62
|
+
self.class.from_redis_val(val)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def nil?
|
|
67
|
+
empty?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def empty?
|
|
71
|
+
redis.hlen(blombo_key) == 0
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def to_hash
|
|
75
|
+
redis.hgetall(blombo_key)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def each(*args, &bl)
|
|
79
|
+
to_hash.each(*args, &bl)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def to_a
|
|
83
|
+
redis.hgetall(blombo_key).to_a
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def keys
|
|
87
|
+
self.class.redis.hkeys(blombo_key)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def values
|
|
91
|
+
self.class.redis.hvals(blombo_key).map {|v| self.class.from_redis_val(v) }
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def type
|
|
95
|
+
@type ||= (t = Blombo.redis.type(blombo_key)) && t != 'none' && t || nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def method_missing(meth, *params, &bl)
|
|
99
|
+
if Blombo.redis.respond_to?(meth)
|
|
100
|
+
Blombo.redis.send(meth, blombo_key, *params, &bl)
|
|
101
|
+
elsif params.empty? && meth =~ /^[a-z_][a-z0-9_]*$/i
|
|
102
|
+
Blombo.new("#{@name}:#{meth}", self)
|
|
103
|
+
else
|
|
104
|
+
super(meth, *params, &bl)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def blombo_children
|
|
109
|
+
self.class.redis.keys("#{blombo_key}:*").map {|k| Blombo.new(k.gsub(/^blombo:/,''), self) }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
=begin
|
|
116
|
+
|
|
117
|
+
blombo = Blombo.new(redis server details)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
blombo.blah = {'hello' => 'world'}
|
|
122
|
+
blombo.blah = OpenStruct(..)
|
|
123
|
+
blombo.blah = activerecord model
|
|
124
|
+
|
|
125
|
+
May as well assign each object a uniq id (using redis counters?)
|
|
126
|
+
to allow referencing / assocations
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
=end
|
data/test/test_all.rb
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../lib/blombo"
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'redis'
|
|
4
|
+
require "#{File.dirname(__FILE__)}/test_helper"
|
|
5
|
+
|
|
6
|
+
class TestBlombo < Test::Unit::TestCase
|
|
7
|
+
def setup
|
|
8
|
+
$redis.flushdb
|
|
9
|
+
Blombo.redis = $redis
|
|
10
|
+
@blombo = Blombo.new('test')
|
|
11
|
+
@blombo[:flibble] = "test123"
|
|
12
|
+
@blombo['derp'] = 'test321'
|
|
13
|
+
@blombo.deep[:firstname] = 'Herp'
|
|
14
|
+
@blombo.deep[:lastname] = 'Derpington'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def test_defined
|
|
18
|
+
assert_equal false, @blombo.defined?('foo')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_undefined_redis_type
|
|
22
|
+
assert_nil @blombo.foo.type
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_empty_hash_lookup
|
|
26
|
+
assert_nil @blombo['foo']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_hash_type
|
|
30
|
+
assert_equal 'hash', @blombo.type
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_hash_setter
|
|
34
|
+
assert_equal({'flibble' => 'test123', 'derp' => 'test321'}, $redis.hgetall('blombo:test'))
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_values
|
|
38
|
+
assert_equal(['test123', 'test321'], @blombo.values.sort)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_keys
|
|
42
|
+
assert_equal(['derp', 'flibble'], @blombo.keys.sort)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_each
|
|
46
|
+
# Blombo includes Enumerable so we can test #each with #inject
|
|
47
|
+
result = @blombo.inject({}) {|hsh, keyval| hsh.merge!(keyval.first => keyval.last) }
|
|
48
|
+
assert_equal($redis.hgetall('blombo:test'), result)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def test_deep_empty_type
|
|
52
|
+
assert Blombo===@blombo.deep
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_deep_empty_array
|
|
56
|
+
assert_equal [], @blombo.empty.to_a
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_deep_empty_method
|
|
60
|
+
assert_equal true, @blombo.empty.empty?
|
|
61
|
+
assert_equal false, @blombo.deep.empty?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_deep_empty_hash_lookup
|
|
65
|
+
assert_nil @blombo.deep['foo']
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_redis_keys
|
|
69
|
+
assert_equal(['blombo:test', 'blombo:test:deep'], $redis.keys.sort)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_deep_hash_setter
|
|
73
|
+
assert_equal({'firstname' => 'Herp', 'lastname' => 'Derpington'}, $redis.hgetall('blombo:test:deep'))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_deeper_hash
|
|
77
|
+
@blombo.a.b.c['d'] = 'e'
|
|
78
|
+
assert_equal({'d' => 'e'}, $redis.hgetall('blombo:test:a:b:c'))
|
|
79
|
+
assert_equal [@blombo.a.b.c], @blombo.a.blombo_children
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_marshal
|
|
83
|
+
@blombo.marshaltest[:number] = 12345
|
|
84
|
+
@blombo.marshaltest[:nil] = nil
|
|
85
|
+
assert_equal 12345, @blombo.marshaltest[:number]
|
|
86
|
+
assert_equal nil, @blombo.marshaltest[:nil]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_redis_ops
|
|
90
|
+
@blombo.listy.rpush('job1')
|
|
91
|
+
@blombo.listy.rpush('job2')
|
|
92
|
+
assert_equal 2, $redis.llen('blombo:test:listy')
|
|
93
|
+
assert_equal ['job1', 'job2'], @blombo.listy.lrange(0, -1)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def test_redis_list_type
|
|
97
|
+
@blombo.listy.rpush('job1')
|
|
98
|
+
assert_equal 'list', @blombo.listy.type
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: blombo
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: '0.1'
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Andrew Snow
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-02-10 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: redis
|
|
16
|
+
requirement: &82662180 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *82662180
|
|
25
|
+
description: ! 'Blombo: Treat redis-server like a deep ruby hash'
|
|
26
|
+
email: andrew@modulus.org
|
|
27
|
+
executables: []
|
|
28
|
+
extensions: []
|
|
29
|
+
extra_rdoc_files:
|
|
30
|
+
- CHANGELOG
|
|
31
|
+
- README
|
|
32
|
+
- lib/blombo.rb
|
|
33
|
+
files:
|
|
34
|
+
- CHANGELOG
|
|
35
|
+
- README
|
|
36
|
+
- Rakefile
|
|
37
|
+
- lib/blombo.rb
|
|
38
|
+
- test/test_all.rb
|
|
39
|
+
- test/test_helper.rb
|
|
40
|
+
- Manifest
|
|
41
|
+
- blombo.gemspec
|
|
42
|
+
homepage: http://github.com/andys/blombo
|
|
43
|
+
licenses: []
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options:
|
|
46
|
+
- --line-numbers
|
|
47
|
+
- --inline-source
|
|
48
|
+
- --title
|
|
49
|
+
- Blombo
|
|
50
|
+
- --main
|
|
51
|
+
- README
|
|
52
|
+
require_paths:
|
|
53
|
+
- lib
|
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
|
+
none: false
|
|
56
|
+
requirements:
|
|
57
|
+
- - ! '>='
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '0'
|
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
|
+
none: false
|
|
62
|
+
requirements:
|
|
63
|
+
- - ! '>='
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '1.2'
|
|
66
|
+
requirements: []
|
|
67
|
+
rubyforge_project: blombo
|
|
68
|
+
rubygems_version: 1.8.10
|
|
69
|
+
signing_key:
|
|
70
|
+
specification_version: 3
|
|
71
|
+
summary: ! 'Blombo: Treat redis-server like a deep ruby hash'
|
|
72
|
+
test_files:
|
|
73
|
+
- test/test_all.rb
|