ohm 2.0.1 → 2.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6d404b17a73aaa3f8e44ef1973cc2c2281bfdeb7
4
- data.tar.gz: 5e59ffee49a2bee96c3417cc0763f31552bf06ff
3
+ metadata.gz: 879b753fd8424a547c5cf83753b2f4d7dd817a14
4
+ data.tar.gz: fab1f4b6971328047ed17e37d589ebc47c32d082
5
5
  SHA512:
6
- metadata.gz: 849b95d5ebfc61b136be8351b6c0887e6c2961c78bb086204c39a1110524efd02fe94d48c5ed05c123c326567aa70ffbb2292e70a10d9f875307dd33e82f72e9
7
- data.tar.gz: db2213eff5791aa09f02e2d79c9059d9ed4d3619f6206257bf3a69c227a2481361f179fd620ec6b07d4c21f7cb89965d6e52e7b90ab08494ef8ed067e637aa31
6
+ metadata.gz: 3538cccef143743083a6a31c672e4e5bacec42f743196fbcf52f1c68ca4ca3bcc3169f9633a40cdfc1633d48428c60e53e999641e252b640767d85b6b8db3117
7
+ data.tar.gz: b51d4ad91623b2357492837a37d1f0f03928e4a2e526849afe4cd558987089fab2a930233065d1230e6dd82c70c6c0341435c0fbbf7f9a467953480e09ec99c4
data/README.md CHANGED
@@ -23,6 +23,7 @@ These are libraries in other languages that were inspired by Ohm.
23
23
 
24
24
  * [JOhm](https://github.com/xetorthio/johm) for Java, created by xetorthio
25
25
  * [Lohm](https://github.com/slact/lua-ohm) for Lua, created by slact
26
+ * [ohm.lua](https://github.com/amakawa/ohm.lua) for Lua, created by amakawa
26
27
  * [Nohm](https://github.com/maritz/nohm) for Node.js, created by maritz
27
28
  * [Redisco](https://github.com/iamteem/redisco) for Python, created by iamteem
28
29
  * [redis3m](https://github.com/luca3m/redis3m) for C++, created by luca3m
@@ -164,11 +165,17 @@ querying. Keep reading to find out what you can do with models.
164
165
  Attribute types
165
166
  ---------------
166
167
 
167
- Ohm::Model provides four attribute types: {Ohm::Model.attribute
168
- attribute}, {Ohm::Model.set set}, {Ohm::Model.list list}
169
- and {Ohm::Model.counter counter}; and two meta types:
170
- {Ohm::Model.reference reference} and {Ohm::Model.collection
171
- collection}.
168
+ Ohm::Model provides 4 attribute types:
169
+
170
+ * {Ohm::Model.attribute attribute},
171
+ * {Ohm::Model.set set}
172
+ * {Ohm::Model.list list}
173
+ * {Ohm::Model.counter counter}
174
+
175
+ and 2 meta types:
176
+
177
+ * {Ohm::Model.reference reference}
178
+ * {Ohm::Model.collection collection}.
172
179
 
173
180
  ### attribute
174
181
 
@@ -439,8 +446,11 @@ User.find(username: "Albert")
439
446
  # Find all users from Argentina
440
447
  User.find(country: "Argentina")
441
448
 
442
- # Find all activated users from Argentina
443
- User.find(country: "Argentina", status: "activated")
449
+ # Find all active users from Argentina
450
+ User.find(country: "Argentina", status: "active")
451
+
452
+ # Find all active users from Argentina and Uruguay
453
+ User.find(status: "active").combine(country: ["Argentina", "Uruguay"])
444
454
 
445
455
  # Find all users from Argentina, except those with a suspended account.
446
456
  User.find(country: "Argentina").except(status: "suspended")
data/examples/chaining.rb CHANGED
@@ -16,12 +16,12 @@ require "ohm"
16
16
  # A `User` has a `collection` of *orders*. Note that a collection
17
17
  # is actually just a convenience, which implemented simply will look like:
18
18
  #
19
- # def orders
20
- # Order.find(:user_id => self.id)
21
- # end
19
+ # def orders
20
+ # Order.find(user_id: self.id)
21
+ # end
22
22
  #
23
23
  class User < Ohm::Model
24
- collection :orders, Order
24
+ collection :orders, :Order
25
25
  end
26
26
 
27
27
  # The product for our purposes will only contain a name.
@@ -29,7 +29,7 @@ class Product < Ohm::Model
29
29
  attribute :name
30
30
  end
31
31
 
32
- # We define an `Order` with just a single `attribute` called state, and
32
+ # We define an `Order` with just a single `attribute` called `state`, and
33
33
  # also add an `index` so we can search an order given its state.
34
34
  #
35
35
  # The `reference` to the `User` is actually required for the `collection`
@@ -58,15 +58,15 @@ prepare { Ohm.flush }
58
58
  setup do
59
59
  @user = User.create
60
60
 
61
- @ipod = Product.create(:name => "iPod")
62
- @ipad = Product.create(:name => "iPad")
61
+ @ipod = Product.create(name: "iPod")
62
+ @ipad = Product.create(name: "iPad")
63
63
 
64
- @pending = Order.create(:user => @user, :state => "pending",
65
- :product => @ipod)
66
- @authorized = Order.create(:user => @user, :state => "authorized",
67
- :product => @ipad)
68
- @captured = Order.create(:user => @user, :state => "captured",
69
- :product => @ipad)
64
+ @pending = Order.create(user: @user, state: "pending",
65
+ product: @ipod)
66
+ @authorized = Order.create(user: @user, state: "authorized",
67
+ product: @ipad)
68
+ @captured = Order.create(user: @user, state: "captured",
69
+ product: @ipad)
70
70
  end
71
71
 
72
72
  # Now let's try and grab all pending orders, and also pending
@@ -74,31 +74,22 @@ end
74
74
  test "finding pending orders" do
75
75
  assert @user.orders.find(state: "pending").include?(@pending)
76
76
 
77
- assert @user.orders.find(:state => "pending",
78
- :product_id => @ipod.id).include?(@pending)
77
+ assert @user.orders.find(state: "pending",
78
+ product_id: @ipod.id).include?(@pending)
79
79
 
80
- assert @user.orders.find(:state => "pending",
81
- :product_id => @ipad.id).empty?
80
+ assert @user.orders.find(state: "pending",
81
+ product_id: @ipad.id).empty?
82
82
  end
83
83
 
84
- # Now we try and find captured and authorized orders. The tricky part
85
- # is trying to find an order that is either *captured* or *authorized*,
86
- # since `Ohm` as of this writing doesn't support unions in its
87
- # finder syntax.
84
+ # Now we try and find captured and/or authorized orders.
88
85
  test "finding authorized and/or captured orders" do
89
- assert @user.orders.find(:state => "authorized").include?(@authorized)
90
- assert @user.orders.find(:state => "captured").include?(@captured)
86
+ assert @user.orders.find(state: "authorized").include?(@authorized)
87
+ assert @user.orders.find(state: "captured").include?(@captured)
91
88
 
92
- assert @user.orders.find(:state => ["authorized", "captured"]).empty?
89
+ results = @user.orders.find(state: "authorized").union(state: "captured")
93
90
 
94
- auth_or_capt = @user.orders.key.volatile[:auth_or_capt]
95
- auth_or_capt.sunionstore(
96
- @user.orders.find(:state => "authorized").key,
97
- @user.orders.find(:state => "captured").key
98
- )
99
-
100
- assert auth_or_capt.smembers.include?(@authorized.id)
101
- assert auth_or_capt.smembers.include?(@captured.id)
91
+ assert results.include?(@authorized)
92
+ assert results.include?(@captured)
102
93
  end
103
94
 
104
95
  #### Creating shortcuts
@@ -106,11 +97,11 @@ end
106
97
  # You can of course define methods to make that code more readable.
107
98
  class User < Ohm::Model
108
99
  def authorized_orders
109
- orders.find(:state => "authorized")
100
+ orders.find(state: "authorized")
110
101
  end
111
102
 
112
103
  def captured_orders
113
- orders.find(:state => "captured")
104
+ orders.find(state: "captured")
114
105
  end
115
106
  end
116
107
 
@@ -121,62 +112,40 @@ test "finding authorized and/or captured orders" do
121
112
  end
122
113
 
123
114
  # In most cases this is fine, but if you want to have a little fun,
124
- # then we can play around with some chainability.
115
+ # then we can play around with some chainability using scopes.
125
116
 
126
- #### Chaining Kung-Fu
117
+ # Let's require `ohm-contrib`, which we will be using for scopes.
118
+ require "ohm/contrib"
127
119
 
128
- # The `Ohm::Model::Set` takes a *Redis* key and a *class monad*
129
- # for its arguments.
130
- #
131
- # We can simply subclass it and define the monad to always be an
132
- # `Order` so we don't have to manually set it everytime.
133
- class UserOrders < Ohm::Model::Set
134
- def initialize(key)
135
- super key, Ohm::Model::Wrapper.wrap(Order)
136
- end
120
+ # Include `Ohm::Scope` module and desired scopes.
121
+ class Order
122
+ include Ohm::Scope
137
123
 
138
- # Here is the crux of the chaining pattern. Instead of
139
- # just doing a straight up `find(:state => "pending")`, we return
140
- # `UserOrders` again.
141
- def pending
142
- self.class.new(model.index_key_for(:state, "pending"))
143
- end
124
+ scope do
125
+ def pending
126
+ find(state: "pending")
127
+ end
144
128
 
145
- def authorized
146
- self.class.new(model.index_key_for(:state, "authorized"))
147
- end
129
+ def authorized
130
+ find(state: "authorized")
131
+ end
148
132
 
149
- def captured
150
- self.class.new(model.index_key_for(:state, "captured"))
151
- end
133
+ def captured
134
+ find(state: "captured")
135
+ end
152
136
 
153
- # Now we wrap the implementation of doing an `SUNIONSTORE` and also
154
- # make it return a `UserOrders` object.
155
- #
156
- # NOTE: `volatile` just returns the key prepended with a `~:`, so in
157
- # this case it would be `~:Order:accepted`.
158
- def accepted
159
- model.key.volatile[:accepted].sunionstore(
160
- authorized.key, captured.key
161
- )
162
-
163
- self.class.new(model.key.volatile[:accepted])
164
- end
165
- end
166
-
167
- # Now let's re-open the `User` class and add a customized `orders` method.
168
- class User < Ohm::Model
169
- def orders
170
- UserOrders.new(Order.index_key_for(:user_id, id))
137
+ def accepted
138
+ find(state: "authorized").union(state: "captured")
139
+ end
171
140
  end
172
141
  end
173
142
 
174
143
  # Ok! Let's put all of that chaining code to good use.
175
144
  test "finding pending orders using a chainable style" do
176
145
  assert @user.orders.pending.include?(@pending)
177
- assert @user.orders.pending.find(:product_id => @ipod.id).include?(@pending)
146
+ assert @user.orders.pending.find(product_id: @ipod.id).include?(@pending)
178
147
 
179
- assert @user.orders.pending.find(:product_id => @ipad.id).empty?
148
+ assert @user.orders.pending.find(product_id: @ipad.id).empty?
180
149
  end
181
150
 
182
151
  test "finding authorized and/or captured orders using a chainable style" do
@@ -188,16 +157,6 @@ test "finding authorized and/or captured orders using a chainable style" do
188
157
 
189
158
  accepted = @user.orders.accepted
190
159
 
191
- assert accepted.find(:product_id => @ipad.id).include?(@authorized)
192
- assert accepted.find(:product_id => @ipad.id).include?(@captured)
160
+ assert accepted.find(product_id: @ipad.id).include?(@authorized)
161
+ assert accepted.find(product_id: @ipad.id).include?(@captured)
193
162
  end
194
-
195
- #### Conclusion
196
-
197
- # This design pattern is something that really depends upon the situation. In
198
- # the example above, you can add more complicated querying on the `UserOrders`
199
- # class.
200
- #
201
- # The most important takeaway here is the ease of which we can weild the
202
- # different components of Ohm, and mold it accordingly to our preferences,
203
- # without having to monkey-patch anything.
data/examples/tagging.rb CHANGED
@@ -156,11 +156,13 @@ class Post
156
156
 
157
157
  # For our scenario, we only need a `before_update` and `after_save`.
158
158
  # The idea for our `before_update` is to decrement the `total` of
159
- # all existing tags. We use `read_remote(:tags)` to make sure that
160
- # we actually get the original `tags` for a particular record.
159
+ # all existing tags. We use `get(:tags)` the original tags for the
160
+ # record and use assigned one on save.
161
161
  protected
162
162
  def before_update
163
- tag(read_remote(:tags)).map(&Tag).each { |t| t.decr :total }
163
+ assigned_tags = tags
164
+ tag(get(:tags)).map(&Tag).each { |t| t.decr :total }
165
+ self.tags = assigned_tags
164
166
  end
165
167
 
166
168
  # And of course, we increment all new tags for a particular record
@@ -186,7 +188,8 @@ class Tag < Ohm::Model
186
188
  # though is that we need to encode the tag name, so special characters
187
189
  # and spaces won't produce an invalid key.
188
190
  def self.[](id)
189
- super(encode(id)) || create(:id => encode(id))
191
+ encoded_id = id.encode
192
+ super(encoded_id) || create(:id => encoded_id)
190
193
  end
191
194
  end
192
195
 
data/lib/ohm.rb CHANGED
@@ -528,6 +528,20 @@ module Ohm
528
528
  MultiSet.new(namespace, model, key).except(dict)
529
529
  end
530
530
 
531
+ # Perform an intersection between the existent set and
532
+ # the new set created by the union of the passed filters.
533
+ #
534
+ # Example:
535
+ #
536
+ # set = User.find(:status => "active")
537
+ # set.combine(:name => ["John", "Jane"])
538
+ #
539
+ # # The result will include all users with active status
540
+ # # and with names "John" or "Jane".
541
+ def combine(dict)
542
+ MultiSet.new(namespace, model, key).combine(dict)
543
+ end
544
+
531
545
  # Do a union to the existing set using any number of filters.
532
546
  #
533
547
  # Example:
@@ -666,6 +680,22 @@ module Ohm
666
680
  )
667
681
  end
668
682
 
683
+ # Perform an intersection between the existent set and
684
+ # the new set created by the union of the passed filters.
685
+ #
686
+ # Example:
687
+ #
688
+ # set = User.find(:status => "active")
689
+ # set.combine(:name => ["John", "Jane"])
690
+ #
691
+ # # The result will include all users with active status
692
+ # # and with names "John" or "Jane".
693
+ def combine(dict)
694
+ MultiSet.new(
695
+ namespace, model, Command[:sinterstore, command, unioned(dict)]
696
+ )
697
+ end
698
+
669
699
  # Do a union to the existing set using any number of filters.
670
700
  #
671
701
  # Example:
data/ohm.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ohm"
3
- s.version = "2.0.1"
3
+ s.version = "2.1.0"
4
4
  s.summary = %{Object-hash mapping library for Redis.}
5
5
  s.description = %Q{Ohm is a library that allows to store an object in Redis, a persistent key-value database. It has very good performance.}
6
6
  s.authors = ["Michel Martens", "Damian Janowski", "Cyril David"]
data/test/filtering.rb CHANGED
@@ -111,6 +111,14 @@ test "#union" do |john, jane|
111
111
  assert res.any? { |e| e.status == "inactive" }
112
112
  end
113
113
 
114
+ test "#combine" do |john, jane|
115
+ res = User.find(:status => "active").combine(fname: ["John", "Jane"])
116
+
117
+ assert_equal 2, res.size
118
+ assert res.include?(john)
119
+ assert res.include?(jane)
120
+ end
121
+
114
122
  # book author thing via @myobie
115
123
  scope do
116
124
  class Book < Ohm::Model
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: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michel Martens
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-06-26 00:00:00.000000000 Z
13
+ date: 2015-01-22 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: redic
@@ -138,7 +138,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
138
  version: '0'
139
139
  requirements: []
140
140
  rubyforge_project: ohm
141
- rubygems_version: 2.0.3
141
+ rubygems_version: 2.0.14
142
142
  signing_key:
143
143
  specification_version: 4
144
144
  summary: Object-hash mapping library for Redis.