Aliasing Global Variables in Ruby

Posted by Jeremy Voorhis Thu, 05 Jul 2007 22:10:00 GMT

And while I am becoming quite the language lawyer, I should mention that Ruby’s alias statement treats global variables quite differently from other kinds of variables.

When aliasing global symbols, the global variable itself is aliased and not evaluated. The result is a true alias, not a copy, so you cannot modify the global and its alias independently.

This feature most likely exists solely for English.rb in the standard library. This being the case, see that file for examples.

no comments

Ruby's Hidden do {} while () Loop

Posted by Jeremy Voorhis Tue, 12 Jun 2007 22:13:00 GMT

I found the following snippet while reading the source for Tempfile#initialize in the Ruby core library:

begin
  tmpname = File.join(tmpdir, make_tmpname(basename, n))
  lock = tmpname + '.lock'
  n += 1
end while @@cleanlist.include?(tmpname) or
  File.exist?(lock) or File.exist?(tmpname)
At first glance, I assumed the while modifier would be evaluated before the contents of begin...end, but that is not the case. Observe:

>> begin
?>   puts "do {} while ()" 
>> end while false
do {} while ()
=> nil
As you would expect, the loop will continue to execute while the modifier is true.

>> n = 3
=> 3
>> begin
?>   puts n
>>   n -= 1
>> end while n > 0
3
2
1
=> nil
While I would be happy to never see this idiom again, begin...end is quite powerful. The following is a common idiom to memoize a one-liner method with no params:

def expensive
  @expensive ||= 2 + 2
end
Here is an ugly, but quick way to memoize something more complex:

def expensive
  @expensive ||=
    begin
      n = 99
      buf = "" 
      begin
        buf << "#{n} bottles of beer on the wall\n" 
        # ...
        n -= 1
      end while n > 0
      buf << "no more bottles of beer" 
    end
end

2 comments

Urlang

Posted by Jeremy Voorhis Tue, 29 May 2007 23:56:00 GMT

Some weeks ago, after discovering Rack, I took it upon myself to experiment with my own anti-framework in Ruby, using existing libraries whenever possible and filling in the blanks as I go. A vital piece of most web frameworks is the dispatcher – the module that delegates web requests to application code.

The basic premise of my design is to encode common data structures within the path of a url, and to lookup the appropriate action in a dispatch table. I don’t have a working dispatcher yet, but I do have this:

irb(main):002:0> UrlParser.parse("/foo/1,2,3/meep=fleem;fliffl=mumble,grumble/")
=> [["foo"], ["1", "2", "3"], {"meep"=>["fleem"], "fliffl"=>["mumble", "grumble"]}]

The simple language uses a slash to separate values, a comma to group them into a list, and equals and semi-colon together to create a hash. The values are returned as a list.

The next step is to determine the semantics of how an action is selected. My tastes would be satisfied by a very simple form of pattern matching, with this approximate syntax, mixing literals and types:

register(:module => PostsController, :action => :show,
         :path => ['posts', Integer], :method => GET)

Further refinements to the path language might include recognizing ints and floats, and distinguishing between array and scalar values.

If you find the idea interesting, or even terrible, I’d love to hear your thoughts on both the path language and the dispatching semantics.

p.s. No, I’m not actually calling this “Urlang”.

no comments

BingD'OH!

Posted by Jeremy Voorhis Fri, 18 May 2007 16:34:39 GMT

DHH keynote buzzword bingo

1 comment

Specifying Duck Types in Ruby

Posted by Jeremy Voorhis Thu, 03 May 2007 22:59:00 GMT

While prototyping a RESTful web service, I wrote the following code to allow Rails to parse a request’s parameters from a POST request containing JSON.


ActionController::Base.param_parsers[Mime::JSON] = JSON.method(:parse)

Unfortunately, it did not work, while the following code did:


ActionController::Base.param_parsers[Mime::JSON] = lambda { |data| JSON.parse(data) }

Theoretically, both of these should accomplish the same thing: assign an object that responds to the message call with an arity of 1 to Mime::JSON entry of the param_parsers hash. They lead to different results, however, because a case statement within the Rails HTTP request parsing code watches for an instance of Proc, instead of an object which responds to call.

As a proof of concept, I whipped up this DuckType class:


class DuckType
  def initialize(*args)
    @args = args
  end

  def ===(other)
    @args.all? { |arg| other.respond_to?(arg) }
  end
end
Now, we can replace this statement from cgi_methods.rb

case strategy = ActionController::Base.param_parsers[mime_type]
  when Proc
    strategy.call(raw_post_data)
  # snip...
end
with the following:

Callable = DuckType.new :call
case strategy = ActionController::Base.param_parsers[mime_type]
  when Callable
    strategy.call(raw_post_data)
  # snip...
end

As you can see, an instance of DuckType has a case comparison operator which asserts that all specified messages are supported, allowing you to focus on an object’s capabilities rather than its class.

My DuckType implementation in its current form is rather crude, but if enough people found this technique useful, I would consider properly packaging and extending it for general use.

9 comments

A compelling alternative to Hpricot

Posted by Jeremy Voorhis Tue, 10 Apr 2007 15:52:00 GMT

After re-reading Nat Pryce’s Scrapheap Challege writeup, I tried to see how easily I could answer a simple question with only lynx, grep and friends. It turns out to be even simpler than I suspected. For example, the following tells me that my average blog post receives 2.2 comments.


# iterate through 17 pages
page=1; until [ $page -eq 17 ] ; do
  lynx -dump "http://www.jvoorhis.com/articles/page/$page" | \
    egrep "([[:digit:]]+|no) comments?" | \
    sed -e "s/\[.*\]//g" -e "s/no/0/g" | \
    awk '{print $1}' >> comments.txt
  page=$(( page + 1 ))
done
avg comments.txt 


    
  

12 comments

Module#method_added

Posted by Jeremy Voorhis Sun, 08 Apr 2007 22:16:00 GMT

Two days ago, I discovered Module#method_added lurking about in the DRP library. Today, let’s take a look at what it does, along with an example implementation of multiple dispatch for Ruby objects.

Module#method_added accepts one parameter – a symbol allowing us to reference the method that was just defined in a class or module definition. We may do a number of things with only that method name – inspect the method, rename it, change its scope, or – in our case – register it with our multiple dispatch system.

The following code is both crude and simple: it allows us to define multimethods based on their arity, and does not support optional arguments or variable-length argument lists. It also only takes hold within the multi do ... end block. With a little extra work, the multi block could be eliminated, and missing features could be added. What is noteworthy is how reflective callbacks such as Module#method_added and Class#inherited make it possible to use the Ruby language to extend the Ruby language.


module Multi
  module Arity
    def method_added(name)
      if @__multi_def__
        @__multi_def__ = false # Disable method_added behavior while aliasing
        arity = instance_method(name).arity
        @__multi_methods__ |= [name]
        class_eval "private :#{name}; alias __multi__#{name}__#{arity} #{name}" 
        @__multi_def__ = true
      end
    end

    def multi
      @__multi_methods__ = []
      @__multi_def__ = true
      yield
      @__multi_def__ = false

      @__multi_methods__.each do |name|
        define_method(name) { |*args| send("__multi__#{name}__#{args.size}", *args) }
      end
    end
  end
end

if __FILE__ == $0
  require 'test/unit'

  class Example
    extend Multi::Arity
    multi do
      def hello
        "Hello, somebody" 
      end

      def hello(name)
        "Hello, #{name}" 
      end
    end
  end

  class MultiTest < Test::Unit::TestCase
    def test_dispatch
      ex = Example.new
      assert_equal "Hello, somebody", ex.hello()
      assert_equal "Hello, multimethods", ex.hello("multimethods")
    end
  end
end

4 comments

Genetic Madlibs

Posted by Jeremy Voorhis Fri, 06 Apr 2007 20:47:00 GMT

Inspired by the eigenclass language generator, I’ve thrown together an example of how it would be implemented with the Directed Ruby Programming library. Directed programming is an interesting hybrid of genetic programming and the recently discovered grammatical evolution technique which generates a program tree according to a grammar.

This example may not be very interesting for those familiar with evolutionary programming techniques, but it created a fun diversion, highlights how the DRP library is to be used, and shows a different solution for a language generator.


class DrpGenerator
  extend DRP::RuleEngine
  begin_rules
    def main() "#{hello}\n#{ex1}\n#{ex2}" end

    def hello() "Hello, #{somebody}!" end

    def somebody() "matz" end
    def somebody() "world" end

    def ex1() "This is a more #{adj1} #{example}." end

    def adj1() "complex" end
    def adj1() "elaborate" end

    def example() "example" end
    def example() "test" end

    def ex2() "Some simple sentence." end
    def ex2() "Another, involving harder stuff." end
    def ex2() "Another, involving a more complex #{exp}." end
    def ex2() "Yet another possibility; each one is chosen with an evolutionary algorithm." end

    def exp() "expression" end
    def exp() "disjunction" end
    def exp() example end
  end_rules
end

g = DrpGenerator.new
3.times { puts g.main }

Hello, matz!
This is a more elaborate example.
Another, involving a more complex disjunction.

Hello, world!
This is a more elaborate test.
Another, involving harder stuff.

Hello, world!
This is a more complex example.
Yet another possibility; each one is chosen with an evolutionary algorithm.

My DrpGenerator isn’t as readable or attractive as the eigenclass DSL, and multiple definitions of the same method will likely confuse most Rubyists at first glance, but makes it easy to see the underlying grammar.

3 comments

Older posts: 1 2 3 ... 18