Technical Archives

Gregory Brown

AddThis Social Bookmark Button

Back in March, I announced the Ruby Mendicant project after several readers of this blog encouraged me to pursue the idea. For those who didn’t see the follow up details elsewhere, here’s the readers digest version:

Thanks to 70 donors, and donation matching from Ruby Central, Inc. and MountainWest Ruby LLC, I am now able to take 22 weeks off from my commercial work to focus on open source development in Ruby. I had a number of project ideas, but the general consensus is that my time would be best spent building a fast, sleek, and simple PDF library for Ruby. I’ve decided to call this library Prawn, for the time being.

Since I have just reached my first checkpoint on the project, I figured I’d give folks an update on where things are.

Gregory Brown

AddThis Social Bookmark Button

While working on Prawn, I ran into this (not-so) fun little gotcha:

>> 1.to_sym
=> nil
>> 101241.to_sym
=> nil

Anyone cool enough to tell me what this feature is all about?

Update:

I guess it isn’t totally clear what I was asking here. I’m not actually trying to convert integers to Symbols. In fact, my specs were failing because I expected some_number.respond_to?(:to_sym) to be false!

As it turns out, Fixnum#to_sym does have a purpose, but it is quite different than something like String#to_sym.

>> :foo.to_i
=> 14369
>> 14369.to_sym
=> :foo

I knew about the existence of #id2name and it didn’t surprise me much, given the way Symbol objects are implemented. Still, for the folks who keep reminding me about what Symbol objects are, please save your comments because that’s not the point here.

The point is that when I see “foo”, I can easily say. Oh… “foo”.to_sym will give me :foo.
When I see [16393, 16401, 16409], I don’t think “Gee… that must be: [:cat, :monkey, :tomato], I just need to map it with to_sym”.

So what this boils down to is an API clarity thing. Even if a Symbol is closely bound to an integer implementation-wise, I think it’s a bit of a flaw to assume that to be important conceptually. Among our readers, has anyone used Fixnum#to_sym in real code? I’d be very interested in seeing a common use case for this feature. If there isn’t one, maybe a less ambiguous name, such as id2sym might be more appropriate.

What’s more, even with the existing name, it’d be nice if some_number_that_has_no_symbol.to_sym would blow up with an error rather than return nil.

Sorry for the earlier confusion, hopefully this update clarifies that I was talking about a design peculiarity., and not some burning desire to get myself back a :1.

Gregory Brown

AddThis Social Bookmark Button

Reposting from the official announcement on RubyTalk

Gobi version 1.0.0 has been released!

* http://gobi.stonecode.org
* http://metametta.blogspot.com
* gregory.t.brown@gmail.com

I am happy to announce the first release of my new fork of Ruby called
Gobi. The goal of Gobi is to implement features that I have noticed to
be completely missing.

For example, Ruby’s standard library does not even implement a
datastructure that can easily represent a Go board. Gobi has this
built in as an NArray based, highly efficient structure:

 >> x = Goban.new
 >> x.place_stone(:black, :at => "a4")
 >> x.place_stone(:white, :at => "c16")
 >> x.place_stone(:black, :at => "a4")
 StoneCollisionError: There is already a stone at a4.
   from (irb):3 in `place_stone`
   from (irb):6

As you can see from the example above, Gobi is very friendly to those
writing computer Go applications. For those wishing to write AI bots
to play the game, Gobi also goes through a lot of effort to make Ruby
more efficient.

A major improvement in performance was gained through the removal of
automatic garbage collection. This means that programmers need to be
sure to clean up after themselves, but any Rubyist who also has an
interest in Go will surely be sufficiently skilled to design programs
that avoid memory leaks.

The implementation of object destructors in Gobi is simple, due to the
addition of a release_resources hook in Object. A delete keyword has
also been added, which will explicitly start up the garbage collection
process.

Here’s an example of manual garbage collection in Gobi:

 class Foo
   def initialize
     @board = Goban.new
   end
   def release_resources
     delete @board
   end
 end

Please keep in mind that although the built in classes all have
sensible release_resources implementations, that if you’re feeling
adventurous, you can of course override them. A current fun game in
Gobi is to run a stopwatch and see how quickly memory runs out when
you write some code like this:

 class String
   def release_resources; end
 end
 string = 'a'
 1_000_000_000.times do
   string = string.succ
 end

Of course, though humorous, this should serve as a warning to you: Be
sure to properly discard your objects!

This announcement just scratches the tip of the iceberg of what Gobi offers.

Other cool features include:

- The removal of Ruby 1.9’s giant interpreter lock, as Go programs
tend to benefit from the power of true concurrency. (Unfortunately,
these patches are very platform dependent)

- A major reshifting of Ruby’s standard library. Things like option
parsing, zlib support, and fileutils aren’t really that useful for
programming computer Go applications, so they have been removed. Many
new libraries have been added, including an SGF analysis tool and a
GTP network implementation.

- An interface to a special (Proverb Semantics Parsing) PSP tool,
which allows you to train Go playing robots by simply reminding them
of proverbs such as “Hane at the head of two stones”, and “The empty
triangle is bad”, rather than resorting to low level, complicated AI
programming. This system can be used via irb while a game is under
review in Gobi’s built in Tk based SGF editor. Gobi shows that by
mindlessly memorizing proverbs, Go playing bots can decrease their
rank by two stones in half the time that an average human can.

- The removal of all lesser data structures such as the Array, the
Hash, and the Set. In Gobi, all of these structures could trivially
be built as a subclass of the Goban, so there is no need to keep them
around.

Though I will be taking off 6 months from Gobi development to work on
the Ruby Mendicant project, I hope that people enjoy this early
experimental release and that soon Ruby will be free from the core
team’s shackles to do what it truly deserves to: Reach 30 kyu on KGS
with a Gobi based bot!

Though only time will tell, I am considering reworking Gobi to fork
Aaron Patterson’s excellent Brobinius implementation, as Gobi deserves
some high quality Grosenbach screencasts.

* http://gobi.stonecode.org
* http://metametta.blogspot.com
* gregory.t.brown@gmail.com

AddThis Social Bookmark Button

This project upgrades an online forum to add a search engine, using Test Driven Development. Our tools are RoR’s Beast, Sphinx, and (naturally) assert{ 2.0 }.

We follow this MVC guideline:

Anything a user can do to the data through the Views,
a unit test can do, the same way, through the Models
Our test cases simulate a user searching.

AddThis Social Bookmark Button

I like developer tests, but I don’t like the primitive assertions - assert_equal, assert_match, assert_not_nil, etc. They only exist for one reason - to print out their input values when they fail. And they don’t even reflect their variable names.

So I wrote an assertion to replace all of them. Put whatever you want into it; it prints out your expression, and all its values. Essentially like this:

__source__ __failure_diagnostic__
x = 43
assert{ x == 42 }
assert{ x == 42 } --> false - should pass
    x --> 43
deny{ x == 43 }
deny{ x == 43 } --> true - should not pass
    x --> 43

The classic versions require a lot more typing, and reflect much less information:

  assert_equal(x, 42)     --> <43> expected but was \n<42> 
  assert_not_equal(x, 43) --> <43> expected to be != to \n<43>

Install this system with:

  gem install assert2

Some systems might require sudo, to tell the ‘puter who’s boss. The “assert2” gem will pull in RubyNode, the library that inspects Ruby blocks. Then add require 'assert2' to your test suites, or to your test_helper.rb file.

AddThis Social Bookmark Button

With the addition of Java Native Access (JNA) to JRuby, systems programmers using JRuby now have greater flexibility in terms of interfacing with underlying operating system.

Some Ruby users are familiar with the ‘Win32API’ library that ships as part of the Ruby standard library. That library lets you interface with the Windows API by defining function pointers from specific DLL’s that you later call. With JRuby’s JNA interface you can now interface with Windows in a similar fashion.

AddThis Social Bookmark Button

To ensure your test cases call efficient MySQL

  def test_my_case
    assert_efficient_sql do

      # just wrap them in this block!

    end
  end

The assertion intercepts and copies out your MySQL SELECT statements, then calls EXPLAIN on each one, and inspects the results for common problems.

The goal is test cases that resist database pessimization, even as you change your data relations, to add new features. If you run your tests after every few changes, you can easily detect which change broke your database’s indices and relations.

This article is a reference for this assertion’s options. The techniques should be ported to any database with an EXPLAIN or similar system.

AddThis Social Bookmark Button

Did you know you can do this with Ruby out of the box?

# A real lambda
λ { puts ‘Hello’ }.call => ‘Hello’

# Sigma - sum of all elements
∑(1,2,3) => 6

# Square root
√ 49 => 7.0

How difficult was this to implement? Keep reading!

Gregory Brown

AddThis Social Bookmark Button

These days, it seems I hardly have the time for doing fun random hacks. So here I’ve started one, and if anyone finds it interesting, please take it from here and let me know how it turns out.

Loosely based off of AIML, kind of, but not really:

class Conversation

  def initialize(person)
    @person = person
    @response_id = 0
  end  

  attr_reader :response_id

  def say(msg)
    print "#{@person}: "
    @response_id = Response[@response_id].respond_to(msg)
  end 

  class Response

    def self.responses
       @responses ||= {}
    end

    def self.[](id)
      responses[id]
    end  

    def initialize(id)
      @id = id
      self.class.responses[id] = self
      @matchers = []
      @messages = []
    end               

    attr_reader :id,:matchers 

    def when(pattern,id)
      @matchers << [pattern,id]
    end     

    def inherits(arr)
      arr.each do |id|
        @matchers += Response[id].matchers
      end
    end

    def might_say(msg,weight=1)
      weight.times do
        @messages << msg
      end
    end        

    def talk
      puts @messages.sort_by { rand }.pop
    end

    def respond_to(msg)
      @matchers.each do |pattern,id|
        if msg =~ pattern
          Response[id].talk
          return id
        end
      end
      return @id
    end

  end     

end           

def response(id)
  r = Conversation::Response[id] || Conversation::Response.new(id)
  yield(r)
end

AddThis Social Bookmark Button

I’m looking for someone to take over PDF::Writer, color-tools, and Transaction::Simple. I do not have time to maintain these anymore. I should have done this months ago, but pride of ownership and a belief that more free time would be just around the corner got in the way.

You can read more details on my original blog posting at my personal blog.

Anyone interested? Anyone know anyone interested?

Gregory Brown

AddThis Social Bookmark Button

I think most Rubyists have picked up a good trick or two from Jim Weirich. Though it’s only a tiny part of his latest article (Using Flexmock to Test Computational Fluid Dynamics Code), I got excited to see his ‘Existence Test’ in his code:

  def test_initial_conditions
    q = F3DQueue.new
    assert_not_nil q
  end

Looks pretty simple, eh? You might be quick to say that this doesn’t do anything. However, it is actually a pretty clever practice. This test makes sure the tests themselves are working as expected. I was already in the habit of starting with a failure, usually something like:

  def test_doomed
    flunk
  end

The purpose of the above is simply to make sure your tests are picked up within your suite, and aren’t being overlooked by your Rakefile, autotest, or whatever runner you’re using. But the existence test actually goes a little farther. Because you’re initializing an object, you’re making sure that the files you need to be loading are present, that you can build your objects, *and* that your tests are hooked up.

After you’ve got a couple tests passing, you can remove this sanity check or morph it into a setup(), whatever makes sense.

Many people think this is a little paranoid, and most of the time, it is. Still, all it takes is one bad experience coding under falsely passing tests, and you’ll be converted in no time. :)

AddThis Social Bookmark Button

From Nick Sutterer, A Computer Science Undergraduate at Albert-Ludwigs University (Freiburg, Germany)

When writing an article about Apotomo I had to make a decision: either introduce it as a simple widget plugin for rails or - as the name Apotomo (”all power to the model”) implies - end up in monologues about model-driven component-oriented enterprize concepts. Today I will simply introduce Apotomo as a widget library for rails.

Gregory Brown

AddThis Social Bookmark Button

Hey folks, I’ve picked a winner for June’s Ruby project spotlight and will have a post out within the next few days about it, but I’d like to remind folks that this is an ongoing project.

What that means is that I’m now accepting July submissions. Every submission we got for June was excellent, and if you were not selected, you can always resubmit for a later month. Here’s a recap of the rules, but see the original post for details.

  • Project must be fresh / actively developed
  • Project must be released before the time I post
  • Proposal should consist of nothing more than a code example and a link to your project page, no additional commentary needed
  • Project can’t be Rails-centric
  • You must be a developer on the project
  • My project choices will be entirely subjective and unjustified. :)

Please email me if you’ve got a cool project to submit!

Gregory Brown

AddThis Social Bookmark Button

To answer a question on RubyTalk the other day, I had to reference Mauricio Fernandez’s nicely compiled list of Changes in Ruby 1.9. While I was there I took another walk through the whole thing.

There are of course some features I *don’t* like.

a = ->(b,c){ b + c }
 a.call(1,2) # => 3

But there are quite a few that I do, and here I’ve listed ten I think will totally rock. I use Mauricio’s examples, so all credit goes to him. Also, this article is from February, so if you find any features below that have changed, shout and I’ll update.

AddThis Social Bookmark Button

Consider this fact: Multi-core CPUs are not only the future, they’re the only way CPUs can continue to grow at their current pace. It’s also a hotly debated subject in the software world. Multi-threaded programming is different and not seen as often as procedural programming, and therefore it’s not yet as well understood. So the question is, how can programming languages (and Ruby in particular) make it easier to harness these systems?

As Ruby struggles to graduate from its current implementation into something more powerful, we’ve already seen several projects attempt to update Ruby to help developers cope. Those who’ve been working with Ruby for awhile may remember YARV, which promises to provide more threading support. JRuby offers all the power of Java’s threads to Ruby, if it can harness it. And Evan Phoenix’s small but rapidly growing project Rubinius is attempting to be the next big contender.

No matter what implementation becomes the next de-facto Ruby platform, one thing is clear: People are interested in taking advantage of their newer, more powerful multi-core systems (as the recent surge in interest in Erlang in recent RailsConf and RubyConfs has shown). As Ruby becomes increasingly part of solutions that deal in high volumes of data processing, this demand can only increase.

That’s why it’s so very surprising to see David Heinemeier Hansson dismiss the whole notion out of hand regarding Rails. His argument seems to be that Rails already scales to multiple cores in the same way it scales to multiple machines, via UNIX process distribution. After all, isn’t this the very crux of “Share Nothing?”

Jeremy McAnally

AddThis Social Bookmark Button

I was not mowing my lawn like Gregory, but I was reading this blog when I got an idea for a Rails version of the Ruby Project Spotlight series Gregory is spinning up.

The idea is that I’ll post an entry once or twice a month about a new and active Rails project that’s looking for more exposure. The project can be a gem, a plugin, an open source Rails application: basically anything that’s related to Rails. The process for getting a project mentioned is simple: send me an e-mail about your project. It should follow these simple rules:

  • Keep it fresh — I’d rather not look at code from pre-Rails 1.0 or that’s been sitting on Rubyforge for 11 months with no activity.
  • Keep it real — Project should be released before the time I post.
  • Keep it brief — A code sample, a project link, and up to two sentences of commentary is all I need.
  • You must be a developer on the project. (Sorry. No clever phrase for this one.)

The rules are so specific because the coverage is plentiful of things that don’t fit within them, but a lot of the newer and (usually) more interesting projects aren’t really gaining the exposure they need to get a flourishing community to spring up around them.

So, if you’re a developer on one of these projects, e-mail me your submission by June 30th. I’ll judiciously pick through them and make my rather subjective choice for July soon after. Hopefully this can bring some really cool Rails projects some exposure, and expose our readers to tools and projects they can make use of.

Gregory Brown

AddThis Social Bookmark Button

As I was mowing the lawn, I had an idea for a series I thought might be fun.

I’d like to put out an entry once a month about an new or highly active Ruby project that’s looking to gain some extra exposure. People can send me proposals for their projects, and I’ll pick one each month to write about here. This way, if you’re way behind on your mailing list reading, you’ll be able to easily find at least one new project announcement each month.

Below are the semi-arbitrary rules for submission:

  • Project must be fresh / actively developed
  • Project must be released before the time I post
  • Proposal should consist of nothing more than a code example and a link to your project page, no additional commentary needed
  • Project can’t be Rails-centric
  • You must be a developer on the project
  • My project choices will be entirely subjective and unjustified. :)

The reason these rules are fairly specific is that I’m hoping that this series will be a sort of grass-roots effort to have Ruby recognized as a useful language standing on its own two legs. If someone else wanted to start up a similar series about Rails projects on this blog or elsewhere, that’d be great.

I’m also stipulating that the project needs to be relatively new and fresh, because there is no shortage of coverage of the more popular Ruby projects out there. This is a chance to give new folks and new projects some time to shine.

Please email me your submissions by June 30th. I’ll get in touch with my favorite pick some time in the first week of July, and have a post out then. Hopefully this will be a fun little series, and a useful service to those having trouble keeping up on the latest Ruby software.

AddThis Social Bookmark Button

At RailsConf 2007 DHH mentioned that Rails 2.0 would support query caching on the client side in order to speed up AR. I immediately thought to myself, “Huh? Why do it on the client side when the database server will handle that?”.

AddThis Social Bookmark Button

Last year, one of the most difficult things about keeping track of the progress of the Ruby projects in Google’s Summer of Code was finding where the students / mentors were talking about their projects. Since several of the bloggers on O’Reilly Ruby are directly involved in the the Summer of Code in one way or another, we decided that we’d try to make things a little easier for the community for GSoC 2007.

We’ve sent out an open invite to all students and mentors who are assigned to RubyCentral for the summer. Rather than just relaying second hand news, we’ve encouraged those involved to submit blog posts to us, and we’ll post them all here using the special GSoC account. If you missed the original announcement, please contact Gregory Brown, as he’ll be coordinating the effort.

Better than half of the students involved this summer have expressed interest in participating with us. We’re busy collecting bios, and will soon make a post that introduces the folks who will be blogging with us this summer, and a little more detail about their projects.

One of the students involved has plans to have an announcement about their project ready by the end of the month, so keep an eye out for that!

Gregory Brown

AddThis Social Bookmark Button

Just because Everyone Is Here In The Future, doesn’t mean you should be too!

The culprit, in camping’s reloader:

86  # The timestamp of the most recently modified app dependency.
87  def mtime
88    ((@requires || []) + [@script]).map do |fname|
89      fname = fname.gsub(/^#{Regexp::quote File.dirname(@script)}//, '')
90      begin
91        File.mtime(File.join(File.dirname(@script), fname))
92        rescue Errno::ENOENT
93        remove_app
94        @mtime
95      end
96    end.max
97  end

If your most recent modified time is more recent than your current system time, your reloader will break until you go Back To The Future.

I figure this is probably a rare case, and not really a bug, but if you’re playing around with system time dependant apps (I am), this might bite you.

Gregory Brown

AddThis Social Bookmark Button

I’m excited to be able to finally get around to another post in this Digging Deep series, in which I hope to delve head first into some Ruby esoterica. This time around, I have an interview with Ara T. Howard about some of the hackery he does with packaging rq

Hope you enjoy it! Questions follow.

Gregory Brown

AddThis Social Bookmark Button

I spend most of my time building relatively large applications with Ruby, and this makes me forget how easy the quick and dirty hacks are. In less than the time it’d take me to google the right UNIX tool for escaping HTML, here is my tiny script that I use for things like blog entries and mass spam emails.

#!/usr/bin/env ruby

require "cgi"
puts CGI.escapeHTML(ARGF.read)

Mmh,… sweet simplicity. If you’ve not worked with the CGI lib before, there are probably other goodies in there so have a look at the API docs.

UPDATE: Sam Aaron does a good job of explaining what this script actually does in the comments

Gregory Brown

AddThis Social Bookmark Button

For those who saw my other post on what the RubyForge forum is about, I apologize for the redundancy here. However, I feel like perhaps if some folks pass this reminder along, it’ll get the message out. I’ve seen a huge resurgence of off topic posts, and I’m actually feeling bad that people end up waiting for replies only to get the same ‘we don’t deal with those questions here’ reply.

The RubyForge support forum is meant to support RubyForge itself. That means that if you have a feature request you might want to talk about before submitting a formal proposal, if you think you might have found a broken service in RubyForge, but you’re not sure, or if you just want to talk to us about some of the stuff we offer, you’ve found the right place.

If you have svn access that works on Windows but not on Linux, If you can’t install rails but you don’t suspect our gem servers are broken, or if you just want to ask what a particular library does, please, don’t use the RubyForge forum. You will get much better help elsewhere.

I am the only active volunteer monitoring our forum right now, so please… help me out a bit by using the great mailing lists out there!

This isn’t to discourage people from using our forum, in fact, if in doubt, post to us anyway. But please, read the FAQ before you post. If others can spread the word by linking my other article on what our forum is for, that’d be very helpful!

Gregory Brown

AddThis Social Bookmark Button

Here’s a little problem I ran into in some old code of mine.

Sometimes we’ve got methods where we want to return a new instance of the same class.

It’s tempting to write the following code:

>> class A
>>   def a_whole_new_me
>>      A.new
>>   end
>> end

Sure enough, that seems to work:

>> a = A.new
>> a.class
=> A
>> a.a_whole_new_me.class
=> A

So what’s wrong with it? We forgot about subclasses!

>> class B < A; end
>> b = B.new
>> b.class
=> B
>> b.a_whole_new_me.class
=> A

If we’re expecting a copy of B and get A, this is certainly going to cause trouble, but the scary part is it might not right away (since B usually has all of A’s methods, but not necessarily the other way around)

Luckily, this is easy to fix, just use self.class

>> class A
>>   def a_whole_new_me
>>     self.class.new
>>   end
>> end
>> a = A.new
>> a.class
=> A
>> a.a_whole_new_me.class
=> A
>> class B < A; end
>> b = B.new
>> b.class
=> B
>> b.a_whole_new_me.class
=> B

This practice is usually a good idea whenever we want to refer to our class object. Rather than making things rigid, if you use self.class when possible, your code will be easier to extend and behave better in general. Of course, your mileage may vary depending on your task.

AddThis Social Bookmark Button

Over the last couple of Ruby releases I’ve made some improvements (with Eric Hodel’s help and blessing) to RDoc for C extensions that I thought I would share with you. If you write C extensions with Ruby then keep reading. If you don’t do C and/or don’t care that much about RDoc, this post may not be that interesting for you. :)

Ryan Leavengood

AddThis Social Bookmark Button

I haven’t posted here in a very long time, but I recently got a full-time job using Ruby and Rails (hurray) so Ruby is more on my mind lately. In fact I’ve gotten a better understanding of what life is like for the average Rails developer by seeing how my co-worker Alex writes his Ruby code. Now Alex is a smart guy, he has been doing web-sites for years, is proficient in ColdFusion, PHP , Flash, HTML and CSS, yet his Ruby code is not always as elegant as he or I would like. Of course I’ve been using Ruby for almost 6 years so know it quite well (and that is a big reason why I was hired.)

Still even I find the occasional new nugget and figured this blog would be a good forum to expose some of my new insights. This way other Rails developers like Alex who aren’t as proficient in Ruby as they would like can benefit from my experience.

Recently I was perusing the documentation for the Enumerable module and took a closer look at the grep method. This method is surprisingly more powerful than it might seem at first glance. To learn more, please continue reading this entry…

Gregory Brown

AddThis Social Bookmark Button

This came up in #camping today and I figured it was worth at least a mention:

Vanilla HashWithIndifferentAccess is slightly more choosy than Camping’s.

A quick irb session with each shows the difference.

From active_support

>> require "active_support"
=> true
>> a = HashWithIndifferentAccess.new
=> {}
>> a.apple
NoMethodError: undefined method `apple' for {}:HashWithIndifferentAccess
        from (irb):4
>> a.apple "bar"
NoMethodError: undefined method `apple' for {}:HashWithIndifferentAccess
        from (irb):5
>> a.apple = "bar"
NoMethodError: undefined method `apple=' for {}:HashWithIndifferentAccess
        from (irb):6

From camping

>> require "camping"
=> true
>> a = HashWithIndifferentAccess.new
=> {}
>> a.apple
=> nil
>> a.apple "bar"
NoMethodError: apple
        from /usr/local/lib/ruby/gems/1.8/gems/camping-1.5/lib/camping.rb:51:in `method_missing'
        from (irb):5
>> a.apple = "bar"
=> "bar"

This is not a complaint, just an observation I hope will be helpful. :)

Jim Alateras

AddThis Social Bookmark Button

Since picking up RoR I have had to dig in to technologies which I had previously only glanced at. One of these is CSS, part of the DHTML set of technologies.

The experience has been rewarding and at times frustrating but the outcomes has been positive. It is a technology that people need to get their heads around in order to develop an effective and usable front end to your web application.

Here are some resources that eased the learning curve

Books

Debugging Tools

Editors

Gregory Brown

AddThis Social Bookmark Button

The following may be a bit of an ‘Advanced NubyGem’ but I think this is an interesting idiom that most people will have to work with.

Sometimes in Ruby you’ll see things, both in core and third party libraries, that look a bit like class names that take arguments.

You may of already seen these in the form of Integer(), Array(), etc.

>> Integer(1)
=> 1
>> Integer("1")
=> 1
>> Integer("")
ArgumentError: invalid value for Integer: ""
        from (irb):3:in `Integer'
        from (irb):3

These weird looking methods are just alternate constructors. They can really come in handy as a way to simplify the most common ways of building a given object, or giving them some different behaviors.

Here is an example from Ruport:

The long way of constructing a Table object:

  table = Ruport::Data::Table.new :data => [[1,2,3],[4,5,6]],
                 :column_names => %w[a b c]

This is the shortcut interface:

 table = Table(%w[a b c]) << [1,2,3] << [4,5,6]

This is usually less typing and looks a little cleaner. Of course, it doesn't support the same exact options of the original constructor, but that's what we're going for afterall.

How it's done

Implementing these methods is as simple as using capitalized method names. In Ruport, we are currently a little surly and do this right on Kernel so you can get the constructors everywhere:

module Kernel
   def Table(*args)
        #implementation here
   end
end

A safer way

Instead of sticking these methods in Kernel, you can play it safe and put them in a module,
this way, they only are available where you include them. For example, if enough people complain, we’ll probably do something like this:

module Ruport::Data::Shortcuts
   def Table(*args)
       #....
   end
end

This way, people would be able to use these shortcuts just in certain classes by including the module in them. If you’re worried about your names conflicting with others, this might be a good idea.

Don’t Overuse Your Shortcuts!

I should fix this problem before I tell folks not to do it, but right now bits of Ruport code use the shortcut methods internally. Unless you have a really compelling reason (other than laziness) to do this, Don’t!

The very thing that makes it ’safe enough’ to stick these shortcuts in core is that a conflict should only break the shortcut. If you use your shortcuts internally in your code, there is a chance of some serious issues if things collide.

Jim Alateras

AddThis Social Bookmark Button

Recently on the ror-talk mailing list there was a question on navigational menus, which revealed some interesting resources.

link_to_unless_current helper
Goldberg, Integrated Site Design for RoR
NavTab Plugin”

The navtab plugin, which is part of SeeSaw toolbox, is a neat little plugin, which provides instant support for tabs in your web applications. We will definitely be using this on our next RoR application.

Gregory Brown

AddThis Social Bookmark Button

I’ve been running local special need gem servers as well as a gem server for beta versions of Ruport and support code (namely plugins). I got tired of manually wget’ing the gems I needed and their dependencies, so with a little help from mechanize and archive_tar_external, my friend Dinko and I came up with this quick (pretty messy) hack.

require 'rubygems'
require 'archive/tar_external'
require 'mechanize'
require 'fileutils'
include FileUtils
include Archive

module RFDownloader

  def populate(archive)
    mkdir ".rf_downloader"
    cd ".rf_downloader"

    yield

    Tar::External.new( "../#{archive}.tar",
                       "*.gem", "gzip")
    cd ".."
  end

  def get(pattern,options={})
    link = "http://rubyforge.org/projects/#{options[:project]}"
    agent = WWW::Mechanize.new
    page = agent.get(link)
    page.links.find { |l| l.text[/File/] }.click
    link = agent.page.links.find { |l| l.text[pattern] }
    link.click.save_as(link.text)
  end

  def fetch(opts,&block)
    populate(opts[:archive]) do
      module_eval &block
    end
  end

  module_function :fetch, :populate, :get

end

With this, we were able to grab automatically a tarball filled with all the gems needed to run Ruport 0.9.0 with a tiny little script:

require "lib/rf_downloader"

RFDownloader.fetch(:archive => "ruport_deps") do
  get /fastercsv.*gem/,          :project => "fastercsv"
  get /pdf-writer.*gem/,         :project => "ruby-pdf"
  get /color-tools.*gem/,        :project => "ruby-pdf"
  get /transaction-simple.*gem/, :project => "trans-simple"
  get /RedCloth.*gem/,           :project => "redcloth"
  get /hoe.*gem/,                :project => "seattlerb"
  get /rubyforge.*gem/,          :project => "codeforpeople"
  get /mailfactory.*gem/,        :project => "mailfactory"
  get /mime-types.*gem/,         :project => "mime-types"
  get /scruffy.*gem/,            :project => "scruffy"
  get /build.*gem/,              :project => "builder"
  get /gem_plugin.*gem/,         :project => "mongrel"
end

Elegant? Nope! A way to be lazy and quickly snapshot the newest versions of a number of gems, you bet ya. Maybe someone will see this and build a nice little library that does this ‘the right way’ :)

UPDATE: Thanks to Aaron Patterson for helping me get rid of the wget call

Gregory Brown

AddThis Social Bookmark Button

RubyForge has been growing fast. As the primary resource for project hosting in Ruby, it’s been expanding with the language. One thing that is interesting about it as a service is that it is more-or-less maintained by just one person (Tom Copeland) with the help of a few other folks and some RubyCentral funding.

A few months ago I joined the RubyForge team to try to lighten Tom’s load a bit, and have been monitoring the support forum since then. I think a whole lot of folks don’t even realize we have one while some others have mistakenly assumed it was a general Ruby forum. This post is meant to explain a little bit about what the forum is for and how you can use it to get the help you need.

Gregory Brown

AddThis Social Bookmark Button

Yet another series attempt

I think my NubyGems series has gone over pretty well, so I figured I’d try my luck with something else.

This new series, digging deep, will be targeted towards the more experienced developer, or at least folks who want to know a little more about some deeper concepts in Ruby. I’m going to do what I can to make these as clear as possible, but I’m relying on input from gurus and skeptics to help improve these posts and make them a good resource for folks.

So this post will focus on a recent topic on RubyTalk, the merit of using Mixins as a suitable replacement for multiple inheritance.

Gregory Brown

AddThis Social Bookmark Button

This was actually inspired by some thoughts at a new_haven.rb meeting I wasn’t able to attend, reintroduced in a RubyTalk thread, and solidified in another blog entry that’s worth a look.

The topic here is simple, and it’s that for most common needs, there is absolute no reason to use class variables. I will show how you can use class instance variables to avoid the problems associated with class variables in most cases at the end of this article, but first, take a look at two compelling and mind melting reasons for *not* using class variables.

From Gary Wright:

>> class A
 >> @@avar = 'hello'
 >> end
=> "hello"
 >> A.class_variables
=> ["@@avar"]
 >> A.class_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
        from (irb):5
        from (irb):5
 >> class A
 >> puts @@avar
 >> end
hello
=> nil
 >> class A
 >> def get_avar
 >> @@avar
 >> end
 >> end
=> nil
 >> a = A.new
=> #
 >> a.get_avar
=> "hello"
 >>   a.instance_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
        from (irb):16
        from (irb):16
 

And the real scary one, from David A. Black:

   @@avar = 1
  class A
    @@avar = "hello"
  end
  puts @@avar  # => hello

  A.class_eval { puts @@avar }  # => hello

Yes, there are reasons why both of these problems occur. Yes, they are likely to give you a headache.

If you’re just looking to store some data in a variable which is unique to your class, but accessible from instances or externally, why not just use instance variables?

>> class A
>>   @foo = "bar"
>>   class << self; attr_reader :foo; end
>> end
=> nil
>> A.