I am having problems refactoring out some duplicated code from two methods sharing a for loop. The two methods with the duplicated code are gcdOfFiveUpToFive and remainderStepsUpToFive. The two loops share in common setting instance variable #m to 5 and the both use a for x in 1..5 loop and then set #n to x as well as both of them need to call euclidGCD although one calls euclidGCD for its return value and the other to add +=1 to the #count variable. I do want want to return 2 values from one method. I guess I could make a 4th instance variable called #countArray and get an array of the remainder step count.
require 'minitest/autorun'
class GCDTest < Minitest::Test
def test_euclid_gcd
gcdTestObject=GCD.new(20,5)
assert gcdTestObject.euclidGcd==5
assert gcdTestObject.gcdRemainderSteps==1
end
def test_euclid_two
gcdTestObject=GCD.new(13,8)
assert gcdTestObject.euclidGcd==1
assert gcdTestObject.gcdRemainderSteps==5
end
def test_euclid_loop
gcdTestObject=GCD.new(0,0)
assert gcdTestObject.gcdOfFiveUpToFive==[1,1,1,1,5]
end
def test_count_of_loop
gcdTestObject=GCD.new(0,0)
assert gcdTestObject.remainderStepsUpToFive==[1,2,3,2,1]
end
end
class GCD
attr_accessor :m,:n
attr_reader :count
def initialize(m,n)
#m=m
#n=n
#count=0
end
def euclidGcd
#count=1
m=#m
n=#n
r= m % n
until r==0
m=n
n=r
r= m % n
#count+=1
end
return n
end
def gcdRemainderSteps
return #count
end
def gcdOfFiveUpToFive
#m=5
gcdArrayUpToFive=[]
for x in 1..5
#n=x
gcdArrayUpToFive << euclidGcd
end
return gcdArrayUpToFive
end
def remainderStepsUpToFive
#m=5
gcdStepArrayUpToFive=[]
for x in 1..5
#n=x
euclidGcd
gcdStepArrayUpToFive << gcdRemainderSteps
end
return gcdStepArrayUpToFive
end
def fiveLoopExtraction
end
Code that repeats itself is this:
array=[]
for x in 1..5
# result = do something with x
array << result
end
return array
That is exactly what map function does.
What does the "map" method do in Ruby?
Ruby methods names should be snake_case. Lets refactor this to use proper naming convention and map function.
def gcd_of_five_up_to_five
#m=5
(1..5).map do |x|
#n = x
# in ruby you don't have to write return
# value of last expression is returned automatically
euclid_gcd
end
end
def remainder_steps_up_to_five
#m=5
(1..5).map do |x|
#n = x
euclid_gcd
gcd_remainder_steps
end
end
I'd call it with params instead of using #m and #n. That would simplify the code. If you change euclid_gcd to this: def euclid_gcd(m:, n:) you'd get this:
def gcd_of_5_up_to_5
(1..5).map { |x| euclid_gcd(m: 5, n: x) }
end
def remainder_steps_up_to_5
(1..5).map do |x|
euclid_gcd(m: 5, n: x)
gcd_remainder_steps
end
end
Seems like this needs little or no further refactoring.
I have a method that prints out a numbered list, yielding to a code block to print a prefix.
arr = %w(a b c)
def print_lines(array)
array.each_with_index do |item, index|
prefix = yield index
puts "#{prefix} #{item}"
end
end
print_lines(arr) do |index|
"(#{index})"
end
This produces the following output:
(0) a
(1) b
(2) c
Now I want to wrap print_lines in another method and call it.
def print_lines_wrapped(array)
puts 'print_lines_wrapped'
print_lines(array)
end
print_lines_wrapped(arr) do |index|
"(#{index})"
end
However, this gives me a LocalJumpError
test_yield.rb:5:in `block in print_lines': no block given (yield) (LocalJumpError)
from test_yield.rb:4:in `each'
from test_yield.rb:4:in `each_with_index'
from test_yield.rb:4:in `print_lines'
from test_yield.rb:16:in `print_lines_wrapped'
from test_yield.rb:19:in `<main>'
Why do I get a LocalJumpError?
How can I implement print_lines_wrapped such that I can call it like this:
print_lines_wrapped(arr) do |index|
"(#{index})"
end
and get the following output:
print_lines_wrapped
(0) a
(1) b
(2) c
?
Your wrapper method also has to accept a block and pass it to the wrapped method. There is no implicit passing of the block:
def print_lines_wrapped(array, &block)
puts 'print_lines_wrapped'
print_lines(array, &block)
end
Example:
def asdf(&block) puts yield(2) end
def qwer(&block)
puts "I am going to call asdf"
asdf &block
end
asdf { |x| x * 3 }
6
=> nil
qwer { |x| x * 5 }
I am going to call asdf
10
=> nil
The & operator converts its operand into a block if possible
qwer &Proc.new { |x| x * 2 }
I am going to call asdf
4
Example:
a = Proc.new do
b = 'hey'
end
def a_method
yield
end
a_method(&a) #=> 'hey'
I understand that yield (or block.call) can be used as a simple co-routine, but I was wondering, are there any more (practical) uses for it beyond simply getting the return value from it? Can we get some of the local variables from the proc into the main method etc.?
If you're not picky about the return value of the block, you can do it using binding.
a = Proc.new do
b = 'hey'
binding
end
def a_method
new_binding = yield
p new_binding.eval("b")
end
a_method(&a)
# => "hey"
If you're using a version of Ruby >= 2.1.0, you can avoid the ickiness of eval by using local_variable_get instead:
p new_binding.local_variable_get(:b)
There are a lot of uses for Procs. For example, you can use it to give instructions to an object. I made a bubble sort using a proc that tells it how to sort. Here it is monkey patched in the array class:
class Array
def bubble_sort(&prc)
self.dup.bubble_sort!(&prc)
end
def bubble_sort!(&prc)
return self if count <= 1
prc = Proc.new { |x, y| x <=> y } unless prc.class == Proc
(0...self.count).each do |x|
((x + 1)...self.count).each do |y|
self[x], self[y] = self[y], self[x] if prc.call(self[x], self[y]) == 1
end
end
self
end
end
When we want to pass blocks to a method, when do we want to do:
block = Proc.new { puts 'test blocks & procs' }
def method(&block)
yield
end
VS
def method
yield
end
method { puts 'test blocks & procs' }
Is there any particular circumstance we would want to use one or the other?
Using Procs lets you not repeat yourself. Compare this:
arr1 = [1,2,3]
arr2 = [4,5,6]
Using blocks, you repeat the block twice:
arr1.map { |n| n * 2 }
arr2.map { |n| n * 2 }
When using Procs, you can reuse the object:
multiply_2 = Proc.new do |n|
n * 2
end
arr1.map(&multiply_2)
arr2.map(&multiply_2)
1) A block is not an object, and therefore a block cannot be captured in a variable, and a block cannot be passed explicitly to a method. However, you can convert a block to a Proc instance using the & operator, and a Proc instance is an object which can be assigned to a variable and passed to a method.
2) Proc.new() doesn't return a block--it returns a Proc instance. So naming your variable block is misleading.
3) yield only calls a block, which is the thing specified after a method call:
do_stuff(10) {puts 'hello'} #<-- block
do_stuf(10) do |x| #<--'do' marks the start of a block
puts x + 2
end #<--end of block
block = Proc.new {puts 'hello'}
^
|
+--- #not a block
yield does not call a Proc instance that happens to be passed as an argument to a method:
def do_stuff(arg)
yield
end
p = Proc.new { puts 'test blocks & procs' }
do_stuff(p)
--output:--
1.rb:2:in `do_stuff': no block given (yield) (LocalJumpError)
from 1.rb:6:in `<main>'
Compare to:
def do_stuff(arg)
puts arg
yield
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
I'm a block
4) You can convert a block to a Proc instance and capture it in a variable using &, like this:
def do_stuff(arg, &p)
puts arg
p.call
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
I'm a block
Liar! You are not a block anymore! Typically, the variable name used to capture a block is written as &block:
def do_stuff(arg, &block)
puts arg
block.call
end
But that's technically incorrect; the block variable will contain a Proc instance, as you can see here:
def do_stuff(arg, &block)
puts arg
puts block.class
end
do_stuff(10) {puts "I'm a block"}
--output:--
10
Proc
5) You can also use the & operator to convert a Proc instance to a block, as Nobita's answer demonstrated:
def do_stuff(x, y)
yield(x, y)
end
p = Proc.new {|x, y| puts x+y}
do_stuff(10, 20, &p)
--output:--
30
In that example, the method call do_stuff(10, 20, &p) is equivalent to writing:
do_stuff(10, 20) {|x, y| puts x+y}
6) When do you want to use a block and yield v. &block and call?
One use case for capturing a block in a variable is so that you can pass it to another method:
def do_stuff(arg, &a_proc)
result = arg * 2
do_other_stuff(result, a_proc)
end
def do_other_stuff(x, p)
1.upto(x) do |i|
p[i] #Proc#[] is a synonym for Proc#call
end
end
do_stuff(2) {|x| puts x}
--output:--
1
2
3
4
I suggest you operate by these two rules:
When you write a method that expects a block, ALWAY execute the block with yield.
If #1 doesn't work for you, consider capturing the block and using call (or [])
Block seems to be a bit faster based on the following benchmark:
require 'benchmark/ips'
prc = Proc.new { '' }
def _proc(&block)
yield
end
def _block
yield
end
Benchmark.ips do |x|
x.report('Block') { _block { '' } }
x.report('Proc') { _proc(&prc) }
end
Benchmark results on an i7-4510U CPU # 2.00GHz
Block 149.700k i/100ms
Proc 144.151k i/100ms
Block 4.786M (± 1.6%) i/s - 23.952M
Proc 4.269M (± 2.3%) i/s - 21.334M
I'm not sure of the best idiom for C style call-backs in Ruby - or if there is something even better ( and less like C ). In C, I'd do something like:
void DoStuff( int parameter, CallbackPtr callback )
{
// Do stuff
...
// Notify we're done
callback( status_code )
}
Whats a good Ruby equivalent? Essentially I want to call a passed in class method, when a certain condition is met within "DoStuff"
The ruby equivalent, which isn't idiomatic, would be:
def my_callback(a, b, c, status_code)
puts "did stuff with #{a}, #{b}, #{c} and got #{status_code}"
end
def do_stuff(a, b, c, callback)
sum = a + b + c
callback.call(a, b, c, sum)
end
def main
a = 1
b = 2
c = 3
do_stuff(a, b, c, method(:my_callback))
end
The idiomatic approach would be to pass a block instead of a reference to a method. One advantage a block has over a freestanding method is context - a block is a closure, so it can refer to variables from the scope in which it was declared. This cuts down on the number of parameters do_stuff needs to pass to the callback. For instance:
def do_stuff(a, b, c, &block)
sum = a + b + c
yield sum
end
def main
a = 1
b = 2
c = 3
do_stuff(a, b, c) { |status_code|
puts "did stuff with #{a}, #{b}, #{c} and got #{status_code}"
}
end
This "idiomatic block" is a very core part of everyday Ruby and is covered frequently in books and tutorials. The Ruby information section provides links to useful [online] learning resources.
The idiomatic way is to use a block:
def x(z)
yield z # perhaps used in conjunction with #block_given?
end
x(3) {|y| y*y} # => 9
Or perhaps converted to a Proc; here I show that the "block", converted to a Proc implicitly with &block, is just another "callable" value:
def x(z, &block)
callback = block
callback.call(z)
end
# look familiar?
x(4) {|y| y * y} # => 16
(Only use the above form to save the block-now-Proc for later use or in other special cases as it adds overhead and syntax noise.)
However, a lambda can be use just as easily (but this is not idiomatic):
def x(z,fn)
fn.call(z)
end
# just use a lambda (closure)
x(5, lambda {|y| y * y}) # => 25
While the above approaches can all wrap "calling a method" as they create closures, bound Methods can also be treated as first-class callable objects:
class A
def b(z)
z*z
end
end
callable = A.new.method(:b)
callable.call(6) # => 36
# and since it's just a value...
def x(z,fn)
fn.call(z)
end
x(7, callable) # => 49
In addition, sometimes it's useful to use the #send method (in particular if a method is known by name). Here it saves an intermediate Method object that was created in the last example; Ruby is a message-passing system:
# Using A from previous
def x(z, a):
a.__send__(:b, z)
end
x(8, A.new) # => 64
Happy coding!
Explored the topic a bit more and updated the code.
The following version is an attempt to generalize the technique, although remaining extremely simplified and incomplete.
I largely stole - hem, found inspiration in - the implementation of callbacks of DataMapper, which seems to me quite complete and beatiful.
I strongly suggest to have a look at the code # http://github.com/datamapper/dm-core/blob/master/lib/dm-core/support/hook.rb
Anyway, trying to reproduce the functionality using the Observable module was quite engaging and instructive.
A few notes:
method added seems to be require because the original instance methods are not available at the moment of registering the callbacks
the including class is made both observed and self-observer
the example is limited to the instance methods, does not support blocks, args and so on
code:
require 'observer'
module SuperSimpleCallbacks
include Observable
def self.included(klass)
klass.extend ClassMethods
klass.initialize_included_features
end
# the observed is made also observer
def initialize
add_observer(self)
end
# TODO: dry
def update(method_name, callback_type) # hook for the observer
case callback_type
when :before then self.class.callbacks[:before][method_name.to_sym].each{|callback| send callback}
when :after then self.class.callbacks[:after][method_name.to_sym].each{|callback| send callback}
end
end
module ClassMethods
def initialize_included_features
#callbacks = Hash.new
#callbacks[:before] = Hash.new{|h,k| h[k] = []}
#callbacks[:after] = #callbacks[:before].clone
class << self
attr_accessor :callbacks
end
end
def method_added(method)
redefine_method(method) if is_a_callback?(method)
end
def is_a_callback?(method)
registered_methods.include?(method)
end
def registered_methods
callbacks.values.map(&:keys).flatten.uniq
end
def store_callbacks(type, method_name, *callback_methods)
callbacks[type.to_sym][method_name.to_sym] += callback_methods.flatten.map(&:to_sym)
end
def before(original_method, *callbacks)
store_callbacks(:before, original_method, *callbacks)
end
def after(original_method, *callbacks)
store_callbacks(:after, original_method, *callbacks)
end
def objectify_and_remove_method(method)
if method_defined?(method.to_sym)
original = instance_method(method.to_sym)
remove_method(method.to_sym)
original
else
nil
end
end
def redefine_method(original_method)
original = objectify_and_remove_method(original_method)
mod = Module.new
mod.class_eval do
define_method(original_method.to_sym) do
changed; notify_observers(original_method, :before)
original.bind(self).call if original
changed; notify_observers(original_method, :after)
end
end
include mod
end
end
end
class MyObservedHouse
include SuperSimpleCallbacks
before :party, [:walk_dinosaure, :prepare, :just_idle]
after :party, [:just_idle, :keep_house, :walk_dinosaure]
before :home_office, [:just_idle, :prepare, :just_idle]
after :home_office, [:just_idle, :walk_dinosaure, :just_idle]
before :second_level, [:party]
def home_office
puts "learning and working with ruby...".upcase
end
def party
puts "having party...".upcase
end
def just_idle
puts "...."
end
def prepare
puts "preparing snacks..."
end
def keep_house
puts "house keeping..."
end
def walk_dinosaure
puts "walking the dinosaure..."
end
def second_level
puts "second level..."
end
end
MyObservedHouse.new.tap do |house|
puts "-------------------------"
puts "-- about calling party --"
puts "-------------------------"
house.party
puts "-------------------------------"
puts "-- about calling home_office --"
puts "-------------------------------"
house.home_office
puts "--------------------------------"
puts "-- about calling second_level --"
puts "--------------------------------"
house.second_level
end
# => ...
# -------------------------
# -- about calling party --
# -------------------------
# walking the dinosaure...
# preparing snacks...
# ....
# HAVING PARTY...
# ....
# house keeping...
# walking the dinosaure...
# -------------------------------
# -- about calling home_office --
# -------------------------------
# ....
# preparing snacks...
# ....
# LEARNING AND WORKING WITH RUBY...
# ....
# walking the dinosaure...
# ....
# --------------------------------
# -- about calling second_level --
# --------------------------------
# walking the dinosaure...
# preparing snacks...
# ....
# HAVING PARTY...
# ....
# house keeping...
# walking the dinosaure...
# second level...
This simple presentation of the use of Observable could be useful: http://www.oreillynet.com/ruby/blog/2006/01/ruby_design_patterns_observer.html
So, this may be very "un-ruby", and I am not a "professional" Ruby developer, so if you guys are going to smack be, be gentle please :)
Ruby has a built-int module called Observer. I have not found it easy to use, but to be fair I did not give it much of a chance. In my projects I have resorted to creating my own EventHandler type (yes, I use C# a lot). Here is the basic structure:
class EventHandler
def initialize
#client_map = {}
end
def add_listener(id, func)
(#client_map[id.hash] ||= []) << func
end
def remove_listener(id)
return #client_map.delete(id.hash)
end
def alert_listeners(*args)
#client_map.each_value { |v| v.each { |func| func.call(*args) } }
end
end
So, to use this I expose it as a readonly member of a class:
class Foo
attr_reader :some_value_changed
def initialize
#some_value_changed = EventHandler.new
end
end
Clients of the "Foo" class can subscribe to an event like this:
foo.some_value_changed.add_listener(self, lambda { some_func })
I am sure this is not idiomatic Ruby and I am just shoehorning my C# experience into a new language, but it has worked for me.
If you are willing to use ActiveSupport (from Rails), you have a straightforward implementation
class ObjectWithCallbackHooks
include ActiveSupport::Callbacks
define_callbacks :initialize # Your object supprots an :initialize callback chain
include ObjectWithCallbackHooks::Plugin
def initialize(*)
run_callbacks(:initialize) do # run `before` callbacks for :initialize
puts "- initializing" # then run the content of the block
end # then after_callbacks are ran
end
end
module ObjectWithCallbackHooks::Plugin
include ActiveSupport::Concern
included do
# This plugin injects an "after_initialize" callback
set_callback :initialize, :after, :initialize_some_plugin
end
end
I know this is an old post, but I found it when tried to solve a similar problem.
It's a really elegant solution, and most importantly, it can work with and without a callback.
Let's say we have the Arithmetic class which implements basic operations on them — addition and subtraction.
class Arithmetic
def addition(a, b)
a + b
end
def subtraction(a, b)
a - b
end
end
And we want to add a callback for each operation which will do something with the input data and result.
In the below example we will implement the after_operation method which accepts the Ruby block which will be executed after an operation.
class Arithmetic
def after_operation(&block)
#after_operation_callback = block
end
def addition(a, b)
do_operation('+', a, b)
end
def subtraction(a, b)
do_operation('-', a, b)
end
private
def do_operation(sign, a, b)
result =
case sign
when '+'
a + b
when '-'
a - b
end
if callback = #after_operation_callback
callback.call(sign, a, b, result)
end
result
end
end
Using with callback:
callback = -> (sign, a, b, result) do
puts "#{a} #{sign} #{b} = #{result}"
end
arithmetic = Arithmetic.new
arithmetic.after_operation(&callback)
puts arithmetic.addition(1, 2)
puts arithmetic.subtraction(3, 1)
Output:
1 + 2 = 3
3
3 - 1 = 2
2
I often implement callbacks in Ruby like in the following example. It's very comfortable to use.
class Foo
# Declare a callback.
def initialize
callback( :on_die_cast )
end
# Do some stuff.
# The callback event :on_die_cast is triggered.
# The variable "die" is passed to the callback block.
def run
while( true )
die = 1 + rand( 6 )
on_die_cast( die )
sleep( die )
end
end
# A method to define callback methods.
# When the latter is called with a block, it's saved into a instance variable.
# Else a saved code block is executed.
def callback( *names )
names.each do |name|
eval <<-EOF
##{name} = false
def #{name}( *args, &block )
if( block )
##{name} = block
elsif( ##{name} )
##{name}.call( *args )
end
end
EOF
end
end
end
foo = Foo.new
# What should be done when the callback event is triggered?
foo.on_die_cast do |number|
puts( number )
end
foo.run
I know this is an old post, but others that come across this may find my solution helpful.
http://chrisshepherddev.blogspot.com/2015/02/callbacks-in-pure-ruby-prepend-over.html