blendris 0.0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -16,11 +16,16 @@ BLENDRIS IS IN VERY EARLY ALPHA!!!
16
16
 
17
17
  PLEASE DON'T USE IT FOR ANYTHING IMPORTANT YET!!!
18
18
 
19
+ Blendris provides a way to create an object hierarchy within Redis,
20
+ a key-value database. It provides very little in the way of indexing
21
+ or querying that data. It is up to the user to maintain objects
22
+ representing the query in which they are interested.
23
+
19
24
 
20
25
 
21
26
  # REQUIREMENTS #
22
27
 
23
- Blendris uses the redis RubyGem.
28
+ Blendris uses the [redis](http://gemcutter.org/gems/redis) gem.
24
29
 
25
30
 
26
31
 
@@ -32,38 +37,64 @@ gem install blendris
32
37
 
33
38
  # EXAMPLES #
34
39
 
35
- The following would create a Website model that knows its url and
36
- paths within the website.
40
+ Let's say we want to maintain a list of employers and employees.
41
+
42
+ class Employer < Blendris::Model
43
+ key "employer", :name
37
44
 
38
- class Website < Blendris::Model
39
- key "website", :title
45
+ string :name
46
+ string :address
40
47
 
41
- string :title
42
- string :url
43
- set :paths
48
+ refs :employees, :class => "Employee", :reverse => :employer
44
49
  end
45
50
 
46
- website = Website.create("One Fake Website")
47
- website.url = "http://fakewebsite.com"
48
- website.paths << "/blog/index"
49
- website.paths << "/admin/index"
51
+ class Employee < Blendris::Model
52
+ key "employee", :name
53
+
54
+ string :name
55
+ string :address
56
+ set :family_members
50
57
 
51
- The above would create the following Redis keys:
58
+ ref :employer, :class => "Employer", :reverse => :employees
59
+ end
52
60
 
53
- website:One_Fake_Website => "Website" (This identifies the model type)
54
- website:One_Fake_Website:name => "One Fake Website"
55
- website:One_Fake_Website:url => "http://fakewebsite.com"
56
- website:One_Fake_Website:paths => [ "/blog/index", "/admin/index" ]
61
+ ### key ###
57
62
 
58
- Now suppose we want to open the Website model back up to add a concept of sister sites:
63
+ Key sets the base key for this object. In the case of the employer
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.
59
67
 
60
- class Website
61
- refs :sister_sites, :class => Website, :reverse => :sister_sites
62
- end
68
+ * Note that spaces are converted to underscores, as spaces are not
69
+ allowed in Redis keys. This could cause problems in some data sets.
70
+ * Also note that the value assigned to the base key is the class name of
71
+ the model being used.
72
+ * Only strings and integers should be used as key values.
73
+
74
+ ### string ###
75
+
76
+ String creates a string key named for the first parameter given to it.
77
+ This means that it would generate a key "employer:37_Signals:name" with
78
+ a value of "37 Signals".
79
+
80
+ ### refs ###
81
+
82
+ Refs maintains a set of references to other objects.
83
+
84
+ * *:class* will limit objects in this reference set to the given class.
85
+ If a string is specified as a class, it will be constantized before
86
+ comparing.
87
+ * *reverse* will cause the given field to be updated on the object when
88
+ it is added to or removed from this set.
89
+
90
+ ### new vs create ###
91
+
92
+ Calling the *create* method will build a new object, generating a new base
93
+ key based upon the parameters. The parameter list should be the same as
94
+ the list of symbols in your *key* field.
63
95
 
64
- This will cause the website to maintain a set of other websites. The reverse tag
65
- causes the other website's sister_sites set to be updated when it is added or removed
66
- from this site's list.
96
+ Calling the *new* method will instantiate an existing object using the
97
+ given *key* as the base key.
67
98
 
68
99
 
69
100
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ require "redis"
9
9
  require "fileutils"
10
10
  require "./lib/blendris"
11
11
 
12
- Echoe.new("blendris", "0.0.4") do |p|
12
+ Echoe.new("blendris", "0.5") 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,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{blendris}
5
- s.version = "0.0.4"
5
+ s.version = "0.5"
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.date = %q{2010-02-16}
9
+ s.date = %q{2010-02-21}
10
10
  s.description = %q{A redis library for Ruby}
11
11
  s.email = %q{alexmchale@gmail.com}
12
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", "tasks/rspec.rake"]
@@ -52,6 +52,19 @@ module Blendris
52
52
  redis.flushdb
53
53
  end
54
54
 
55
+ # Build a new temporary set with the given contents, yielding it to
56
+ # the passed block. After the block exits, destroy the temporary set.
57
+ def in_temporary_set(*contents)
58
+ index = RedisInteger.new("blendris:temporary:index").increment
59
+
60
+ temporary_set = RedisSet.new("blendris:temporary:set:#{index}")
61
+ temporary_set << contents
62
+ yield temporary_set
63
+ temporary_set.clear
64
+
65
+ self
66
+ end
67
+
55
68
  end
56
69
 
57
70
  end
@@ -17,6 +17,14 @@ module Blendris
17
17
  value.to_i if value
18
18
  end
19
19
 
20
+ def increment
21
+ redis.incr key
22
+ end
23
+
24
+ def decrement
25
+ redis.decr key
26
+ end
27
+
20
28
  end
21
29
 
22
30
  end
@@ -76,6 +76,7 @@ module Blendris
76
76
 
77
77
  options[:type].new subkey, options
78
78
  end
79
+ alias :[] :redis_symbol
79
80
 
80
81
  # Calculate the key to address the given child node.
81
82
  def subkey(child)
data/lib/blendris/node.rb CHANGED
@@ -33,6 +33,12 @@ module Blendris
33
33
  self.class.cast_from_redis redis.get(self.key), @options
34
34
  end
35
35
 
36
+ def rename(newkey)
37
+ redis.rename @key, sanitize_key(newkey)
38
+
39
+ @key = newkey
40
+ end
41
+
36
42
  def clear
37
43
  redis.del key
38
44
  ensure
@@ -12,8 +12,16 @@ module Blendris
12
12
  @refs ||= RedisSet.new(@key)
13
13
  end
14
14
 
15
- # TODO set should be a real set, while << appends
16
15
  def set(*objs)
16
+ refkeys = objs.flatten.compact.map {|o| o.key}
17
+ self.refs.set refkeys
18
+
19
+ self
20
+ ensure
21
+ notify_changed
22
+ end
23
+
24
+ def <<(*objs)
17
25
  objs.flatten!
18
26
  objs.compact!
19
27
 
@@ -28,7 +36,6 @@ module Blendris
28
36
 
29
37
  self
30
38
  end
31
- alias :<< :set
32
39
 
33
40
  def delete(obj)
34
41
  if refkey = self.class.cast_to_redis(obj, @options)
@@ -56,7 +63,7 @@ module Blendris
56
63
  end
57
64
 
58
65
  def assign_ref(*values)
59
- self.set *values
66
+ self << values
60
67
  end
61
68
 
62
69
  def remove_ref(value)
data/lib/blendris/set.rb CHANGED
@@ -21,6 +21,18 @@ module Blendris
21
21
  self
22
22
  end
23
23
 
24
+ def set(*values)
25
+ self.clear
26
+
27
+ values.flatten.compact.each do |v|
28
+ redis.sadd key, v
29
+ end
30
+
31
+ self
32
+ ensure
33
+ notify_changed
34
+ end
35
+
24
36
  def <<(value)
25
37
  [ value ].flatten.compact.each do |v|
26
38
  redis.sadd key, v
@@ -41,6 +53,20 @@ module Blendris
41
53
  notify_changed
42
54
  end
43
55
 
56
+ # Set this set's members to the intersection of this set and the given set.
57
+ def intersect!(other)
58
+ redis.sinterstore key, key, other.key
59
+ ensure
60
+ notify_changed
61
+ end
62
+
63
+ # Set this set's members to the union of this set and the given set.
64
+ def union!(other)
65
+ redis.sunionstore key, key, other.key
66
+ ensure
67
+ notify_changed
68
+ end
69
+
44
70
  end
45
71
 
46
72
  end
@@ -32,6 +32,8 @@ module Blendris
32
32
  return false
33
33
  end
34
34
 
35
+ # Redis keys cannot contain spaces, carriage returns, or newlines.
36
+ # We do not want colons at the start or end of keys.
35
37
  def sanitize_key(key)
36
38
  key.to_s.gsub(/[\r\n\s]/, "_").gsub(/^:+|:+$/, "")
37
39
  end
data/spec/model_spec.rb CHANGED
@@ -35,6 +35,11 @@ describe Model do
35
35
  @fruit.foods.should be_include(@lemon)
36
36
  @fruit.foods.should be_include(Food.new("food:lemon"))
37
37
  @fruit.foods.should_not be_include(@steak)
38
+
39
+ @fruit.foods = @onion
40
+
41
+ @fruit.foods.count.should == 1
42
+ @fruit.foods.first.should == @onion
38
43
  end
39
44
 
40
45
  it "should not allow you to instantiate with a key that doesnt match its class" do
@@ -14,4 +14,16 @@ describe "redis connection accessor" do
14
14
  redis.del(testkey).should == false
15
15
  end
16
16
 
17
+ it "should allow for keys to be renamed" do
18
+ s = RedisString.new("string1")
19
+ s.set "hobo"
20
+
21
+ s.rename "string2"
22
+ s.key.should == "string2"
23
+ s.get.should == "hobo"
24
+
25
+ RedisString.new("string1").get.should be_nil
26
+ RedisString.new("string2").get.should == "hobo"
27
+ end
28
+
17
29
  end
data/spec/set_spec.rb CHANGED
@@ -17,4 +17,50 @@ describe "redis sets" do
17
17
  @onion.qualities.to_a.sort.should == %w( delicious white )
18
18
  end
19
19
 
20
+ it "should allow for temporary sets" do
21
+ extend RedisAccessor
22
+
23
+ redis.keys("blendris:temporary:set:*").count.should == 0
24
+
25
+ in_temporary_set do |set|
26
+ redis.keys("blendris:temporary:set:*").count.should == 0
27
+ set.count.should == 0
28
+ end
29
+
30
+ redis.keys("blendris:temporary:set:*").count.should == 0
31
+
32
+ in_temporary_set(1, 2, 3) do |set|
33
+ redis.keys("blendris:temporary:set:*").count.should == 1
34
+ set.count.should == 3
35
+ end
36
+
37
+ redis.keys("blendris:temporary:set:*").count.should == 0
38
+ end
39
+
40
+ it "should do intersections properly" do
41
+ s1 = RedisSet.new("set1")
42
+ s2 = RedisSet.new("set2")
43
+
44
+ s1 << [ 1, 2, 3 ]
45
+ s2 << [ 1, 4, 5 ]
46
+
47
+ s1.intersect!(s2).should == 1
48
+
49
+ s1.sort.should == %w( 1 )
50
+ s2.sort.should == %w( 1 4 5 )
51
+ end
52
+
53
+ it "should be able to union two sets" do
54
+ s1 = RedisSet.new("set1")
55
+ s2 = RedisSet.new("set2")
56
+
57
+ s1 << %w( 1 4 5 )
58
+ s2 << %w( 1 2 3 )
59
+
60
+ s1.union!(s2).should == 5
61
+
62
+ s1.sort.should == %w( 1 2 3 4 5 )
63
+ s2.sort.should == %w( 1 2 3 )
64
+ end
65
+
20
66
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blendris
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: "0.5"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex McHale
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-16 00:00:00 -06:00
12
+ date: 2010-02-21 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies: []
15
15