ohm 0.1.0.rc2 → 0.1.0.rc4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +12 -5
- data/Rakefile +10 -2
- data/lib/ohm.rb +76 -9
- data/lib/ohm/version.rb +1 -1
- data/test/1.8.6_test.rb +1 -1
- data/test/connection_test.rb +1 -1
- data/test/errors_test.rb +1 -1
- data/test/hash_key_test.rb +36 -0
- data/test/indices_test.rb +2 -2
- data/test/model_module_test.rb +1 -1
- data/test/model_test.rb +123 -1
- data/test/mutex_test.rb +1 -1
- data/test/upgrade_script_test.rb +1 -1
- data/test/validations_test.rb +1 -1
- data/test/wrapper_test.rb +20 -0
- metadata +11 -4
data/README.markdown
CHANGED
@@ -228,7 +228,7 @@ An index is a set that's handled automatically by Ohm. For any index declared,
|
|
228
228
|
Ohm maintains different sets of objects IDs for quick lookups.
|
229
229
|
|
230
230
|
In the `Event` example, the index on the name attribute will
|
231
|
-
allow for searches like `Event.find(name
|
231
|
+
allow for searches like `Event.find(:name => "some value")`.
|
232
232
|
|
233
233
|
Note that the `assert_unique` validation and the methods `find` and `except` need a
|
234
234
|
corresponding index in order to work.
|
@@ -238,18 +238,18 @@ corresponding index in order to work.
|
|
238
238
|
You can find a collection of records with the `find` method:
|
239
239
|
|
240
240
|
# This returns a collection of users with the username "Albert"
|
241
|
-
User.find(username
|
241
|
+
User.find(:username => "Albert")
|
242
242
|
|
243
243
|
### Filtering results
|
244
244
|
|
245
245
|
# Find all users from Argentina
|
246
|
-
User.find(country
|
246
|
+
User.find(:country => "Argentina")
|
247
247
|
|
248
248
|
# Find all activated users from Argentina
|
249
|
-
User.find(country
|
249
|
+
User.find(:country => "Argentina", :status => "activated")
|
250
250
|
|
251
251
|
# Find all users from Argentina, except those with a suspended account.
|
252
|
-
User.find(country
|
252
|
+
User.find(:country => "Argentina").except(:status => "suspended")
|
253
253
|
|
254
254
|
Note that calling these methods results in new sets being created
|
255
255
|
on the fly. This is important so that you can perform further operations
|
@@ -365,6 +365,13 @@ values. The result of the block is used as the error message:
|
|
365
365
|
error_messages
|
366
366
|
# => ["The email foo@example.com is already registered."]
|
367
367
|
|
368
|
+
Ohm Extensions
|
369
|
+
==============
|
370
|
+
|
371
|
+
Ohm is rather small and can be extended in many ways.
|
372
|
+
|
373
|
+
A lot of amazing contributions are available at [Ohm Contrib](http://labs.sinefunc.com/ohm-contrib/doc/), make sure to check them if you need to extend Ohm's functionality.
|
374
|
+
|
368
375
|
Versions
|
369
376
|
========
|
370
377
|
|
data/Rakefile
CHANGED
@@ -24,6 +24,14 @@ task :stop do
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
27
|
+
task :test do
|
28
|
+
Dir["test/**/*_test.rb"].each do |file|
|
29
|
+
fork do
|
30
|
+
load file
|
31
|
+
end
|
32
|
+
|
33
|
+
Process.wait
|
34
|
+
|
35
|
+
exit $?.exitstatus unless $?.success?
|
36
|
+
end
|
29
37
|
end
|
data/lib/ohm.rb
CHANGED
@@ -518,7 +518,7 @@ module Ohm
|
|
518
518
|
end
|
519
519
|
|
520
520
|
def self.all
|
521
|
-
|
521
|
+
Ohm::Model::Index.new(key(:all), Wrapper.wrap(self))
|
522
522
|
end
|
523
523
|
|
524
524
|
def self.attributes
|
@@ -623,6 +623,48 @@ module Ohm
|
|
623
623
|
incr(att, -count)
|
624
624
|
end
|
625
625
|
|
626
|
+
# Export the id and errors of the object. The `to_hash` takes the opposite
|
627
|
+
# approach of providing all the attributes and instead favors a
|
628
|
+
# white listed approach.
|
629
|
+
#
|
630
|
+
# @example
|
631
|
+
#
|
632
|
+
# person = Person.create(:name => "John Doe")
|
633
|
+
# person.to_hash == { :id => '1' }
|
634
|
+
# # => true
|
635
|
+
#
|
636
|
+
# # if the person asserts presence of name, the errors will be included
|
637
|
+
# person = Person.create(:name => "John Doe")
|
638
|
+
# person.name = nil
|
639
|
+
# person.valid?
|
640
|
+
# # => false
|
641
|
+
#
|
642
|
+
# person.to_hash == { :id => '1', :errors => [[:name, :not_present]] }
|
643
|
+
# # => true
|
644
|
+
#
|
645
|
+
# # for cases where you want to provide white listed attributes just do:
|
646
|
+
#
|
647
|
+
# class Person < Ohm::Model
|
648
|
+
# def to_hash
|
649
|
+
# super.merge(:name => name)
|
650
|
+
# end
|
651
|
+
# end
|
652
|
+
#
|
653
|
+
# # now we have the name when doing a to_hash
|
654
|
+
# person = Person.create(:name => "John Doe")
|
655
|
+
# person.to_hash == { :id => '1', :name => "John Doe" }
|
656
|
+
# # => true
|
657
|
+
def to_hash
|
658
|
+
attrs = {}
|
659
|
+
attrs[:id] = id unless new?
|
660
|
+
attrs[:errors] = errors unless errors.empty?
|
661
|
+
attrs
|
662
|
+
end
|
663
|
+
|
664
|
+
def to_json(*args)
|
665
|
+
to_hash.to_json(*args)
|
666
|
+
end
|
667
|
+
|
626
668
|
def attributes
|
627
669
|
self.class.attributes
|
628
670
|
end
|
@@ -644,6 +686,11 @@ module Ohm
|
|
644
686
|
rescue MissingID
|
645
687
|
false
|
646
688
|
end
|
689
|
+
alias :eql? :==
|
690
|
+
|
691
|
+
def hash
|
692
|
+
new? ? super : key.hash
|
693
|
+
end
|
647
694
|
|
648
695
|
# Lock the object before executing the block, and release it once the block is done.
|
649
696
|
def mutex
|
@@ -694,21 +741,41 @@ module Ohm
|
|
694
741
|
end
|
695
742
|
|
696
743
|
def write
|
697
|
-
unless attributes.empty?
|
698
|
-
attributes.
|
744
|
+
unless (attributes + counters).empty?
|
745
|
+
atts = (attributes + counters).inject([]) { |ret, att|
|
699
746
|
value = send(att).to_s
|
700
747
|
|
701
|
-
if value.empty?
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
748
|
+
ret.push(att, value) if not value.empty?
|
749
|
+
ret
|
750
|
+
}
|
751
|
+
|
752
|
+
db.multi do
|
753
|
+
db.del(key)
|
754
|
+
db.hmset(key, *atts.flatten) if atts.any?
|
706
755
|
end
|
707
756
|
end
|
708
757
|
end
|
709
758
|
|
759
|
+
def write_remote(att, value)
|
760
|
+
write_local(att, value)
|
761
|
+
|
762
|
+
if value.to_s.empty?
|
763
|
+
db.hdel(key, att)
|
764
|
+
else
|
765
|
+
db.hset(key, att, value)
|
766
|
+
end
|
767
|
+
end
|
768
|
+
|
710
769
|
def self.const_missing(name)
|
711
|
-
Wrapper.new(name) { const_get(name) }
|
770
|
+
wrapper = Wrapper.new(name) { const_get(name) }
|
771
|
+
|
772
|
+
# Allow others to hook to const_missing.
|
773
|
+
begin
|
774
|
+
super(name)
|
775
|
+
rescue NameError
|
776
|
+
end
|
777
|
+
|
778
|
+
wrapper
|
712
779
|
end
|
713
780
|
|
714
781
|
private
|
data/lib/ohm/version.rb
CHANGED
data/test/1.8.6_test.rb
CHANGED
data/test/connection_test.rb
CHANGED
data/test/errors_test.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
4
|
+
|
5
|
+
class Tag < Ohm::Model
|
6
|
+
attribute :name
|
7
|
+
end
|
8
|
+
|
9
|
+
class HashKeyTest < Test::Unit::TestCase
|
10
|
+
setup do
|
11
|
+
Ohm.flush
|
12
|
+
end
|
13
|
+
|
14
|
+
test "using a new record as a hash key" do
|
15
|
+
tag = Tag.new
|
16
|
+
hash = { tag => "Ruby" }
|
17
|
+
|
18
|
+
assert_equal "Ruby", hash[tag]
|
19
|
+
assert_nil hash[Tag.new]
|
20
|
+
end
|
21
|
+
|
22
|
+
test "on a persisted model" do
|
23
|
+
tag = Tag.create(:name => "Ruby")
|
24
|
+
|
25
|
+
assert_equal "Ruby", { tag => "Ruby" }[tag]
|
26
|
+
end
|
27
|
+
|
28
|
+
test "on a reloaded model" do
|
29
|
+
tag = Tag.create(:name => "Ruby")
|
30
|
+
hash = { tag => "Ruby" }
|
31
|
+
|
32
|
+
tag = Tag[tag.id]
|
33
|
+
assert_equal "Ruby", hash[tag]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/test/indices_test.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "test_helper")
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
2
|
|
3
3
|
class IndicesTest < Test::Unit::TestCase
|
4
4
|
setup do
|
@@ -43,7 +43,7 @@ class IndicesTest < Test::Unit::TestCase
|
|
43
43
|
end
|
44
44
|
|
45
45
|
should "raise an error if the parameter supplied is not a hash" do
|
46
|
-
assert_raises ArgumentError
|
46
|
+
assert_raises ArgumentError, "You need to supply a hash with filters. If you want to find by ID, use IndicesTest::User[id] instead." do
|
47
47
|
User.find(1)
|
48
48
|
end
|
49
49
|
end
|
data/test/model_module_test.rb
CHANGED
data/test/model_test.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require File.join(File.dirname(__FILE__), "test_helper")
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
4
4
|
require "ostruct"
|
5
|
+
require "json"
|
5
6
|
|
6
7
|
class Post < Ohm::Model
|
7
8
|
attribute :body
|
@@ -256,6 +257,16 @@ class ModelTest < Test::Unit::TestCase
|
|
256
257
|
|
257
258
|
assert_equal "foo", event.slug
|
258
259
|
end
|
260
|
+
|
261
|
+
should "save counters" do
|
262
|
+
event = Event.create(:name => "Foo")
|
263
|
+
|
264
|
+
event.incr(:votes)
|
265
|
+
event.save
|
266
|
+
|
267
|
+
assert_equal 1, Event[event.id].votes
|
268
|
+
end
|
269
|
+
|
259
270
|
end
|
260
271
|
|
261
272
|
context "Delete" do
|
@@ -942,6 +953,18 @@ class ModelTest < Test::Unit::TestCase
|
|
942
953
|
assert_equal car, Car[1]
|
943
954
|
assert_nil Make[1]
|
944
955
|
end
|
956
|
+
|
957
|
+
should "allow changing the database" do
|
958
|
+
Car.create(:name => "Twingo")
|
959
|
+
|
960
|
+
assert_equal ["1"], Car.all.raw
|
961
|
+
|
962
|
+
Car.connect :db => 15
|
963
|
+
assert_equal [], Car.all.raw
|
964
|
+
|
965
|
+
Car.connect :db => 14
|
966
|
+
assert_equal ["1"], Car.all.raw
|
967
|
+
end
|
945
968
|
end
|
946
969
|
|
947
970
|
context "Persistence" do
|
@@ -959,4 +982,103 @@ class ModelTest < Test::Unit::TestCase
|
|
959
982
|
assert_equal 1, Event[1].votes
|
960
983
|
end
|
961
984
|
end
|
985
|
+
|
986
|
+
context "Exporting" do
|
987
|
+
class Venue < Ohm::Model
|
988
|
+
attribute :name
|
989
|
+
|
990
|
+
def validate
|
991
|
+
assert_present :name
|
992
|
+
end
|
993
|
+
end
|
994
|
+
|
995
|
+
context "a new model without errors" do
|
996
|
+
should "export an empty hash via to_hash" do
|
997
|
+
person = Venue.new
|
998
|
+
assert_equal({}, person.to_hash)
|
999
|
+
end
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
context "a new model with some errors" do
|
1003
|
+
should "export a hash with the errors" do
|
1004
|
+
person = Venue.new
|
1005
|
+
person.valid?
|
1006
|
+
|
1007
|
+
assert_equal({ :errors => [[:name, :not_present]] }, person.to_hash)
|
1008
|
+
end
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
context "an existing model" do
|
1012
|
+
should "export a hash with the its id" do
|
1013
|
+
person = Venue.create(:name => "John Doe")
|
1014
|
+
assert_equal({ :id => '1' }, person.to_hash)
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
context "an existing model with validation errors" do
|
1019
|
+
should "export a hash with its id and the errors" do
|
1020
|
+
person = Venue.create(:name => "John Doe")
|
1021
|
+
person.name = nil
|
1022
|
+
person.valid?
|
1023
|
+
|
1024
|
+
expected_hash = { :id => '1', :errors => [[:name, :not_present]] }
|
1025
|
+
|
1026
|
+
assert_equal expected_hash, person.to_hash
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
|
1030
|
+
class Programmer < Ohm::Model
|
1031
|
+
attribute :language
|
1032
|
+
|
1033
|
+
def validate
|
1034
|
+
assert_present :language
|
1035
|
+
end
|
1036
|
+
|
1037
|
+
def to_hash
|
1038
|
+
super.merge(:language => language)
|
1039
|
+
end
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
context "a subclassed to_hash" do
|
1043
|
+
should "return the merged attributes" do
|
1044
|
+
programmer = Programmer.create(:language => "Ruby")
|
1045
|
+
expected_hash = { :id => '1', :language => 'Ruby' }
|
1046
|
+
|
1047
|
+
assert_equal expected_hash, programmer.to_hash
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
context "the JSON representation of an object" do
|
1052
|
+
should "just be the to_hash of a model" do
|
1053
|
+
json = JSON.parse(Programmer.create(:language => "Ruby").to_json)
|
1054
|
+
|
1055
|
+
assert_equal ["id", "language"], json.keys.sort
|
1056
|
+
assert_equal "1", json["id"]
|
1057
|
+
assert_equal "Ruby", json["language"]
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
describe "a Model with individual attribute writing needs" do
|
1063
|
+
class Order < Ohm::Model
|
1064
|
+
attribute :state
|
1065
|
+
|
1066
|
+
def authorize!
|
1067
|
+
write_remote :state, 'authorized'
|
1068
|
+
end
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
test "writes locally" do
|
1072
|
+
order = Order.create(:state => "pending")
|
1073
|
+
order.authorize!
|
1074
|
+
assert_equal 'authorized', order.state
|
1075
|
+
end
|
1076
|
+
|
1077
|
+
test "writes remotely" do
|
1078
|
+
order = Order.create(:state => "pending")
|
1079
|
+
order.authorize!
|
1080
|
+
order = Order[order.id]
|
1081
|
+
assert_equal 'authorized', order.state
|
1082
|
+
end
|
1083
|
+
end
|
962
1084
|
end
|
data/test/mutex_test.rb
CHANGED
data/test/upgrade_script_test.rb
CHANGED
data/test/validations_test.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
|
2
|
+
|
3
|
+
$missing_constants = []
|
4
|
+
|
5
|
+
class Object
|
6
|
+
def self.const_missing(name)
|
7
|
+
$missing_constants << name
|
8
|
+
super(name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Foo < Ohm::Model
|
13
|
+
set :bars, Bar
|
14
|
+
end
|
15
|
+
|
16
|
+
class Tests < Test::Unit::TestCase
|
17
|
+
test "calls other const_missing hooks" do
|
18
|
+
assert_equal [:Bar], $missing_constants
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
|
|
6
6
|
- 0
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.1.0.
|
9
|
+
- rc4
|
10
|
+
version: 0.1.0.rc4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Michel Martens
|
@@ -16,13 +16,14 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-
|
19
|
+
date: 2010-07-02 00:00:00 -03:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
23
23
|
name: redis
|
24
24
|
prerelease: false
|
25
25
|
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
26
27
|
requirements:
|
27
28
|
- - ">="
|
28
29
|
- !ruby/object:Gem::Version
|
@@ -38,6 +39,7 @@ dependencies:
|
|
38
39
|
name: contest
|
39
40
|
prerelease: false
|
40
41
|
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
41
43
|
requirements:
|
42
44
|
- - ~>
|
43
45
|
- !ruby/object:Gem::Version
|
@@ -51,6 +53,7 @@ dependencies:
|
|
51
53
|
name: batch
|
52
54
|
prerelease: false
|
53
55
|
requirement: &id003 !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
54
57
|
requirements:
|
55
58
|
- - ~>
|
56
59
|
- !ruby/object:Gem::Version
|
@@ -86,6 +89,7 @@ files:
|
|
86
89
|
- test/all_tests.rb
|
87
90
|
- test/connection_test.rb
|
88
91
|
- test/errors_test.rb
|
92
|
+
- test/hash_key_test.rb
|
89
93
|
- test/indices_test.rb
|
90
94
|
- test/model_module_test.rb
|
91
95
|
- test/model_test.rb
|
@@ -93,6 +97,7 @@ files:
|
|
93
97
|
- test/test_helper.rb
|
94
98
|
- test/upgrade_script_test.rb
|
95
99
|
- test/validations_test.rb
|
100
|
+
- test/wrapper_test.rb
|
96
101
|
- test/test.conf
|
97
102
|
has_rdoc: true
|
98
103
|
homepage: http://github.com/soveran/ohm
|
@@ -104,6 +109,7 @@ rdoc_options: []
|
|
104
109
|
require_paths:
|
105
110
|
- lib
|
106
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
107
113
|
requirements:
|
108
114
|
- - ">="
|
109
115
|
- !ruby/object:Gem::Version
|
@@ -111,6 +117,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
117
|
- 0
|
112
118
|
version: "0"
|
113
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
114
121
|
requirements:
|
115
122
|
- - ">"
|
116
123
|
- !ruby/object:Gem::Version
|
@@ -122,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
129
|
requirements: []
|
123
130
|
|
124
131
|
rubyforge_project: ohm
|
125
|
-
rubygems_version: 1.3.
|
132
|
+
rubygems_version: 1.3.7
|
126
133
|
signing_key:
|
127
134
|
specification_version: 3
|
128
135
|
summary: Object-hash mapping library for Redis.
|