Skip to content

Instantly share code, notes, and snippets.

@Paxa
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Paxa/604a3896cdb29a011728 to your computer and use it in GitHub Desktop.
Save Paxa/604a3896cdb29a011728 to your computer and use it in GitHub Desktop.
This make class-level method "cached" what makes that method cachable
module CachableMethod
def cachable(merhod_name)
#aliased_merhod_name = :"uncached_#{merhod_name}"
#alias_method aliased_merhod_name, merhod_name
method_proc = instance_method(merhod_name)
ivar_name = :"@#{merhod_name}"
define_method(merhod_name) do |*args, &proc|
if instance_variable_defined?(ivar_name)
instance_variable_get(ivar_name)
else
value = method_proc.bind(self).call(*args, &proc)
instance_variable_set(ivar_name, value)
value
end
end
end
def accepts(*types)
# this proc should be called with symbol of new method
Proc.new do |method_name|
method_proc = instance_method(method_name)
define_method(method_name) do |*args, &proc|
types.each_with_index do |type, arg_i|
unless args[arg_i].kind_of?(type)
raise ArgumentError.new("Argument num #{arg_i} is type of: #{args[arg_i].class.name}, but must be #{type.name}")
end
end # types.each
method_proc.bind(self).call(*args, &proc)
end # define_method
end # Proc.new
end
def returns(type)
# this proc should be called with symbol of new method
Proc.new do |method_name|
method_proc = instance_method(method_name)
define_method(method_name) do |*args, &proc|
value = method_proc.bind(self).call(*args, &proc)
unless value.kind_of?(type)
raise ArgumentError.new("method :#{method_name} returns type #{value.class.name} but must #{type.name}")
end
value
end # define_method
end # Proc.new
end
end
class Something
extend CachableMethod
accepts(String, Numeric).call \
returns(Time).call \
cachable \
def time(a, b)
puts "getting a time"
Time.now
end
end
s = Something.new
p s.time("a", 4)
p s.time("a", 5)
p s.time("a", []) # => this will raise error ArgumentError, type mismatch
p s
class Fee
private :method_name
private def bar
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment