blendris 0.5 → 0.6
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.tar.gz.sig +2 -0
- data/Manifest +1 -1
- data/README.markdown +124 -12
- data/Rakefile +2 -2
- data/blendris.gemspec +7 -5
- data/lib/blendris/accessor.rb +57 -16
- data/lib/blendris/errors.rb +0 -2
- data/lib/blendris/integer.rb +5 -3
- data/lib/blendris/list.rb +13 -2
- data/lib/blendris/model.rb +18 -35
- data/lib/blendris/node.rb +22 -1
- data/lib/blendris/reference.rb +0 -2
- data/lib/blendris/reference_base.rb +5 -7
- data/lib/blendris/reference_set.rb +15 -3
- data/lib/blendris/set.rb +1 -2
- data/lib/blendris/string.rb +1 -3
- data/spec/integer_spec.rb +15 -0
- data/spec/list_spec.rb +6 -0
- data/spec/model_spec.rb +9 -2
- data/spec/ref_spec.rb +9 -0
- data/spec/spec_helper.rb +11 -3
- metadata +35 -8
- metadata.gz.sig +1 -0
- data/tasks/rspec.rake +0 -21
data.tar.gz.sig
ADDED
data/Manifest
CHANGED
@@ -21,6 +21,7 @@ lib/blendris/utils.rb
|
|
21
21
|
script/console
|
22
22
|
script/destroy
|
23
23
|
script/generate
|
24
|
+
spec/integer_spec.rb
|
24
25
|
spec/list_spec.rb
|
25
26
|
spec/model_spec.rb
|
26
27
|
spec/redis-tools_spec.rb
|
@@ -29,4 +30,3 @@ spec/set_spec.rb
|
|
29
30
|
spec/spec.opts
|
30
31
|
spec/spec_helper.rb
|
31
32
|
spec/string_spec.rb
|
32
|
-
tasks/rspec.rake
|
data/README.markdown
CHANGED
@@ -6,7 +6,8 @@ http://github.com/alexmchale/blendris
|
|
6
6
|
|
7
7
|
# DESCRIPTION #
|
8
8
|
|
9
|
-
Blendris is a Ruby interface to a Redis database.
|
9
|
+
Blendris is a Ruby interface to a Redis database. It performs no caching,
|
10
|
+
causing all reads and writes to interact directly with Redis.
|
10
11
|
|
11
12
|
|
12
13
|
|
@@ -58,33 +59,74 @@ Let's say we want to maintain a list of employers and employees.
|
|
58
59
|
ref :employer, :class => "Employer", :reverse => :employees
|
59
60
|
end
|
60
61
|
|
62
|
+
And now some examples of using them:
|
63
|
+
|
64
|
+
>> captain = Employee.create("Captain Amazing")
|
65
|
+
=> #<Employee:0x45d18084 @key="employee:Captain_Amazing">
|
66
|
+
|
67
|
+
>> captain.address = "123 Fake Street"
|
68
|
+
=> "123 Fake Street"
|
69
|
+
|
70
|
+
>> guild = Employer.create("The Really Fantastic Guild of Heroes")
|
71
|
+
=> #<Employer:0x476e46f5 @key="employer:The_Really_Fantastic_Guild_of_Heroes">
|
72
|
+
|
73
|
+
>> guild.employees << captain
|
74
|
+
=> #<Blendris::RedisReferenceSet:0x500150a0 @key="employer:The_Really_Fantastic_Guild_of_Heroes:employees", ...>
|
75
|
+
|
76
|
+
>> guild.employees.first.address
|
77
|
+
=> "123 Fake Street"
|
78
|
+
|
79
|
+
>> guild.employees.count
|
80
|
+
=> 1
|
81
|
+
|
82
|
+
>> guild.employees.first.employer.employees.first.name
|
83
|
+
=> "Captain Amazing"
|
84
|
+
|
61
85
|
### key ###
|
62
86
|
|
63
|
-
Key sets the base key for this object.
|
64
|
-
"37 Signals" it would create a key "employer:37_Signals" and set its value
|
65
|
-
to "Employer". In the key, strings are interpreted as literals and
|
66
|
-
symbols are interpreted as pointers to that data field.
|
87
|
+
Key sets the base key for this object.
|
67
88
|
|
68
|
-
*
|
69
|
-
|
70
|
-
*
|
71
|
-
|
89
|
+
* Any strings in the key will be used as literal strings.
|
90
|
+
* Any symbols in the key will be set to the value of that field in this object.
|
91
|
+
* In the case of the employer "37 Signals" it would create a key
|
92
|
+
"employer:37_Signals" and set its value to "Employer".
|
93
|
+
* Note that spaces are converted to underscores, as spaces are not allowed in
|
94
|
+
Redis keys. This could cause problems in some data sets.
|
95
|
+
* Also note that the value assigned to the base key is the class name of the
|
96
|
+
model being used.
|
72
97
|
* Only strings and integers should be used as key values.
|
73
98
|
|
99
|
+
Examples of keys in use:
|
100
|
+
|
101
|
+
>> employer = Employer.create("37 Signals")
|
102
|
+
=> #<Employer:0x169da74 @key="employer:37_Signals">
|
103
|
+
|
104
|
+
>> employer.key
|
105
|
+
=> "employer:37_Signals"
|
106
|
+
|
107
|
+
>> employer.name
|
108
|
+
=> "37 Signals"
|
109
|
+
|
110
|
+
>> employer[:name]
|
111
|
+
=> #<Blendris::RedisString:0x20dbd794 @key="employer:37_Signals:name", ...>
|
112
|
+
|
113
|
+
>> employer[:name].key
|
114
|
+
=> "employer:37_Signals:name"
|
115
|
+
|
74
116
|
### string ###
|
75
117
|
|
76
118
|
String creates a string key named for the first parameter given to it.
|
77
119
|
This means that it would generate a key "employer:37_Signals:name" with
|
78
120
|
a value of "37 Signals".
|
79
121
|
|
80
|
-
### refs ###
|
122
|
+
### ref and refs ###
|
81
123
|
|
82
|
-
Refs
|
124
|
+
Refs maintain references to other objects.
|
83
125
|
|
84
126
|
* *:class* will limit objects in this reference set to the given class.
|
85
127
|
If a string is specified as a class, it will be constantized before
|
86
128
|
comparing.
|
87
|
-
*
|
129
|
+
* *:reverse* will cause the given field to be updated on the object when
|
88
130
|
it is added to or removed from this set.
|
89
131
|
|
90
132
|
### new vs create ###
|
@@ -96,7 +138,77 @@ the list of symbols in your *key* field.
|
|
96
138
|
Calling the *new* method will instantiate an existing object using the
|
97
139
|
given *key* as the base key.
|
98
140
|
|
141
|
+
Calling *create* on an object key that already exists is perfectly acceptable
|
142
|
+
and only results in new Ruby objects being instantiated. They will all read
|
143
|
+
and write to the same Redis data. Calling *new* however must be done on a
|
144
|
+
Redis key that already exists and is set to the name of the requested model.
|
145
|
+
|
146
|
+
>> Employer.create("Giant Faceless Corporation")
|
147
|
+
=> #<Employer:0x45a84b38 @key="employer:Giant_Faceless_Corporation">
|
148
|
+
|
149
|
+
>> Employer.create("Giant Faceless Corporation")
|
150
|
+
=> #<Employer:0x12b8501d @key="employer:Giant_Faceless_Corporation">
|
151
|
+
|
152
|
+
>> Employer.create("Giant Faceless Corporation")
|
153
|
+
=> #<Employer:0x742136c6 @key="employer:Giant_Faceless_Corporation">
|
154
|
+
|
155
|
+
>> Employer.new("Anything")
|
156
|
+
TypeError: Anything does not exist, not a Employer - you may want create instead of new
|
157
|
+
from .../blendris/lib/blendris/model.rb:25:in `initialize'
|
158
|
+
from (irb):32:in `new'
|
159
|
+
from (irb):32
|
160
|
+
|
161
|
+
>> Employer.new("employer:Giant_Faceless_Corporation")
|
162
|
+
=> #<Employer:0x73cb4cae @key="employer:Giant_Faceless_Corporation">
|
163
|
+
|
164
|
+
>> Employee.create("Invisible Woman")
|
165
|
+
=> #<Employee:0x5f27a49c @key="employee:Invisible_Woman">
|
166
|
+
|
167
|
+
>> Employer.new("employee:Invisible_Woman")
|
168
|
+
TypeError: employee:Invisible_Woman is a Employee, not a Employer
|
169
|
+
from /Users/amchale/Dropbox/Projects/blendris/lib/blendris/model.rb:26:in `initialize'
|
170
|
+
from (irb):36:in `new'
|
171
|
+
from (irb):36
|
172
|
+
|
173
|
+
### on_change ###
|
174
|
+
|
175
|
+
This keyword allows you to execute a block when one or more fields on the
|
176
|
+
object change. The block is executed within the context of the object.
|
177
|
+
|
178
|
+
class Dog < Blendris::Model
|
179
|
+
key "dog", :name
|
180
|
+
|
181
|
+
string :name
|
182
|
+
string :color
|
183
|
+
integer :attention
|
184
|
+
integer :food
|
185
|
+
|
186
|
+
on_change do
|
187
|
+
puts "Bark, bark!"
|
188
|
+
end
|
189
|
+
|
190
|
+
on_change :attention, :food do
|
191
|
+
puts "Woof, woof!"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
>> d = Dog.create("Spot")
|
196
|
+
Bark, bark!
|
197
|
+
=> #<Dog:0x000001011739e8 @key="dog:Spot">
|
198
|
+
|
199
|
+
>> d.attention = 0
|
200
|
+
Bark, bark!
|
201
|
+
Woof, woof!
|
202
|
+
=> 0
|
203
|
+
|
204
|
+
>> d.color = "brown"
|
205
|
+
Bark, bark!
|
206
|
+
=> "brown"
|
99
207
|
|
208
|
+
>> d[:attention].increment
|
209
|
+
Bark, bark!
|
210
|
+
Woof, woof!
|
211
|
+
=> 1
|
100
212
|
|
101
213
|
# LICENSE #
|
102
214
|
|
data/Rakefile
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
require "rubygems"
|
2
|
+
require "rubygems/commands/push_command"
|
2
3
|
|
3
4
|
gem "echoe", ">= 4.1"
|
4
5
|
gem "redis", ">= 0.1.2"
|
5
6
|
|
6
7
|
require "echoe"
|
7
|
-
|
8
8
|
require "redis"
|
9
9
|
require "fileutils"
|
10
10
|
require "./lib/blendris"
|
11
11
|
|
12
|
-
Echoe.new("blendris", "0.
|
12
|
+
Echoe.new("blendris", "0.6") do |p|
|
13
13
|
|
14
14
|
p.description = "A redis library for Ruby"
|
15
15
|
p.url = "http://github.com/alexmchale/blendris"
|
data/blendris.gemspec
CHANGED
@@ -2,20 +2,22 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{blendris}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.6"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Alex McHale"]
|
9
|
-
s.
|
9
|
+
s.cert_chain = ["/Users/alexmchale/Dropbox/Security/gem-public_cert.pem"]
|
10
|
+
s.date = %q{2010-02-27}
|
10
11
|
s.description = %q{A redis library for Ruby}
|
11
12
|
s.email = %q{alexmchale@gmail.com}
|
12
|
-
s.extra_rdoc_files = ["README.markdown", "lib/blendris.rb", "lib/blendris/accessor.rb", "lib/blendris/errors.rb", "lib/blendris/integer.rb", "lib/blendris/list.rb", "lib/blendris/model.rb", "lib/blendris/node.rb", "lib/blendris/reference.rb", "lib/blendris/reference_base.rb", "lib/blendris/reference_set.rb", "lib/blendris/set.rb", "lib/blendris/string.rb", "lib/blendris/types.rb", "lib/blendris/utils.rb"
|
13
|
-
s.files = ["History.txt", "Manifest", "PostInstall.txt", "README.markdown", "Rakefile", "autotest/discover.rb", "lib/blendris.rb", "lib/blendris/accessor.rb", "lib/blendris/errors.rb", "lib/blendris/integer.rb", "lib/blendris/list.rb", "lib/blendris/model.rb", "lib/blendris/node.rb", "lib/blendris/reference.rb", "lib/blendris/reference_base.rb", "lib/blendris/reference_set.rb", "lib/blendris/set.rb", "lib/blendris/string.rb", "lib/blendris/types.rb", "lib/blendris/utils.rb", "script/console", "script/destroy", "script/generate", "spec/list_spec.rb", "spec/model_spec.rb", "spec/redis-tools_spec.rb", "spec/ref_spec.rb", "spec/set_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/string_spec.rb", "
|
13
|
+
s.extra_rdoc_files = ["README.markdown", "lib/blendris.rb", "lib/blendris/accessor.rb", "lib/blendris/errors.rb", "lib/blendris/integer.rb", "lib/blendris/list.rb", "lib/blendris/model.rb", "lib/blendris/node.rb", "lib/blendris/reference.rb", "lib/blendris/reference_base.rb", "lib/blendris/reference_set.rb", "lib/blendris/set.rb", "lib/blendris/string.rb", "lib/blendris/types.rb", "lib/blendris/utils.rb"]
|
14
|
+
s.files = ["History.txt", "Manifest", "PostInstall.txt", "README.markdown", "Rakefile", "autotest/discover.rb", "lib/blendris.rb", "lib/blendris/accessor.rb", "lib/blendris/errors.rb", "lib/blendris/integer.rb", "lib/blendris/list.rb", "lib/blendris/model.rb", "lib/blendris/node.rb", "lib/blendris/reference.rb", "lib/blendris/reference_base.rb", "lib/blendris/reference_set.rb", "lib/blendris/set.rb", "lib/blendris/string.rb", "lib/blendris/types.rb", "lib/blendris/utils.rb", "script/console", "script/destroy", "script/generate", "spec/integer_spec.rb", "spec/list_spec.rb", "spec/model_spec.rb", "spec/redis-tools_spec.rb", "spec/ref_spec.rb", "spec/set_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/string_spec.rb", "blendris.gemspec"]
|
14
15
|
s.homepage = %q{http://github.com/alexmchale/blendris}
|
15
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Blendris", "--main", "README.markdown"]
|
16
17
|
s.require_paths = ["lib"]
|
17
18
|
s.rubyforge_project = %q{blendris}
|
18
|
-
s.rubygems_version = %q{1.3.
|
19
|
+
s.rubygems_version = %q{1.3.6}
|
20
|
+
s.signing_key = %q{/Users/alexmchale/Dropbox/Security/gem-private_key.pem}
|
19
21
|
s.summary = %q{A redis library for Ruby}
|
20
22
|
|
21
23
|
if s.respond_to? :specification_version then
|
data/lib/blendris/accessor.rb
CHANGED
@@ -1,5 +1,47 @@
|
|
1
1
|
module Blendris
|
2
2
|
|
3
|
+
class << self
|
4
|
+
|
5
|
+
attr_accessor :host, :port, :database
|
6
|
+
|
7
|
+
# Specify the host to connect to for the Redis connection.
|
8
|
+
def host=(host)
|
9
|
+
@host = host || "localhost"
|
10
|
+
$_redis_connection = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
# Specify the port to connect to for the Redis connection.
|
14
|
+
def port=(port)
|
15
|
+
@port = port.to_i
|
16
|
+
@port = 6379 unless (1 .. 65535).include? @port
|
17
|
+
$_redis_connection = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Specify the database number to use in the Redis database.
|
21
|
+
def database=(index)
|
22
|
+
@database = index.to_i
|
23
|
+
$_redis_connection = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
# Retrieve the connection to the current Redis database.
|
27
|
+
def redis
|
28
|
+
parms =
|
29
|
+
{
|
30
|
+
:host => @host,
|
31
|
+
:port => @port,
|
32
|
+
:db => @database
|
33
|
+
}
|
34
|
+
|
35
|
+
$_redis_connection ||= Redis.new(parms)
|
36
|
+
end
|
37
|
+
|
38
|
+
# This will delete all keys in the current database. Dangerous!
|
39
|
+
def flushdb
|
40
|
+
redis.flushdb
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
3
45
|
# This module serves as a gateway to the Redis library. Any object
|
4
46
|
# that needs to access Redis directly should include it.
|
5
47
|
|
@@ -8,11 +50,11 @@ module Blendris
|
|
8
50
|
include Utils
|
9
51
|
|
10
52
|
def redis
|
11
|
-
|
53
|
+
Blendris.redis
|
12
54
|
end
|
13
55
|
|
14
56
|
def self.redis
|
15
|
-
|
57
|
+
Blendris.redis
|
16
58
|
end
|
17
59
|
|
18
60
|
# Generate a key for the given model class with the given values list.
|
@@ -28,10 +70,15 @@ module Blendris
|
|
28
70
|
when Symbol
|
29
71
|
value = values[value_index]
|
30
72
|
value_index += 1
|
31
|
-
|
32
73
|
raise ArgumentError.new("#{self.name} created without #{symbol}") unless value
|
33
74
|
|
34
|
-
klass.
|
75
|
+
options = klass.redis_symbols[symbol.to_s]
|
76
|
+
raise ArgumentError.new("#{self.name} is missing its #{symbol}") unless options
|
77
|
+
|
78
|
+
subklass = options[:type]
|
79
|
+
raise ArgumentError.new("#{symbol} (#{subklass.name}) cannot be used in the key") unless subklass.respond_to? :cast_to_redis
|
80
|
+
|
81
|
+
subklass.cast_to_redis value, options
|
35
82
|
|
36
83
|
else
|
37
84
|
raise TypeError.new("only strings and symbols allowed in key definition for #{klass.name} (#{symbol.class.name})")
|
@@ -42,16 +89,6 @@ module Blendris
|
|
42
89
|
end.compact.join(":")
|
43
90
|
end
|
44
91
|
|
45
|
-
# Change which database we're accessing in Redis.
|
46
|
-
def self.database=(index)
|
47
|
-
$_redis_connection = Redis.new(:db => index.to_i)
|
48
|
-
end
|
49
|
-
|
50
|
-
# This will delete all keys in the current database. Dangerous!
|
51
|
-
def self.flushdb
|
52
|
-
redis.flushdb
|
53
|
-
end
|
54
|
-
|
55
92
|
# Build a new temporary set with the given contents, yielding it to
|
56
93
|
# the passed block. After the block exits, destroy the temporary set.
|
57
94
|
def in_temporary_set(*contents)
|
@@ -59,8 +96,12 @@ module Blendris
|
|
59
96
|
|
60
97
|
temporary_set = RedisSet.new("blendris:temporary:set:#{index}")
|
61
98
|
temporary_set << contents
|
62
|
-
|
63
|
-
|
99
|
+
|
100
|
+
begin
|
101
|
+
yield temporary_set
|
102
|
+
ensure
|
103
|
+
temporary_set.clear
|
104
|
+
end
|
64
105
|
|
65
106
|
self
|
66
107
|
end
|
data/lib/blendris/errors.rb
CHANGED
data/lib/blendris/integer.rb
CHANGED
@@ -3,9 +3,7 @@ module Blendris
|
|
3
3
|
# RedisInteger is a string-value in Redis wrapped up to make
|
4
4
|
# sure that it is used as an integer.
|
5
5
|
|
6
|
-
class RedisInteger
|
7
|
-
|
8
|
-
include RedisNode
|
6
|
+
class RedisInteger < RedisNode
|
9
7
|
|
10
8
|
def self.cast_to_redis(value, options = {})
|
11
9
|
raise TypeError.new("#{value.class.name} is not an integer") unless value.kind_of? Fixnum
|
@@ -19,10 +17,14 @@ module Blendris
|
|
19
17
|
|
20
18
|
def increment
|
21
19
|
redis.incr key
|
20
|
+
ensure
|
21
|
+
notify_changed
|
22
22
|
end
|
23
23
|
|
24
24
|
def decrement
|
25
25
|
redis.decr key
|
26
|
+
ensure
|
27
|
+
notify_changed
|
26
28
|
end
|
27
29
|
|
28
30
|
end
|
data/lib/blendris/list.rb
CHANGED
@@ -2,9 +2,8 @@ module Blendris
|
|
2
2
|
|
3
3
|
# RedisList is a wrapper for the Redis LIST data type.
|
4
4
|
|
5
|
-
class RedisList
|
5
|
+
class RedisList < RedisNode
|
6
6
|
|
7
|
-
include RedisNode
|
8
7
|
include Enumerable
|
9
8
|
|
10
9
|
def initialize(key, options = {})
|
@@ -13,6 +12,18 @@ module Blendris
|
|
13
12
|
@on_change = options[:on_change]
|
14
13
|
end
|
15
14
|
|
15
|
+
def set(*values)
|
16
|
+
# Remove all of the old values.
|
17
|
+
self.clear
|
18
|
+
|
19
|
+
# Add all of the new values.
|
20
|
+
self << values
|
21
|
+
|
22
|
+
self
|
23
|
+
ensure
|
24
|
+
notify_changed
|
25
|
+
end
|
26
|
+
|
16
27
|
def each
|
17
28
|
redis.lrange(key, 0, -1).each do |value|
|
18
29
|
yield value
|
data/lib/blendris/model.rb
CHANGED
@@ -40,34 +40,14 @@ module Blendris
|
|
40
40
|
Digest::SHA1.hexdigest key
|
41
41
|
end
|
42
42
|
|
43
|
-
# TODO: Create the methods in the initialize method instead of depending
|
44
|
-
# on method_missing to dispatch to the correct methods. This will make
|
45
|
-
# these objects better for mocking and stubbing.
|
46
|
-
def method_missing(method_sym, *arguments)
|
47
|
-
(name, setter) = method_sym.to_s.scan(/(.*[^=])(=)?/).first
|
48
|
-
|
49
|
-
if node = redis_symbol(name)
|
50
|
-
if setter
|
51
|
-
if self.class.local_parameters.find {|p| p.kind_of?(Symbol) && p.to_s == name}
|
52
|
-
raise BlendrisCannotSetKeyValue.new(name)
|
53
|
-
end
|
54
|
-
|
55
|
-
return node.set(*arguments)
|
56
|
-
else
|
57
|
-
return node.get
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
super
|
62
|
-
end
|
63
|
-
|
64
43
|
# Look up the given symbol by its name. The list of symbols are defined
|
65
44
|
# when the model is declared.
|
66
|
-
|
67
|
-
|
45
|
+
def [](name)
|
46
|
+
name = name.to_s
|
47
|
+
|
68
48
|
subkey = self.subkey(name)
|
69
49
|
|
70
|
-
options = self.class.redis_symbols[name
|
50
|
+
options = self.class.redis_symbols[name]
|
71
51
|
|
72
52
|
return unless options
|
73
53
|
|
@@ -76,7 +56,6 @@ module Blendris
|
|
76
56
|
|
77
57
|
options[:type].new subkey, options
|
78
58
|
end
|
79
|
-
alias :[] :redis_symbol
|
80
59
|
|
81
60
|
# Calculate the key to address the given child node.
|
82
61
|
def subkey(child)
|
@@ -136,7 +115,7 @@ module Blendris
|
|
136
115
|
obj = new(key, :verify => false)
|
137
116
|
|
138
117
|
parameters.each_with_index do |parm, i|
|
139
|
-
obj
|
118
|
+
obj[parm].set args[i]
|
140
119
|
end
|
141
120
|
|
142
121
|
obj
|
@@ -156,7 +135,7 @@ module Blendris
|
|
156
135
|
end
|
157
136
|
|
158
137
|
def index_key
|
159
|
-
"index:model:#{self.name}"
|
138
|
+
"blendris:index:model:#{self.name}"
|
160
139
|
end
|
161
140
|
|
162
141
|
# Defines a new data type for Blendris:Model construction.
|
@@ -168,6 +147,18 @@ module Blendris
|
|
168
147
|
|
169
148
|
options[:type] = klass
|
170
149
|
redis_symbols[varname] = options
|
150
|
+
|
151
|
+
# Declare the getter for this field.
|
152
|
+
define_method(varname) do
|
153
|
+
self[varname].get
|
154
|
+
end
|
155
|
+
|
156
|
+
# Declare the setter for this field, if it is not a key field.
|
157
|
+
unless local_parameters.find {|p| p.to_s == varname}
|
158
|
+
define_method("#{varname}=") do |value|
|
159
|
+
self[varname].set value
|
160
|
+
end
|
161
|
+
end
|
171
162
|
end
|
172
163
|
end
|
173
164
|
end
|
@@ -182,14 +173,6 @@ module Blendris
|
|
182
173
|
@local_parameters ||= []
|
183
174
|
end
|
184
175
|
|
185
|
-
# Take a value and attempt to make it fit the given field.
|
186
|
-
def cast_value(symbol, value)
|
187
|
-
options = redis_symbols[symbol.to_s]
|
188
|
-
raise ArgumentError.new("#{self.name} is missing its #{symbol}") unless options
|
189
|
-
|
190
|
-
options[:type].cast_to_redis value, options
|
191
|
-
end
|
192
|
-
|
193
176
|
# Define a block to call when one of the given symbol values changes.
|
194
177
|
def on_change(*symbols, &block)
|
195
178
|
symbols.flatten!
|
data/lib/blendris/node.rb
CHANGED
@@ -2,12 +2,19 @@ module Blendris
|
|
2
2
|
|
3
3
|
# RedisNode is used to compose all Redis value wrapper classes.
|
4
4
|
|
5
|
-
|
5
|
+
class RedisNode
|
6
6
|
|
7
7
|
include RedisAccessor
|
8
8
|
|
9
9
|
attr_reader :key
|
10
10
|
|
11
|
+
# Initialize a new node, which represents a basic Redis data object.
|
12
|
+
#
|
13
|
+
# === Parameters ===
|
14
|
+
#
|
15
|
+
# * :on_change - Pass a block to be run within the context of this object
|
16
|
+
# when its value is changed.
|
17
|
+
# * :default - Use the given value as a default value.
|
11
18
|
def initialize(key, options = {})
|
12
19
|
@key = sanitize_key(key)
|
13
20
|
@default = options[:default]
|
@@ -19,6 +26,12 @@ module Blendris
|
|
19
26
|
end
|
20
27
|
end
|
21
28
|
|
29
|
+
# Set this object's value to be the given value.
|
30
|
+
#
|
31
|
+
# * The method cast_to_redis should be overridden by classes that
|
32
|
+
# include this module, as it is used to determine how to convert
|
33
|
+
# the given value to a redis string.
|
34
|
+
# * The on_change block is always called after this method.
|
22
35
|
def set(value)
|
23
36
|
if value
|
24
37
|
redis.set key, self.class.cast_to_redis(value, @options)
|
@@ -29,14 +42,22 @@ module Blendris
|
|
29
42
|
notify_changed
|
30
43
|
end
|
31
44
|
|
45
|
+
# Retrieve the value of this object and cast it.
|
46
|
+
#
|
47
|
+
# * The method cast_from_redis should be overridden by classes that
|
48
|
+
# include this module. It is used to convert the redis string
|
49
|
+
# to this specific object type.
|
32
50
|
def get
|
33
51
|
self.class.cast_from_redis redis.get(self.key), @options
|
34
52
|
end
|
35
53
|
|
54
|
+
# Rename this key to the given new key name.
|
36
55
|
def rename(newkey)
|
37
56
|
redis.rename @key, sanitize_key(newkey)
|
38
57
|
|
39
58
|
@key = newkey
|
59
|
+
ensure
|
60
|
+
notify_changed
|
40
61
|
end
|
41
62
|
|
42
63
|
def clear
|
data/lib/blendris/reference.rb
CHANGED
@@ -3,17 +3,15 @@ module Blendris
|
|
3
3
|
# RedisReferenceBase holds the methods that are common to
|
4
4
|
# RedisReference objects and RedisReferenceSet objects.
|
5
5
|
|
6
|
-
class RedisReferenceBase
|
6
|
+
class RedisReferenceBase < RedisNode
|
7
7
|
|
8
|
-
include RedisNode
|
9
8
|
extend RedisAccessor
|
10
9
|
|
11
10
|
def initialize(key, options = {})
|
11
|
+
super key, options
|
12
|
+
|
12
13
|
@model = options[:model]
|
13
|
-
@key = sanitize_key(key)
|
14
14
|
@reverse = options[:reverse]
|
15
|
-
@options = options
|
16
|
-
@on_change = options[:on_change]
|
17
15
|
|
18
16
|
@klass = options[:class] || Model
|
19
17
|
@klass = constantize(camelize @klass) if @klass.kind_of? String
|
@@ -25,14 +23,14 @@ module Blendris
|
|
25
23
|
|
26
24
|
def apply_reverse_add(value)
|
27
25
|
if @reverse && value
|
28
|
-
reverse = value
|
26
|
+
reverse = value[@reverse]
|
29
27
|
reverse.assign_ref(@model) if !reverse.references @model
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
33
31
|
def apply_reverse_delete(value)
|
34
32
|
if @reverse && value
|
35
|
-
reverse = value
|
33
|
+
reverse = value[@reverse]
|
36
34
|
reverse.remove_ref(@model) if reverse.references @model
|
37
35
|
end
|
38
36
|
end
|
@@ -5,7 +5,6 @@ module Blendris
|
|
5
5
|
|
6
6
|
class RedisReferenceSet < RedisReferenceBase
|
7
7
|
|
8
|
-
include RedisNode
|
9
8
|
include Enumerable
|
10
9
|
|
11
10
|
def refs
|
@@ -13,8 +12,21 @@ module Blendris
|
|
13
12
|
end
|
14
13
|
|
15
14
|
def set(*objs)
|
16
|
-
|
17
|
-
|
15
|
+
objs.flatten!
|
16
|
+
objs.compact!
|
17
|
+
|
18
|
+
# Delete reference keys that were removed.
|
19
|
+
self.each do |obj|
|
20
|
+
unless objs.include? obj
|
21
|
+
apply_reverse_delete obj
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Clear the current set.
|
26
|
+
self.refs.clear
|
27
|
+
|
28
|
+
# Add the new objects to the set.
|
29
|
+
self << objs
|
18
30
|
|
19
31
|
self
|
20
32
|
ensure
|
data/lib/blendris/set.rb
CHANGED
data/lib/blendris/string.rb
CHANGED
@@ -2,9 +2,7 @@ module Blendris
|
|
2
2
|
|
3
3
|
# RedisString is a wrapper to the Redis string data type.
|
4
4
|
|
5
|
-
class RedisString
|
6
|
-
|
7
|
-
include RedisNode
|
5
|
+
class RedisString < RedisNode
|
8
6
|
|
9
7
|
def self.cast_to_redis(value, options = {})
|
10
8
|
raise TypeError.new("#{value.class.name} is not a string") unless value.kind_of? String
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe "redis integers" do
|
4
|
+
|
5
|
+
it "should always be an integer" do
|
6
|
+
@onion.calories.should == 0
|
7
|
+
@onion.calories = 450
|
8
|
+
@onion.calories.should == 450
|
9
|
+
@onion[:calories].increment.should == 451
|
10
|
+
@onion.calories.should == 451
|
11
|
+
@onion[:calories].decrement.should == 450
|
12
|
+
@onion.calories.should == 450
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/list_spec.rb
CHANGED
@@ -14,4 +14,10 @@ describe "redis lists" do
|
|
14
14
|
@onion.sales.to_a.should == %w( to-tom to-tom )
|
15
15
|
end
|
16
16
|
|
17
|
+
it "should be able to be set to a new list" do
|
18
|
+
@onion.sales = %w( one two three )
|
19
|
+
@onion.sales.count.should == 3
|
20
|
+
@onion.sales.to_a.should == %w( one two three )
|
21
|
+
end
|
22
|
+
|
17
23
|
end
|
data/spec/model_spec.rb
CHANGED
@@ -22,8 +22,11 @@ describe Model do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it "should not allow its key values to be changed" do
|
25
|
-
|
26
|
-
|
25
|
+
@onion.should respond_to :name
|
26
|
+
@onion.should_not respond_to :name=
|
27
|
+
|
28
|
+
@onion.should respond_to :description
|
29
|
+
@onion.should respond_to :description=
|
27
30
|
end
|
28
31
|
|
29
32
|
it "should have a valid reference set" do
|
@@ -225,4 +228,8 @@ describe Model do
|
|
225
228
|
lambda { o.refs << o }.should raise_exception TestEx
|
226
229
|
end
|
227
230
|
|
231
|
+
it "should be ok when you have sets and lists in the key" do
|
232
|
+
lambda { WeirdKeyModel.create([ "ok" ], [ "weird" ]) }.should raise_exception(ArgumentError)
|
233
|
+
end
|
234
|
+
|
228
235
|
end
|
data/spec/ref_spec.rb
CHANGED
@@ -35,6 +35,15 @@ describe "references" do
|
|
35
35
|
@fruit.foods.count.should == 0
|
36
36
|
@onion.category.should == @vegetable
|
37
37
|
|
38
|
+
@vegetable.foods = [ @apple, @lemon, @lemon ]
|
39
|
+
@vegetable.foods << @apple
|
40
|
+
@vegetable.foods.count.should == 2
|
41
|
+
@vegetable.foods.should be_include @apple
|
42
|
+
@vegetable.foods.should be_include @lemon
|
43
|
+
@apple.category.should == @vegetable
|
44
|
+
@lemon.category.should == @vegetable
|
45
|
+
@onion.category.should == nil
|
46
|
+
|
38
47
|
end
|
39
48
|
|
40
49
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -75,6 +75,13 @@ module TestFixtures
|
|
75
75
|
on_change { raise TestEx.new }
|
76
76
|
end
|
77
77
|
|
78
|
+
class WeirdKeyModel < Blendris::Model
|
79
|
+
key "setkey", :myset, "listkey", :mylist
|
80
|
+
|
81
|
+
set :myset
|
82
|
+
list :mylist
|
83
|
+
end
|
84
|
+
|
78
85
|
class TestEx < Exception; end
|
79
86
|
|
80
87
|
end
|
@@ -83,8 +90,8 @@ Spec::Runner.configure do |config|
|
|
83
90
|
include TestFixtures
|
84
91
|
|
85
92
|
config.before(:each) do
|
86
|
-
|
87
|
-
|
93
|
+
Blendris.database = 11
|
94
|
+
Blendris.flushdb
|
88
95
|
|
89
96
|
@vegetable = Category.create("vegetable")
|
90
97
|
@onion = Food.create("onion")
|
@@ -99,7 +106,8 @@ Spec::Runner.configure do |config|
|
|
99
106
|
end
|
100
107
|
|
101
108
|
config.after(:each) do
|
102
|
-
|
109
|
+
Blendris.database = 11
|
110
|
+
Blendris.flushdb
|
103
111
|
end
|
104
112
|
end
|
105
113
|
|
metadata
CHANGED
@@ -1,15 +1,40 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blendris
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 6
|
8
|
+
version: "0.6"
|
5
9
|
platform: ruby
|
6
10
|
authors:
|
7
11
|
- Alex McHale
|
8
12
|
autorequire:
|
9
13
|
bindir: bin
|
10
|
-
cert_chain:
|
14
|
+
cert_chain:
|
15
|
+
- |
|
16
|
+
-----BEGIN CERTIFICATE-----
|
17
|
+
MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMRMwEQYDVQQDDAphbGV4
|
18
|
+
bWNoYWxlMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNj
|
19
|
+
b20wHhcNMTAwMjExMjEyNTU4WhcNMTEwMjExMjEyNTU4WjBBMRMwEQYDVQQDDAph
|
20
|
+
bGV4bWNoYWxlMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
|
21
|
+
FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9mTbsd+4JqyuW
|
22
|
+
z/J6OxXyyzb89ydr/wKmJZMyQmD7w/Qf3V8uGW9+NlYbRMJZYqY08QhTbSX3IW6c
|
23
|
+
6Hj4Xo0wqR0Fd6c0Vxdt9m5LZDEo2H+2jisgDBYFUN1itg+FGZtGczISlmG34tWN
|
24
|
+
efWA+DgtzKD9UG13AtzxoxfqeY03v0+/1/SCtpvbZrungWND8sg9sHSxsME0xB9d
|
25
|
+
u6BkunOrdy7iqd105MuPHL35SLhr57GKU/hjR2+FKAauT4eu7CeQXEWCBPXizknN
|
26
|
+
5w/HNs311sBJmzaZwDiX98e+/X10tMxJqWo4t4Us7Ke8b/0uYbuwWoaoKWjM3UYX
|
27
|
+
ppWhyNNFAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQW
|
28
|
+
BBQK0Aj0bDKnLJrVNjdgNAXnVaS1qDANBgkqhkiG9w0BAQUFAAOCAQEAU/1kVZUf
|
29
|
+
wjl9bhqLZXgcKgIkzgVYwDcqFE0OdBXFD/N+oNBfV80iN/R8iCf6y4dymYDzWalD
|
30
|
+
Rho49BN531OSYbWAD0lv5/MQYDpH8uHU4cDTzV1cYkOcjFVGsO26aPM7q1SoMhf+
|
31
|
+
8tCJEl/PSHrV6JmgGRDy6YTnbQGSKPNmykEZep8wWEFXMSW9OmwaeyZyEuWUZIS4
|
32
|
+
RtAGR/Bf1/mwYLD0ZZPvsgRy0yBrTeJoaRzJXCT08cN8xBX9sa+PFsjpc267TFsv
|
33
|
+
b0cDNnwAzS78yK9xMdpD5l7/mqtfdQPVLfvra4sMBknSW3ukOP3S/WUOfKOz7Ohf
|
34
|
+
V3OoCfxVK/4Dqg==
|
35
|
+
-----END CERTIFICATE-----
|
11
36
|
|
12
|
-
date: 2010-02-
|
37
|
+
date: 2010-02-27 00:00:00 -06:00
|
13
38
|
default_executable:
|
14
39
|
dependencies: []
|
15
40
|
|
@@ -35,7 +60,6 @@ extra_rdoc_files:
|
|
35
60
|
- lib/blendris/string.rb
|
36
61
|
- lib/blendris/types.rb
|
37
62
|
- lib/blendris/utils.rb
|
38
|
-
- tasks/rspec.rake
|
39
63
|
files:
|
40
64
|
- History.txt
|
41
65
|
- Manifest
|
@@ -60,6 +84,7 @@ files:
|
|
60
84
|
- script/console
|
61
85
|
- script/destroy
|
62
86
|
- script/generate
|
87
|
+
- spec/integer_spec.rb
|
63
88
|
- spec/list_spec.rb
|
64
89
|
- spec/model_spec.rb
|
65
90
|
- spec/redis-tools_spec.rb
|
@@ -68,7 +93,6 @@ files:
|
|
68
93
|
- spec/spec.opts
|
69
94
|
- spec/spec_helper.rb
|
70
95
|
- spec/string_spec.rb
|
71
|
-
- tasks/rspec.rake
|
72
96
|
- blendris.gemspec
|
73
97
|
has_rdoc: true
|
74
98
|
homepage: http://github.com/alexmchale/blendris
|
@@ -88,18 +112,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
88
112
|
requirements:
|
89
113
|
- - ">="
|
90
114
|
- !ruby/object:Gem::Version
|
115
|
+
segments:
|
116
|
+
- 0
|
91
117
|
version: "0"
|
92
|
-
version:
|
93
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
119
|
requirements:
|
95
120
|
- - ">="
|
96
121
|
- !ruby/object:Gem::Version
|
122
|
+
segments:
|
123
|
+
- 1
|
124
|
+
- 2
|
97
125
|
version: "1.2"
|
98
|
-
version:
|
99
126
|
requirements: []
|
100
127
|
|
101
128
|
rubyforge_project: blendris
|
102
|
-
rubygems_version: 1.3.
|
129
|
+
rubygems_version: 1.3.6
|
103
130
|
signing_key:
|
104
131
|
specification_version: 3
|
105
132
|
summary: A redis library for Ruby
|
metadata.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
���C:��F�E�����8���t6?��9CI�������X=�4�ƨ�[i1b���no�X�������pE�`����C��2�aօ�N�P5�~xuX�M�n|8Qڷ��iR�G�ɕ�܋fD������bq�A������������iB%�OV�ެ�0DF����-J@�}�4�-�#ū�M�8l�;^���h�7b�_�5T6)����q������K�����q^�>n�����z{�S��rJpK����
|
data/tasks/rspec.rake
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
begin
|
2
|
-
require 'spec'
|
3
|
-
rescue LoadError
|
4
|
-
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
-
require 'spec'
|
6
|
-
end
|
7
|
-
begin
|
8
|
-
require 'spec/rake/spectask'
|
9
|
-
rescue LoadError
|
10
|
-
puts <<-EOS
|
11
|
-
To use rspec for testing you must install rspec gem:
|
12
|
-
gem install rspec
|
13
|
-
EOS
|
14
|
-
exit(0)
|
15
|
-
end
|
16
|
-
|
17
|
-
desc "Run the specs under spec/models"
|
18
|
-
Spec::Rake::SpecTask.new do |t|
|
19
|
-
t.spec_opts = ['--options', "spec/spec.opts"]
|
20
|
-
t.spec_files = FileList['spec/**/*_spec.rb']
|
21
|
-
end
|