Friday, December 29, 2006

Questions? Lets talk about the ruby way

In The Ruby Way By Nicholas Petreley on Tue, 2006-12-05 11:09.
He asks "So here's my question to you Ruby aficianados. Did you have trouble adjusting to The Ruby Way of doing things? How long did it take for you to get used to Ruby's approach to objects, classes, instances, and the various oddities? How long was it before you started to feel like you really began tapping the power inherent in the language, and how much of that power do you attribute to Ruby's unique approach?"

I am quickly becoming a "Ruby aficianado", so I will take a stab at answering his questions.

I was able to adjust to the Ruby Way of doing things fairly quickly. Having recently spent a fair amount of time with python, Ruby's dynamic nature was welcoming, and familiar; However, up front blocks and procs were not. I would also add Ruby's open class nature was a surprise.

It took me about a month to get used to most of the various oddities. I tripped over small things, but found answers quickly online, or in a book. Irb is a great tool to work out understanding how to wield Ruby syntax, or code in general. I found I could read and understand most Ruby code quickly. Love the show source link on online rdoc, something sorely missing from javadoc.

I wrote an enterprise glue application that needed to be completed in one week. I was almost immediately able to tap the power inherent in the language. I found that I could express my thoughts more rapidly and adapt the codebase quickly to the changing requirements. Without going into any further detail, I will say that Ruby, ActiveRecord, and Rake saved the day. Not sure anything else would have done as well for the same task. Yes, Ruby has a unique approach and well worth using within the enterprise.

By the way the book The Ruby Way 2nd edition is well worth it. Like Nicholas I too was in a way put off by the list of Ruby oddities in the first chapter. I would recommend skipping that at first and coming back to it later.

Thursday, December 14, 2006

Get the edge, that is edgemocha

I had read over the past month, or so, a few blog posts on stubba and mocha. I especially appreciated Jay Fields coverage in his blog and Chris at err.the-blog. Here are some links that will get you started.

So, all that reading made me want to get immediately started with Mocha. When the time came to put it to work for me I installed the gem only to discover that at least version 0.3.2 did not appear to be working. The first surprise was that test/unit had to be required, or loaded first. But, even though that eliminated the unknown constant Test error, mocha still did not work. I am avoiding detailing the errors, etc, because their usefulness has expired. Why? Take a look if you dare at the head revision. I found the mocha team has been busy refactoring, apparently removing the test/unit dependency, and possibly other improvements.

I decided maybe I should try the head revision, that is go to the edge. I did not want to go back in versions as I was not sure how far I might need to and I thought going forward might allow me the chance to help with the project in some fashion. After following the directions at the project rubyforge site I launched an irb session to test.
irb(main):001:0> require 'mocha_standalone'
=> true
irb(main):002:0> include Mocha::SetupAndTeardown
=> Object
irb(main):003:0> setup_stubs
=> #<Mocha::Central:0xb791ac04 @stubba_methods=[]>
irb(main):004:0> $stubba
=> #<Mocha::Central:0xb791ac04 @stubba_methods=[]>
irb(main):005:0> class Foo
irb(main):006:1> end
=> nil
irb(main):007:0> foo = Foo.new
=> #<Foo:0xb7913f30>
irb(main):008:0> foo.expects(:nil?).returns("hello, mocha")
=> #<Mocha::Expectation:0xb790c384>
irb(main):009:0> foo.nil?
=> "hello, mocha"
irb(main):010:0> foo.nil?
=> "hello, mocha"
irb(main):011:0>

As you can see from the irb session you need to invoke the setup_stubs module function, or you will get an error about "stub" method not found on NilClass ($stubba). Once that is done, it appeared things were working. I wish I could say edgemocha is ready to go, but I am not sure, and hope to find out soon. Leave a comment if your experience was different, etc.

UPDATE:
Since it was requested, here is the problem I was having with 0.3.2, my apologies for any confusion. Compare:
~$ sudo gem install mocha
Attempting local installation of 'mocha'
Successfully installed mocha-0.3.2
~$ irb
irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'test/unit'
=> true
irb(main):003:0> require 'mocha'
=> false
irb(main):004:0> Object.methods.include? "expects"
=> false
irb(main):005:0>

Now using the head revision...
~$ irb
irb(main):001:0> require 'mocha'
=> true
irb(main):002:0> include Mocha::SetupAndTeardown
=> Object
irb(main):003:0> setup_stubs
=> #<Mocha::Central:0xb78bf49c @stubba_methods=[]>
irb(main):004:0> Object.ex
Object.expects Object.extend
irb(main):004:0> Object.methods.include? "expects"
=> true
irb(main):005:0>

Shortly after I discovered requiring stubba resolved my 0.3.2 issues it appears. Oddly examples I have seen only have a require 'mocha', for example: Start Trek Example

Monday, December 04, 2006

From "C" style printf to Ruby ERB, a better way to printf

Let's start with a quick "Hello, World" ruby program using ERB and the DATA pseudo file.
require "erb"
hw_end = "World"
ERB.new(DATA.read).run
__END__
Hello, <%=hw_end%>

So, this is a bit more complex than puts "Hello, World"; However, it served its purpose. Now could it be that this is a better way to express formated text output in a script versus printf? So, lets simulate a database table viewer with column headers and rows using text.
# create some sample data
Stats = Struct.new(:table_name, :ex_dt, :maint_dt, :maint_t)
data = [ Stats.new("table1", "Fri Dec 01 03:47:50 PST 2006", "2006-12-01", "03:47"), Stats.new("table2", "Fri Dec 01 03:48:50 PST 2006", "2006-12-01", "03:48") ]

For our text output we might be tempted to do the following:
# here is the a printf version
printf("%-26s|%-28s|%-10s|%-10s\n", "table_name", "extract_dt", "maint_dt", "maint_time")
printf("%-26s|%-28s|%-10s|%-10s\n", "-"*26, "-"*28, "-"*10, "-"*10)
data.each do |st|
printf("%-26s|%28s|%10s|%10s\n", st.table_name, st.ex_dt, st.maint_dt, st.maint_t)
end

While this works well, maybe it would be better expressed using ERB and the DATA pseudo file? Take a look.
require "erb"
ERB.new(DATA.read, 0, "%").run
__END__
table_name |extract_dt |maint_dt |maint_time
--------------------------|----------------------------|----------|----------
% data.each do |st|
<%="%-26s|%28s|%10s|%10s" % [st.table_name, st.ex_dt, st.maint_dt, st.maint_t]%>
% end

Now to me this is a much nicer, cleaner expression, do you agree?

I would like a better expression for the row format, spacing, and alignment. That is replace the "%%-26s|%28s|%10s|%10s"... with something simpler, any ideas?

The one caveat I should highlight is for each ruby file there is only one DATA pseudo file. I would suggest using here-docs when more templates are needed. The ERB rdoc has good examples and save the DATA pseudo file for .

For reference ERB recognizes the following tags in a template.
<% Ruby code -- inline with output %>
<%= Ruby expression -- replace with result %>
<%# comment -- ignored -- useful in testing %>
% a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
%% replaced with % if first thing on a line and % processing is used
<%% or %%> -- replace with <% or %> respectively

UPDATE:
I recently discovered that the DATA psuedo file is only for the main program and not the file it appears within. Sometimes this is the same file as in my example; However, it does not have to be. So, if you execute ruby some.rb, then DATA is the __END__ within some.rb. And while some.rb may require another.rb which has its own __END__, that one is ignored. So, when this occurs I would use HERE docs which provide the same clarity I was in search of.

Thursday, November 30, 2006

String#split, String#scan, and String#each_byte which is faster?

irb(main):026:0> Benchmark.bm do |bm|
irb(main):027:1* bm.report("split:") {
10000.times do a = "1234567890".split('') end }
irb(main):028:1> bm.report(" scan:") {
10000.times do a = "1234567890".scan(/./) end }
irb(main):029:1> bm.report(" eb:") {
10000.times do "1234567890".each_byte { |by| (a ||= []) << by } end }
irb(main):030:1> end
user system total real
split: 0.320000 0.000000 0.320000 ( 0.321568)
scan: 0.200000 0.000000 0.200000 ( 0.210951)
eb: 0.260000 0.030000 0.290000 ( 0.345428)

So, I am surprised that scan was faster, did you guess that? I wonder if pre-compiling the regex will make it even faster?
irb(main):033:0> Benchmark.bm do |bm|
irb(main):034:1* bm.report("split:") {
10000.times do a = "1234567890".split('') end }
irb(main):035:1> bm.report(" scan:") {
10000.times do a = "1234567890".scan(rx) end }
irb(main):036:1> bm.report(" eb:") {
10000.times do "1234567890".each_byte { |by| (a ||= []) << by } end }
irb(main):037:1> end
user system total real
split: 0.280000 0.010000 0.290000 ( 0.292449)
scan: 0.180000 0.000000 0.180000 ( 0.180988)
eb: 0.280000 0.050000 0.330000 ( 0.367461)

Interesting, I may need to dig deep into the ruby core and see what makes the speed difference. I believe split and scan are implemented as native code. I can understand why each_byte is the slowest given the loop complexity. More may follow as I dig in just for fun and the learning value.

Monday, November 13, 2006

Strange how string splitting is the same in Ruby, Python, and Perl, but maybe not?

Recently I wanted to have the individual characters of a string be assigned to left hand local variables. The string is always the same size, so after validating the size I wanted a single statement to assign values to local variables for each character within the string. Python was the most recent language I had spent time in, so I was reminded of the following:
>>> s = "12"
>>> a, b = s
>>> a
'1'
>>> b
'2'
>>>

This was exactly how I accomplished it before, so how about ruby. Let's try that in ruby using irb
irb(main):001:0> s = "12"
=> "12"
irb(main):002:0> a, b = s
=> ["12"]
irb(main):003:0> a
=> "12"
irb(main):004:0> b
=> nil
irb(main):005:0>

That is definetly not what I wanted. I thought so, how about perl?
$ perl -e '$s="12";($a,$b)=split("", $s);print "$a\n";print "$b\n"'
1
2

That works and looks like it would be close to the same in ruby I guess. Let's try:
irb(main):001:0> s = "12"
=> "12"
irb(main):002:0> s.split("")
=> ["1", "2"]
irb(main):003:0> a, b = s.split("")
=> ["1", "2"]
irb(main):004:0> a
=> "1"
irb(main):005:0> b
=> "2"
irb(main):006:0>

Now I have accomplished my original goal in ruby. Looking back I see python using an implicit action which wins for breavity, not that this was a competition. Ruby is close to that with an explicit action in an object esque, or message reciever way. Perl is explicit too, but dare I say a little harder to follow, and certainly not in a object esque syntax. It is amazing how close and far away the implementations are. As a final note Python's split does not allow the empty string, look at the ipython session below:
In [1]: "12".split("")
---------------------------------------------------------------------------
exceptions.ValueError Traceback (most recent call last)
/home/johnnyp/
ValueError: empty separator
In [2]:

Again because I had done a fair amount of python most recently I was surprised and expected the python behaviour a,b = "12" in ruby. This all led to asking on the ruby-talk mailing list. because I thought I might be missing some hidden ruby syntax. I initially used String#scan in my script and was quickly reminded of split from responses on the mailing list. Split more than likely can be found in your language of the day; However, be aware that it might miss behave ;-)

Thursday, November 09, 2006

Why Python? Actually why not python?

Eric Raymond (ESR) wrote "Why Python?" which is amazingly persistent in popularity on the linuxjournal.com website. I even asked ESR at a LinuxWorld what he thought about this fact and he remarked that he was pleasantly surprised. I can remember reading it and being inspired to try python. I used python in a successfully project and enjoyed it, mostly its dynamic nature. So, this blog is called ruby-talk, where am I going with this and what does it have to do with ruby? Let's see what led me away from python.

The repetitious "self" is often cited, but it actually did not bother me, nor did strict indentation. What really got me was the global keyword, pythons super syntax, and over abundance of web development frameworks. The web development framework situation has really changed and I only mention it because it was then an issue for me and would not be today.

Looking at the global keyword, say in a python module you might have:

foo = "bar"
def zoo:
global foo
foo = "baz"
end

This code shows how zoo can rebind foo, that is change it from "bar" to "baz" and have that change visible outside of zoo. I just could not get used to that and while it is small it continually annoyed me. Now, on to python's super syntax, for example:

class Derived(base.Base):
def __init__(self,x,y,z,**kw):
super(Derived, self).__init__(self,x,y,**kw)

Every time I looked at this it was not evident within seconds what is happening, nor obvious even after studying it. I won't explain it here as that is not my point, or intention, so if you need an explanation then you are getting my point here.

These may be small things, but they continually bothered me. I am thankful to "Why Python?" for getting me looking at python, but what it really did was get me on the dynamic language page. This led me to look at the other dynamic language Ruby. Upon looking at Ruby I began to see it was striking this really nice balance between several influential languages. What bothered me in python no longer bothered me in Ruby and I also gained some of the things I missed in perl. For me I am continually able to look at Ruby code from others, code I write, and it meshes nicely with the way I think. What a nice surprise.