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 27, 2006
Wouldn't it be great if I can set breakpoints right from within TextMate? I've been thinking about this myself for sometime.
And now I'd like to introduce a new Ruby Debug Bundle.
Note that in order to use it you must have the latest version (0.4.1 or higher) of ruby-debug installed.
How to use it?
Let's say you want to debug your Rails application.
Start your application with the remote debugging enabled:
$ rdebug -sn ./script/server webrick
Connect to the debugger (in new terminal):
$ rdebug -c
Connected.
In TextMate go to the line where you want to set a breakpoint and press ⇧⌘B and select Set Breakpoint at Current Line.
Open your browser and start using your application until you reach the breakpoint.
That's it.
Currently, these commands are available:
- Set Breakpoint at Current Line
- Delete All Breakpoints.
- Show Breakpoints - show all breakpoints as a tooltip.
- Interrupt - interrupt the last debugged thread or, if there is no one, the main thread.
- Quit - quit application.
Filed under: ruby-debug TextMate |
7 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 25, 2006
New release 0.4 is uploaded to gem server. Thanks to Pascal for providing a valuable feedback and suggestions for this release.
What's new?
sa[ve] FILE command saves current breakpoints and checkpoint to a script file.
sc[ript] FILE command runs a script file. Note that script file can contain only control commands: add/remove breakpoints, interrupt program or thread, etc.
l[ist] on/off command. I don't know about you, but when I step through my application I immediately need to use list command to see where I am in the source code. Now if you use list on, ruby-debug will start doing this for you. To turn it off, use list off.
e[val] on/off command. When it's on*, ruby-debug will evaluate your input if it doesn't recognize it as one of the commands. To turn it off, use *eval off.
tm[ate] n command now accepts a frame number.
Note that in my last announcement I forgot to mention that if you don't want to use rdebug script to start debugger and instead prefer to require 'ruby-debug', now you must activate debugger explicitly by running Debugger.start or Debugger.start_remote method. Also, if you want to debug just a small part of your application, you can wrap it in a block and pass it to Debugger.start method. When start method finishes, it disactivates debugger. For example:
...
Debugger.start do
# code you want to debug goes here
...
end
Enjoy.
Filed under: ruby-debug |
1 comment
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
Posted on August 10, 2006
Yesterday Rails core team announced the release of Rails 1.1.5 version which supposedly fixes a major security vulnerability. Unfortunately, they didn't disclose what the actual problem was. I don't know about you, but I find it an appropriate and very frustrating. I'm a sys admin of a commercial web site and I must know what kind of problem I'm facing.
What even more frustrating is that 1.1.5 release introduced another huge security vulnerability. Just enter URL in your browser consisting a name of any standard Ruby library and your rails application will happily load this library. For example, if you want to bring down any web site powered by Rails 1.1.5, just run this:
# wget http://<your-website>/debug
several times. This URL makes Rails to load the standard debug.rb library which halts dispatcher process waiting for a terminal input.
I hope the next time rails core team will be more open about security threats. An extra pair of eyes wouldn't hurt with the patch evaluation.
Below is the patch that fixes this hole in Rails 1.1.5:
Index: actionpack/lib/action_controller/routing.rb
===================================================================
--- actionpack/lib/action_controller/routing.rb (revision 4745)
+++ actionpack/lib/action_controller/routing.rb (working copy)
@@ -270,10 +270,11 @@
protected
def safe_load_paths #:nodoc:
if defined?(RAILS_ROOT)
+ extended_root = Regexp.escape(File.expand_path(RAILS_ROOT))
$LOAD_PATH.select do |base|
base = File.expand_path(base)
extended_root = File.expand_path(RAILS_ROOT)
- base.match(/\A#{Regexp.escape(extended_root)}\/*#{file_kinds(:lib) * '|'}/) || base =~ %r{rails-[\d.]+/builtin}
+ base.match(/\A#{extended_root}\/*(#{file_kinds(:lib) * '|'})/) || base =~ %r{rails-[\d.]+/builtin}
end
else
$LOAD_PATH
Filed under: Rails |
0 comments