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 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