How to create a simple timer method in Ruby that takes an arbitrary function call?
For example:
time rspec or time get_primes(54784637)
It should still return the result of the function that is passed in (get_primes).
The following doesn't quite work:
def time block
t = Time.now
result = eval(block)
puts "\nCompleted in #{(Time.now - t).format} seconds"
result
end
Ruby 1.9.3
It's more Rubyesque to use a block:
def time
t = Time.now
result = yield
puts "\nCompleted in #{Time.now - t} seconds"
result
end
time { rspec }
This functionality is already available in Ruby's standard library, in the Benchmark module:
require 'benchmark'
time = Benchmark.realtime { 10_000.times { print "a" } }
Try it like this:
def time(&block)
t = Time.now
result = block.call
puts "\nCompleted in #{(Time.now - t)} seconds"
result
end
Related
I would like to be able to insert some code at the beginning and at the end of methods in my class. I would like to avoid repetition as well.
I found this answer helpful, however it doesn't help with the repetition.
class MyClass
def initialize
[:a, :b].each{ |method| add_code(method) }
end
def a
sleep 1
"returning from a"
end
def b
sleep 1
"returning from b"
end
private
def elapsed
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
block_value = yield
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: #{finish - start} seconds, block_value: #{block_value}."
block_value
end
def add_code(meth)
meth = meth.to_sym
self.singleton_class.send(:alias_method, "old_#{meth}".to_sym, meth)
self.singleton_class.send(:define_method, meth) do
elapsed do
send("old_#{meth}".to_sym)
end
end
end
end
The above does work, but what would be a more elegant solution? I would love to be able to, for example, put attr_add_code at the beginning of the class definition and list the methods I want the code added to, or perhaps even specify that I want it added to all public methods.
Note: The self.singleton_class is just a workaround since I am adding code during the initialisation.
If by repetition you mean the listing of methods you want to instrument, then you can do something like:
module Measure
def self.prepended(base)
method_names = base.instance_methods(false)
base.instance_eval do
method_names.each do |method_name|
alias_method "__#{method_name}_without_timing", method_name
define_method(method_name) do
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
public_send("__#{method_name}_without_timing")
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "Method #{method_name} took #{t2 - t1}"
end
end
end
end
end
class Foo
def a
puts "a"
sleep(1)
end
def b
puts "b"
sleep(2)
end
end
Foo.prepend(Measure)
foo = Foo.new
foo.a
foo.b
# => a
# => Method a took 1.0052679998334497
# => b
# => Method b took 2.0026899999938905
Main change is that i use prepend and inside the prepended callback you can find the list of methods defined on the class with instance_methods(false), the falseparameter indicating that ancestors should not be considered.
Instead of using method aliasing, which in my opinion is something of the past since the introduction of Module#prepend, we can prepend an anonymous module that has a method for each instance method of the class to be measured. This will cause calling MyClass#a to invoke the method in this anonymous module, which measures the time and simply resorts to super to invoke the actual MyClass#a implementation.
def measure(klass)
mod = Module.new do
klass.instance_methods(false).each do |method|
define_method(method) do |*args, &blk|
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
value = super(*args, &blk)
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: #{finish - start} seconds, value: #{value}."
value
end
end
end
klass.prepend(mod)
end
Alternatively, you can use class_eval, which is also faster and allows you to just call super without specifying any arguments to forward all arguments from the method call, which isn't possible with define_method.
def measure(klass)
mod = Module.new do
klass.instance_methods(false).each do |method|
class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{method}(*)
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
value = super
finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
puts "elapsed: \#{finish - start} seconds, value: \#{value}."
value
end
CODE
end
end
klass.prepend(mod)
end
To use this, simply do:
measure(MyClass)
It looks like you're trying to do some benchmarking. Have you checked out the benchmark library? It's in the standard library.
require 'benchmark'
puts Benchmark.measure { MyClass.new.a }
puts Benchmark.measure { MyClass.new.b }
Another possibility would be to create a wrapper class like so:
class Measure < BasicObject
def initialize(target)
#target = target
end
def method_missing(name, *args)
t1 = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
target.public_send(name, *args)
t2 = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
::Kernel.puts "Method #{name} took #{t2 - t1}"
end
def respond_to_missing?(*args)
target.respond_to?(*args)
end
private
attr_reader :target
end
foo = Measure.new(Foo.new)
foo.a
foo.b
How do I define a function in Ruby so that such call f[true,1,2,3] could be made?
I tried something like this def f(arr)
...
end
But it requires f([true,1,2,3]).
I'm total newb in Ruby, just need it to complete certain task.
I'd do it like this:
class MyClass
def [](a,b,c,d)
print "#{a} #{b} #{c} #{d}"
end
end
f = MyClass.new
f[true,1,2,3] # => true 1 2 3
I was looking in detail at the Thread class. Basically, I was looking for an elegant mechanism to allow thread-local variables to be inherited as threads are created. For example the functionality I am looking to create would ensure that
Thread.new do
self[:foo]="bar"
t1=Thread.new { puts self[:foo] }
end
=> "bar"
i.e. a Thread would inherit it's calling thread's thread-local variables
So I hit upon the idea of redefining Thread.new, so that I could add an extra step to copy the thread-local variables into the new thread from the current thread. Something like this:
class Thread
def self.another_new(*args)
o=allocate
o.send(:initialize, *args)
Thread.current.keys.each{ |k| o[k]=Thread.current[k] }
o
end
end
But when I try this I get the following error:
:in `allocate': allocator undefined for Thread (TypeError)
I thought that as Thread is a subclass of Object, it should have a working #allocate method. Is this not the case?
Does anyone have any deep insight on this, and on how to achieve the functionality I am looking for.
Thanks in advance
Steve
Thread.new do
Thread.current[:foo]="bar"
t1=Thread.new(Thread.current) do |parent|
puts parent[:foo] ? parent[:foo] : 'nothing'
end.join
end.join
#=> bar
UPDATED:
Try this in irb:
thread_ext.rb
class Thread
def self.another_new(*args)
parent = Thread.current
a = Thread.new(parent) do |parent|
parent.keys.each{ |k| Thread.current[k] = parent[k] }
yield
end
a
end
end
use_case.rb
A = Thread.new do
Thread.current[:local_a]="A"
B1 =Thread.another_new do
C1 = Thread.another_new{p Thread.current[:local_a] }.join
end
B2 =Thread.another_new do
C2 = Thread.another_new{p Thread.current[:local_a] }.join
end
[B1, B2].each{|b| b.join }
end.join
output
"A"
"A"
Here is a revised answer based on #CodeGroover's suggestion, with a simple unit test harness
ext/thread.rb
class Thread
def self.inherit(*args, &block)
parent = Thread.current
t = Thread.new(parent, *args) do |parent|
parent.keys.each{ |k| Thread.current[k] = parent[k] }
yield *args
end
t
end
end
test/thread.rb
require 'test/unit'
require 'ext/thread'
class ThreadTest < Test::Unit::TestCase
def test_inherit
Thread.current[:foo]=1
m=Mutex.new
#check basic inheritence
t1= Thread.inherit do
assert_equal(1, Thread.current[:foo])
end
#check inheritence with parameters - in this case a mutex
t2= Thread.inherit(m) do |m|
assert_not_nil(m)
m.synchronize{ Thread.current[:bar]=2 }
assert_equal(1, Thread.current[:foo])
assert_equal(2, Thread.current[:bar])
sleep 0.1
end
#ensure t2 runs its mutexs-synchronized block first
sleep 0.05
#check that the inheritence works downwards only - not back up in reverse
m.synchronize do
assert_nil(Thread.current[:bar])
end
[t1,t2].each{|x| x.join }
end
end
I was looking for the same thing recently and was able to come up with the following answer. Note I am aware the following is a hack and not recommended, but for the sake of answering the specific question on how you could alter the Thread.new functionality, I have done as following:
class Thread
class << self
alias :original_new :new
def new(*args, **options, &block)
original_thread = Thread.current
instance = original_new(*args, **options, &block)
original_thread.keys.each do |key|
instance[key] = original_thread[key]
end
instance
end
end
end
I could use some help on this one, given this code:
result1, result2, result3 = do_stuff {
method_1
method_2
method_3
}
I would like to be able to write a method called do_stuff that can call each line of that block individually and return a result for each line/block. Can it be done? Am I going about this the wrong way? Something like this (doesn't work at all) is what I am thinking.
def do_stuff(&block)
block.each_block do |block|
block.call
end
end
EDIT: What I am trying to accomplish is to be able to run each method/block call inside the method "do_stuff" in parallel (in it's own thread) and also add some logging around each method call.
I agree with mu above, you should explain what you are trying to do, as there is probably a more suitable pattern to use.
BTW, you can do what you ask for with a minor change:
result1, result2 = do_stuff {
[
method_1,
method_2,
method_3
]
}
or, perhaps, more elegantly, without the block:
result1, result2 = [
method_1,
method_2,
method_3
]
:)
OK, it looks clearer after the question was updated. You could do something like this, using method_missing, instance_eval and threads:
class Parallelizer
class << self
def run(receiver, &block)
#receiver = receiver
instance_eval &block
# wait for all threads to finish
#threads.each{|t| t.join}
#results
end
def method_missing *args, &block
#threads ||= []
#results ||= []
#threads.push Thread.new{
# you could add here custom wrappings
#results.push(#receiver.send(*args, &block))
}
end
end
end
class Test
def take_a_break name, sec
puts "#{name} taking a break for #{sec} seconds"
Kernel.sleep sec
puts "#{name} done."
name
end
end
t = Test.new
results = Parallelizer.run(t) do
take_a_break 'foo', 3
take_a_break 'bar', 2
take_a_break 'baz', 1
end
Be careful, though, that this is not well-tested and I am not sure how threadsafe.
Essentially I'm wondering if the following can be done in Ruby.
So for example:
def bar(symbol)
# magic code goes here, it outputs "a = 100"
end
def foo
a = 100
bar(:a)
end
You have to pass foo's context to bar:
def foo
a = 100
bar(:a, binding)
end
def bar(sym, b)
puts "#{sym} is #{eval(sym.to_s, b)}"
end
There is no built-in way to get a callers binding in Ruby in 1.8.X or 1.9.X.
You can use https://github.com/banister/binding_of_caller to work around.
In MRI 2.0 you can use RubyVM::DebugInspector, see: https://github.com/banister/binding_of_caller/blob/master/lib/binding_of_caller/mri2.rb
Working sample in MRI 2.0:
require 'debug_inspector'
def bar(symbol)
RubyVM::DebugInspector.open do |inspector|
val = eval(symbol.to_s, inspector.frame_binding(2))
puts "#{symbol}: #{val}"
end
end
def foo
a = 100
bar(:a)
end
foo
# a: 100
Here's a easier syntax hack, using a passed in block binding:
def loginfo &block
what = yield.to_s
evaled = eval(what, block.binding)
Rails.logger.info "#{what} = #{evaled.inspect}"
end
called like this:
x = 1
loginfo{ :x }
will log out:
x = 1
Just FYI, here's a "hacky way".
This is my (re-)implementation of well-known ppp.rb:
#!/usr/bin/ruby
#
# better ppp.rb
#
require 'continuation' if RUBY_VERSION >= '1.9.0'
def ppp(*sym)
cc = nil
ok = false
set_trace_func lambda {|event, file, lineno, id, binding, klass|
if ok
set_trace_func nil
cc.call(binding)
else
ok = event == "return"
end
}
return unless bb = callcc{|c| cc = c; nil }
sym.map{|s| v = eval(s.to_s, bb); puts "#{s.inspect} = #{v}"; v }
end
a = 1
s = "hello"
ppp :a, :s
exit 0
This currently fails with 1.9.[012] due to a bug in ruby's set_trace_func.
Check article out Variable Bindings in Ruby
class Reference
def initialize(var_name, vars)
#getter = eval "lambda { #{var_name} }", vars
#setter = eval "lambda { |v| #{var_name} = v }", vars
end
def value
#getter.call
end
def value=(new_value)
#setter.call(new_value)
end
end
def ref(&block)
Reference.new(block.call, block.binding)
end
def bar(ref)
# magic code goes here, it outputs "a = 100"
p ref.value
end
def foo
a = 100
bar(ref{:a})
end
foo