How to cache method results in Ruby - ruby

In Python I can easily decorate methods so that they remember their result:
def store(self):
a = line1()
b = line2(a)
return line3(b)
=>
from lazy import lazy
#lazy
def store(self):
a = line1()
b = line2(a)
return line3(b)
Is there some similar idiom in Ruby for calculating method result only once?

In Ruby this is generally called memoization and it takes the naive form of:
def store
#store ||= begin
a = line1
b = line2(a)
line3(b)
end
end
There are important concerns if this code is used in a multi-threaded environment, though, which is why there are gems that manage this and ensure your lazy initializers are run only once if that's a concern.

Another option that works with false and nil too:
def store
unless defined?(#store)
a = line1
b = line2(a)
#store = line3(b)
end
#store
end

Not really. There is an operator (||=) that assigns a value only if the left operand is falsy (nil or false). Usually using that along with an instance variable does the trick.
Memoist and Memoizable are gems often used for that purpose.
But my guess is that your question is more general - how do you implement method decorators in ruby?
class Module
def decorate(method_name, &decoration)
undecorated_method = instance_method(method_name)
define_method(method_name) do
decoration.call(&undecorated_method.bind(self))
end
end
def memoize(method_name)
#values ||= {}
decorate(method_name) do |&evaluator|
unless #values.key?(method_name)
#values[method_name] = evaluator.call
end
#values[method_name]
end
end
end
class SuperComputer
memoize def answer
puts "Pending... 7½ million years remaining."
42
end
end
deep_mind = SuperComputer.new
deep_mind.answer # => 42 (and prints)
deep_mind.answer # => 42 (doesn't print)
Now there is a lot to be desired from this implementation (args, kwargs, blocks, per instance memoization, etc), but it should give you a general idea of how decorators can be implemented without the need for changes to the language itself.

Related

How can I control which fields to serialize with YAML

For instance,
class Point
attr_accessor :x, :y, :pointer_to_something_huge
end
I only want to serialize x and y and leave everything else as nil.
In Ruby 1.9, to_yaml_properties is deprecated; if you're using Ruby 1.9, a more future proof method would be to use encode_with:
class Point
def encode_with coder
coder['x'] = #x
coder['y'] = #y
end
end
In this case that’s all you need, as the default is to set the corresponding instance variable of the new object to the appropriate value when loading from Yaml, but in more comple cases you could use init_with:
def init_with coder
#x = coder['x']
#y = coder['y']
end
After an inordinate amount of searching I stumbled on this:
class Point
def to_yaml_properties
["#x", "#y"]
end
end
This method is used to select the properties that YAML serializes. There is a more powerful approach that involves custom emitters (in Psych) but I don't know what it is.
This solution only works in Ruby 1.8; in Ruby 1.9, to_yaml has switched to using Psych, for which Matt's answer using encode_with is the appropriate solution.
If you want all fields but a few, you could do this
def encode_with(coder)
vars = instance_variables.map{|x| x.to_s}
vars = vars - ['#unwanted_field1', '#unwanted_field2']
vars.each do |var|
var_val = eval(var)
coder[var.gsub('#', '')] = var_val
end
end
This stops you from manually having to manage the list. Tested on Ruby 1.9
If you have a plenty of instance variables, you could use a short version like this one
def encode_with( coder )
%w[ x y a b c d e f g ].each { |v| coder[ v ] = instance_variable_get "##{v}" }
end
You should use #encode_with because #to_yaml_properties is deprecated:
def encode_with(coder)
# remove #unwanted and #other_unwanted variable from the dump
(instance_variables - [:#unwanted, :#other_unwanted]).each do |var|
var = var.to_s # convert symbol to string
coder[var.gsub('#', '')] = eval(var) # set key and value in coder hash
end
end
or you might prefer this if eval is too dangerous and you only need to filter out one instance var. All other vars need to have an accessor:
attr_accessor :keep_this, :unwanted
def encode_with(coder)
# reject #unwanted var, all others need to have an accessor
instance_variables.reject{|x|x==:#unwanted}.map(&:to_s).each do |var|
coder[var[1..-1]] = send(var[1..-1])
end
end
I'd recommend adding a custom to_yaml method in your class that constructs the specific yaml format you want.
I know that to_json accepts parameters to tell it what attributes to serialize, but I can't find the same for to_yaml.
Here's the actual source for to_yaml:
# File activerecord/lib/active_record/base.rb, line 653
def to_yaml(opts = {}) #:nodoc:
if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
super
else
coder = {}
encode_with(coder)
YAML.quick_emit(self, opts) do |out|
out.map(taguri, to_yaml_style) do |map|
coder.each { |k, v| map.add(k, v) }
end
end
end
end
So it looks like there may be an opportunity to set opts so that it includes specific key/value pairs in the yaml.

Change the binding of a Proc in Ruby

I have this code:
l = lambda { a }
def some_function
a = 1
end
I just want to access a by the lambda and a special scope which has defined a already somewhere like inside some_function in the example, or just soon later in the same scope as:
l = lambda { a }
a = 1
l.call
Then I found when calling l, it is still using its own binding but not the new one where it was called.
And then I tried to use it as:
l.instance_eval do
a = 1
call
end
But this also failed, it is strange that I can't explain why.
I know the one of the solution is using eval, in which I could special a binding and executing some code in text, but I really do not want to use as so.
And, I know it is able to use a global variable or instance variable. However, actually my code is in a deeper embedded environment, so I don't want to break the completed parts if not quite necessary.
I have referred the Proc class in the documentation, and I found a function names binding that referred to the Proc's context. While the function only provided a way to access its binding but cannot change it, except using Binding#eval. It evaluate text also, which is exactly what I don't like to do.
Now the question is, do I have a better (or more elegant) way to implement this? Or using eval is already the regular manner?
Edit to reply to #Andrew:
Okay, this is a problem which I met when I'm writing a lexical parser, in which I defined a array with fixed-number of items, there including at least a Proc and a regular expression. My purpose is to matching the regular expressions and execute the Procs under my special scope, where the Proce will involved some local variables that should be defined later. And then I met the problem above.
Actually I suppose it is not same completely to that question, as mine is how to pass in binding to a Proc rather than how to pass it out.
#Niklas:
Got your answer, I think that is what exactly I want. It has solved my problem perfectly.
You can try the following hack:
class Proc
def call_with_vars(vars, *args)
Struct.new(*vars.keys).new(*vars.values).instance_exec(*args, &self)
end
end
To be used like this:
irb(main):001:0* lambda { foo }.call_with_vars(:foo => 3)
=> 3
irb(main):002:0> lambda { |a| foo + a }.call_with_vars({:foo => 3}, 1)
=> 4
This is not a very general solution, though. It would be better if we could give it Binding instance instead of a Hash and do the following:
l = lambda { |a| foo + a }
foo = 3
l.call_with_binding(binding, 1) # => 4
Using the following, more complex hack, this exact behaviour can be achieved:
class LookupStack
def initialize(bindings = [])
#bindings = bindings
end
def method_missing(m, *args)
#bindings.reverse_each do |bind|
begin
method = eval("method(%s)" % m.inspect, bind)
rescue NameError
else
return method.call(*args)
end
begin
value = eval(m.to_s, bind)
return value
rescue NameError
end
end
raise NoMethodError
end
def push_binding(bind)
#bindings.push bind
end
def push_instance(obj)
#bindings.push obj.instance_eval { binding }
end
def push_hash(vars)
push_instance Struct.new(*vars.keys).new(*vars.values)
end
def run_proc(p, *args)
instance_exec(*args, &p)
end
end
class Proc
def call_with_binding(bind, *args)
LookupStack.new([bind]).run_proc(self, *args)
end
end
Basically we define ourselves a manual name lookup stack and instance_exec our proc against it. This is a very flexible mechanism. It not only enables the implementation of call_with_binding, it can also be used to build up much more complex lookup chains:
l = lambda { |a| local + func(2) + some_method(1) + var + a }
local = 1
def func(x) x end
class Foo < Struct.new(:add)
def some_method(x) x + add end
end
stack = LookupStack.new
stack.push_binding(binding)
stack.push_instance(Foo.new(2))
stack.push_hash(:var => 4)
p stack.run_proc(l, 5)
This prints 15, as expected :)
UPDATE: Code is now also available at Github. I use this for one my projects too now.
class Proc
def call_with_obj(obj, *args)
m = nil
p = self
Object.class_eval do
define_method :a_temp_method_name, &p
m = instance_method :a_temp_method_name; remove_method :a_temp_method_name
end
m.bind(obj).call(*args)
end
end
And then use it as:
class Foo
def bar
"bar"
end
end
p = Proc.new { bar }
bar = "baz"
p.call_with_obj(self) # => baz
p.call_with_obj(Foo.new) # => bar
Perhaps you don't actually need to define a later, but instead only need to set it later.
Or (as below), perhaps you don't actually need a to be a local variable (which itself references an array). Instead, perhaps you can usefully employ a class variable, such as ##a. This works for me, by printing "1":
class SomeClass
def l
#l ||= lambda { puts ##a }
end
def some_function
##a = 1
l.call
end
end
SomeClass.new.some_function
a similar way:
class Context
attr_reader :_previous, :_arguments
def initialize(_previous, _arguments)
#_previous = _previous
#_arguments = _arguments
end
end
def _code_def(_previous, _arguments = [], &_block)
define_method("_code_#{_previous}") do |_method_previous, _method_arguments = []|
Context.new(_method_previous, _method_arguments).instance_eval(&_block)
end
end
_code_def('something') do
puts _previous
puts _arguments
end

Perform method after select variable assignments in Ruby

I'm trying to DRY up some code, and I feel like Ruby's variable assignment must provide a way to simplify this. I have a class with a number of different instance variables defined. Some of these are intended to be hidden (or read-only), but many are public, with read/write access.
For all of the variables with public write-access, I want to perform a certain method after each assignment. I know that, in general, I can do this:
def foo=(new_foo)
#foo = new_foo
post_process(#foo)
end
def bar=(new_bar)
#bar = new_bar
post_process(#foo)
end
However, it seems that there should be a nice way to DRY this up, since I'm doing essentially the same thing after each assignment (ie, running the same method, and passing the newly-assigned variable as a parameter to that method). Since I have a number of such variables, it would be great to have a general-purpose solution.
Simpler solution
If you assign those variables in batch, you can do something like this:
kv_pairs = {:foo => new_foo_value,
:bar => new_bar_value}
kv_pairs.each do |k, v|
self.send(k.to_s + '=', v)
post_process(v)
end
Metaprogramming
Here's some ruby magic :-)
module PostProcessAssignments
def hooked_accessor( *symbols )
symbols.each { | symbol |
class_eval( "def #{symbol}() ##{symbol}; end" )
class_eval( "def #{symbol}=(val) ##{symbol} = val; post_process('#{symbol}', val); end" )
}
end
end
class MyClass
extend PostProcessAssignments
hooked_accessor :foo
def post_process prop, val
puts "#{prop} was set to #{val}"
end
end
mc = MyClass.new
mc.foo = 4
puts mc.foo
Outputs:
foo was set to 4
4

How do I add 'each' method to Ruby object (or should I extend Array)?

I have an object Results that contains an array of result objects along with some cached statistics about the objects in the array. I'd like the Results object to be able to behave like an array. My first cut at this was to add methods like this
def <<(val)
#result_array << val
end
This feels very c-like and I know Ruby has better way.
I'd also like to be able to do this
Results.each do |result|
result.do_stuff
end
but am not sure what the each method is really doing under the hood.
Currently I simply return the underlying array via a method and call each on it which doesn't seem like the most-elegant solution.
Any help would be appreciated.
For the general case of implementing array-like methods, yes, you have to implement them yourself. Vava's answer shows one example of this. In the case you gave, though, what you really want to do is delegate the task of handling each (and maybe some other methods) to the contained array, and that can be automated.
require 'forwardable'
class Results
include Enumerable
extend Forwardable
def_delegators :#result_array, :each, :<<
end
This class will get all of Array's Enumerable behavior as well as the Array << operator and it will all go through the inner array.
Note, that when you switch your code from Array inheritance to this trick, your << methods would start to return not the object intself, like real Array's << did -- this can cost you declaring another variable everytime you use <<.
each just goes through array and call given block with each element, that is simple. Since inside the class you are using array as well, you can just redirect your each method to one from array, that is fast and easy to read/maintain.
class Result
include Enumerable
def initialize
#results_array = []
end
def <<(val)
#results_array << val
end
def each(&block)
#results_array.each(&block)
end
end
r = Result.new
r << 1
r << 2
r.each { |v|
p v
}
#print:
# 1
# 2
Note that I have mixed in Enumerable. That will give you a bunch of array methods like all?, map, etc. for free.
BTW with Ruby you can forget about inheritance. You don't need interface inheritance because duck-typing doesn't really care about actual type, and you don't need code inheritance because mixins are just better for that sort of things.
Your << method is perfectly fine and very Ruby like.
To make a class act like an array, without actually inheriting directly from Array, you can mix-in the Enumerable module and add a few methods.
Here's an example (including Chuck's excellent suggestion to use Forwardable):
# You have to require forwardable to use it
require "forwardable"
class MyArray
include Enumerable
extend Forwardable
def initialize
#values = []
end
# Map some of the common array methods to our internal array
def_delegators :#values, :<<, :[], :[]=, :last
# I want a custom method "add" available for adding values to our internal array
def_delegator :#values, :<<, :add
# You don't need to specify the block variable, yield knows to use a block if passed one
def each
# "each" is the base method called by all the iterators so you only have to define it
#values.each do |value|
# change or manipulate the values in your value array inside this block
yield value
end
end
end
m = MyArray.new
m << "fudge"
m << "icecream"
m.add("cake")
# Notice I didn't create an each_with_index method but since
# I included Enumerable it knows how and uses the proper data.
m.each_with_index{|value, index| puts "m[#{index}] = #{value}"}
puts "What about some nice cabbage?"
m[0] = "cabbage"
puts "m[0] = #{m[0]}"
puts "No! I meant in addition to fudge"
m[0] = "fudge"
m << "cabbage"
puts "m.first = #{m.first}"
puts "m.last = #{m.last}"
Which outputs:
m[0] = fudge
m[1] = icecream
m[2] = cake
What about some nice cabbage?
m[0] = cabbage
No! I meant in addition to fudge
m.first = fudge
m.last = cabbage
This feels very c-like and I know Ruby
has better way.
If you want an object to 'feel' like an array, than overriding << is a good idea and very 'Ruby'-ish.
but am not sure what the each method
is really doing under the hood.
The each method for Array just loops through all the elements (using a for loop, I think). If you want to add your own each method (which is also very 'Ruby'-ish), you could do something like this:
def each
0.upto(#result_array.length - 1) do |x|
yield #result_array[x]
end
end
If you create a class Results that inherit from Array, you will inherit all the functionality.
You can then supplement the methods that need change by redefining them, and you can call super for the old functionality.
For example:
class Results < Array
# Additional functionality
def best
find {|result| result.is_really_good? }
end
# Array functionality that needs change
def compact
delete(ininteresting_result)
super
end
end
Alternatively, you can use the builtin library forwardable. This is particularly useful if you can't inherit from Array because you need to inherit from another class:
require 'forwardable'
class Results
extend Forwardable
def_delegator :#result_array, :<<, :each, :concat # etc...
def best
#result_array.find {|result| result.is_really_good? }
end
# Array functionality that needs change
def compact
#result_array.delete(ininteresting_result)
#result_array.compact
self
end
end
In both of these forms, you can use it as you want:
r = Results.new
r << some_result
r.each do |result|
# ...
end
r.compact
puts "Best result: #{r.best}"
Not sure I'm adding anything new, but decided to show a very short code that I wish I could have found in the answers to quickly show available options. Here it is without the enumerator that #shelvacu talks about.
class Test
def initialize
#data = [1,2,3,4,5,6,7,8,9,0,11,12,12,13,14,15,16,172,28,38]
end
# approach 1
def each_y
#data.each{ |x| yield(x) }
end
#approach 2
def each_b(&block)
#data.each(&block)
end
end
Lets check performance:
require 'benchmark'
test = Test.new
n=1000*1000*100
Benchmark.bm do |b|
b.report { 1000000.times{ test.each_y{|x| #foo=x} } }
b.report { 1000000.times{ test.each_b{|x| #foo=x} } }
end
Here's the result:
user system total real
1.660000 0.000000 1.660000 ( 1.669462)
1.830000 0.000000 1.830000 ( 1.831754)
This means yield is marginally faster than &block what we already know btw.
UPDATE: This is IMO the best way to create an each method which also takes care of returning an enumerator
class Test
def each
if block_given?
#data.each{|x| yield(x)}
else
return #data.each
end
end
end
If you really do want to make your own #each method, and assuming you don't want to forward, you should return an Enumerator if no block is given
class MyArrayLikeClass
include Enumerable
def each(&block)
return enum_for(__method__) if block.nil?
#arr.each do |ob|
block.call(ob)
end
end
end
This will return an Enumerable object if no block is given, allowing Enumerable method chaining

Extend for one block call only

I have a class that contains some private attributes. What I would like to do is to dynamically add some setters for these only for the execution of a specific block.
Example of what I would like to be able to:
class Content
attr_reader :a, :b
def initialize
#a = 1
#b = "plop"
end
def set(&block)
extend(Setter)
instance_eval(&block)
unextend(Setter) ????
end
module Setter
def a(value)
#a = value
end
def b(value)
#b = value
end
end
end
content = Content.new
content.set do
a 2
b "yeah!"
end
content.a # should return 2
EDIT: Thanks for the great answers so far. I clarified the question because I actually need to define attribute readers in the class itself that may conflict with the setters defined in the module. I forgot about this part when posting the question. (It was late ^^)
CLARIFICATION: This class is intended for a DSL to write a configuration file. It is targeted at non-developer so the less operators, the better.
I currently implement this using a proxy class that instance_eval the block but I have to mess with instance_variable_set in order to set the values and I don't like it. I am just trying another way to see if I can make my code more readable.
There's no native way to "unextend" modules in Ruby. The mixology gem implements this pattern as a C (and Java, for JRuby) extension, creating mixin and unmix methods. It appears you may need to apply a patch if you need Ruby 1.9 support, however.
If you'd prefer to avoid using third-party libraries, another approach might simply be to make the setters private:
class Content
def initialize
#a = 1
#b = "plop"
end
def set(&block)
instance_eval(&block)
end
private
def a(val)
#a = val
end
def b(val)
#b = val
end
end
content = Content.new
#This will succeed
content.set do
a 2
b "yeah!"
end
# This will raise a NoMethodError, as it attempts to call a private method
content.a 3
def set(&block)
extend(Setter)
instance_eval(&block)
Setter.instance_methods.each do |m|
instance_eval "undef #{m}"
end
end
I don't know of any method that would do that for you although there might be something.. This should do the job though, by finding all the instance methods of Setter and undefining them in Content.
You could use _why's mixico library (available on github)
It would let you do this:
require 'mixology'
#...
def set(&block)
Setter.mix_eval(Setter, &block)
end
The mixology gem does much the same thing, just slightly differently.
if you're feeling in an experimental mood also check out: dup_eval
It's similar in some ways to mixico but with some interesting extras (object2module)

Resources