blombo 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+
2
+ v0.1. First version
data/Manifest ADDED
@@ -0,0 +1,7 @@
1
+ CHANGELOG
2
+ README
3
+ Rakefile
4
+ lib/blombo.rb
5
+ test/test_all.rb
6
+ test/test_helper.rb
7
+ Manifest
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
@@ -0,0 +1,9 @@
1
+ require 'echoe'
2
+
3
+ Echoe.new("blombo") do |p|
4
+ p.author = "Andrew Snow"
5
+ p.email = 'andrew@modulus.org'
6
+ p.summary = "Blombo: Treat redis-server like a deep ruby hash"
7
+ p.url = "http://github.com/andys/blombo"
8
+ p.runtime_dependencies = ['redis']
9
+ end
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
@@ -0,0 +1,4 @@
1
+
2
+ # WARNING: The database specified here will be CLEARED of ALL DATA
3
+ $redis = Redis.new(:host => 'localhost', :port => 6379, :db => 15)
4
+
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