ohm 2.0.0.alpha5 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -2
- data/CHANGELOG +60 -0
- data/README.md +57 -205
- data/Rakefile +0 -2
- data/lib/ohm.rb +60 -23
- data/lib/ohm/json.rb +0 -7
- data/lib/ohm/lua/save.lua +4 -3
- data/ohm.gemspec +2 -2
- data/test/enumerable.rb +4 -4
- data/test/filtering.rb +18 -142
- data/test/helper.rb +0 -1
- data/test/json.rb +32 -39
- data/test/model.rb +6 -10
- data/test/set.rb +20 -0
- data/test/to_hash.rb +29 -0
- metadata +5 -5
- data/test/extensibility.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60d1fadf47380356ffbc44627e28f9b15ff8528a
|
4
|
+
data.tar.gz: f911d9c462235f7c56f5216b10f1b2d48f3ab287
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67eea41a25fd17691a9cc79700abf248438a7bccefc7624053212d6439d6252bfc2850e0a7905fe8a2ad46eadac6d9d11d150978cec4f937a2bbba89ea05e90b
|
7
|
+
data.tar.gz: 1e17aace64652f6c96cd79fa6ff071a67fbed614951af15e8487d8fee78b21ec69f10313b7e8b1004292d1f97a22c3d8be74d5f892172742fe634fea84989ef2
|
data/.gitignore
CHANGED
data/CHANGELOG
CHANGED
@@ -1,3 +1,63 @@
|
|
1
|
+
(unreleased)
|
2
|
+
|
3
|
+
- Include Ohm::BasicSet#exists? in the public API. This makes possible
|
4
|
+
to check if an id is included in a set. Check Ohm::BasicSet#exists?
|
5
|
+
documentation for more details.
|
6
|
+
|
7
|
+
- Change Ohm::MultiSet#except to union keys instead of intersect them
|
8
|
+
when passing an array.
|
9
|
+
|
10
|
+
class User < Ohm::Model
|
11
|
+
attribute :name
|
12
|
+
end
|
13
|
+
|
14
|
+
john = User.create(:name => "John")
|
15
|
+
jane = User.create(:name => "Jane")
|
16
|
+
|
17
|
+
res = User.all.except(:name => [john.name, jane.name])
|
18
|
+
|
19
|
+
# before
|
20
|
+
res.size # => 2
|
21
|
+
|
22
|
+
# now
|
23
|
+
res.size # => 0
|
24
|
+
|
25
|
+
- Move ID generation to Lua. With this change, it's no longer possible
|
26
|
+
to generate custom ids. All ids are autoincremented.
|
27
|
+
|
28
|
+
- Ohm::Model#reference accepts strings as model references. For example:
|
29
|
+
|
30
|
+
class Bar < Ohm::Model
|
31
|
+
reference :foo, "SomeNamespace::Foo"
|
32
|
+
end
|
33
|
+
|
34
|
+
- Nest dependency has been removed. Now, Ohm uses Nido
|
35
|
+
(https://github.com/soveran/nido) to generate the keys that hold
|
36
|
+
the data.
|
37
|
+
|
38
|
+
- Scrivener dependency has been removed.
|
39
|
+
|
40
|
+
- Ohm no longer supports model validations and favors filter validation
|
41
|
+
on the boundary layer. Check Scrivener project
|
42
|
+
(https://github.com/soveran/scrivener) for more information.
|
43
|
+
|
44
|
+
- Redis dependency has been removed. Now, Ohm uses Redic
|
45
|
+
(https://github.com/amakawa/redic), a lightweight Redis client.
|
46
|
+
Redic uses the hiredis gem for the connection and for parsing
|
47
|
+
the replies. Check Redic's README for more details.
|
48
|
+
|
49
|
+
- Ohm::Model#transaction has been removed.
|
50
|
+
|
51
|
+
- Ohm::Transaction has been removed.
|
52
|
+
|
53
|
+
1.3.2
|
54
|
+
|
55
|
+
- Fetching a batch of objects is now done in batches of 1000 objects at
|
56
|
+
a time. If you are iterating over large collections, this change should
|
57
|
+
provide a significant performance boost both in used memory and total
|
58
|
+
execution time.
|
59
|
+
- MutableSet#<< is now an alias for #add.
|
60
|
+
|
1
61
|
1.3.1
|
2
62
|
|
3
63
|
- Improve memory consumption when indexing persisted attributes.
|
data/README.md
CHANGED
@@ -7,8 +7,7 @@ Description
|
|
7
7
|
-----------
|
8
8
|
|
9
9
|
Ohm is a library for storing objects in [Redis][redis], a persistent key-value
|
10
|
-
database. It
|
11
|
-
performance.
|
10
|
+
database. It has very good performance.
|
12
11
|
|
13
12
|
Community
|
14
13
|
---------
|
@@ -17,7 +16,6 @@ Join the mailing list: [http://groups.google.com/group/ohm-ruby](http://groups.g
|
|
17
16
|
|
18
17
|
Meet us on IRC: [#ohm](irc://chat.freenode.net/#ohm) on [freenode.net](http://freenode.net/)
|
19
18
|
|
20
|
-
|
21
19
|
Related projects
|
22
20
|
----------------
|
23
21
|
|
@@ -58,61 +56,55 @@ Now, in an irb session you can test the Redis adapter directly:
|
|
58
56
|
|
59
57
|
>> require "ohm"
|
60
58
|
=> true
|
61
|
-
>> Ohm.
|
62
|
-
=> []
|
63
|
-
>> Ohm.redis.set "Foo", "Bar"
|
59
|
+
>> Ohm.redis.call "SET", "Foo", "Bar"
|
64
60
|
=> "OK"
|
65
|
-
>> Ohm.redis.
|
61
|
+
>> Ohm.redis.call "GET", "Foo"
|
66
62
|
=> "Bar"
|
67
63
|
|
68
|
-
## Connecting to
|
69
|
-
|
70
|
-
There are a couple of different strategies for connecting to your Redis
|
71
|
-
database. The first is to explicitly set the `:host`, `:port`, `:db` and
|
72
|
-
`:timeout` options. You can also set only a few of them, and let the other
|
73
|
-
options fall back to the default.
|
74
|
-
|
75
|
-
The other noteworthy style of connecting is by just doing `Ohm.connect` and
|
76
|
-
set the environment variable `REDIS_URL`.
|
64
|
+
## Connecting to a Redis database
|
77
65
|
|
78
|
-
|
66
|
+
Ohm uses a lightweight Redis client called [Redic][redic]. To connect
|
67
|
+
to a Redis database, you will need to set an instance of `Redic`, with
|
68
|
+
an URL of the form `redis://:<passwd>@<host>:<port>/<db>`, through the
|
69
|
+
`Ohm.redis=` method, e.g.
|
79
70
|
|
80
|
-
|
81
|
-
|
82
|
-
A Redis URL of the form `redis://:<passwd>@<host>:<port>/<db>`.
|
83
|
-
Note that if you specify a URL and one of the other options at
|
84
|
-
the same time, the other options will take precedence. Also, if
|
85
|
-
you try and do `Ohm.connect` without any arguments, it will check
|
86
|
-
if `ENV["REDIS_URL"]` is set, and will use it as the argument for
|
87
|
-
`:url`.
|
71
|
+
```ruby
|
72
|
+
require "ohm"
|
88
73
|
|
89
|
-
|
74
|
+
Ohm.redis = Redic.new("redis://127.0.0.1:6379")
|
90
75
|
|
91
|
-
|
76
|
+
Ohm.redis.call "SET", "Foo", "Bar"
|
92
77
|
|
93
|
-
|
78
|
+
Ohm.redis.call "GET", "Foo"
|
79
|
+
# => "Bar"
|
80
|
+
```
|
94
81
|
|
95
|
-
|
82
|
+
Ohm defaults to a Redic connection to "redis://127.0.0.1:6379". The
|
83
|
+
example above could be rewritten as:
|
96
84
|
|
97
|
-
|
85
|
+
```ruby
|
86
|
+
require "ohm"
|
98
87
|
|
99
|
-
|
88
|
+
Ohm.redis.call "SET", "Foo", "Bar"
|
100
89
|
|
101
|
-
|
90
|
+
Ohm.redis.call "GET", "Foo"
|
91
|
+
# => "Bar"
|
92
|
+
```
|
102
93
|
|
103
|
-
|
104
|
-
|
94
|
+
All Ohm models inherit the same connection settings from `Ohm.redis`.
|
95
|
+
For cases where certain models need to connect to different databases,
|
96
|
+
they simple have to override that, i.e.
|
105
97
|
|
106
|
-
|
98
|
+
```ruby
|
99
|
+
require "ohm"
|
107
100
|
|
108
|
-
|
101
|
+
Ohm.redis = Redic.new(ENV["REDIS_URL1"])
|
109
102
|
|
110
|
-
|
103
|
+
class User < Ohm::Model
|
104
|
+
end
|
111
105
|
|
112
|
-
|
113
|
-
|
114
|
-
instance per thread. I you have no choice, then pass `:thread_safe => true`
|
115
|
-
when connecting.
|
106
|
+
User.redis = Redic.new(ENV["REDIS_URL2"])
|
107
|
+
```
|
116
108
|
|
117
109
|
Models
|
118
110
|
------
|
@@ -131,10 +123,6 @@ class Event < Ohm::Model
|
|
131
123
|
counter :votes
|
132
124
|
|
133
125
|
index :name
|
134
|
-
|
135
|
-
def validate
|
136
|
-
assert_present :name
|
137
|
-
end
|
138
126
|
end
|
139
127
|
|
140
128
|
class Venue < Ohm::Model
|
@@ -165,12 +153,12 @@ Event[2]
|
|
165
153
|
# => nil
|
166
154
|
|
167
155
|
# Finding all the events
|
168
|
-
Event.all
|
169
|
-
# => [
|
156
|
+
Event.all.to_a
|
157
|
+
# => [<Event:1 name='Ohm Worldwide Conference 2031'>]
|
170
158
|
```
|
171
159
|
|
172
160
|
This example shows some basic features, like attribute declarations and
|
173
|
-
|
161
|
+
querying. Keep reading to find out what you can do with models.
|
174
162
|
|
175
163
|
Attribute types
|
176
164
|
---------------
|
@@ -223,31 +211,20 @@ Persistence strategy
|
|
223
211
|
--------------------
|
224
212
|
|
225
213
|
The attributes declared with `attribute` are only persisted after
|
226
|
-
calling `save`.
|
227
|
-
to Redis (see the section on **Validations** below).
|
214
|
+
calling `save`.
|
228
215
|
|
229
216
|
Operations on attributes of type `list`, `set` and `counter` are
|
230
217
|
possible only after the object is created (when it has an assigned
|
231
218
|
`id`). Any operation on these kinds of attributes is performed
|
232
|
-
immediately
|
233
|
-
|
234
|
-
buffering the operations and waiting for a call to `save`.
|
219
|
+
immediately. This design yields better performance than buffering
|
220
|
+
the operations and waiting for a call to `save`.
|
235
221
|
|
236
222
|
For most use cases, this pattern doesn't represent a problem.
|
237
|
-
If you need to check for validity before operating on lists, sets or
|
238
|
-
counters, you can use this pattern:
|
239
|
-
|
240
|
-
```ruby
|
241
|
-
if event.valid?
|
242
|
-
event.comments.add(Comment.create(:body => "Great event!"))
|
243
|
-
end
|
244
|
-
```
|
245
|
-
|
246
223
|
If you are saving the object, this will suffice:
|
247
224
|
|
248
225
|
```ruby
|
249
226
|
if event.save
|
250
|
-
event.comments.add(Comment.create(:
|
227
|
+
event.comments.add(Comment.create(body: "Wonderful event!"))
|
251
228
|
end
|
252
229
|
```
|
253
230
|
|
@@ -267,7 +244,7 @@ You can add instances of `Person` to the set of attendees with the
|
|
267
244
|
`add` method:
|
268
245
|
|
269
246
|
```ruby
|
270
|
-
event.attendees.add(Person.create(:
|
247
|
+
event.attendees.add(Person.create(name: "Albert"))
|
271
248
|
|
272
249
|
# And now...
|
273
250
|
event.attendees.each do |person|
|
@@ -317,7 +294,7 @@ and it's within the current model you are sorting.
|
|
317
294
|
|
318
295
|
```ruby
|
319
296
|
Post.all.sort_by(:title) # SORT Post:all BY Post:*->title
|
320
|
-
Post.all.sort(:
|
297
|
+
Post.all.sort(by: :title) # SORT Post:all BY title
|
321
298
|
```
|
322
299
|
|
323
300
|
__Tip:__ Unless you absolutely know what you're doing, use `sort`
|
@@ -332,10 +309,10 @@ the `:by` option, using {Ohm::Model::Collection#sort sort} and
|
|
332
309
|
that `sort_by` does much of the hand-coding for you.
|
333
310
|
|
334
311
|
```ruby
|
335
|
-
Post.all.sort_by(:title, :
|
312
|
+
Post.all.sort_by(:title, get: :title)
|
336
313
|
# SORT Post:all BY Post:*->title GET Post:*->title
|
337
314
|
|
338
|
-
Post.all.sort(:
|
315
|
+
Post.all.sort(by: :title, get: :title)
|
339
316
|
# SORT Post:all BY title GET title
|
340
317
|
```
|
341
318
|
|
@@ -360,7 +337,7 @@ end
|
|
360
337
|
|
361
338
|
After this, every time you refer to `post.comments` you will be talking
|
362
339
|
about instances of the model `Comment`. If you want to get a list of IDs
|
363
|
-
you can use `post.comments.
|
340
|
+
you can use `post.comments.ids`.
|
364
341
|
|
365
342
|
### References explained
|
366
343
|
|
@@ -391,7 +368,7 @@ The net effect here is we can conveniently set and retrieve `Post` objects,
|
|
391
368
|
and also search comments using the `post_id` index.
|
392
369
|
|
393
370
|
```ruby
|
394
|
-
Comment.find(:
|
371
|
+
Comment.find(post_id: 1)
|
395
372
|
```
|
396
373
|
|
397
374
|
### Collections explained
|
@@ -409,7 +386,7 @@ class Post < Ohm::Model
|
|
409
386
|
attribute :body
|
410
387
|
|
411
388
|
def comments
|
412
|
-
Comment.find(:
|
389
|
+
Comment.find(post_id: self.id)
|
413
390
|
end
|
414
391
|
end
|
415
392
|
```
|
@@ -441,7 +418,7 @@ any index declared, Ohm maintains different sets of objects IDs for quick
|
|
441
418
|
lookups.
|
442
419
|
|
443
420
|
In the `Event` example, the index on the name attribute will
|
444
|
-
allow for searches like `Event.find(:
|
421
|
+
allow for searches like `Event.find(name: "some value")`.
|
445
422
|
|
446
423
|
Note that the methods {Ohm::Model::Set#find find} and
|
447
424
|
{Ohm::Model::Set#except except} need a corresponding index in order to work.
|
@@ -452,23 +429,23 @@ You can find a collection of records with the `find` method:
|
|
452
429
|
|
453
430
|
```ruby
|
454
431
|
# This returns a collection of users with the username "Albert"
|
455
|
-
User.find(:
|
432
|
+
User.find(username: "Albert")
|
456
433
|
```
|
457
434
|
|
458
435
|
### Filtering results
|
459
436
|
|
460
437
|
```ruby
|
461
438
|
# Find all users from Argentina
|
462
|
-
User.find(:
|
439
|
+
User.find(country: "Argentina")
|
463
440
|
|
464
441
|
# Find all activated users from Argentina
|
465
|
-
User.find(:
|
442
|
+
User.find(country: "Argentina", status: "activated")
|
466
443
|
|
467
444
|
# Find all users from Argentina, except those with a suspended account.
|
468
|
-
User.find(:
|
445
|
+
User.find(country: "Argentina").except(status: "suspended")
|
469
446
|
|
470
447
|
# Find all users both from Argentina and Uruguay
|
471
|
-
User.find(:
|
448
|
+
User.find(country: "Argentina").union(country: "Uruguay")
|
472
449
|
```
|
473
450
|
|
474
451
|
Note that calling these methods results in new sets being created
|
@@ -499,131 +476,6 @@ User.create(email: "foo@bar.com")
|
|
499
476
|
# => raises Ohm::UniqueIndexViolation
|
500
477
|
```
|
501
478
|
|
502
|
-
Validations
|
503
|
-
-----------
|
504
|
-
|
505
|
-
Before every save, the `validate` method is called by Ohm. In the method
|
506
|
-
definition you can use assertions that will determine if the attributes
|
507
|
-
are valid. Nesting assertions is a good practice, and you are also
|
508
|
-
encouraged to create your own assertions. You can trigger validations at
|
509
|
-
any point by calling `valid?` on a model instance.
|
510
|
-
|
511
|
-
Assertions
|
512
|
-
-----------
|
513
|
-
|
514
|
-
Ohm ships with some basic assertions. Check Ohm::Validations to see
|
515
|
-
the method definitions.
|
516
|
-
|
517
|
-
### assert
|
518
|
-
|
519
|
-
The `assert` method is used by all the other assertions. It pushes the
|
520
|
-
second parameter to the list of errors if the first parameter evaluates
|
521
|
-
to false.
|
522
|
-
|
523
|
-
```ruby
|
524
|
-
def assert(value, error)
|
525
|
-
value or errors.push(error) && false
|
526
|
-
end
|
527
|
-
```
|
528
|
-
|
529
|
-
### assert_present
|
530
|
-
|
531
|
-
Checks that the given field is not nil or empty. The error code for this
|
532
|
-
assertion is `:not_present`.
|
533
|
-
|
534
|
-
```ruby
|
535
|
-
assert_present :name
|
536
|
-
```
|
537
|
-
|
538
|
-
### assert_format
|
539
|
-
|
540
|
-
Checks that the given field matches the provided format. The error code
|
541
|
-
for this assertion is :format.
|
542
|
-
|
543
|
-
```ruby
|
544
|
-
assert_format :username, /^\w+$/
|
545
|
-
```
|
546
|
-
|
547
|
-
### assert_numeric
|
548
|
-
|
549
|
-
Checks that the given field holds a number as a Fixnum or as a string
|
550
|
-
representation. The error code for this assertion is :not_numeric.
|
551
|
-
|
552
|
-
```ruby
|
553
|
-
assert_numeric :votes
|
554
|
-
```
|
555
|
-
|
556
|
-
### assert_url
|
557
|
-
|
558
|
-
Provides a pretty general URL regular expression match. An important
|
559
|
-
point to make is that this assumes that the URL should start with
|
560
|
-
`http://` or `https://`. The error code for this assertion is
|
561
|
-
`:not_url`.
|
562
|
-
|
563
|
-
### assert_email
|
564
|
-
|
565
|
-
In this current day and age, almost all web applications need to
|
566
|
-
validate an email address. This pretty much matches 99% of the emails
|
567
|
-
out there. The error code for this assertion is `:not_email`.
|
568
|
-
|
569
|
-
### assert_member
|
570
|
-
|
571
|
-
Checks that a given field is contained within a set of values (i.e.
|
572
|
-
like an `ENUM`).
|
573
|
-
|
574
|
-
``` ruby
|
575
|
-
def validate
|
576
|
-
assert_member :state, %w{pending paid delivered}
|
577
|
-
end
|
578
|
-
```
|
579
|
-
|
580
|
-
The error code for this assertion is `:not_valid`
|
581
|
-
|
582
|
-
### assert_length
|
583
|
-
|
584
|
-
Checks that a given field's length falls under a specified range.
|
585
|
-
|
586
|
-
``` ruby
|
587
|
-
def validate
|
588
|
-
assert_length :username, 3..20
|
589
|
-
end
|
590
|
-
```
|
591
|
-
|
592
|
-
The error code for this assertion is `:not_in_range`.
|
593
|
-
|
594
|
-
### assert_decimal
|
595
|
-
|
596
|
-
Checks that a given field looks like a number in the human sense
|
597
|
-
of the word. Valid numbers are: 0.1, .1, 1, 1.1, 3.14159, etc.
|
598
|
-
|
599
|
-
The error code for this assertion is `:not_decimal`.
|
600
|
-
|
601
|
-
Errors
|
602
|
-
------
|
603
|
-
|
604
|
-
When an assertion fails, the error report is added to the errors array.
|
605
|
-
Each error report contains two elements: the field where the assertion
|
606
|
-
was issued and the error code.
|
607
|
-
|
608
|
-
### Validation example
|
609
|
-
|
610
|
-
Given the following example:
|
611
|
-
|
612
|
-
```ruby
|
613
|
-
def validate
|
614
|
-
assert_present :foo
|
615
|
-
assert_numeric :bar
|
616
|
-
assert_format :baz, /^\d{2}$/
|
617
|
-
end
|
618
|
-
```
|
619
|
-
|
620
|
-
If all the assertions fail, the following errors will be present:
|
621
|
-
|
622
|
-
```ruby
|
623
|
-
obj.errors
|
624
|
-
# => { foo: [:not_present], bar: [:not_numeric], baz: [:format] }
|
625
|
-
```
|
626
|
-
|
627
479
|
Ohm Extensions
|
628
480
|
==============
|
629
481
|
|
@@ -637,10 +489,10 @@ make sure to check them if you need to extend Ohm's functionality.
|
|
637
489
|
Upgrading
|
638
490
|
=========
|
639
491
|
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
for new projects.
|
492
|
+
Ohm 2 breaks the compatibility with previous versions. If you're upgrading an
|
493
|
+
existing application, it's nice to have a good test coverage before going in.
|
494
|
+
To know about fixes and changes, please refer to the CHANGELOG file.
|
644
495
|
|
645
496
|
[redis]: http://redis.io
|
646
497
|
[ohm]: http://github.com/soveran/ohm
|
498
|
+
[redic]: https://github.com/amakawa/redic
|
data/Rakefile
CHANGED
data/lib/ohm.rb
CHANGED
@@ -56,11 +56,12 @@ module Ohm
|
|
56
56
|
# reference :user, User # NameError undefined constant User.
|
57
57
|
# end
|
58
58
|
#
|
59
|
-
# Instead of relying on some clever `const_missing` hack, we can
|
60
|
-
# simply use a
|
59
|
+
# # Instead of relying on some clever `const_missing` hack, we can
|
60
|
+
# # simply use a symbol or a string.
|
61
61
|
#
|
62
62
|
# class Comment < Ohm::Model
|
63
63
|
# reference :user, :User
|
64
|
+
# reference :post, "Post"
|
64
65
|
# end
|
65
66
|
#
|
66
67
|
def self.const(context, name)
|
@@ -166,7 +167,6 @@ module Ohm
|
|
166
167
|
def size
|
167
168
|
redis.call("LLEN", key)
|
168
169
|
end
|
169
|
-
alias :count :size
|
170
170
|
|
171
171
|
# Returns the first element of the list using LINDEX.
|
172
172
|
def first
|
@@ -342,7 +342,6 @@ module Ohm
|
|
342
342
|
def size
|
343
343
|
execute { |key| redis.call("SCARD", key) }
|
344
344
|
end
|
345
|
-
alias :count :size
|
346
345
|
|
347
346
|
# Syntactic sugar for `sort_by` or `sort` when you only need the
|
348
347
|
# first element.
|
@@ -385,11 +384,29 @@ module Ohm
|
|
385
384
|
model[id] if exists?(id)
|
386
385
|
end
|
387
386
|
|
388
|
-
|
387
|
+
# Returns +true+ if +id+ is included in the set. Otherwise, returns +false+.
|
388
|
+
#
|
389
|
+
# Example:
|
390
|
+
#
|
391
|
+
# class Post < Ohm::Model
|
392
|
+
# end
|
393
|
+
#
|
394
|
+
# class User < Ohm::Model
|
395
|
+
# set :posts, :Post
|
396
|
+
# end
|
397
|
+
#
|
398
|
+
# user = User.create
|
399
|
+
# post = Post.create
|
400
|
+
# user.posts.add(post)
|
401
|
+
#
|
402
|
+
# user.posts.exists?('nonexistent') # => false
|
403
|
+
# user.posts.exists?(post.id) # => true
|
404
|
+
#
|
389
405
|
def exists?(id)
|
390
406
|
execute { |key| redis.call("SISMEMBER", key, id) == 1 }
|
391
407
|
end
|
392
408
|
|
409
|
+
private
|
393
410
|
def to_key(att)
|
394
411
|
if model.counters.include?(att)
|
395
412
|
namespace["*:counters->%s" % att]
|
@@ -569,7 +586,7 @@ module Ohm
|
|
569
586
|
#
|
570
587
|
def except(dict)
|
571
588
|
MultiSet.new(
|
572
|
-
namespace, model, Command[:sdiffstore, command,
|
589
|
+
namespace, model, Command[:sdiffstore, command, unioned(dict)]
|
573
590
|
)
|
574
591
|
end
|
575
592
|
|
@@ -598,6 +615,10 @@ module Ohm
|
|
598
615
|
Command[:sinterstore, *model.filters(dict)]
|
599
616
|
end
|
600
617
|
|
618
|
+
def unioned(dict)
|
619
|
+
Command[:sunionstore, *model.filters(dict)]
|
620
|
+
end
|
621
|
+
|
601
622
|
def execute
|
602
623
|
# namespace[:tmp] is where all the temp keys should be stored in.
|
603
624
|
# redis will be where all the commands are executed against.
|
@@ -677,7 +698,7 @@ module Ohm
|
|
677
698
|
@redis ||= Redic.new(Ohm.redis.url)
|
678
699
|
end
|
679
700
|
|
680
|
-
#
|
701
|
+
# Returns the namespace for all the keys generated using this model.
|
681
702
|
#
|
682
703
|
# Example:
|
683
704
|
#
|
@@ -1018,7 +1039,7 @@ module Ohm
|
|
1018
1039
|
# u = User.create
|
1019
1040
|
# u.incr :points
|
1020
1041
|
#
|
1021
|
-
#
|
1042
|
+
# u.points
|
1022
1043
|
# # => 1
|
1023
1044
|
#
|
1024
1045
|
# Note: You can't use counters until you save the model. If you
|
@@ -1049,21 +1070,8 @@ module Ohm
|
|
1049
1070
|
new(atts).save
|
1050
1071
|
end
|
1051
1072
|
|
1052
|
-
#
|
1053
|
-
#
|
1054
|
-
# Example:
|
1055
|
-
#
|
1056
|
-
# class User < Ohm::Model
|
1057
|
-
# attribute :name
|
1058
|
-
# end
|
1059
|
-
#
|
1060
|
-
# u = User.create(:name => "John")
|
1061
|
-
# u.key.hget(:name)
|
1062
|
-
# # => John
|
1063
|
-
#
|
1064
|
-
# For more details see
|
1065
|
-
# http://github.com/soveran/nest
|
1066
|
-
#
|
1073
|
+
# Returns the namespace for the keys generated using this model.
|
1074
|
+
# Check `Ohm::Model.key` documentation for more details.
|
1067
1075
|
def key
|
1068
1076
|
model.key[id]
|
1069
1077
|
end
|
@@ -1153,6 +1161,21 @@ module Ohm
|
|
1153
1161
|
@attributes[att] = val
|
1154
1162
|
end
|
1155
1163
|
|
1164
|
+
# Returns +true+ if the model is not persisted. Otherwise, returns +false+.
|
1165
|
+
#
|
1166
|
+
# Example:
|
1167
|
+
#
|
1168
|
+
# class User < Ohm::Model
|
1169
|
+
# attribute :name
|
1170
|
+
# end
|
1171
|
+
#
|
1172
|
+
# u = User.new(:name => "John")
|
1173
|
+
# u.new?
|
1174
|
+
# # => true
|
1175
|
+
#
|
1176
|
+
# u.save
|
1177
|
+
# u.new?
|
1178
|
+
# # => false
|
1156
1179
|
def new?
|
1157
1180
|
!defined?(@id)
|
1158
1181
|
end
|
@@ -1184,6 +1207,20 @@ module Ohm
|
|
1184
1207
|
end
|
1185
1208
|
alias :eql? :==
|
1186
1209
|
|
1210
|
+
# Returns a hash of the attributes with their names as keys
|
1211
|
+
# and the values of the attributes as values. It doesn't
|
1212
|
+
# include the ID of the model.
|
1213
|
+
#
|
1214
|
+
# Example:
|
1215
|
+
#
|
1216
|
+
# class User < Ohm::Model
|
1217
|
+
# attribute :name
|
1218
|
+
# end
|
1219
|
+
#
|
1220
|
+
# u = User.create(:name => "John")
|
1221
|
+
# u.attributes
|
1222
|
+
# # => { :name => "John" }
|
1223
|
+
#
|
1187
1224
|
def attributes
|
1188
1225
|
@attributes
|
1189
1226
|
end
|
data/lib/ohm/json.rb
CHANGED
data/lib/ohm/lua/save.lua
CHANGED
@@ -6,10 +6,11 @@
|
|
6
6
|
--
|
7
7
|
-- # model
|
8
8
|
--
|
9
|
-
-- Table with
|
10
|
-
-- id (model instance id)
|
11
|
-
-- key (hash where the attributes will be saved)
|
9
|
+
-- Table with one or two attributes:
|
12
10
|
-- name (model name)
|
11
|
+
-- id (model instance id, optional)
|
12
|
+
--
|
13
|
+
-- If the id is not provided, it is treated as a new record.
|
13
14
|
--
|
14
15
|
-- # attrs
|
15
16
|
--
|
data/ohm.gemspec
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "ohm"
|
3
|
-
s.version = "2.0.0.
|
3
|
+
s.version = "2.0.0.rc1"
|
4
4
|
s.summary = %{Object-hash mapping library for Redis.}
|
5
|
-
s.description = %Q{Ohm is a library that allows to store an object in Redis, a persistent key-value database. It
|
5
|
+
s.description = %Q{Ohm is a library that allows to store an object in Redis, a persistent key-value database. It has very good performance.}
|
6
6
|
s.authors = ["Michel Martens", "Damian Janowski", "Cyril David"]
|
7
7
|
s.email = ["michel@soveran.com", "djanowski@dimaion.com", "me@cyrildavid.com"]
|
8
8
|
s.homepage = "http://soveran.github.io/ohm/"
|
data/test/enumerable.rb
CHANGED
@@ -12,14 +12,14 @@ scope do
|
|
12
12
|
[john, jane]
|
13
13
|
end
|
14
14
|
|
15
|
-
test "Set#
|
15
|
+
test "Set#size doesn't do each" do
|
16
16
|
set = Contact.all
|
17
17
|
|
18
18
|
def set.each
|
19
19
|
raise "Failed"
|
20
20
|
end
|
21
21
|
|
22
|
-
assert_equal 2, set.
|
22
|
+
assert_equal 2, set.size
|
23
23
|
end
|
24
24
|
|
25
25
|
test "Set#each as an Enumerator" do |john, jane|
|
@@ -67,13 +67,13 @@ scope do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
test "List#
|
70
|
+
test "List#size doesn't do each" do |post, c1, c2|
|
71
71
|
list = post.comments
|
72
72
|
|
73
73
|
def list.each
|
74
74
|
raise "Failed"
|
75
75
|
end
|
76
76
|
|
77
|
-
assert_equal 2, list.
|
77
|
+
assert_equal 2, list.size
|
78
78
|
end
|
79
79
|
end
|
data/test/filtering.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
__END__
|
2
1
|
require File.expand_path("./helper", File.dirname(__FILE__))
|
3
2
|
|
4
3
|
class User < Ohm::Model
|
5
4
|
attribute :fname
|
6
5
|
attribute :lname
|
7
6
|
attribute :status
|
7
|
+
|
8
8
|
index :fname
|
9
9
|
index :lname
|
10
10
|
index :status
|
@@ -64,9 +64,24 @@ test "#except" do |john, jane|
|
|
64
64
|
res = User.all.except(:status => "inactive")
|
65
65
|
|
66
66
|
assert_equal 2, res.size
|
67
|
+
assert res.include?(john)
|
67
68
|
assert res.include?(jane)
|
68
69
|
end
|
69
70
|
|
71
|
+
test "#except unions keys when passing an array" do |john, jane|
|
72
|
+
expected = User.create(:fname => "Jean", :status => "inactive")
|
73
|
+
|
74
|
+
res = User.find(:status => "inactive").except(:fname => [john.fname, jane.fname])
|
75
|
+
|
76
|
+
assert_equal 1, res.size
|
77
|
+
assert res.include?(expected)
|
78
|
+
|
79
|
+
res = User.all.except(:fname => [john.fname, jane.fname])
|
80
|
+
|
81
|
+
assert_equal 1, res.size
|
82
|
+
assert res.include?(expected)
|
83
|
+
end
|
84
|
+
|
70
85
|
test "indices bug related to a nil attribute" do |john, jane|
|
71
86
|
# First we create a record with a nil attribute
|
72
87
|
out = User.create(:status => nil, :lname => "Doe")
|
@@ -77,7 +92,7 @@ test "indices bug related to a nil attribute" do |john, jane|
|
|
77
92
|
|
78
93
|
# At this point, the index for the nil attribute should
|
79
94
|
# have been cleared.
|
80
|
-
assert_equal 0, User.
|
95
|
+
assert_equal 0, User.redis.call("SCARD", "User:indices:status:")
|
81
96
|
end
|
82
97
|
|
83
98
|
test "#union" do |john, jane|
|
@@ -150,7 +165,7 @@ scope do
|
|
150
165
|
|
151
166
|
assert_equal 1, res.size
|
152
167
|
assert res.map(&:mood).include?("sad")
|
153
|
-
assert res.map(&:book_id).include?(book2.id)
|
168
|
+
assert res.map(&:book_id).include?(book2.id.to_s)
|
154
169
|
end
|
155
170
|
|
156
171
|
test "@myobie usecase" do |book1, book2|
|
@@ -160,142 +175,3 @@ scope do
|
|
160
175
|
assert_equal 2, res.size
|
161
176
|
end
|
162
177
|
end
|
163
|
-
|
164
|
-
# test precision of filtering commands
|
165
|
-
require "logger"
|
166
|
-
require "stringio"
|
167
|
-
scope do
|
168
|
-
class Post < Ohm::Model
|
169
|
-
attribute :author
|
170
|
-
index :author
|
171
|
-
|
172
|
-
attribute :mood
|
173
|
-
index :mood
|
174
|
-
end
|
175
|
-
|
176
|
-
setup do
|
177
|
-
io = StringIO.new
|
178
|
-
|
179
|
-
Post.connect(:logger => Logger.new(io))
|
180
|
-
|
181
|
-
Post.create(author: "matz", mood: "happy")
|
182
|
-
Post.create(author: "rich", mood: "mad")
|
183
|
-
|
184
|
-
io
|
185
|
-
end
|
186
|
-
|
187
|
-
def read(io)
|
188
|
-
io.rewind
|
189
|
-
io.read
|
190
|
-
end
|
191
|
-
|
192
|
-
test "SINTERSTORE a b" do |io|
|
193
|
-
Post.find(author: "matz").find(mood: "happy").to_a
|
194
|
-
|
195
|
-
# This is the simple case. We should only do one SINTERSTORE
|
196
|
-
# given two direct keys. Anything more and we're performing badly.
|
197
|
-
expected = "SINTERSTORE Post:tmp:[a-f0-9]{64} " +
|
198
|
-
"Post:indices:author:matz Post:indices:mood:happy"
|
199
|
-
|
200
|
-
assert(read(io) =~ Regexp.new(expected))
|
201
|
-
end
|
202
|
-
|
203
|
-
test "SUNIONSTORE a b" do |io|
|
204
|
-
Post.find(author: "matz").union(mood: "happy").to_a
|
205
|
-
|
206
|
-
# Another simple case where we must only do one operation at maximum.
|
207
|
-
expected = "SUNIONSTORE Post:tmp:[a-f0-9]{64} " +
|
208
|
-
"Post:indices:author:matz Post:indices:mood:happy"
|
209
|
-
|
210
|
-
assert(read(io) =~ Regexp.new(expected))
|
211
|
-
end
|
212
|
-
|
213
|
-
test "SUNIONSTORE c (SINTERSTORE a b)" do |io|
|
214
|
-
Post.find(author: "matz").find(mood: "happy").union(author: "rich").to_a
|
215
|
-
|
216
|
-
# For this case we need an intermediate key. This will
|
217
|
-
# contain the intersection of matz + happy.
|
218
|
-
expected = "SINTERSTORE (Post:tmp:[a-f0-9]{64}) " +
|
219
|
-
"Post:indices:author:matz Post:indices:mood:happy"
|
220
|
-
|
221
|
-
assert(read(io) =~ Regexp.new(expected))
|
222
|
-
|
223
|
-
# The next operation is simply doing a UNION of the previously
|
224
|
-
# generated intermediate key and the additional single key.
|
225
|
-
expected = "SUNIONSTORE (Post:tmp:[a-f0-9]{64}) " +
|
226
|
-
"%s Post:indices:author:rich" % $1
|
227
|
-
|
228
|
-
assert(read(io) =~ Regexp.new(expected))
|
229
|
-
end
|
230
|
-
|
231
|
-
test "SUNIONSTORE (SINTERSTORE c d) (SINTERSTORE a b)" do |io|
|
232
|
-
Post.find(author: "matz").find(mood: "happy").
|
233
|
-
union(author: "rich", mood: "sad").to_a
|
234
|
-
|
235
|
-
# Similar to the previous case, we need to do an intermediate
|
236
|
-
# operation.
|
237
|
-
expected = "SINTERSTORE (Post:tmp:[a-f0-9]{64}) " +
|
238
|
-
"Post:indices:author:matz Post:indices:mood:happy"
|
239
|
-
|
240
|
-
match1 = read(io).match(Regexp.new(expected))
|
241
|
-
assert match1
|
242
|
-
|
243
|
-
# But now, we need to also hold another intermediate key for the
|
244
|
-
# condition of author: rich AND mood: sad.
|
245
|
-
expected = "SINTERSTORE (Post:tmp:[a-f0-9]{64}) " +
|
246
|
-
"Post:indices:author:rich Post:indices:mood:sad"
|
247
|
-
|
248
|
-
match2 = read(io).match(Regexp.new(expected))
|
249
|
-
assert match2
|
250
|
-
|
251
|
-
# Now we expect that it does a UNION of those two previous
|
252
|
-
# intermediate keys.
|
253
|
-
expected = sprintf(
|
254
|
-
"SUNIONSTORE (Post:tmp:[a-f0-9]{64}) %s %s",
|
255
|
-
match1[1], match2[1]
|
256
|
-
)
|
257
|
-
|
258
|
-
assert(read(io) =~ Regexp.new(expected))
|
259
|
-
end
|
260
|
-
|
261
|
-
test do |io|
|
262
|
-
Post.create(author: "kent", mood: "sad")
|
263
|
-
|
264
|
-
Post.find(author: "kent", mood: "sad").
|
265
|
-
union(author: "matz", mood: "happy").
|
266
|
-
except(mood: "sad", author: "rich").to_a
|
267
|
-
|
268
|
-
expected = "SINTERSTORE (Post:tmp:[a-f0-9]{64}) " +
|
269
|
-
"Post:indices:author:kent Post:indices:mood:sad"
|
270
|
-
|
271
|
-
match1 = read(io).match(Regexp.new(expected))
|
272
|
-
assert match1
|
273
|
-
|
274
|
-
expected = "SINTERSTORE (Post:tmp:[a-f0-9]{64}) " +
|
275
|
-
"Post:indices:author:matz Post:indices:mood:happy"
|
276
|
-
|
277
|
-
match2 = read(io).match(Regexp.new(expected))
|
278
|
-
assert match2
|
279
|
-
|
280
|
-
expected = sprintf(
|
281
|
-
"SUNIONSTORE (Post:tmp:[a-f0-9]{64}) %s %s",
|
282
|
-
match1[1], match2[1]
|
283
|
-
)
|
284
|
-
|
285
|
-
match3 = read(io).match(Regexp.new(expected))
|
286
|
-
assert match3
|
287
|
-
|
288
|
-
expected = "SINTERSTORE (Post:tmp:[a-f0-9]{64}) " +
|
289
|
-
"Post:indices:mood:sad Post:indices:author:rich"
|
290
|
-
|
291
|
-
match4 = read(io).match(Regexp.new(expected))
|
292
|
-
assert match4
|
293
|
-
|
294
|
-
expected = sprintf(
|
295
|
-
"SDIFFSTORE (Post:tmp:[a-f0-9]{64}) %s %s",
|
296
|
-
match3[1], match4[1]
|
297
|
-
)
|
298
|
-
|
299
|
-
assert(read(io) =~ Regexp.new(expected))
|
300
|
-
end
|
301
|
-
end
|
data/test/helper.rb
CHANGED
data/test/json.rb
CHANGED
@@ -1,70 +1,63 @@
|
|
1
|
-
|
1
|
+
require_relative 'helper'
|
2
2
|
|
3
|
-
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
-
|
5
|
-
require "json"
|
6
3
|
require "ohm/json"
|
7
4
|
|
8
5
|
class Venue < Ohm::Model
|
9
6
|
attribute :name
|
10
7
|
list :programmers, :Programmer
|
11
|
-
|
12
|
-
def validate
|
13
|
-
assert_present :name
|
14
|
-
end
|
15
8
|
end
|
16
9
|
|
17
10
|
class Programmer < Ohm::Model
|
18
11
|
attribute :language
|
19
12
|
|
20
|
-
|
21
|
-
assert_present :language
|
22
|
-
end
|
13
|
+
index :language
|
23
14
|
|
24
15
|
def to_hash
|
25
|
-
super.merge(:
|
16
|
+
super.merge(language: language)
|
26
17
|
end
|
27
18
|
end
|
28
19
|
|
29
|
-
test "
|
30
|
-
|
31
|
-
assert Hash.new == person.to_hash
|
32
|
-
end
|
20
|
+
test "exports model.to_hash to json" do
|
21
|
+
assert_equal Hash.new, JSON.parse(Venue.new.to_json)
|
33
22
|
|
34
|
-
|
35
|
-
|
36
|
-
assert_equal
|
37
|
-
|
23
|
+
venue = Venue.create(name: "foo")
|
24
|
+
json = JSON.parse(venue.to_json)
|
25
|
+
assert_equal venue.id, json["id"]
|
26
|
+
assert_equal nil, json["name"]
|
38
27
|
|
39
|
-
|
40
|
-
|
41
|
-
expected_hash = { :id => 1, :language => 'Ruby' }
|
28
|
+
programmer = Programmer.create(language: "Ruby")
|
29
|
+
json = JSON.parse(programmer.to_json)
|
42
30
|
|
43
|
-
|
31
|
+
assert_equal programmer.id, json["id"]
|
32
|
+
assert_equal programmer.language, json["language"]
|
44
33
|
end
|
45
34
|
|
46
|
-
test "
|
47
|
-
|
35
|
+
test "exports a set to json" do
|
36
|
+
Programmer.create(language: "Ruby")
|
37
|
+
Programmer.create(language: "Python")
|
48
38
|
|
49
|
-
|
50
|
-
|
51
|
-
|
39
|
+
expected = [{ id: "1", language: "Ruby" }, { id: "2", language: "Python"}].to_json
|
40
|
+
|
41
|
+
assert_equal expected, Programmer.all.to_json
|
52
42
|
end
|
53
43
|
|
54
|
-
test "
|
55
|
-
Programmer.create(:
|
56
|
-
Programmer.create(:
|
44
|
+
test "exports a multiset to json" do
|
45
|
+
Programmer.create(language: "Ruby")
|
46
|
+
Programmer.create(language: "Python")
|
57
47
|
|
58
|
-
expected = [{ :
|
59
|
-
|
48
|
+
expected = [{ id: "1", language: "Ruby" }, { id: "2", language: "Python"}].to_json
|
49
|
+
result = Programmer.find(language: "Ruby").union(language: "Python").to_json
|
50
|
+
|
51
|
+
assert_equal expected, result
|
60
52
|
end
|
61
53
|
|
62
|
-
test "
|
63
|
-
venue = Venue.create(:
|
54
|
+
test "exports a list to json" do
|
55
|
+
venue = Venue.create(name: "Foo")
|
56
|
+
|
57
|
+
venue.programmers.push(Programmer.create(language: "Ruby"))
|
58
|
+
venue.programmers.push(Programmer.create(language: "Python"))
|
64
59
|
|
65
|
-
|
66
|
-
venue.programmers.push(Programmer.create(:language => "Python"))
|
60
|
+
expected = [{ id: "1", language: "Ruby" }, { id: "2", language: "Python"}].to_json
|
67
61
|
|
68
|
-
expected = [{ :id => "1", :language => "Ruby" }, { :id => "2", :language => "Python"}].to_json
|
69
62
|
assert_equal expected, venue.programmers.to_json
|
70
63
|
end
|
data/test/model.rb
CHANGED
@@ -7,12 +7,12 @@ require "ostruct"
|
|
7
7
|
class Post < Ohm::Model
|
8
8
|
attribute :body
|
9
9
|
attribute :published
|
10
|
-
set :related, Post
|
10
|
+
set :related, :Post
|
11
11
|
end
|
12
12
|
|
13
13
|
class User < Ohm::Model
|
14
14
|
attribute :email
|
15
|
-
set :posts, Post
|
15
|
+
set :posts, :Post
|
16
16
|
end
|
17
17
|
|
18
18
|
class Person < Ohm::Model
|
@@ -28,7 +28,7 @@ end
|
|
28
28
|
class Event < Ohm::Model
|
29
29
|
attribute :name
|
30
30
|
counter :votes
|
31
|
-
set :attendees, Person
|
31
|
+
set :attendees, :Person
|
32
32
|
|
33
33
|
attribute :slug
|
34
34
|
|
@@ -51,10 +51,6 @@ end
|
|
51
51
|
class Meetup < Ohm::Model
|
52
52
|
attribute :name
|
53
53
|
attribute :location
|
54
|
-
|
55
|
-
def validate
|
56
|
-
assert_present :name
|
57
|
-
end
|
58
54
|
end
|
59
55
|
|
60
56
|
test "booleans" do
|
@@ -311,8 +307,8 @@ end
|
|
311
307
|
test "delete an existing model" do
|
312
308
|
class ModelToBeDeleted < Ohm::Model
|
313
309
|
attribute :name
|
314
|
-
set :foos, Post
|
315
|
-
set :bars, Post
|
310
|
+
set :foos, :Post
|
311
|
+
set :bars, :Post
|
316
312
|
end
|
317
313
|
|
318
314
|
@model = ModelToBeDeleted.create(:name => "Lorem")
|
@@ -774,7 +770,7 @@ test "be persisted" do
|
|
774
770
|
|
775
771
|
assert "foo" == SomeNamespace::Foo[1].name
|
776
772
|
assert "foo" == SomeNamespace::Bar[1].foo.name
|
777
|
-
end
|
773
|
+
end if RUBY_VERSION >= "2.0.0"
|
778
774
|
|
779
775
|
test "typecast attributes" do
|
780
776
|
class Option < Ohm::Model
|
data/test/set.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class Post < Ohm::Model
|
4
|
+
end
|
5
|
+
|
6
|
+
class User < Ohm::Model
|
7
|
+
set :posts, :Post
|
8
|
+
end
|
9
|
+
|
10
|
+
test '#exists? returns false if the given id is not included in the set' do
|
11
|
+
assert !User.create.posts.exists?('nonexistent')
|
12
|
+
end
|
13
|
+
|
14
|
+
test '#exists? returns true if the given id is included in the set' do
|
15
|
+
user = User.create
|
16
|
+
post = Post.create
|
17
|
+
user.posts.add(post)
|
18
|
+
|
19
|
+
assert user.posts.exists?(post.id)
|
20
|
+
end
|
data/test/to_hash.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
|
3
|
+
class User < Ohm::Model
|
4
|
+
end
|
5
|
+
|
6
|
+
test "returns an empty hash if model doesn't have set attributes" do
|
7
|
+
assert_equal Hash.new, User.new.to_hash
|
8
|
+
end
|
9
|
+
|
10
|
+
test "returns a hash with its id if model is persisted" do
|
11
|
+
user = User.create
|
12
|
+
|
13
|
+
assert_equal Hash[id: user.id], user.to_hash
|
14
|
+
end
|
15
|
+
|
16
|
+
class Person < Ohm::Model
|
17
|
+
attribute :name
|
18
|
+
|
19
|
+
def to_hash
|
20
|
+
super.merge(name: name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
test "returns additional attributes if the method is overrided" do
|
25
|
+
person = Person.create(name: "John")
|
26
|
+
expected = { id: person.id, name: person.name }
|
27
|
+
|
28
|
+
assert_equal expected, person.to_hash
|
29
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ohm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michel Martens
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-12-18 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: redic
|
@@ -69,8 +69,7 @@ dependencies:
|
|
69
69
|
- !ruby/object:Gem::Version
|
70
70
|
version: '0'
|
71
71
|
description: Ohm is a library that allows to store an object in Redis, a persistent
|
72
|
-
key-value database. It
|
73
|
-
performance.
|
72
|
+
key-value database. It has very good performance.
|
74
73
|
email:
|
75
74
|
- michel@soveran.com
|
76
75
|
- djanowski@dimaion.com
|
@@ -110,7 +109,6 @@ files:
|
|
110
109
|
- test/counters.rb
|
111
110
|
- test/db/.gitignore
|
112
111
|
- test/enumerable.rb
|
113
|
-
- test/extensibility.rb
|
114
112
|
- test/filtering.rb
|
115
113
|
- test/hash_key.rb
|
116
114
|
- test/helper.rb
|
@@ -119,7 +117,9 @@ files:
|
|
119
117
|
- test/json.rb
|
120
118
|
- test/list.rb
|
121
119
|
- test/model.rb
|
120
|
+
- test/set.rb
|
122
121
|
- test/test.conf
|
122
|
+
- test/to_hash.rb
|
123
123
|
- test/uniques.rb
|
124
124
|
homepage: http://soveran.github.io/ohm/
|
125
125
|
licenses:
|
data/test/extensibility.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
require File.expand_path("./helper", File.dirname(__FILE__))
|
4
|
-
|
5
|
-
if defined?(Ohm::Model::PureRuby)
|
6
|
-
class User < Ohm::Model
|
7
|
-
attribute :email
|
8
|
-
|
9
|
-
attr_accessor :foo
|
10
|
-
|
11
|
-
def save
|
12
|
-
super do |t|
|
13
|
-
t.before do
|
14
|
-
self.email = email.downcase
|
15
|
-
end
|
16
|
-
|
17
|
-
t.after do
|
18
|
-
if @foo
|
19
|
-
key[:foos].sadd(@foo)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def delete
|
26
|
-
super do |t|
|
27
|
-
foos = nil
|
28
|
-
|
29
|
-
t.before do
|
30
|
-
foos = key[:foos].smembers
|
31
|
-
end
|
32
|
-
|
33
|
-
t.after do
|
34
|
-
foos.each { |foo| key[:foos].srem(foo) }
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
test do
|
41
|
-
u = User.create(:email => "FOO@BAR.COM", :foo => "bar")
|
42
|
-
assert_equal "foo@bar.com", u.email
|
43
|
-
assert_equal ["bar"], u.key[:foos].smembers
|
44
|
-
|
45
|
-
u.delete
|
46
|
-
assert_equal [], User.key[u.id][:foos].smembers
|
47
|
-
end
|
48
|
-
end
|