ohm 0.1.0.rc2 → 0.1.0.rc4

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.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.