remodel 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -66,7 +66,9 @@ now you can do:
66
66
 
67
67
  >> require './example/book'
68
68
  => true
69
- >> book = Book.create 'shelf', :title => 'Moby Dick', :year => 1851
69
+ >> context = Remodel.create_context('shelf')
70
+ => #<Remodel::Context(shelf)>
71
+ >> book = Book.create context, :title => 'Moby Dick', :year => 1851
70
72
  => #<Book(shelf, 1) title: "Moby Dick", year: 1851, author: "(anonymous)">
71
73
  >> chapter = book.chapters.create :title => 'Ishmael'
72
74
  => #<Chapter(shelf, 1) title: "Ishmael">
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.0
1
+ 0.4.1
@@ -17,6 +17,20 @@ module Remodel
17
17
  @context.key
18
18
  end
19
19
 
20
+ def batched
21
+ raise InvalidUse, "cannot nest batched blocks" if @dirty
22
+ begin
23
+ @dirty = Set.new
24
+ yield
25
+ ensure
26
+ to_delete = @dirty.select { |field| @cache[field].nil? }
27
+ to_update = (@dirty - to_delete).to_a
28
+ @context.hmset(*to_update.zip(@cache.values_at(*to_update)).flatten)
29
+ @context.hmdel(*to_delete)
30
+ @dirty = nil
31
+ end
32
+ end
33
+
20
34
  def hget(field)
21
35
  @cache[field] = @context.hget(field) unless @cache.has_key?(field)
22
36
  @cache[field]
@@ -30,18 +44,19 @@ module Remodel
30
44
  def hset(field, value)
31
45
  value = value.to_s if value
32
46
  @cache[field] = value
33
- @context.hset(field, value)
47
+ @dirty ? @dirty.add(field) : @context.hset(field, value)
34
48
  end
35
49
 
36
50
  def hincrby(field, value)
37
- result = @context.hincrby(field, value)
38
- @cache[field] = result.to_s
39
- result
51
+ new_value = @dirty ? hget(field).to_i + value : @context.hincrby(field, value)
52
+ @cache[field] = new_value.to_s
53
+ @dirty.add(field) if @dirty
54
+ new_value
40
55
  end
41
56
 
42
57
  def hdel(field)
43
58
  @cache[field] = nil
44
- @context.hdel(field)
59
+ @dirty ? @dirty.add(field) : @context.hdel(field)
45
60
  end
46
61
 
47
62
  def inspect
@@ -25,6 +25,11 @@ module Remodel
25
25
  Remodel.redis.hset(@key, field, value)
26
26
  end
27
27
 
28
+ def hmset(*fields_and_values)
29
+ return if fields_and_values.empty?
30
+ Remodel.redis.hmset(@key, *fields_and_values)
31
+ end
32
+
28
33
  def hincrby(field, value)
29
34
  Remodel.redis.hincrby(@key, field, value)
30
35
  end
@@ -33,6 +38,13 @@ module Remodel
33
38
  Remodel.redis.hdel(@key, field)
34
39
  end
35
40
 
41
+ def hmdel(*fields)
42
+ return if fields.empty?
43
+ Remodel.redis.pipelined do
44
+ fields.each { |field| Remodel.redis.hdel(@key, field) }
45
+ end
46
+ end
47
+
36
48
  def inspect
37
49
  "\#<#{self.class.name}(#{@key})>"
38
50
  end
data/lib/remodel.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'rubygems'
2
2
  require 'redis'
3
3
  require 'date'
4
+ require 'set'
4
5
 
5
6
  # If available, use the superfast YAJL lib to parse JSON.
6
7
  begin
@@ -37,6 +38,7 @@ module Remodel
37
38
  class InvalidKeyPrefix < Error; end
38
39
  class InvalidType < Error; end
39
40
  class MissingContext < Error; end
41
+ class InvalidUse < Error; end
40
42
 
41
43
  # By default, the redis server is expected to listen at `localhost:6379`.
42
44
  # Otherwise you will have to set `Remodel.redis` to a suitably initialized
@@ -111,6 +111,60 @@ class TestCachingContext < Test::Unit::TestCase
111
111
  assert @cache.cache.has_key?('x')
112
112
  end
113
113
  end
114
+
115
+ context 'batched' do
116
+ should "ensure batched blocks are not nested" do
117
+ assert_raise(Remodel::InvalidUse) do
118
+ @cache.batched do
119
+ @cache.batched do
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ should "collect hset calls into one hmset" do
126
+ context.expects(:hset).never
127
+ context.expects(:hmset).with('a', '3', 'b', '2') #might break in ruby 1.8
128
+ @cache.batched do
129
+ @cache.hset('a', 1)
130
+ @cache.hset('b', 2)
131
+ @cache.hset('a', 3)
132
+ end
133
+ end
134
+
135
+ should "collect hdel calls into one hmdel" do
136
+ context.expects(:hdel).never
137
+ context.expects(:hmdel).with('a', 'b')
138
+ @cache.batched do
139
+ @cache.hdel('a')
140
+ @cache.hdel('b')
141
+ @cache.hdel('a')
142
+ end
143
+ end
144
+
145
+ should "handle multiple hset and hdel to the same field" do
146
+ context.expects(:hset).never
147
+ context.expects(:hdel).never
148
+ context.expects(:hmset).with('a', '3')
149
+ context.expects(:hmdel).with()
150
+ @cache.batched do
151
+ @cache.hset('a', 1)
152
+ @cache.hdel('a')
153
+ @cache.hset('a', 3)
154
+ end
155
+ end
156
+
157
+ should "handle hincrby" do
158
+ context.expects(:hset).never
159
+ context.expects(:hmset).with('i', '2')
160
+ @cache.batched do
161
+ @cache.hdel('i')
162
+ @cache.hincrby('i', 1)
163
+ @cache.hincrby('i', 1)
164
+ end
165
+ end
166
+ end
167
+
114
168
  end
115
169
 
116
170
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 4
8
- - 0
9
- version: 0.4.0
8
+ - 1
9
+ version: 0.4.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Tim Lossen
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-07-05 00:00:00 +02:00
17
+ date: 2011-07-26 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies: []
20
20