Skip to content

Ruby Blender

  • Blog
  • About
  • Archives
  • Log in
 
Less
More
Trim
Untrim
« Older
Home
Loading
Newer »
Archive for February, 2009
23Feb09 Overriding operators: two dimensional arrays
programming ruby
1 Comment
A two-dimensional array stored as a one-dimens...
Image via Wikipedia

One of the neat things about ruby is that, in general, operators are methods, so they can be overridden.

When working with multidimensional arrays, some languages allow you to do the following:

a[0,0]

whereas ruby uses:

a[0][0]

Which makes sense, since Ruby implements it as an array of arrays and you’re chaining methods to get to the element. But, since we can override the [] method, we can then say a[0,0].

class Grid
attr_reader :cols, :rows

# initialize our grid and optionally prepopulate it.
# klass can behave in the following fashions:
# nil -- nil
# a value (like "", 0, true) -- that value
# a class which responds to new -- an instance of that class
def initialize(rows=1, cols=1, klass = nil)
@rows = rows
@cols = cols
@grid = (0 ... @rows).collect do |y|
(0 ... @cols).collect do |x|
if klass.nil? then
nil
elsif klass.respond_to? :new
klass.new
else
klass
end
end
end
end

# This method allows us to say +grid[x, y]+ instead of +grid[y][x]+
def [](x, y=nil)
(x,y) = x if x.instance_of? Array
@grid[y][x]
end

# This method allows us to set the value of a grid grid entry via
# +grid[x, y]+ instead of +grid[y][x]+
def []=(*args)
if (args[0].instance_of? Array)
((x, y),value) = args
else
(x,y,value) = args
end
@grid[y][x] = value
end

end

So, it can be used like this:

$ irb
>> require 'grid'
=> true
>> g=Grid.new
=> #< Grid:0xb747d760 @cols=1, @rows=1, @grid=[[nil]] >
>> g=Grid.new(2,2)
=> #< Grid:0xb747bb04 @cols=2, @rows=2, @grid=[[nil, nil], [nil, nil]] >
>> g=Grid.new(2,2,0)
=> #< Grid:0xb7479aac @cols=2, @rows=2, @grid=[[0, 0], [0, 0]] >
>> g=Grid.new(2,2,String)
=> #< Grid:0xb7477810 @cols=2, @rows=2, @grid=[["", ""], ["", ""]] >
>> g=Grid.new(2,2,false)
=> #< Grid:0xb74755d8 @cols=2, @rows=2, @grid=[[false, false], [false, false]] >
>> g[0,0]
=> false
>> g[0,0]=true
=> true
>> g
=> #< Grid:0xb74755d8 @cols=2, @rows=2, @grid=[[true, false], [false, false]] >

It’s an interesting technique — and given that most people think of arrays/coordinates in pairs, I think that it can make the code more “readable”.

Enhanced by Zemanta
20Feb09 To Paren, or not to Paren
programming ruby
2 Comments

To paren, or not to paren: that is the question:

Whether ’tis nobler in the mind to suffer

The bugs and errors of maintenance programs,

Or to take arms against a host of typos,

And by debugging end them? To hack: to slash;

No more; and by a slash to say we end

The heart-ache and the thousand natural shocks

Of cut and paste code, ’tis a maturation

Devoutly to be wished. To hack, not slash;

Not slash: perchance to code: ay, there’s the rub;

For in that new programme what code may come

When we have shuffled off this unix box,

Must give us pause: there’s the respect

That makes wuffy of so long life;

— Not William Shakespeare

There’s been a good deal of conversation of late on comp.lang.ruby as to whether or not to use parentheses. And when to use them. Ruby is such that parentheses are optional, except, of course, when they’re not. Here’s some examples of where they are not:

irb(main):002:0> "parenthesis".length()
=> 11
irb(main):003:0> "parenthesis".length
=> 11

...

irb(main):009:0> class Foo
irb(main):010:1> attr_accessor :bar, :groo
irb(main):011:1> attr_reader(:gruff)
irb(main):012:1> end
=> nil
irb(main):013:0> f=Foo.new
=> #
irb(main):014:0> f.gruff
=> nil
irb(main):015:0> f.bar
=> nil

Notice that Ruby also doesn’t care if you use parenthesis or not for the arguments; in this case it doesn’t matter whether or not the parenthesis are there, because the meaning is clear, at least to the compiler. And now, for something completely different, an instance where meaning is not clear to the compiler.

irb(main):016:0> class Foo
irb(main):017:1> def fud(thing)
irb(main):018:2> thing.reverse
irb(main):019:2> end
irb(main):020:1> end
=> nil
irb(main):021:0> f.fud "hi"
=> "ih"
irb(main):022:0> f.fud "hi" ? true : false
(irb):22: warning: string literal in condition
NoMethodError: undefined method `reverse' for true:TrueClass
from (irb):18:in `fud'
from (irb):22
from /usr2/jest/tools//lib/ruby/site_ruby/1.8/rubygems/dependency.rb:19
irb(main):023:0> f.fud("hi") ? true : false
=> true

In the first instance, it is trying to evaluate
"hi" ? true : false
and then pass it to f.fud. This doesn’t work very well, since true does not have a reverse method. We’re running into an issue of order of operation. However, when we do
f.fud("hi") ? true : false
then we are successful. “hi” can be reversed and the result can be checked for non-nil-ness. In this (admittedly simplistic) example, the parenthesis were needed in order to achieve a satisfactory result.

In terms of background, I learned C 20 years ago. I cut my teeth on basic back in 1980. So I’ve been around for a little while. I mention this because several posters mentioned that one’s preference for using parenthesis may depend on one’s background, with those who come from C potentially more likely to use parenthesis whether they were needed or not.

I am of the opinion that parenthesis can make the code harder to read.
attr_accessor :first, :last
has_many :pets

is easier to my eyes and far easier to read as it mimics “natural” language than
attr_accessor(:first, :last)
has_many(:pets)

However, I realize that it is a personal choice. So my rule of thumb is to not use parenthesis, except where there is a question of clarity. I think that writing clear, maintainable code is more important than adhering to a rule of always using parenthesis. I like that Ruby, like Unix, generally has more way than one to do a thing. I understand that there are people who prefer one way of doing a thing. For those people, there’s Python. I’m kidding, of course — you can adhere to doing things a single way, such as always using parenthesis, in Ruby. To me, however, it would lessen my enjoyment of the language. And I write code in Ruby because it makes me happy to do so.

So, what do you think? Is there a compelling reason to use parentheses?

Enhanced by Zemanta
19Feb09 my_methods revisited
programming ruby
0 Comments

In irbrc goodness, I touched briefly on my_methods, a method of discovering the methods of an object which are distinct from those inherited from Object. The method looks like this:

class Object
def my_methods
(self.methods - Object.methods).sort
end
end

I have since had the idea of extending it — now you can also choose to see only the methods which are implemented by an object’s Class. You can see it in use here (code at the end):
$ irb
>> class Object
>> def my_methods(_super=false)
>> _methods = (_super) ? self.class.superclass.new.methods : Object.methods
>> (self.methods – _methods).sort
>> end
>> end
=> nil
>> class Foo < String >> def fud
>> puts “fud”
>> end
>> end
=> nil
>> f=Foo.new
=> “”
>> f.my_methods
=> [“%”, “*”, “+”, “<<", "[]", "[]=", "all?", "any?", "between?", "capitalize", "capitalize!", "casecmp", "center", "chomp", "chomp!", "chop", "chop!", "collect", "concat", "count", "crypt", "delete", "delete!", "detect", "downcase", "downcase!", "dump", "each", "each_byte", "each_line", "each_with_index", "empty?", "entries", "find", "find_all", "fud", "grep", "gsub", "gsub!", "hex", "index", "inject", "insert", "intern", "is_binary_data?", "is_complex_yaml?", "length", "ljust", "lstrip", "lstrip!", "map", "match", "max", "member?", "min", "next", "next!", "oct", "partition", "reject", "replace", "reverse", "reverse!", "rindex", "rjust", "rstrip", "rstrip!", "scan", "select", "size", "slice", "slice!", "sort", "sort_by", "split", "squeeze", "squeeze!", "strip", "strip!", "strip_tags", "sub", "sub!", "succ", "succ!", "sum", "swapcase", "swapcase!", "to_f", "to_i", "to_str", "to_sym", "tr", "tr!", "tr_s", "tr_s!", "unpack", "upcase", "upcase!", "upto", "zip"] >> f.my_methods(true)
=> [“fud”]
>>

Here’s the promised code:
class Object
def my_methods(_super=false)
_methods = (_super) ? self.class.superclass.new.methods : Object.methods
(self.methods - _methods).sort
end
end

18Feb09 irbrc goodness
configuration programming ruby rubygems
2 Comments

Here’s my (current) .irbrc, with comments


# I am including gems in my irb session. Therefore, the next require
require 'rubygems'

# wirble is a wonderful gem which add nice features to irb
require 'wirble'

# Dr. Nic's useful helper gem. It makes it so you can say:
# foo.map_by_bar
# instead of having to say:
# foo.map{|f| f.bar}
# more to the point you can do
# people.map_by_first_and_last
# instead of
# people.map{|p| [p.first, p.last]}
require 'map_by_method'

# what_methods is a way to see which methods, when performed on an object, return a particular value:
# >> "hi".what? 'h'
# "hi".chop! == "h"
# "hi".chop == "h"
# => ["chop!", "chop"]
require 'what_methods'

# pretty print --> provides a "pretty" view of an object
require 'pp'

# auto indent irb; it's useful for when you're just experimenting
IRB.conf[:AUTO_INDENT]=true

# start wirble (with color)
Wirble.init
#Wirble.colorize

# What are the methods which belong only to an object, and not those inherited from Object
class Object
def my_methods
(self.methods - Object.methods).sort
end
end

# strip html tags from a string
class String
def strip_tags
self.gsub(/<\S[^><]*>/,"")
end
end

I’ve shown mine. Show me yours?

Here are links to the referenced rubygems:

  • what_methods
  • map_by_method
  • wirble
Enhanced by Zemanta
16Feb09 Why ||=?
mini-saga programming ruby
0 Comments

||= is a very useful technique in Ruby programming and is used like:
x ||= 5
It relies on nil evaluating as false. It works like this: a variable is equal to its value xor some other value. If the variable is nil, then the other value is used. Otherwise, it keeps its value.

irb(main):001:0> x ||= 5
=> 5
irb(main):002:0> x
=> 5
irb(main):003:0> y=2
=> 2
irb(main):004:0> y ||= 7
=> 2
irb(main):005:0> z
NameError: undefined local variable or method `z' for main:Object
from (irb):5
from :0
irb(main):006:0> z=nil
=> nil
irb(main):007:0> z ||= 3
=> 3
irb(main):008:0> m
NameError: undefined local variable or method `m' for main:Object
from (irb):8
from :0
irb(main):009:0> m ||= 1
=> 1
irb(main):010:0>

Enhanced by Zemanta
15Feb09 It went (that) way
mini-saga programming ruby
0 Comments
Logical and arithmetic rotate one bit left
Image via Wikipedia

Ruby supports operator overloading — operators behave as methods of an object. So, << behaves differently based on the context. Generally for anything other than bit shifting << means to append or concatenate, such as with a string or an array. Concatenate is generally faster than addition — new objects are not created.

matt:~$ irb
>> 32 << 3 => 256
>> "cat" << 'nip' => "catnip"
>> [0,2] << 2 => [0, 2, 2]

Enhanced by Zemanta
14Feb09 Open-uri makes for developer friendly I/O
mini-saga programming ruby
0 Comments
A Venn diagram of Uniform Resource Identifier ...
Image via Wikipedia

open-uri, a part of the standard Ruby distribution, makes opening and reading from a URI easy. With it, developers use familiar methods like open for performing I/O with URI’s.

require 'open-uri'
open("http://www.ruby-lang.org/") {|f|
f.each_line {|line| p line}
}

Contrast Net::HTTP which uses numerous methods to achieve the same effect.

require 'net/http'

url = URI.parse('http://www.example.com/index.html')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
puts res.body

An addon, SuperIO, adds more flexiblity in attempting to DTRT.

Enhanced by Zemanta
13Feb09 More on Mini-Sagas
administrivia mini-saga
0 Comments

While I’ve decided to limit the Mini Sagas to 50 words, I’ve decided to not count the words in code snippets. Why? I’ve written one and the 50 word limit, when code snippets are included is too constraining. It was extremely vague and didn’t begin to explain what was necessary.

13Feb09 Holy Ruby Methods, Batman!
mini-saga programming ruby
0 Comments

bang!Conventions are one of Ruby‘s nicest features, making it easier to read and maintain. One convention is that methods which may modify an object have a ‘!’ in their name, such as ‘chop!’, which indicates if there are no changes, then nil is returned. This can cause issues with method chaining.

Enhanced by Zemanta
13Feb09 Ruby Mini Sagas
administrivia ruby
0 Comments

Elsewhere I’ve written about mini-sagas. I’m setting a goal to write one about a ruby topic daily. It will limit me to fifty words. But there certainly can be a great deal of freedom arising through constraints. It’s been said, in fact, that Creativity loves constraints. Here’s to creative constraint!

Enhanced by Zemanta
 
Browse Archives ยป
  • administrivia (2)
  • configuration (1)
  • metaprogramming (1)
  • mini-saga (5)
  • programming (10)
  • rails (1)
  • ruby (15)
  • rubygems (2)
  • Uncategorized (1)
 

Recent Posts

  • Default values for Attributes
  • Arguments with Trollop
  • Database Paranoia — ActiveRecord Callbacks
  • Ruby Bindings and Scope
  • What’s #method_missing missing?

Search

Browse by Category

  • administrivia (2)
  • configuration (1)
  • metaprogramming (1)
  • mini-saga (5)
  • programming (10)
  • rails (1)
  • ruby (15)
  • rubygems (2)
  • Uncategorized (1)

Browse by Tag

  • ActiveRecord
  • binding
  • Command-line interface
  • gotcha
  • irb
  • irbc
  • Languages
  • Library
  • Local variable
  • metaprogramming
  • mini-saga
  • paradigm
  • philosophy
  • programming
  • rails
  • Recursion
  • ruby
  • rubygems
  • Ruby on Rails
  • scope
  • utilities

Browse by Month

  • September 2009 (1)
  • August 2009 (4)
  • April 2009 (1)
  • February 2009 (11)
 
 
  • Blog
  • About
  • Archives
  • Log in
 


Theme Design by Jay Kwong | Powered by WordPress and K2

 

Home Top Archives Entries FeedComments Feed