Skip to content

Ruby Blender

  • Blog
  • About
  • Archives
  • Log in
 
Less
More
Trim
Untrim
« Older
Home
Loading
Newer »
Tag Archive for 'ruby'
01Sep09 Default values for Attributes
metaprogramming programming ruby
0 Comments

This is the first in a series of entries which I’m pulling over articles from an old blog, revising, etc…

The Problem

One of the neat things about Ruby is it’s ability to create accessor methods for you, by simply declaring attr_reader, attr_writer, or attr_accessor.  However, there’s not an easy way to define a default value for an attribute.  The original version of this code was based off of Create getter and setter on a valorized variable and ideas from Ruby Quiz #67: Metakoans.  The main difference between it and Sandro Paganotti’s version is that you can pass in a block which will be evaluated each time it is invoked (in case the value might depend on something else).  Additionally, it will work with boolean types.

The Solution

class Object
def self.attribute(*arg,&block)
(name, default) = arg
short_name = name.to_s.sub(/\?/,"")
self.send(:define_method, name) {
if instance_variables.include? "@#{short_name}"
self.instance_eval "@#{short_name}"
else
if block_given?
instance_eval &block
else
default
end
end
}
self.send(:define_method, "#{short_name}="){ |value|
self.instance_eval "@#{short_name} = value"
}
end
end

 

In order to use it, you could do something like this:

class Foo
attribute :bar
attribute(:fud) {instance_variables.include?("@bar") ? @bar : ' '}
attribute :fi, 10
attribute :flag?, true
end

And, in action, it would look like this:

>> f=Foo.new
=> #
>> f.bar # defined, but not set to anything (nil)
=> nil
>> f.fud # since bar is not defined, return an empty space
=> " "
>> f.fi # just return the default
=> 10
>> f.flag? # and here's a boolean
=> true
>> f.bar = 5 # now we set bar
=> 5
>> f.fud # Since bar is set, then fud will return its value
=> 5
>> f.fud = 20 # now we explicitly set fud, and the block is no longer used
=> 20
>> f.fud # fud returns 20 as expected
=> 20
>> f.bar # and, as expected, changing fud has no effect on bar
=> 5

 

There might be a better way to do this; but one of the things I love about Ruby is that you can add new features to the language very easily.

Enhanced by Zemanta
21Aug09 Arguments with Trollop
ruby rubygems
0 Comments

At various points in my life, I’ve used many methods of parsing command line options, from rolling my own, to using getopt or other libraries.  Recently I came across a new one which has its own view of how to parse commandline arguments.

Trollop is, as they put it, “Yet Another Fine CommandLine Argument Parsing Library” (YAFCLAP).  It’s goal is to be as easy as possible.  You can install it as a single file in lib, or use it as a gem.  Trollop doesn’t care.  To install, you can download it from rubyforge, or use the ever popular:

gem install trollop

(you may need to prepend sudo, or run it as root).

Let’s take a look at a simple example:

require 'rubygems'
require 'trollop'
opts = Trollop::options do
opt :host, "Host to connect to", :default => "localhost"
opt :port, "jmx remote port", :default => 4444
opt :interval, "How often do we poll (in seconds)", :default => 10
opt :count, "How many intervals, 0 == infinite, use ^C (SIGINT) to exit and write output", :default => 0
end
p opts

 

The first argument to opt is the name of the option.  We don’t have to specify a switch; it’s smart enough to figure out a mapping for them.  The second is a description of the argument.  You can specify a default value and/or a type.  In this example, we’ve specified defaults.  And here it is in use:

$ ruby trollop_simple.rb
{:interval=>10, :count=>0, :help=>false, :host=>"localhost", :port=>4444}
$ ruby trollop_simple.rb -h
Error: option '-h' needs a parameter.
Try --help for help.
$ ruby trollop_simple.rb --help
Options:
--host, -h : Host to connect to (default: localhost)
--port, -p : jmx remote port (default: 4444)
--interval, -i : How often do we poll (in seconds) (default: 10)
--count, -c : How many intervals, 0 == infinite, use ^C (SIGINT) to
exit and write output (default: 0)
--help, -e: Show this message

Notice that it has set up mappings for us as well as created a nicely formatted help — though it’s a default, without a lot of information.   Let’s add a version and usage:

require 'rubygems'
require 'trollop'
opts = Trollop::options do
version < "localhost"
opt :port, "jmx remote port", :default => 4444
opt :interval, "How often do we poll (in seconds)", :default => 10
opt :count, "How many intervals, 0 == infinite, use ^C (SIGINT) to exit and write output", :default => 0
end
p opts

Now let’s see what we have:

$ ruby trollop_simple.rb --help
jmx_mon is a program to monitor a jmx bean's value over time.
It can output the data as a csv, a graph in a pdf, or both.

Usage jmx_mon [options]
where [options] are:
--host, -h : Host to connect to (default: localhost)
--port, -p : jmx remote port (default: 4444)
--interval, -i : How often do we poll (in seconds) (default: 10)
--count, -c : How many intervals, 0 == infinite, use ^C (SIGINT) to
exit and write output (default: 0)
--version, -v: Print version and exit
--help, -e: Show this message

$ ruby trollop_simple.rb -v
jmx_mon -- we be jammin' with version zz9-za aka Arthur Dent
Don't forget your towel!

We now have a nicer usage, as well as version.  Also, it will stop automagickally if we ask for help or the version.

All of the options are placed in the opts hash; let’s see what we can do with it:

require 'rubygems'
require 'trollop'

aliases = {
:MEMORY_HEAP => "Heap memory usage, multiple values",
:MEMORY_HEAP_USED => "Used heap memory"
}

opts = Trollop::options do
version < "localhost"
opt :port, "jmx remote port", :default => 4444
opt :interval, "How often do we poll (in seconds)", :default => 10
opt :count, "How many intervals, 0 == infinite, use ^C (SIGINT) to exit and write output", :default => 0
opt :aliases, "Print defined bean aliases & exit.", :default => false
opt :towel, "Don't forget this!", :default => false
end

if opts[:aliases_given]
aliases.each_pair do |key, value|
puts "#{key}: #{value}"
end
exit
end

Trollop::die :towel, "You forgot your towel. You've been eaten by a Ravenous Bugblatter Beast of Traal" unless opts[:towel]

p opts

We’ve added two more options, one for printing out aliases, and another indicating whether or not you have your towel — with deadly results should you forget.

$ ruby trollop_simple.rb -a
MEMORY_HEAP: Heap memory usage, multiple values
MEMORY_HEAP_USED: Used heap memory

$ ruby trollop_simple.rb
Error: argument --towel You forgot your towel. You've been eaten by a Ravenous Bugblatter Beast of Traal.
Try --help for help.

There’s more that you can do with trollop; the website and documentation gives more examples.  However, I’d suggest considering trollop the next time you need to parse the command line.

 

 

Enhanced by Zemanta
20Aug09 Database Paranoia — ActiveRecord Callbacks
rails ruby
1 Comment

On a particular, nameless, heterogenous project using ruby on rails, ant, and shell scripts, there was an instance where data was not being properly cleaned before going into the database (primarily due to user errors in property files which were used by ant to feed the database).   As a result, the database was filled with extraneous spaces which were causing many issues.  A perfect illustration of GIGO.

One problem was that there were multiple databases, each with their own data.   By the time the issue was discovered, a fix was needed soonest, so the solution was less than elegant, but it does illustrate the use of callbacks in ActiveRecord:

module DbParanoia
# This is a really stupid thing to have to back-fit; it is making
# sure, however, that the users enter good data. We ensure that
# strings are stripped on read and write.

def trim_space
self.attributes.each do |attr|
attr.strip! if attr.instance_of? String
end
end

alias_method :after_find, :trim_space
alias_method :before_save, :trim_space
end

 

The above module is using the after_find and before_save callbacks to make sure that:

  1. Any spaces coming back from the database are trimmed.
  2. Any new records and/or updates will have the spaces trimmed.

You can use this method to perform pretty much any sort of validation or data manipulation of the data of an ActiveRecord class.  Other callbacks include:

  • after_create
  • after_destroy
  • after_save
  • after_update
  • after_validation
  • after_validation_on_create
  • after_validation_on_update
  • before_create
  • before_destroy
  • before_save
  • before_update
  • before_validation
  • before_validation_on_create
  • before_validation_on_update

You can read more about ActiveRecord::Callbacks at http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html.

Enhanced by Zemanta
19Aug09 Ruby Bindings and Scope
ruby
1 Comment

One of the features of Ruby’s Kernel module (which is imported into Object, so it’s available in every class) is the binding.  The binding allows you to keep a pointer to the scope at a particular location in your application and then later evaluate code from that location.

For example (and this came up as the result of a question on the ruby talk  mailing list), one of the things you can do is obtain a list of the local variables of a method:

def my_vars(a)
b=a
c=b+a
puts local_variables
end

 

returns the three variables, a, b, and c.  That’s fine, we’re still within the scope of the method.  But how about outside of our method?  This is where #binding and the Binding class come into play:

def outside(b)
puts eval("local_variables", b)
end

def my_vars(a)
b=a
c=b+a
outside(binding)
end

 

One thing to note: in order to work with the binding, we have to #eval code within its scope.  Thus the call to #eval with the method we are invoking and the binding.  This leads to the question from the mailing list:

we already have #has_block? to see if a block was passed. So how about
a #has_arguments? to query if _any_ arguments have been passed — Intransition

So how would we go about writing a #has_arguments? — here is a first stab:

class Object
def has_arguments?(b)
vars = eval("local_variables",b)
return false if vars.length == 0
vars.each do |v|
return false if eval("#{v}.nil?",b)
end
return true
end
end

class Foo
def initialize(first=nil)
if (has_arguments? binding)
puts "We're defined"
else
puts "Not!"
end
end
end

The only real drawback here is that we’ve got to pass in the binding itself.  Let’s try again:

class Object
def has_arguments?(&b)
vars = eval("local_variables",b.binding)
return false if vars.length == 0
vars.each do |v|
return false if eval("#{v}.nil?",b)
end
return true
end
end

class Foo
def initialize(first=nil)
if (has_arguments? {}) # note the empty block
puts "We're defined"
else
puts "Not!"
end
end
end

In this case, instead of explicitly calling #binding, we’re passing in an empty block — the block has it’s own scope, but it happens to contain the scope of then enclosing method.  It’s still not perfect, however:

  1. You need to pass in an empty block.
  2. It fails if you have local variables other than those passed in as arguments. (Pointed out by Joel VanderWerf)

Ok, it’s got some serious flaws (Charles Nutter posted a different way of solving the problem, which does work for all cases, and doesn’t use #binding).  But it does give an idea of what you can do with #binding.

Enhanced by Zemanta
18Aug09 What’s #method_missing missing?
ruby
2 Comments

#method_missing is a very useful part of the ruby language.  However, there’s one common mistake that developers make when using it.  They forget to add a call to #super.

Let’s take a look:

$ irb
>> class Foo
>> end
=> nil
>> f=Foo.new
=> #
>> f.i_do_not_exist
NoMethodError: undefined method `i_do_not_exist' for #
from (irb):5
>> class Foo
>> def method_missing(symbol,*args)
>> if (symbol.to_s === "i_do_not_exist")
>> puts "Yes, actually you do"
>> end
>> end
>> end
=> nil
>> f.i_do_not_exist
Yes, actually you do
=> nil
>> f.i_exist
=> nil

Unfortunately, we no longer get the error when we try to invoke a method which does not exist.  When we add an invocation to super, it’ll behave as expected:

>> class Foo
def method_missing(symbol,*args)
if (symbol.to_s === "i_do_not_exist")
puts "Yes, actually you do"
else
super
end
end
end
>> >> >> >> ?> >> >> >> => nil
>> f.i_exist
NoMethodError: undefined method `i_exist' for #
from (irb):31:in `method_missing'
from (irb):35
>> f.i_do_not_exist
Yes, actually you do
=> nil
>>

 

Enhanced by Zemanta
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
 
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