lib/ohm.rb in ohm-0.0.28 vs lib/ohm.rb in ohm-0.0.29
- old
+ new
@@ -366,50 +366,60 @@
# Defines a string attribute for the model. This attribute will be persisted by Redis
# as a string. Any value stored here will be retrieved in its string representation.
#
# @param name [Symbol] Name of the attribute.
def self.attribute(name)
- define_method(name) do
- read_local(name)
- end
+ unless attributes.include?(name)
- define_method(:"#{name}=") do |value|
- write_local(name, value)
- end
+ define_method(name) do
+ read_local(name)
+ end
- attributes << name
+ define_method(:"#{name}=") do |value|
+ write_local(name, value)
+ end
+
+ attributes << name
+ end
end
# Defines a counter attribute for the model. This attribute can't be assigned, only incremented
# or decremented. It will be zero by default.
#
# @param name [Symbol] Name of the counter.
def self.counter(name)
- define_method(name) do
- read_local(name).to_i
- end
+ unless counters.include?(name)
- counters << name
+ define_method(name) do
+ read_local(name).to_i
+ end
+
+ counters << name
+ end
end
# Defines a list attribute for the model. It can be accessed only after the model instance
# is created.
#
# @param name [Symbol] Name of the list.
def self.list(name, model = nil)
- attr_list_reader(name, model)
- collections << name
+ unless collections.include?(name)
+ attr_list_reader(name, model)
+ collections << name
+ end
end
# Defines a set attribute for the model. It can be accessed only after the model instance
# is created. Sets are recommended when insertion and retrival order is irrelevant, and
# operations like union, join, and membership checks are important.
#
# @param name [Symbol] Name of the set.
def self.set(name, model = nil)
- attr_set_reader(name, model)
- collections << name
+ unless collections.include?(name)
+ attr_set_reader(name, model)
+ collections << name
+ end
end
# Creates an index (a set) that will be used for finding instances.
#
# If you want to find a model instance by some attribute value, then an index for that
@@ -424,11 +434,13 @@
# # Now this is possible:
# User.find email: "ohm@example.com"
#
# @param name [Symbol] Name of the attribute to be indexed.
def self.index(att)
- indices << att
+ unless indices.include?(att)
+ indices << att
+ end
end
def self.attr_list_reader(name, model = nil)
define_method(name) do
instance_variable_get("@#{name}") ||
@@ -607,19 +619,53 @@
def key(*args)
self.class.key(id, *args)
end
+ # Rewrite at runtime to use either SET or MSET for persisting to
+ # Redis. The idea is to use MSET when possible.
def write
+ if legacy_redis_version?
+ def write
+ write_with_set
+ end
+ else
+ def write
+ write_with_mset
+ end
+ end
+ write
+ end
+
+ # Write attributes using SET
+ # This method will be removed once MSET becomes standard.
+ def write_with_set
+ attributes.each do |att|
+ (value = send(att)) ?
+ db.set(key(att), value) :
+ db.del(key(att))
+ end
+ end
+
+ # Write attributes using MSET
+ # This is the preferred method, and will be the only option
+ # available once MSET becomes standard.
+ def write_with_mset
unless attributes.empty?
rems, adds = attributes.map { |a| [key(a), send(a)] }.partition { |t| t.last.nil? }
-
db.del(*rems.flatten.compact) unless rems.empty?
db.mset(adds.flatten) unless adds.empty?
end
end
private
+
+ # Determine if MSET is available. This method
+ # and the branch at #write will be deprecated
+ # once Redis 1.1 becomes the recommended version.
+ def legacy_redis_version?
+ db.info[:redis_version] <= "1.02"
+ end
def self.db
Ohm.redis
end