blendris 0.0.4 → 0.5

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