ohm 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,6 +3,7 @@ Ohm ॐ
3
3
 
4
4
  Object-hash mapping library for Redis.
5
5
 
6
+
6
7
  Description
7
8
  -----------
8
9
 
@@ -11,17 +12,48 @@ Ohm is a library that allows to store an object in
11
12
  database. It includes an extensible list of validations and has very
12
13
  good performance.
13
14
 
14
- Usage
15
- -----
16
15
 
17
- require 'ohm'
16
+ Getting started
17
+ ---------------
18
+
19
+ Install [Redis](http://code.google.com/p/redis/). On most platforms
20
+ it's as easy as grabbing the sources, running make and then putting the
21
+ `redis-server` binary in the PATH.
22
+
23
+ Once you have it installed, you can execute `redis-server` and it will
24
+ run on `localhost:6379` by default. Check the `redis.conf` file that comes
25
+ with the sources if you want to change some settings.
26
+
27
+ If you don't have Ohm, try this:
28
+
29
+ $ sudo gem install ohm
30
+
31
+ Now, in an irb session you can test the Redis adapter directly:
32
+
33
+ >> require "ohm"
34
+ => true
35
+ >> Ohm.connect
36
+ => []
37
+ >> Ohm.redis.set "Foo", "Bar"
38
+ => "OK"
39
+ >> Ohm.redis.get "Foo"
40
+ => "Bar"
41
+
42
+
43
+ Models
44
+ ------
18
45
 
19
- Ohm.connect
46
+ Ohm's purpose in life is to map objects to a key value datastore. It
47
+ doesn't need migrations or external schema definitions. Take a look at
48
+ the example below:
49
+
50
+ ### Example
20
51
 
21
52
  class Event < Ohm::Model
22
53
  attribute :name
23
54
  set :participants
24
55
  list :comments
56
+ counter :votes
25
57
 
26
58
  index :name
27
59
 
@@ -30,53 +62,183 @@ Usage
30
62
  end
31
63
  end
32
64
 
33
- event = Event.create(:name => "Ruby Tuesday")
34
- event.participants << "Michel Martens"
35
- event.participants << "Damian Janowski"
36
- event.participants.all #=> ["Damian Janowski", "Michel Martens"]
65
+ This example shows some basic features, like attribute declarations and
66
+ validations. Keep reading to find out what you can do with models.
37
67
 
38
- event.comments << "Very interesting event!"
39
- event.comments << "Agree"
40
- event.comments.all #=> ["Very interesting event!", "Agree"]
41
68
 
42
- another_event = Event.new
43
- another_event.valid? #=> false
44
- another_event.errors #=> [[:name, :nil]]
69
+ Attribute types
70
+ ---------------
45
71
 
46
- another_event.name = ""
47
- another_event.valid? #=> false
48
- another_event.errors #=> [[:name, :empty]]
72
+ Ohm::Model provides four attribute types: `attribute`, `set`, `list` and
73
+ `counter`.
49
74
 
50
- another_event.name = "Ruby Lunch"
51
- another_event.create #=> true
75
+ ### attribute
52
76
 
53
- Installation
54
- ------------
77
+ An `attribute` is just any value that can be stored as a string. In the
78
+ example above, we used this field to store the Event's `name`. You can
79
+ use it to store numbers, but be aware that Redis will return a string
80
+ when you retrieve the value.
55
81
 
56
- $ sudo gem install ohm
82
+ ### set
83
+
84
+ A `set` in Redis is an unordered list, with an external behavior similar
85
+ to that of Ruby arrays, but optimized for faster membership lookups.
86
+ It's used internaly by Ohm to keep track of the instances of each model
87
+ and for generating and maintaining indexes.
88
+
89
+ ### list
90
+
91
+ A `list` is like an array in Ruby. It's perfectly suited for queues and
92
+ for keeping elements in order.
57
93
 
58
- License
94
+ ### counter
95
+
96
+ A `counter` is like a regular attribute, but the direct manipulation
97
+ of the value is not allowed. You can retrieve, increase or decrease
98
+ the value, but you can not assign it. In the example above, we used a
99
+ counter attribute for tracking votes. As the incr and decr operations
100
+ are atomic, you can rest assured a vote won't be counted twice.
101
+
102
+
103
+ Indexes
59
104
  -------
60
105
 
61
- Copyright (c) 2009 Michel Martens and Damian Janowski
62
-
63
- Permission is hereby granted, free of charge, to any person
64
- obtaining a copy of this software and associated documentation
65
- files (the "Software"), to deal in the Software without
66
- restriction, including without limitation the rights to use,
67
- copy, modify, merge, publish, distribute, sublicense, and/or sell
68
- copies of the Software, and to permit persons to whom the
69
- Software is furnished to do so, subject to the following
70
- conditions:
71
-
72
- The above copyright notice and this permission notice shall be
73
- included in all copies or substantial portions of the Software.
74
-
75
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
76
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
77
- OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
78
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
79
- HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
80
- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
81
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
82
- OTHER DEALINGS IN THE SOFTWARE.
106
+ An index is a set that's handled automatically by Ohm. For any index declared,
107
+ Ohm maintains different sets of objects ids for quick lookups.
108
+
109
+ For example, in the example above, the index on the name attribute will
110
+ allow for searches like Event.find(:name, "some value").
111
+
112
+ You can also declare an index on multiple colums, like this:
113
+
114
+ index [:name, :company]
115
+
116
+ Note that the `find` method and the `assert_unique` validation need a
117
+ corresponding index to exist.
118
+
119
+
120
+ Validations
121
+ -----------
122
+
123
+ Before every save, the `validate` method is called by Ohm. In the method
124
+ definition you can use assertions that will determine if the attributes
125
+ are valid. Nesting assertions is a good practice, and you are also
126
+ encouraged to create your own assertions. You can trigger validations at
127
+ any point by calling `valid?` on a model instance.
128
+
129
+
130
+ Assertions
131
+ -----------
132
+
133
+ Ohm ships with some basic assertions. Check Ohm::Validations to see
134
+ the method definitions.
135
+
136
+ ### assert
137
+
138
+ The `assert` method is used by all the other assertions. It pushes the
139
+ second parameter to the list of errors if the first parameter evaluates
140
+ to false.
141
+
142
+ def assert(value, error)
143
+ value or errors.push(error) && false
144
+ end
145
+
146
+ ### assert_present
147
+
148
+ Checks that the given field is not nil or empty. The error code for this
149
+ assertion is :not_present.
150
+
151
+ def assert_present(att, error = [att, :not_present])
152
+ assert(!send(att).to_s.empty?, error)
153
+ end
154
+
155
+ ### assert_format
156
+
157
+ Checks that the given field matches the provided format. The error code
158
+ for this assertion is :format.
159
+
160
+ def assert_format(att, format, error = [att, :format])
161
+ if assert_present(att, error)
162
+ assert(send(att).to_s.match(format), error)
163
+ end
164
+ end
165
+
166
+ ### assert_numeric
167
+
168
+ Checks that the given field holds a number as a Fixnum or as a string
169
+ representation. The error code for this assertion is :not_numeric.
170
+
171
+ def assert_numeric(att, error = [att, :not_numeric])
172
+ if assert_present(att, error)
173
+ assert_format(att, /^\d+$/, error)
174
+ end
175
+ end
176
+
177
+ ### assert_unique
178
+
179
+ Validates that the attribute or array of attributes are unique.
180
+ For this, an index of the same kind must exist. The error code is
181
+ :not_unique.
182
+
183
+ def assert_unique(attrs)
184
+ index_key = index_key_for(Array(attrs), read_locals(Array(attrs)))
185
+ assert(db.scard(index_key).zero? || db.sismember(index_key, id), [Array(attrs), :not_unique])
186
+ end
187
+
188
+
189
+ Errors
190
+ ------
191
+
192
+ When an assertion fails, the error report is added to the errors array.
193
+ Each error report contains two elements: the field where the assertion
194
+ was issued and the error code.
195
+
196
+ ### Validation example
197
+
198
+ Given the following example:
199
+
200
+ def validate
201
+ assert_present :foo
202
+ assert_numeric :bar
203
+ assert_format :baz, /^\d{2}$/
204
+ assert_unique :qux
205
+ end
206
+
207
+ If all the assertions fail, the following errors will be present:
208
+
209
+ obj.errors #=> [[:foo, :not_present], [:bar, :not_numeric], [:baz, :format], [[:qux], :not_unique]]
210
+
211
+ Note that the error for assert_unique wraps the field in an array.
212
+ The purpose for this is to standardize the format for both single and
213
+ multicolumn indexes.
214
+
215
+
216
+ Presenting errors
217
+ -----------------
218
+
219
+ Unlike other ORMs, that define the full error messages in the model
220
+ itself, Ohm encourages you to define the error messages outside. If
221
+ you are using Ohm in the context of a web framework, the views are the
222
+ proper place to write the error messages.
223
+
224
+ Ohm provides a presenter that helps you in this quest. The basic usage
225
+ is as follows:
226
+
227
+ error_messages = @model.errors.present do |e|
228
+ e.on [:name, :not_present], "Name must be present"
229
+ e.on [:account, :not_present], "You must supply an account"
230
+ end
231
+
232
+ error_messages #=> ["Name must be present", "You must supply an account"]
233
+
234
+ Having the error message definitions in the views means you can use any
235
+ sort of helpers. You can also use blocks instead of strings for the
236
+ values. The result of the block is used as the error message:
237
+
238
+ error_messages = @model.errors.present do |e|
239
+ e.on [:email, :not_unique] do
240
+ "The email #{@model.email} is already registered."
241
+ end
242
+ end
243
+
244
+ error_messages #=> ["The email foo@example.com is already registered."]
data/Rakefile CHANGED
@@ -1,9 +1,3 @@
1
- require "rake/testtask"
2
-
3
- task :default => :test
4
-
5
- desc 'Run all tests'
6
- Rake::TestTask.new(:test) do |t|
7
- t.pattern = 'test/**/*_test.rb'
8
- t.verbose = false
1
+ task :default do
2
+ exec "thor ohm:test"
9
3
  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: 0.0.15
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michel Martens
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-07-30 00:00:00 -03:00
13
+ date: 2009-08-04 00:00:00 -03:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -34,15 +34,13 @@ files:
34
34
  - test/all_tests.rb
35
35
  - test/benchmarks.rb
36
36
  - test/connection_test.rb
37
- - test/db/dump.rdb
38
- - test/db/redis.pid
39
37
  - test/errors_test.rb
40
38
  - test/indices_test.rb
41
39
  - test/model_test.rb
42
40
  - test/redis_test.rb
43
- - test/test.conf
44
41
  - test/test_helper.rb
45
42
  - test/validations_test.rb
43
+ - test/test.conf
46
44
  has_rdoc: true
47
45
  homepage: http://github.com/soveran/ohm
48
46
  licenses: []
@@ -67,7 +65,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
65
  requirements: []
68
66
 
69
67
  rubyforge_project: ohm
70
- rubygems_version: 1.3.4
68
+ rubygems_version: 1.3.5
71
69
  signing_key:
72
70
  specification_version: 3
73
71
  summary: Object-hash mapping library for Redis.
Binary file
@@ -1 +0,0 @@
1
- 39163