As @sagarpandya82 suggests, you could use #method_missing. Suppose you wish to shorten the following.
class Redis
def scard(str)
str.upcase
end
end
class Patterns
def address_key
"address_key"
end
def address_count
redis.send(:scard, "address_count->#{address_key}")
end
def user_key
"user_key"
end
def user_count
redis.send(:scard, "user_count->#{user_key}")
end
def modify(str)
yield str
end
private
def redis
Redis.new
end
end
which behaves like so:
pat = Patterns.new #=> #<Patterns:0x007fe12b9968d0>
pat.address_key #=> "address_key"
pat.address_count #=> "ADDRESS_COUNT->ADDRESS_KEY"
pat.user_key #=> "user_key"
pat.user_count #=> "USER_COUNT->USER_KEY"
pat.modify("what ho!") { |s| s.upcase } #=> "WHAT HO!"
Note that since the object redis
was not defined in the class I assumed it to be an instance of another class, which I named Redis
.
You could reduce the number of methods to one, by changing class Patterns
as follows.
class Patterns
def method_missing(m, *args, &blk)
case m
when :address_key, :user_key then m.to_s
when :address_count, :user_count then redis.send(:scard, m.to_s)
when :modify then send(m, *args, blk)
else super
end
end
private
def redis
Redis.new
end
end
pat = Patterns.new #=> #<Patterns:0x007fe12b9cc548>
pat.address_key #=> "address_key"
pat.address_count #=> "ADDRESS_COUNT->ADDRESS_KEY"
pat.user_key #=> "user_key"
pat.user_count #=> "USER_COUNT=>USER_KEY"
pat.modify("what ho!") { |s| s.upcase } #=> "WHAT HO!"
pat.what_the_heck! #=> #NoMethodError:\
# undefined method `what_the_heck!' for #<Patterns:0x007fe12b9cc548>
There are, however, some disadvantages with this approach:
- the code using
method_missing
is not as easily understood as the conventional way of writing each method separately.
- the numbers of variables and presence or absence of a block is not enforced
- debugging can be a pain, with stack overflow exceptions commonplace.