Posted on August 30, 2006
How often did you write this kind of code?
def initialize(arg1, arg2, arg3)
@arg1 = arg1
@arg2 = arg2
@arg3 = arg3
end
All this constructor does it propagates parameters to initialize method to instance variables. In Ruby, there is a better way:
class Binding
def local_to_instance
eval("local_variables").each do |name|
eval("self").instance_variable_set("@#{name}", eval(name))
end
end
alias :kernel_eval :eval
def eval(code)
kernel_eval(code, self)
end
end
class Test
attr_accessor :arg1, :arg2, :arg3
def initialize(arg1, arg2, arg3)
binding.local_to_instance
end
end
t = Test.new(1,2,3)
puts t.arg1
# => 1
puts t.arg3
# => 3
p t
# => #<Test:0x1c6600 @arg1=1, @arg3=3, @arg2=2>
Note that Ruby 1.9 already provides Binding#eval method, so you don't need this kernel_eval hack.
I know this kind of silly and, I guess, inefficient. But still.
Filed under: Ruby |
4 comments
Posted on August 25, 2006
Many Rails users enjoyed this little gem developed by Florian Groß. But as Mauricio Fernandez noted in his blog, this extension is broken with the brand new Ruby 1.8.5. In order to make its magic possible, breakpoint library relied on the implementation of Binding.of_caller, which in turn relied on the bug in Ruby's implementation of trace calls. With new release, this bug has been patched.
Mauricio has started working of fixing this problem and proposed a new method binding_n(n), which would return a binding for any frame in the call stack. But you don't have to wait for his work to complete. ruby-debug has this functionality already implemented for you.
Consider this small snippet:
require "rubygems"
require 'ruby-debug'
module Kernel
def binding_n(n = 0)
frame = Debugger.current_context.frames[n+1]
raise "Unknown frame #{n}" unless frame
frame.binding
end
end
def test
puts eval("var", binding_n(1))
end
Debugger.start do
var = 'Hello'
test
end
And most likely, I will add this method to the next version of ruby-debug. It can be handy sometimes.
Filed under: Ruby ruby-debug |
0 comments
Posted on August 24, 2006
Rinda framework is part of the standard Ruby library. But what is it and how can it be useful? This question I will try to address in this article.
In the center of Rinda is a concept called tuple spaces. The idea of tuple spaces was initially introduced in the programming language Linda in 1982 which was designed to ease the implementation of distributed applications. With Rinda your application consists of many simultaneously running programs located anywhere on your network. All these programs are coordinated by a single process, tuple space. In essence, tuple space is a shared repository of objects accessed via network. What is interesting is that TupleSpace itself doesn't coordinate programs, but rather programs use TupleSpace to coordinate their workflow with each other. TupleSpace service provides a handful set of operations that I am going to describe next. What is really interesting is that just by using this small number of methods you can implement very powerful concepts.
What kind of objects TupleSpace can hold?
In essence, Rinda tuple space can hold Arrays or Hashs. Actually, it can hold any object that resembles (via ducktyping):
- array, by implementing
size and [] methods.
- hash, by implementing
each {|k,v| ...} and keys methods.
Filed under: Ruby |
5 comments
Posted on August 16, 2006
I remember a long time ago when I was programming C++ and using CORBA/COM(+) most of the time, frameworks spent reams of code dedicated to make one simple thing possible: asynchronous remote calls. You start a remote call, then go about your business and return for a result.
I remember I spent huge amount of time trying to make this thing work. Let's see how Ruby can handle this task. I'm going to use XMLRPC framework for demonstration purposes. Let's say you want to fetch the latest post from your Typo blog and you want to do it asynchronously of course.
require "xmlrpc/client"
client = XMLRPC::Client.new2("http://www.yourblog.com/backend/xmlrpc")
post = Thread.start {
client.call_async(*%w|metaWeblog.getRecentPosts blog user pwd 1|).first
}
# do your stuff here
$stdout.sync = true
5.times do print '.'; sleep 1; end
puts
# done
puts post.value['url']
In this code I rely on the fact that Thread#value method returns a result of the last statement of the thread's block and it joins on the thread if it's still running.
Not too bad for one-liner!
Filed under: Ruby |
0 comments
Posted on August 15, 2006
OK, here's a new version of ruby-debug. Most changes are related to the remote debugging and improvements targeted for a possible GUI integration:
Wait for a client connection. With this option on, the debugger will wait for a connection, before returning control to the script. You can enable it with -w option of rdebug script or by calling Debugger.wait_connection = true.
Stop on connect. With this option on, the debugger will stop when a remote client establishes a connection. rdebug script has this parameter enabled by default, but you can disable it with -n option. In your own script you can use Debugger.stop_on_connect = true to activate it.
Controlling thread. When activating a remote debugger, a control thread is activated as well. It listens on the socket (port 8990, by default) and accepts a number of commands that you can use to control a debugger, such as add/delete breakpoints, interrupt an application, etc. This is quite helpful for a GUI frontend, where you can set breakpoints at any time while your application is running.
There are also a couple of additions to the debugger commands:
l[ist] = - displays the current exception point.
f[rame] n - switches to nth frame. You can see the list of frames and their numbers with frame or where command.
tm[ate] - if you are running Mac OSX and addicted to TextMate, this command opens the current file using this editor.
That's all for now. Enjoy.
Filed under: Ruby ruby-debug |
8 comments