This repository has been archived by the owner on Oct 18, 2022. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b64f19b
Showing
7 changed files
with
347 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
|
||
v0.1. First version |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
CHANGELOG | ||
README | ||
Rakefile | ||
lib/blombo.rb | ||
test/test_all.rb | ||
test/test_helper.rb | ||
Manifest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
|
||
Blombo | ||
------- | ||
|
||
Tread redis-server like a deep ruby hash. | ||
|
||
|
||
Example usage | ||
------------- | ||
|
||
Blombo.redis = Redis.new | ||
$blombo = Blombo.new('ServerApp') | ||
|
||
$blombo.servers.status['web1'] = 'ok' | ||
$blombo.servers.status['web2'] = 'down' | ||
|
||
$blombo.servers.status[:web1] | ||
#=> "ok" | ||
|
||
$blombo.servers.status[:web3] | ||
#=> nil | ||
|
||
This creates a Redis Hash with the key 'blombo:ServerApp:servers:status', | ||
and two fields ('web1', 'web2'), with two associated values. | ||
|
||
You can store any Ruby objects as values, they will be automaticallly | ||
Marshalled. (Strings are stored as-is). Blombo does not cache anything but | ||
goes back to redis to get data whenever it is requested with a lookup[key]. | ||
|
||
Ruby's Enumerable is included along with each() so you can enjoy the usual | ||
range of ruby hash methods: | ||
|
||
$blombo.server.status | ||
#=> #<Blombo:0x9ab0d84 @name="ServerApp:server:status" ...> | ||
|
||
$blombo.servers.status.exists | ||
=> true | ||
|
||
$blombo.servers.status.keys | ||
#=> ['web1', 'web2'] | ||
|
||
$blombo.servers.status.type | ||
#=> 'hash' | ||
|
||
$blombo.servers.status.select {|server, status| status == 'ok' } | ||
#=> [["web1", "ok"]] | ||
|
||
|
||
Blombo only saves the object back into redis if the []= method is used. | ||
Assignment must always be used to save to db. This means you should | ||
maintain ruby objects like arrays carefully: | ||
|
||
$blombo.servers[:list] = ["web1"] | ||
$blombo.servers[:list] << "web2" | ||
$blombo.servers[:list] | ||
#=> ["web1"] #oops | ||
|
||
$blombo.servers[:list] += ["web2"] | ||
$blombo.servers[:list] | ||
#=> ["web1", "web2"] #ahh! | ||
|
||
|
||
Other Redis types | ||
----------------- | ||
|
||
What if I don't want a Redis hash? Thats OK - Blombo passes through redis | ||
commands curried with the key as the first parameter: | ||
|
||
This: $blombo.joblist.rpush('job1') | ||
Equals: $redis.rpush('blombo:ServerApp:joblist', 'job1') | ||
|
||
Then I can pop it off the list: | ||
|
||
$blombo.joblist.type | ||
#=> "list" | ||
|
||
$blombo.joblist.llen | ||
#=> 1 | ||
|
||
$blombo.joblist.lpop | ||
#=> "job1" | ||
|
||
|
||
|
||
|
||
|
||
|
||
Contact the author | ||
------------------ | ||
|
||
Andrew Snow <andrew@modulus.org> | ||
Andys^ on irc.freenode.net | ||
|
||
|
||
Blombo never forgets. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require 'echoe' | ||
|
||
Echoe.new("blombo") do |p| | ||
p.author = "Andrew Snow" | ||
p.email = 'andrew@modulus.org' | ||
p.summary = "Blombo: Treat redis-server like a deep ruby hash" | ||
p.url = "http://github.com/andys/blombo" | ||
p.runtime_dependencies = ['redis'] | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
|
||
class Blombo | ||
|
||
include Enumerable | ||
include Comparable | ||
attr_reader :blombo_parent | ||
|
||
class << self | ||
attr_accessor :redis | ||
def is_marshalled?(str) | ||
Marshal.dump(nil)[0,2] == str[0,2] # Marshall stores its version info in first 2 bytes | ||
end | ||
def to_redis_val(obj) | ||
if Integer===obj || String===obj && obj !~ /^\d+$/ && !is_marshalled?(obj) | ||
obj.to_s | ||
else | ||
Marshal.dump(obj) | ||
end | ||
end | ||
def from_redis_val(str) | ||
if(is_marshalled?(str)) | ||
Marshal.load(str) | ||
elsif(str =~ /^\d+$/) | ||
str.to_i | ||
else | ||
str | ||
end | ||
end | ||
end | ||
|
||
def redis | ||
self.class.redis | ||
end | ||
|
||
def initialize(name, blombo_parent=nil) | ||
@name = name | ||
@blombo_parent = blombo_parent | ||
end | ||
|
||
def <=>(other) | ||
@name <=> other.blombo_name | ||
end | ||
|
||
def blombo_key | ||
"blombo:#{@name}" | ||
end | ||
|
||
def blombo_name | ||
@name | ||
end | ||
|
||
def []=(key, val) | ||
redis.hset(blombo_key, key.to_s, self.class.to_redis_val(val)) | ||
end | ||
|
||
def defined?(key) | ||
redis.exists(key.to_s) | ||
end | ||
|
||
def [](key) | ||
if(val = redis.hget(blombo_key, key.to_s)) | ||
self.class.from_redis_val(val) | ||
end | ||
end | ||
|
||
def nil? | ||
empty? | ||
end | ||
|
||
def empty? | ||
redis.hlen(blombo_key) == 0 | ||
end | ||
|
||
def to_hash | ||
redis.hgetall(blombo_key) | ||
end | ||
|
||
def each(*args, &bl) | ||
to_hash.each(*args, &bl) | ||
end | ||
|
||
def to_a | ||
redis.hgetall(blombo_key).to_a | ||
end | ||
|
||
def keys | ||
self.class.redis.hkeys(blombo_key) | ||
end | ||
|
||
def values | ||
self.class.redis.hvals(blombo_key).map {|v| self.class.from_redis_val(v) } | ||
end | ||
|
||
def type | ||
@type ||= (t = Blombo.redis.type(blombo_key)) && t != 'none' && t || nil | ||
end | ||
|
||
def method_missing(meth, *params, &bl) | ||
if Blombo.redis.respond_to?(meth) | ||
Blombo.redis.send(meth, blombo_key, *params, &bl) | ||
elsif params.empty? && meth =~ /^[a-z_][a-z0-9_]*$/i | ||
Blombo.new("#{@name}:#{meth}", self) | ||
else | ||
super(meth, *params, &bl) | ||
end | ||
end | ||
|
||
def blombo_children | ||
self.class.redis.keys("#{blombo_key}:*").map {|k| Blombo.new(k.gsub(/^blombo:/,''), self) } | ||
end | ||
|
||
end | ||
|
||
|
||
=begin | ||
blombo = Blombo.new(redis server details) | ||
blombo.blah = {'hello' => 'world'} | ||
blombo.blah = OpenStruct(..) | ||
blombo.blah = activerecord model | ||
May as well assign each object a uniq id (using redis counters?) | ||
to allow referencing / assocations | ||
=end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
require "#{File.dirname(__FILE__)}/../lib/blombo" | ||
require 'test/unit' | ||
require 'redis' | ||
require "#{File.dirname(__FILE__)}/test_helper" | ||
|
||
class TestBlombo < Test::Unit::TestCase | ||
def setup | ||
$redis.flushdb | ||
Blombo.redis = $redis | ||
@blombo = Blombo.new('test') | ||
@blombo[:flibble] = "test123" | ||
@blombo['derp'] = 'test321' | ||
@blombo.deep[:firstname] = 'Herp' | ||
@blombo.deep[:lastname] = 'Derpington' | ||
end | ||
|
||
def test_defined | ||
assert_equal false, @blombo.defined?('foo') | ||
end | ||
|
||
def test_undefined_redis_type | ||
assert_nil @blombo.foo.type | ||
end | ||
|
||
def test_empty_hash_lookup | ||
assert_nil @blombo['foo'] | ||
end | ||
|
||
def test_hash_type | ||
assert_equal 'hash', @blombo.type | ||
end | ||
|
||
def test_hash_setter | ||
assert_equal({'flibble' => 'test123', 'derp' => 'test321'}, $redis.hgetall('blombo:test')) | ||
end | ||
|
||
def test_values | ||
assert_equal(['test123', 'test321'], @blombo.values.sort) | ||
end | ||
|
||
def test_keys | ||
assert_equal(['derp', 'flibble'], @blombo.keys.sort) | ||
end | ||
|
||
def test_each | ||
# Blombo includes Enumerable so we can test #each with #inject | ||
result = @blombo.inject({}) {|hsh, keyval| hsh.merge!(keyval.first => keyval.last) } | ||
assert_equal($redis.hgetall('blombo:test'), result) | ||
end | ||
|
||
def test_deep_empty_type | ||
assert Blombo===@blombo.deep | ||
end | ||
|
||
def test_deep_empty_array | ||
assert_equal [], @blombo.empty.to_a | ||
end | ||
|
||
def test_deep_empty_method | ||
assert_equal true, @blombo.empty.empty? | ||
assert_equal false, @blombo.deep.empty? | ||
end | ||
|
||
def test_deep_empty_hash_lookup | ||
assert_nil @blombo.deep['foo'] | ||
end | ||
|
||
def test_redis_keys | ||
assert_equal(['blombo:test', 'blombo:test:deep'], $redis.keys.sort) | ||
end | ||
|
||
def test_deep_hash_setter | ||
assert_equal({'firstname' => 'Herp', 'lastname' => 'Derpington'}, $redis.hgetall('blombo:test:deep')) | ||
end | ||
|
||
def test_deeper_hash | ||
@blombo.a.b.c['d'] = 'e' | ||
assert_equal({'d' => 'e'}, $redis.hgetall('blombo:test:a:b:c')) | ||
assert_equal [@blombo.a.b.c], @blombo.a.blombo_children | ||
end | ||
|
||
def test_marshal | ||
@blombo.marshaltest[:number] = 12345 | ||
@blombo.marshaltest[:nil] = nil | ||
assert_equal 12345, @blombo.marshaltest[:number] | ||
assert_equal nil, @blombo.marshaltest[:nil] | ||
end | ||
|
||
def test_redis_ops | ||
@blombo.listy.rpush('job1') | ||
@blombo.listy.rpush('job2') | ||
assert_equal 2, $redis.llen('blombo:test:listy') | ||
assert_equal ['job1', 'job2'], @blombo.listy.lrange(0, -1) | ||
end | ||
|
||
def test_redis_list_type | ||
@blombo.listy.rpush('job1') | ||
assert_equal 'list', @blombo.listy.type | ||
end | ||
|
||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
|
||
# WARNING: The database specified here will be CLEARED of ALL DATA | ||
$redis = Redis.new(:host => 'localhost', :port => 6379, :db => 15) | ||
|