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 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: "some value")`.
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: "Albert")
241
+ User.find(:username => "Albert")
242
242
 
243
243
  ### Filtering results
244
244
 
245
245
  # Find all users from Argentina
246
- User.find(country: "Argentina")
246
+ User.find(:country => "Argentina")
247
247
 
248
248
  # Find all activated users from Argentina
249
- User.find(country: "Argentina", status: "activated")
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: "Argentina").except(status: "suspended")
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
- Rake::TestTask.new(:test) do |t|
28
- t.pattern = 'test/**/*_test.rb'
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
- @all ||= Ohm::Model::Index.new(key(:all), Wrapper.wrap(self))
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.each do |att|
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
- db.hdel(key, att)
703
- else
704
- db.hset(key, att, value)
705
- end
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
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
2
 
3
3
  module Ohm
4
- VERSION = "0.1.0.rc2"
4
+ VERSION = "0.1.0.rc4"
5
5
  end
data/test/1.8.6_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 TestString < Test::Unit::TestCase
4
4
  context "String#lines" do
@@ -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 ConnectionTest < Test::Unit::TestCase
4
4
  setup do
data/test/errors_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 ErrorsTest < Test::Unit::TestCase
4
4
  class User < Ohm::Model
@@ -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.new("You need to supply a hash with filters. If you want to find by ID, use IndicesTest::User[id] instead.") do
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
@@ -1,6 +1,6 @@
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
5
 
6
6
  module Model
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
@@ -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 TestMutex < Test::Unit::TestCase
4
4
  class Person < Ohm::Model
@@ -1,6 +1,6 @@
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
 
5
5
  require "ohm/utils/upgrade"
6
6
 
@@ -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 ValidationsTest < Test::Unit::TestCase
4
4
  class Event < Ohm::Model
@@ -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
- - rc2
10
- version: 0.1.0.rc2
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-05-12 00:00:00 -03:00
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.6
132
+ rubygems_version: 1.3.7
126
133
  signing_key:
127
134
  specification_version: 3
128
135
  summary: Object-hash mapping library for Redis.