remodel 0.1.2 → 0.1.3

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.md CHANGED
@@ -29,24 +29,17 @@ persistence to disk. for example, on my macbook (2 ghz):
29
29
  $ brew install redis
30
30
  $ gem install redis
31
31
 
32
- 2. install the super-fast [yajl](http://github.com/lloyd/yajl) json parser
33
- plus ruby bindings:
32
+ 2. start redis:
34
33
 
35
- $ brew install yajl
36
- $ gem install yajl-ruby
34
+ $ ./redis-server
37
35
 
38
- 3. start redis:
39
-
40
- $ redis-server
41
-
42
- 4. now the tests should run successfully:
36
+ 3. now the tests should run successfully:
43
37
 
44
38
  $ rake
45
39
  Started
46
- .................................................................
47
- Finished in 0.063041 seconds.
48
- 65 tests, 103 assertions, 0 failures, 0 errors
49
-
40
+ .......................................................................................
41
+ Finished in 0.072304 seconds.
42
+ 87 tests, 138 assertions, 0 failures, 0 errors
50
43
 
51
44
  ## example
52
45
 
@@ -79,23 +72,23 @@ now you can do:
79
72
 
80
73
  * [how to redis](http://www.paperplanes.de/2009/10/30/how_to_redis.html)
81
74
  — good overview of different mapping options by [mattmatt](http://github.com/mattmatt).
82
- * [hurl](http://github.com/defunkt/hurl) — basically i started with
83
- defunkts [Hurl::Model](http://github.com/defunkt/hurl/blob/master/models/model.rb).
75
+ * [hurl](http://github.com/defunkt/hurl) — basically
76
+ defunkts [Hurl::Model](http://github.com/defunkt/hurl/blob/master/models/model.rb) is what i started with.
84
77
  * [ohm](http://github.com/soveran/ohm) — object-hash mapping for redis.
85
78
  somewhat similar, but instead of serializing to json, stores each attribute under a separate key.
86
79
 
87
80
 
88
81
  ## todo
89
82
 
90
- * documentation ([rocco](http://github.com/rtomayko/rocco))
91
- * benchmarks
92
- * `delete`
83
+ * better docs
93
84
  * `find_by`
85
+ * make serializer (json, messagepack, marshal ...) configurable
86
+ * benchmarks
94
87
 
95
88
 
96
89
  ## status
97
90
 
98
- alpha. play around at your own risk :)
91
+ still pretty alpha — play around at your own risk :)
99
92
 
100
93
 
101
94
  ## license
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
data/lib/remodel.rb CHANGED
@@ -16,7 +16,7 @@ end
16
16
 
17
17
  # Define `Boolean` as the superclass of `true` and `false`.
18
18
  module Boolean; end
19
- true.extend(Boolean)
19
+ true.extend(Boolean)
20
20
  false.extend(Boolean)
21
21
 
22
22
  # Find the `Class` object for a given class name, which can be a `String` or `Symbol` (or `Class`).
@@ -28,7 +28,7 @@ end
28
28
  #### Remodel
29
29
 
30
30
  module Remodel
31
-
31
+
32
32
  # By default, we expect to find the redis server on `localhost:6379` —
33
33
  # otherwise you will have to set `Remodel.redis` to a suitably initialized redis client.
34
34
  def self.redis
@@ -45,7 +45,7 @@ module Remodel
45
45
  class EntityNotSaved < Error; end
46
46
  class InvalidKeyPrefix < Error; end
47
47
  class InvalidType < Error; end
48
-
48
+
49
49
  #### Mapper
50
50
 
51
51
  # A mapper converts a given value into a native JSON value &mdash;
@@ -60,13 +60,13 @@ module Remodel
60
60
  @pack_method = pack_method
61
61
  @unpack_method = unpack_method
62
62
  end
63
-
63
+
64
64
  def pack(value)
65
65
  return nil if value.nil?
66
66
  raise(InvalidType, "#{value.inspect} is not a #{@clazz}") if @clazz && !value.is_a?(@clazz)
67
67
  @pack_method ? value.send(@pack_method) : value
68
68
  end
69
-
69
+
70
70
  def unpack(value)
71
71
  return nil if value.nil?
72
72
  @unpack_method ? @clazz.send(@unpack_method, value) : value
@@ -105,11 +105,15 @@ module Remodel
105
105
  add(@clazz.create(attributes))
106
106
  end
107
107
 
108
+ def find(id)
109
+ detect { |x| x.id == id } || raise(EntityNotFound, "no element with id #{id}")
110
+ end
111
+
108
112
  def add(entity)
109
113
  _add_to_reverse_association_of(entity) if @reverse
110
114
  _add(entity)
111
115
  end
112
-
116
+
113
117
  def remove(entity)
114
118
  _remove_from_reverse_association_of(entity) if @reverse
115
119
  _remove(entity)
@@ -136,7 +140,7 @@ module Remodel
136
140
  entity.send("_#{@reverse}=", @this)
137
141
  end
138
142
  end
139
-
143
+
140
144
  def _remove_from_reverse_association_of(entity)
141
145
  if entity.send(@reverse).is_a? HasMany
142
146
  entity.send(@reverse).send(:_remove, @this)
@@ -153,13 +157,13 @@ module Remodel
153
157
  end.compact
154
158
  end
155
159
  end
156
-
160
+
157
161
  #### Entity
158
162
 
159
163
  # The superclass of all persistent remodel entities.
160
164
  class Entity
161
165
  attr_accessor :key
162
-
166
+
163
167
  def initialize(attributes = {}, key = nil)
164
168
  @attributes = {}
165
169
  @key = key
@@ -168,22 +172,22 @@ module Remodel
168
172
  send("#{name}=", value) if respond_to? "#{name}="
169
173
  end
170
174
  end
171
-
175
+
172
176
  def id
173
177
  key && key.split(':').last.to_i
174
178
  end
175
-
179
+
176
180
  def save
177
181
  @key = self.class.next_key unless @key
178
182
  Remodel.redis.set(@key, to_json)
179
183
  self
180
184
  end
181
-
185
+
182
186
  def update(properties)
183
187
  properties.each { |name, value| send("#{name}=", value) }
184
188
  save
185
189
  end
186
-
190
+
187
191
  def reload
188
192
  raise EntityNotSaved unless @key
189
193
  initialize(self.class.parse(self.class.fetch(@key)), @key)
@@ -192,7 +196,7 @@ module Remodel
192
196
  end
193
197
  self
194
198
  end
195
-
199
+
196
200
  def delete
197
201
  raise EntityNotSaved unless @key
198
202
  Remodel.redis.del(@key)
@@ -205,7 +209,7 @@ module Remodel
205
209
  def to_json
206
210
  JSON.generate(self.class.pack(@attributes))
207
211
  end
208
-
212
+
209
213
  def inspect
210
214
  properties = @attributes.map { |name, value| "#{name}: #{value.inspect}" }.join(', ')
211
215
  "\#<#{self.class.name}(#{id}) #{properties}>"
@@ -214,12 +218,12 @@ module Remodel
214
218
  def self.create(attributes = {})
215
219
  new(attributes).save
216
220
  end
217
-
221
+
218
222
  def self.find(key)
219
223
  key = "#{key_prefix}:#{key}" if key.kind_of? Integer
220
224
  restore(key, fetch(key))
221
225
  end
222
-
226
+
223
227
  def self.all
224
228
  keys = Remodel.redis.keys("#{key_prefix}:*").select { |k| k =~ /:[0-9]+$/ }
225
229
  values = keys.empty? ? [] : Remodel.redis.mget(keys)
@@ -231,7 +235,7 @@ module Remodel
231
235
  def self.restore(key, json)
232
236
  new(parse(json), key)
233
237
  end
234
-
238
+
235
239
  #### DSL for subclasses
236
240
 
237
241
  protected
@@ -248,10 +252,10 @@ module Remodel
248
252
  define_method(name) { @attributes[name] }
249
253
  define_method("#{name}=") { |value| @attributes[name] = value }
250
254
  end
251
-
255
+
252
256
  def self.has_many(name, options)
253
257
  var = "@association_#{name}".to_sym
254
-
258
+
255
259
  define_method(name) do
256
260
  if instance_variable_defined? var
257
261
  instance_variable_get(var)
@@ -261,10 +265,10 @@ module Remodel
261
265
  end
262
266
  end
263
267
  end
264
-
268
+
265
269
  def self.has_one(name, options)
266
270
  var = "@association_#{name}".to_sym
267
-
271
+
268
272
  define_method(name) do
269
273
  if instance_variable_defined? var
270
274
  instance_variable_get(var)
@@ -274,12 +278,12 @@ module Remodel
274
278
  instance_variable_set(var, clazz.find(value_key)) if value_key
275
279
  end
276
280
  end
277
-
281
+
278
282
  define_method("#{name}=") do |value|
279
283
  send("_reverse_association_of_#{name}=", value) if options[:reverse]
280
284
  send("_#{name}=", value)
281
285
  end
282
-
286
+
283
287
  define_method("_#{name}=") do |value|
284
288
  if value
285
289
  instance_variable_set(var, value)
@@ -289,7 +293,7 @@ module Remodel
289
293
  Remodel.redis.del("#{key}:#{name}")
290
294
  end
291
295
  end; private "_#{name}="
292
-
296
+
293
297
  if options[:reverse]
294
298
  define_method("_reverse_association_of_#{name}=") do |value|
295
299
  if value
@@ -312,30 +316,30 @@ module Remodel
312
316
  end; private "_reverse_association_of_#{name}="
313
317
  end
314
318
  end
315
-
319
+
316
320
  #### Helper methods
317
321
 
318
322
  private
319
-
323
+
320
324
  def self.fetch(key)
321
325
  Remodel.redis.get(key) || raise(EntityNotFound, "no #{name} with key #{key}")
322
326
  end
323
-
327
+
324
328
  # Each entity has its own sequence to generate unique ids.
325
329
  def self.next_key
326
330
  id = Remodel.redis.incr("#{key_prefix}:seq")
327
331
  "#{key_prefix}:#{id}"
328
332
  end
329
-
333
+
330
334
  # Default key prefix is the first letter of the class name, in lowercase.
331
335
  def self.key_prefix
332
336
  @key_prefix ||= name.split('::').last[0,1].downcase
333
337
  end
334
-
338
+
335
339
  def self.parse(json)
336
340
  unpack(JSON.parse(json))
337
341
  end
338
-
342
+
339
343
  def self.pack(attributes)
340
344
  result = {}
341
345
  attributes.each do |name, value|
@@ -343,7 +347,7 @@ module Remodel
343
347
  end
344
348
  result
345
349
  end
346
-
350
+
347
351
  def self.unpack(attributes)
348
352
  result = {}
349
353
  attributes.each do |name, value|
@@ -352,16 +356,16 @@ module Remodel
352
356
  end
353
357
  result
354
358
  end
355
-
359
+
356
360
  # Lazy init
357
361
  def self.mapper
358
362
  @mapper ||= {}
359
363
  end
360
-
364
+
361
365
  def self.default_values
362
366
  @default_values ||= {}
363
367
  end
364
-
368
+
365
369
  end
366
-
370
+
367
371
  end
data/remodel.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{remodel}
8
- s.version = "0.1.2"
8
+ s.version = "0.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tim Lossen"]
12
- s.date = %q{2010-04-30}
12
+ s.date = %q{2010-05-03}
13
13
  s.default_executable = %q{redis-monitor.rb}
14
14
  s.description = %q{build your domain model in ruby, persist your objects to redis.}
15
15
  s.email = %q{tim@lossen.de}
data/test/helper.rb CHANGED
@@ -5,9 +5,9 @@ require 'shoulda'
5
5
  require File.dirname(__FILE__) + '/../lib/remodel.rb'
6
6
 
7
7
  class Test::Unit::TestCase
8
-
8
+
9
9
  def redis
10
10
  Remodel.redis
11
11
  end
12
-
12
+
13
13
  end
data/test/test_entity.rb CHANGED
@@ -17,60 +17,60 @@ class TestEntity < Test::Unit::TestCase
17
17
  assert 1, foo.x
18
18
  assert 2, foo.y
19
19
  end
20
-
20
+
21
21
  should "ignore undefined properties" do
22
22
  foo = Foo.new :z => 3
23
23
  assert foo.instance_eval { !@attributes.key? :z }
24
24
  end
25
-
25
+
26
26
  should "not set the key" do
27
27
  foo = Foo.new :x => 23
28
28
  assert_equal nil, foo.key
29
29
  end
30
-
30
+
31
31
  should "not set the id" do
32
32
  foo = Foo.new :x => 23
33
33
  assert_equal nil, foo.id
34
34
  end
35
-
35
+
36
36
  should "use default values for missing properties" do
37
37
  bar = Bar.new
38
38
  assert_equal 123, bar.d
39
39
  end
40
-
40
+
41
41
  should "not use default values for given properties" do
42
42
  bar = Bar.new :d => 'cool'
43
43
  assert_equal 'cool', bar.d
44
44
  end
45
45
  end
46
-
46
+
47
47
  context "create" do
48
48
  setup do
49
49
  redis.flushdb
50
50
  end
51
-
51
+
52
52
  should "work without attributes" do
53
53
  foo = Foo.create
54
54
  assert foo.is_a?(Foo)
55
55
  end
56
-
56
+
57
57
  should "give the entity a key based on the class name" do
58
58
  assert_equal 'f:1', Foo.create.key
59
59
  assert_equal 'b:1', Bar.create.key
60
60
  assert_equal 'b:2', Bar.create.key
61
61
  end
62
-
62
+
63
63
  should "give the entity an id which is unique per entity class" do
64
64
  assert_equal 1, Foo.create.id
65
65
  assert_equal 1, Bar.create.id
66
66
  assert_equal 2, Bar.create.id
67
67
  end
68
-
68
+
69
69
  should "store the entity under its key" do
70
70
  foo = Foo.create :x => 'hello', :y => false
71
71
  assert redis.exists(foo.key)
72
72
  end
73
-
73
+
74
74
  should "store all properties" do
75
75
  foo = Foo.create :x => 'hello', :y => false
76
76
  foo.reload
@@ -87,23 +87,23 @@ class TestEntity < Test::Unit::TestCase
87
87
  bar = Bar.create
88
88
  assert_equal 123, bar.d
89
89
  end
90
-
90
+
91
91
  should "not use default values for given properties" do
92
92
  bar = Bar.create :d => 'cool'
93
93
  assert_equal 'cool', bar.d
94
94
  end
95
95
  end
96
-
96
+
97
97
  context "save" do
98
98
  setup do
99
99
  redis.flushdb
100
100
  end
101
-
101
+
102
102
  should "give the entity a key, if necessary" do
103
103
  foo = Foo.new.save
104
104
  assert foo.key
105
105
  end
106
-
106
+
107
107
  should "store the entity under its key" do
108
108
  foo = Foo.new :x => 'hello', :y => false
109
109
  foo.save
@@ -118,7 +118,7 @@ class TestEntity < Test::Unit::TestCase
118
118
  assert_equal false, foo.y
119
119
  end
120
120
  end
121
-
121
+
122
122
  context "reload" do
123
123
  setup do
124
124
  @foo = Foo.create :x => 'hello', :y => true
@@ -130,41 +130,41 @@ class TestEntity < Test::Unit::TestCase
130
130
  assert_equal 23, @foo.x
131
131
  assert_equal 'adios', @foo.y
132
132
  end
133
-
133
+
134
134
  should "keep the key" do
135
135
  key = @foo.key
136
136
  @foo.reload
137
137
  assert_equal key, @foo.key
138
138
  end
139
-
139
+
140
140
  should "stay the same object" do
141
141
  id = @foo.object_id
142
142
  @foo.reload
143
143
  assert_equal id, @foo.object_id
144
144
  end
145
-
145
+
146
146
  should "raise EntityNotFound if the entity does not exist any more" do
147
147
  redis.del @foo.key
148
148
  assert_raise(Remodel::EntityNotFound) { @foo.reload }
149
149
  end
150
-
150
+
151
151
  should "raise EntityNotSaved if the entity was never saved" do
152
152
  assert_raise(Remodel::EntityNotSaved) { Foo.new.reload }
153
153
  end
154
154
  end
155
-
155
+
156
156
  context "update" do
157
157
  setup do
158
158
  redis.flushdb
159
159
  @foo = Foo.create :x => 'Tim', :y => true
160
160
  end
161
-
161
+
162
162
  should "set the given properties" do
163
163
  @foo.update(:x => 12, :y => 'Jan')
164
164
  assert_equal 12, @foo.x
165
165
  assert_equal 'Jan', @foo.y
166
166
  end
167
-
167
+
168
168
  should "save the entity" do
169
169
  @foo.update(:x => 12, :y => 'Jan')
170
170
  @foo.reload
@@ -172,13 +172,13 @@ class TestEntity < Test::Unit::TestCase
172
172
  assert_equal 'Jan', @foo.y
173
173
  end
174
174
  end
175
-
175
+
176
176
  context "delete" do
177
177
  setup do
178
178
  redis.flushdb
179
179
  @foo = Foo.create :x => 'Tim', :y => true
180
180
  end
181
-
181
+
182
182
  should "delete the given entity" do
183
183
  @foo.delete
184
184
  assert_nil redis.get(@foo.key)
@@ -188,7 +188,7 @@ class TestEntity < Test::Unit::TestCase
188
188
  assert_raise(Remodel::EntityNotSaved) { Foo.new.delete }
189
189
  end
190
190
  end
191
-
191
+
192
192
  context "to_json" do
193
193
  should "serialize to json" do
194
194
  foo = Foo.new :x => 42, :y => true
@@ -196,7 +196,7 @@ class TestEntity < Test::Unit::TestCase
196
196
  assert_match /"y":true/, foo.to_json
197
197
  end
198
198
  end
199
-
199
+
200
200
  context "as_json" do
201
201
  should "serialize into a hash" do
202
202
  foo = Foo.create :x => 42, :y => true
@@ -204,39 +204,39 @@ class TestEntity < Test::Unit::TestCase
204
204
  assert_equal expected, foo.as_json
205
205
  end
206
206
  end
207
-
207
+
208
208
  context "#set_key_prefix" do
209
209
  should "use the given key prefix" do
210
210
  class Custom < Remodel::Entity; set_key_prefix 'my'; end
211
211
  assert_match /^my:\d+$/, Custom.create.key
212
212
  end
213
-
213
+
214
214
  should "ensure that the prefix is letters only" do
215
215
  assert_raise(Remodel::InvalidKeyPrefix) do
216
216
  class InvalidPrefix < Remodel::Entity; set_key_prefix '666'; end
217
217
  end
218
218
  end
219
219
  end
220
-
220
+
221
221
  context "#find" do
222
222
  setup do
223
223
  redis.flushdb
224
224
  @foo = Foo.create :x => 'hello', :y => 123
225
225
  Foo.create :x => 'hallo', :y => 124
226
226
  end
227
-
227
+
228
228
  should "find and load an entity by key" do
229
229
  foo = Foo.find(@foo.key)
230
230
  assert_equal foo.x, @foo.x
231
231
  assert_equal foo.y, @foo.y
232
232
  end
233
-
233
+
234
234
  should "find and load an entity by id" do
235
235
  foo = Foo.find(@foo.id)
236
236
  assert_equal foo.x, @foo.x
237
237
  assert_equal foo.y, @foo.y
238
238
  end
239
-
239
+
240
240
  should "reject a key which does not exist" do
241
241
  assert_raise(Remodel::EntityNotFound) { Foo.find('x:66') }
242
242
  end
@@ -245,20 +245,20 @@ class TestEntity < Test::Unit::TestCase
245
245
  assert_raise(Remodel::EntityNotFound) { Foo.find(66) }
246
246
  end
247
247
  end
248
-
248
+
249
249
  context "#all" do
250
250
  setup do
251
251
  redis.flushdb
252
252
  17.times { |i| Foo.create :x => 'hello', :y => i }
253
253
  5.times { |i| Bar.create }
254
254
  end
255
-
255
+
256
256
  should "find all entities of the given class" do
257
257
  assert_equal 17, Foo.all.size
258
258
  assert_equal 5, Bar.all.size
259
259
  end
260
260
  end
261
-
261
+
262
262
  context "properties" do
263
263
  should "have property x" do
264
264
  foo = Foo.new
@@ -267,34 +267,34 @@ class TestEntity < Test::Unit::TestCase
267
267
  foo.x += 10
268
268
  assert_equal 33, foo.x
269
269
  end
270
-
270
+
271
271
  should "not have property z" do
272
272
  foo = Foo.new
273
273
  assert_raise(NoMethodError) { foo.z }
274
274
  assert_raise(NoMethodError) { foo.z = 42 }
275
275
  end
276
-
276
+
277
277
  context "types" do
278
278
  should "work with nil" do
279
279
  foo = Foo.create :x => nil
280
280
  assert_equal nil, foo.reload.x
281
281
  end
282
-
282
+
283
283
  should "work with booleans" do
284
284
  foo = Foo.create :x => false
285
285
  assert_equal false, foo.reload.x
286
286
  end
287
-
287
+
288
288
  should "work with integers" do
289
289
  foo = Foo.create :x => -42
290
290
  assert_equal -42, foo.reload.x
291
291
  end
292
-
292
+
293
293
  should "work with floats" do
294
294
  foo = Foo.create :x => 3.141
295
295
  assert_equal 3.141, foo.reload.x
296
296
  end
297
-
297
+
298
298
  should "work with strings" do
299
299
  foo = Foo.create :x => 'hello'
300
300
  assert_equal 'hello', foo.reload.x
@@ -304,7 +304,7 @@ class TestEntity < Test::Unit::TestCase
304
304
  foo = Foo.create :x => [1, 2, 3]
305
305
  assert_equal [1, 2, 3], foo.reload.x
306
306
  end
307
-
307
+
308
308
  should "work with hashes" do
309
309
  hash = { 'a' => 17, 'b' => 'test' }
310
310
  foo = Foo.create :x => hash
@@ -312,7 +312,7 @@ class TestEntity < Test::Unit::TestCase
312
312
  end
313
313
  end
314
314
  end
315
-
315
+
316
316
  context "#restore" do
317
317
  should "restore an entity from json" do
318
318
  before = Foo.create :x => 42, :y => true
@@ -322,5 +322,5 @@ class TestEntity < Test::Unit::TestCase
322
322
  assert_equal before.y, after.y
323
323
  end
324
324
  end
325
-
325
+
326
326
  end
@@ -17,40 +17,40 @@ class TestManyToMany < Test::Unit::TestCase
17
17
  assert_equal [], Person.new.groups
18
18
  assert_equal [], Group.new.members
19
19
  end
20
-
20
+
21
21
  context "create" do
22
22
  should "add a new group to both associations" do
23
23
  tim = Person.create :name => 'tim'
24
24
  rugb = tim.groups.create :name => 'rug-b'
25
25
  assert_equal [tim], rugb.members
26
26
  end
27
-
27
+
28
28
  should "add a new person to both associations" do
29
29
  rugb = Group.create :name => 'rug-b'
30
30
  tim = rugb.members.create :name => 'tim'
31
31
  assert_equal [rugb], tim.groups
32
32
  end
33
33
  end
34
-
34
+
35
35
  context "add" do
36
36
  setup do
37
37
  @tim = Person.create :name => 'tim'
38
38
  @rugb = Group.create :name => 'rug-b'
39
39
  end
40
-
40
+
41
41
  should "add a new group to both associations" do
42
42
  @tim.groups.add(@rugb)
43
43
  assert_equal [@tim], @rugb.members
44
44
  assert_equal [@rugb], @tim.groups
45
45
  end
46
-
46
+
47
47
  should "add a new person to both associations" do
48
48
  @rugb.members.add(@tim)
49
49
  assert_equal [@tim], @rugb.members
50
50
  assert_equal [@rugb], @tim.groups
51
51
  end
52
52
  end
53
-
53
+
54
54
  context "remove" do
55
55
  setup do
56
56
  @tim = Person.create :name => 'tim'
@@ -58,20 +58,20 @@ class TestManyToMany < Test::Unit::TestCase
58
58
  @erlang = @tim.groups.create(:name => 'erlang')
59
59
  @aws = @tim.groups.create(:name => 'aws')
60
60
  end
61
-
61
+
62
62
  should "remove a group from both associations" do
63
63
  @tim.groups.remove(@erlang)
64
64
  assert_equal [@rugb, @aws], @tim.groups
65
65
  assert_equal [], @erlang.members
66
66
  end
67
-
67
+
68
68
  should "remove a person from both associations" do
69
69
  @erlang.members.remove(@tim)
70
70
  assert_equal [@rugb, @aws], @tim.groups
71
71
  assert_equal [], @erlang.members
72
72
  end
73
-
73
+
74
74
  end
75
75
  end
76
-
76
+
77
77
  end
@@ -17,11 +17,11 @@ class TestManyToOne < Test::Unit::TestCase
17
17
  should "exist" do
18
18
  assert Puzzle.create.respond_to?(:pieces)
19
19
  end
20
-
20
+
21
21
  should "return an empty list by default" do
22
22
  assert_equal [], Puzzle.create.pieces
23
23
  end
24
-
24
+
25
25
  should "return any existing children" do
26
26
  puzzle = Puzzle.create
27
27
  redis.rpush "#{puzzle.key}:pieces", Piece.create(:color => 'red').key
@@ -30,18 +30,18 @@ class TestManyToOne < Test::Unit::TestCase
30
30
  assert_equal Piece, puzzle.pieces[0].class
31
31
  assert_equal 'red', puzzle.pieces[0].color
32
32
  end
33
-
33
+
34
34
  context "create" do
35
35
  should "have a create method" do
36
36
  assert Puzzle.create.pieces.respond_to?(:create)
37
37
  end
38
-
38
+
39
39
  should "work without attributes" do
40
40
  puzzle = Puzzle.create
41
41
  piece = puzzle.pieces.create
42
42
  assert piece.is_a?(Piece)
43
43
  end
44
-
44
+
45
45
  should "create and store a new child" do
46
46
  puzzle = Puzzle.create
47
47
  puzzle.pieces.create :color => 'green'
@@ -51,7 +51,7 @@ class TestManyToOne < Test::Unit::TestCase
51
51
  assert_equal Piece, puzzle.pieces[0].class
52
52
  assert_equal 'green', puzzle.pieces[0].color
53
53
  end
54
-
54
+
55
55
  should "associate the created child with self" do
56
56
  puzzle = Puzzle.create :topic => 'provence'
57
57
  piece = puzzle.pieces.create :color => 'green'
@@ -71,10 +71,26 @@ class TestManyToOne < Test::Unit::TestCase
71
71
  assert_equal 'white', puzzle.pieces[0].color
72
72
  end
73
73
  end
74
-
74
+
75
+ context "find" do
76
+ setup do
77
+ @puzzle = Puzzle.create
78
+ 5.times { @puzzle.pieces.create :color => 'blue' }
79
+ end
80
+
81
+ should "find the element with the given id" do
82
+ piece = @puzzle.pieces[2]
83
+ assert_equal piece, @puzzle.pieces.find(piece.id)
84
+ end
85
+
86
+ should "raise an exception if no element with the given id exists" do
87
+ assert_raises(Remodel::EntityNotFound) { @puzzle.pieces.find(-1) }
88
+ end
89
+ end
90
+
75
91
  end
76
92
  end
77
-
93
+
78
94
  context "reload" do
79
95
  should "reset has_many associations" do
80
96
  puzzle = Puzzle.create
@@ -84,5 +100,5 @@ class TestManyToOne < Test::Unit::TestCase
84
100
  assert_equal [], puzzle.pieces
85
101
  end
86
102
  end
87
-
103
+
88
104
  end
data/test/test_mappers.rb CHANGED
@@ -17,12 +17,12 @@ class TestMappers < Test::Unit::TestCase
17
17
  setup do
18
18
  @item = Item.create :time => Time.at(1234567890), :date => Date.parse("1972-06-16")
19
19
  end
20
-
20
+
21
21
  should "store unmapped values" do
22
22
  assert_equal Time, @item.instance_eval { @attributes[:time].class }
23
23
  assert_equal Date, @item.instance_eval { @attributes[:date].class }
24
24
  end
25
-
25
+
26
26
  should "not change mapped values" do
27
27
  assert_equal Time.at(1234567890), @item.time
28
28
  assert_equal Date.parse("1972-06-16"), @item.date
@@ -33,13 +33,13 @@ class TestMappers < Test::Unit::TestCase
33
33
  assert_equal Time.at(1234567890), @item.time
34
34
  assert_equal Date.parse("1972-06-16"), @item.date
35
35
  end
36
-
36
+
37
37
  should "serialize mapped values correctly" do
38
38
  json = redis.get(@item.key)
39
39
  assert_match /1234567890/, json
40
40
  assert_match /"1972-06-16"/, json
41
41
  end
42
-
42
+
43
43
  should "handle nil values" do
44
44
  item = Item.create
45
45
  assert_nil item.boolean
@@ -51,7 +51,7 @@ class TestMappers < Test::Unit::TestCase
51
51
  assert_nil item.time
52
52
  assert_nil item.date
53
53
  end
54
-
54
+
55
55
  should "reject invalid types" do
56
56
  assert_raise(Remodel::InvalidType) { Item.create :boolean => 'hello' }
57
57
  assert_raise(Remodel::InvalidType) { Item.create :string => true }
@@ -13,7 +13,7 @@ class TestMonkeypatches < Test::Unit::TestCase
13
13
  should "return given Class objects" do
14
14
  assert_equal String, Class[String]
15
15
  end
16
-
16
+
17
17
  should "return the Class object for a given String" do
18
18
  assert_equal String, Class['String']
19
19
  end
@@ -21,7 +21,7 @@ class TestMonkeypatches < Test::Unit::TestCase
21
21
  should "return the Class object for a given Symbol" do
22
22
  assert_equal String, Class[:String]
23
23
  end
24
-
24
+
25
25
  should "work for nested classes" do
26
26
  assert_equal Remodel::Entity, Class['Remodel::Entity']
27
27
  end
@@ -18,18 +18,18 @@ class TestOneToMany < Test::Unit::TestCase
18
18
  should "exist" do
19
19
  assert Piece.create.respond_to?(:puzzle)
20
20
  end
21
-
21
+
22
22
  should "return nil by default" do
23
23
  assert_nil Piece.create.puzzle
24
24
  end
25
-
25
+
26
26
  should "return the associated entity" do
27
27
  puzzle = Puzzle.create :topic => 'animals'
28
28
  piece = Piece.create
29
29
  redis.set("#{piece.key}:puzzle", puzzle.key)
30
30
  assert_equal 'animals', piece.puzzle.topic
31
31
  end
32
- end
32
+ end
33
33
 
34
34
  context "association setter" do
35
35
  should "exist" do
@@ -42,14 +42,14 @@ class TestOneToMany < Test::Unit::TestCase
42
42
  piece.puzzle = puzzle
43
43
  assert_equal puzzle.key, redis.get("#{piece.key}:puzzle")
44
44
  end
45
-
45
+
46
46
  should "add the entity to the reverse association" do
47
47
  puzzle = Puzzle.create
48
48
  piece = Piece.create
49
49
  piece.puzzle = puzzle
50
50
  assert_equal 1, puzzle.pieces.size
51
51
  end
52
-
52
+
53
53
  should "be settable to nil" do
54
54
  piece = Piece.create
55
55
  piece.puzzle = nil
@@ -62,7 +62,7 @@ class TestOneToMany < Test::Unit::TestCase
62
62
  piece.puzzle = nil
63
63
  assert_nil redis.get("#{piece.key}:puzzle")
64
64
  end
65
-
65
+
66
66
  should "remove the entity from the reverse association if set to nil" do
67
67
  puzzle = Puzzle.create
68
68
  piece = Piece.create
@@ -83,5 +83,5 @@ class TestOneToMany < Test::Unit::TestCase
83
83
  assert_nil piece.puzzle
84
84
  end
85
85
  end
86
-
86
+
87
87
  end
@@ -17,35 +17,35 @@ class TestOneToOne < Test::Unit::TestCase
17
17
  assert_equal nil, Man.new.wife
18
18
  assert_equal nil, Woman.new.husband
19
19
  end
20
-
20
+
21
21
  context "setter" do
22
22
  setup do
23
23
  @bill = Man.create :name => 'Bill'
24
24
  @mary = Woman.create :name => 'Mary'
25
25
  end
26
-
26
+
27
27
  context "non-nil value" do
28
28
  should "also set husband" do
29
29
  @bill.wife = @mary
30
30
  assert_equal @bill, @mary.husband
31
31
  end
32
-
32
+
33
33
  should "also set wife" do
34
34
  @mary.husband = @bill
35
35
  assert_equal @mary, @bill.wife
36
36
  end
37
37
  end
38
-
38
+
39
39
  context "nil value" do
40
40
  setup do
41
41
  @bill.wife = @mary
42
42
  end
43
-
43
+
44
44
  should "also clear husband" do
45
45
  @bill.wife = nil
46
46
  assert_equal nil, @mary.husband
47
47
  end
48
-
48
+
49
49
  should "also clear wife" do
50
50
  @mary.husband = nil
51
51
  assert_equal nil, @bill.wife
@@ -53,5 +53,5 @@ class TestOneToOne < Test::Unit::TestCase
53
53
  end
54
54
  end
55
55
  end
56
-
56
+
57
57
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Lossen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-04-30 00:00:00 +02:00
12
+ date: 2010-05-03 00:00:00 +02:00
13
13
  default_executable: redis-monitor.rb
14
14
  dependencies: []
15
15