I have a bunch of methods that are repeating, and I am sure I can use Ruby's metaprogramming somehow.
My class looks like this:
class SomePatterns
def address_key
"..."
end
def user_key
"..."
end
def location_key
"..."
end
def address_count
redis.scard("#{address_key}")
end
def location_count
redis.scard("#{location_key}")
end
def user_count
redis.scard("#{user_key}")
end
end
I was thinking I could have only one method like:
def count(prefix)
redis.scard("#{prefix}_key") # wrong, but something like this
end
The above is wrong, but I'm saying that the *_count
methods will follow a pattern. I'm hoping to learn to use metaprogramming to avoid the duplication.
How could I do this?
I would put all of the "function prefixes" into an array. Upon initialization you can use the :define_singleton_method
on these prefixes to dynamically create a instance method on every one of them:
class SomePatterns
def initialize()
prefixes = [:address, :location, :user]
prefixes.each do |prefix|
define_singleton_method("#{prefix}_count") { redis.scard("#{prefix}_key") }
end
end
end
EDIT:
:define_singleton_method
might actually be overkill. It will work for what you want, but it will define these functions for that specific instance (hence why its called singleton). The difference is subtle, but important. Instead, it would probably be better to use :class_eval in conjunction with :define_method.
class SomePatterns
# ...
class_eval do
[:address, :location, :user].each do |prefix|
define_method("#{prefix}_count") { redis.scard("#{prefix}_key") }
end
end
end
You could create a macro-style method to tidy things up. For example:
Create a new class Countable
:
class Countable
def self.countable(key, value)
define_method("#{key}_count") do
redis.scard(value)
end
# You might not need these methods anymore? If so, this can be removed
define_method("#{key}_key") do
value
end
end
end
Inherit from Countable
and then just use the macro. This is just an example - you could also e.g. implement it as an ActiveSupport Concern, or extend a module (as suggested in the comments below):
class SomePatterns < Countable
countable :address, '...'
countable :user, '...'
countable :location, '...'
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With