ohm 0.0.15 → 0.0.16

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