15th - 21st August 2005

Ruby Weekly News is a summary of the week’s activity on the ruby-talk mailing list / the comp.lang.ruby newsgroup, brought to you by Tim Sutherland.

Articles and Announcements

  • Rails docs as a CHM file
  • Dema transformed the Rails documentation into the CHM format, as used by Windows Help.

    Bill Guindon: “Thx much! Bit spooky tho, just mentioned how much I liked chm docs to a partner the other day. Gotta check that phone for bugs.”

  • Next Maryland Ruby on Rails codefest August 15th 7pm
  • Jeff Waltzer annnounced the next Agile Maryland CodeProject code fest. (Held in Columbia, Maryland, U.S.)

    “For this meeting we will be attempting to generate mailing labels in PDF format using Test Driven Development.”

  • Instiki with SQL backend
  • Alex Verhovsky announced that wiki-implementation Instiki now has support for using ActiveRecord and SQLite. Until now it has only been able to run with WEBRick and the Madeleine persistence layer.

    The new backend will provide increased reliability and performance (once some tuning is done).

    Still need to do performance testing, refactor the database for speed, define indexes, implement some caching etc. In other words, all the “wizardry” bits. So, I thought maybe I can get some wizards with Rails production expertise interested to the point of getting involved at this stage.

  • Interview with Chris Harrop - making sure you can make sure the sun will be shining
  • In this week’s SciRuby interview, Ara.T.Howard and Justin Crawford talk to to Chris Harrop about how Ruby assists his efforts to improve the reliability of systems running weather and climate models.

    Chris works at the Cooperative Institute for Research in Environmental Sciences, University of Colorado.

Threads

Rio 0.3.3

Christopher Kleckner released a new version of Rio, with expanded support for CSV files.

“Rio is a Ruby I/O convenience class wrapping much of the functionality of IO, File and Dir.”

rio('/etc/passwd').csv(':').columns(0,2,4) > rio('rpt').csv("\t") 

The above example creates a tab-separated file containing the username, uid and realname for each user in the unix passwd file.

Ezra Zygmuntowicz: “This is a very nice library. Great docs too. I will use this heavily.”

YAENQ: Variable as a pattern

basi: “How do I tell Ruby to use the content of a variable as the pattern, rather than interpreting the variable name as a literal?”

The aim was to do something like the following, but with v “interepreted not as a literal but as a variable name”,

v = "aeiou" 
"goodness" =~ /[v]/

Adam Sanderson said that the same interpolation that is used in string literals also works for regular expressions. So the answer is simply

"goodness" =~ /[#{v}]/

The change is the use of #{v} instead of just v. As with strings, the contents of the #{} can be any expression, so #{'foo'*100} is just as valid as a simple variable substitution.

Installing MySQL Module on Windows?

Christopher Aldridge was having a “tuff time” getting the C extension mysql-ruby to work on Windows. (It allows Ruby to connect to a MySQL database server.)

Dema directed him untowards one of his blog entries, which includes a link to a binary for this extension.

Using it, you can simply drop a single file into your Ruby library directory without having to compile anything.

Alternatively, ruby-mysql is a pure-Ruby alternative, although it is about half the speed of mysql-ruby.

object pattern matching

Ara.T.Howard had been thinking about “how one would crawl an object graph to determine if it matched a specific object”.

A modified example:
  pattern = [ {}, {} ]

  object1 = [ { 'one' => 1 }, { 'two' => 2 } ]
  object2 = [ { 'one' => 1 } ]

  object1.is_shaped_like? pattern # => true
  object2.is_shaped_like? pattern # => false

James Britt murmured “Isn’t there a Ruby project that allows one to run regexen over object hierarchies?”

Phil Tomson said that the project is Reg, by Caleb Clausen.

Reg is a library for pattern matching in ruby data structures. Reg provides Regexp-like match and match-and-replace for all data structures (particularly Arrays, Objects, and Hashes), not just Strings.

Newbie:Differences between arrays

graham:

Quick question – I have 2 arrays, one which holds the list of people who had access to a system when I last checked (OLD), and and another which is the current list of people who should have access (NEW).

Is there some neat syntax in Ruby which would allow me to find the people added in NEW who are not in OLD, and then find the people in OLD who have need to be delete as they are not in NEW?

William James:
irb(main):005:0> %w(oldb newa newb) - %w(oldc oldb olda)
=> ["newa", "newb"]

irb(main):006:0> %w(oldc oldb olda) -  %w(oldb newa newb)
=> ["oldc", "olda"] 

any messaging frameworks in ruby

hsun wanted to know if Ruby has any messaging frameworks, similar to Java’s JMS.

Ara.T.Howard said to look at rb_spread, which allows Ruby to participate in “Spread reliable multicast groups”.

Brian McCallister said that he would shortly be releasing code that allows Ruby to act as a client with JMS.

Troubles with the installation of RAILS

Jan Meskens tried to install Rails on Ubuntu Linux, but got the error “uninitialized constant Base” upon running the rails command.

It turned out to be a problem with Ubuntu’s Rails package, which failed to include dependencies for some required libraries.

(Ubuntu is based on Debian, which used to split up Ruby’s standard library into many different optional packages. The current stable and development releases of Debian all do the right thing.)

Generic Parsing Library

Adam Sanderson wondered if there was a generic parsing library for Ruby.

RACC and Rockit were mentioned. They generate parsers from grammars.

For simpler requirements, James Edward Gray II’s new library Parse Input may be of interest.

“Parse Input is a library that aids in parsing generic input with Ruby. This isn’t intended to be a full-blown parser, but instead a chain-saw tool for data mining arbitrary inputs quickly and easily.”

Is there a simpler way to do this?

Julian Leviston was looking for a simpler way to do

file = File.open("/usr/blah/1.txt") do | file |
  while line = file.gets
    the_string += line
  end
end 
James Edward Gray II:
file_contents = File.read("/usr/blah/1.txt")
Austin Ziegler said that he prefers the following because it also allows a ‘filename’ that is a URL to a remote location.
require 'open-uri'
contents = open(filename, "rb") { |f| f.read }

Additionally, it’s “safe for text or binary files on all platforms” (thanks to the ‘b’ for ‘binary’ in the second argument).

RExpect

entropic_rune wanted to know if anyone was using RExpect, as he was having problems getting it to run. (It is a library used for automating interactive console programs.)

James F. Hranicky said that he too had had problems, and had switched to using the pty and expect libraries, both of which are part of Ruby’s standard library.

He attached an example that uses pty with its own simple ‘expect’ equivalent.

Why and His Guide Mentioned...

James Edward Gray II observed that “Why the Lucky Stiff and The Poignant Guide to Ruby are mentioned multiple times in the recent IT Conversations podcast with Joel Spolsky.”

Julian Leviston: “What is why’s guide?”

Timothy Hunter: “You are in for a treat! http://poignantguide.net/ruby/”.

(X)emacs user unite!

Forrest Chang introduced a plan to “beef up” (x)emacs support for Ruby, including improvements to the refactoring browser, and the addition of code completion.

For the latter, Daniel Debertin directed attention to the ECB – Emacs Code Browser project.

It’s a code-browser that uses the Semantic engine underneath to provide intellisense-like features. If you’re using a language that’s supported by Semantic (c, c++, Java, Python, some others), ECB is a great tool.

Why is this germane to Ruby, you may ask? I’m 90% finished with a Semantic grammar for Ruby, and it will probably be released as part of Semantic in the near future. Which means you get completion, intellisense, and Class/Module/method mapping in ECB for free.

seek/sysseek 64 bit support under Windows

Adam tried to open a disk device in Windows, but couldn’t seek beyond 2 GB. The same did work in Linux.

Nobu said his large file patch solves this problem.

Adam thanked him, and asked why the patch hadn’t been merged into Ruby CVS. There was not (yet?) a reply.

gem & rdoc: How to avoid "Could not find main page name" warning when using gems?

Thomas: “When I automatically the rdoc documentation of a gem I made, I always get this error/warning. I know there is a rdoc command-line option for defining the main page when invoking rdoc from the command line. But how do I pass this option from via a gemspec?”

Chad Fowler directed him to the rdoc options section of the RubyGems documentation.

templating system

Horndude77 wondered if there were any general purpose templating systems for Ruby, suitable for generating HTML or LaTeX.

Devin Mullins motioned to ERb, which is part of Ruby’s standard library.

Paul added that the book Code Generation in Action by Jack Herrington includes many examples of ERb usage.

NEWBIE QUESTION: pattern with nil

basi was tired of typing

if a == "" or a == nil
if a != "" and a != nil

“I’m sure there is a Ruby way to do this.”

David A. Black said that you can “normalize” the object to a string: if a.to_s.empty? or unless a.to_s.empty?.

Wilson Bilkovich said that Rails defines the method Object#blank? as returning true for objects which are empty? (initially, or after strip), those which are zero?, and false/nil.

There was a long discussion on what nil? and empty? should mean.

$SAFE >= 2

Mark Volkmann quoted the Pickaxe as saying that setting $SAFE >= 2 “prohits loading program files from globally writable locations”.

Can somewhat clarify what counts as a “globally writable location”? In the context of Windows, does it mean that you can load program files from any directory of a local hard drive unless it is shared?

Konstantin Levinski explained that it has to do with file permissions: ‘globally writable’ means that any local user can modify the file.

(And therefore change it to have code that you don’t want to run.)

It has nothing to do with the possibility that the code is shared over some sort of network filesystem.

ruby-dev summary 26662-26760

Minero Aoki summarised the Japanese mailing list ruby-dev.

Included is reference to a patch by Tadashi Saito that roughly doubles the speed of calculations involving Fixnums (small integers).

It achieves this by reducing the number of Fixnum#coerce calls. “Matz accepted this patch.”

Case Expressions and Classes

Daniel Schierbeck asked why the following code displays ‘no’.

case :foo.class
  when Symbol then
    puts 'yes'
  else
    puts 'no'
end 

James Edward Gray II explained that case works by comparing objects with ===, and not == as you might assume. In this case it calls Symbol === :foo.class.

For classes, === checks whether the parameter is an instance of the class. :foo.class is Symbol, which is not an instance of Symbol, so Symbol === :foo.class is false.

“Put another way, you’re outsmarting Ruby’s very intelligent case statement. Let it do all the work:”

case :foo
  when Symbol
    puts 'yes'
  else
    puts 'no'
end 

Now :foo is an instance of Symbol, so Symbol ===:foo is true.

Ara.T.Howard gave a more detailed explanation of case, and included more examples of the sort of matches that can be performed:

case obj
  when String, Fixnum, Array
  when File
  when %r/foo/, %r/bar/
  else
end 

Sodoku Solver (#43)

This week’s Ruby Quiz comes from quiz-maestro James Edward Gray II. The task is to write a program that can solve Sodoku puzzles.

See also the SuDoku-X Solver thread.

Ruby Quiz is a weekly programming challenge for Ruby programmers in the spirit of the Perl Quiz of the Week. A new Ruby Quiz is sent to the Ruby Talk mailing list each Friday. (Watch for the [QUIZ] subject identifier.) After a 48 hour no-spoiler period has passed, everyone is invited to contribute solutions and/or discussion back to the list. The following Thursday a Summary will be sent to the list, discussing the quiz, solutions and discussion. The next day, the cycle begins again.

is there a shorter way to compare these 2 objects?

Lowell Kirsh asked if there was a simpler way to implement <=> in the following class:

class Foo
  attr_accessor :a, :b, :c, :d

  def <=>(rhs)
    if (@a <=> rhs.a) != 0
      @a <=> rhs
    elsif (@b <=> rhs.b) != 0
      @b <=> rhs.b
    elsif ....
    end
  end
end

(<=> is the ‘spaceship operator’, used to compare two objects for ordering. It returns -1, 0 or 1 depending on whether the first object is less than, equal to, or greater than the second.)

James Edward Gray II suggested:

def <=>( other )
  [@a, @b, @c, @d] <=> [other.a, other.b, other.c, other.d]
end

It works because Array#<=> compares its elements in lexicographical order. (i.e. the same way as Lowell was doing by hand in the first <=> definition.)

James also mentioned the Comparable mixin. Including Comparable in Foo will gain it methods such as Foo#==, Foo#> and Foo#between?.

Robert Klemme gave three alternative implementations of Foo#<=>, using the name of the fields and send, while Simon Kroeger proffered:

def <=>( other )
  (@a <=> other.a).nonzero? ||
  (@b <=> other.b).nonzero? ||
  (@c <=> other.c).nonzero? ||
  (@d <=> other.d)
end

This is an interesting solution because it uses the fact that nonzero? returns either nil or self. (Rather than false/true.)

"string"[0.."e"]

basi wanted to index a string via a pattern. The code below demonstrates the sort of behaviour that was desired, although it does not work:

"astring"[0../r/]     # "ast" 
"astring"[/ast/..-1]  # "ring" 

Joel VanderWerf set forth:

"astring"[/.*?(?=r)/]   # --> "ast" 
"astring"[/ast(.*)/, 1] # --> "ring" 

He explained, “The (?=r) is a lookahead operator that matches but does not consume characters. The numerical argument n=1 in the second example indicates that #[] should return the value of the n-th capture”.

The numerical argument could also be used to re-implement the first line without using the lookahead operator:
"astring"[/(.*?)r/, 1]   # --> "ast" 

As an alternative, William James said that you could instead use String#sub to remove the part of the string you don’t want to match.

"astring".sub(/r.*/,  '') # --> "ast" 
"astring".sub(/^ast/, '') # --> "ring"