#define rubyfied 0

Posted by Matt Williams

Remember #defined FOO = 1; from your C days? Or public static int FOO = 1; from java? Well, I recently had reason to use this functionality within Ruby when I wanted to define a series of types which would each have a unique id used in a database, but I really didn't want to waste the space on a string.

I ended up with two methods, the first which takes a name and an enumerable, sets class variables for each element of an array (such as %w(The fat cat sat on a hat)) as well as a method for resolving an integer to a string.

Taking the following class:

1
2
3
4
5
6

require 'definer'
class Project
  define_class_types :states, %w(planning development testing production)
  define :myself, 1
end

you would have the following definitions:

  • Project.planning
  • Project.development
  • Project.testing
  • Project.prodution
  • Project.@@states(not accessible outside of class, but that's easily remedied)
  • Project.myself

Additionally, you would have a method Project.state_name(state) which would take a integer and return the string associated with that state. So, Project.state_name(0) or Project.state_name(Project.planning) would both return "planning".

In the define_class_types method, the name can be either pluralized or singular. The array of the types will be pluralized (as in states above) and the method for getting the string singularized (as in Project.state_name above.

There is one dependency -- it uses ActiveSupport's pluralize and singularize. The code follows below or you can download it here: definer.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

require 'active_support'

class Module
  def class_attr_reader(*symbols)
    symbols.each do |symbol|
      self.class.send(:define_method, symbol) do
        self.class_eval "@@#{symbol}"
      end
    end
  end

  def define(name,value)
    name = name.to_s
    class_variable_set("@@#{name}",value)
    class_attr_reader(name)
  end

  def add_class_types(name, types = [])
    name = name.to_s
    class_variable_set("@@#{name.pluralize}",types)
    types.each_with_index do |type, index|
      class_variable_set("@@#{type}", index)
      class_attr_reader(type)
    end
    self.class.send(:define_method,"#{name.singularize}_name") do |arg|
      self.class_eval "@@#{name.pluralize}[#{arg}]"
    end
  end
end

Order Matters! 2

Posted by Matt Williams

The order in which operations occur can often make a difference in Ruby:
1
2
3
4
5
6
7
8
9

$ irb
>> 5 * "a"
TypeError: String can't be coerced into Fixnum
  from (irb):1:in `*'
  from (irb):1
>> "a" * 5
=> "aaaaa"
>> 

The reason is quite simple — everything in Ruby is an object. The '*' behaves differently when applied to different objects (and, in fact, can be overridden). So, because the '*' method as implemented for Fixnum expects a number as its argument, and a String isn't a number, it complains. By the same token, the behaviour of '*' for String is for the string to repeat itself as many times as the argument specifies, it works.

Reconsidering Forth 0

Posted by Matt Williams

Recently I re-read Rick Cook's Wizard's Bane and The Wizardry Compiled. I strongly recommend that series to anyone who wishes to be a serious developer.

And I realized that I'd been missing out on a lot of fun lately. Ruby's become so dry and boring, it isn't funny. I really miss the days of having a function named corned_beef which uses such wondrous numbers as 65353. And stack based programming really is da-bomb! I remember all of the fun I used to have with it and have realized it's time to go back to it.

Gems Server

Posted by Matt Williams

Ever wonder how to view information about:
  • What ruby gems are installed?
  • Documentation for each gem?

rubygems has a built-in server which you can use to peruse the rdocs for a gem. To use it, type gem server at a prompt and then point your browser to href://localhost:8808.

It's pretty nifty.

Totally RAD Java Applications with Java Scripting Languages

Posted by Matt Williams

In January, 2008, this presentation was given at Code Mash. It talks about JSR223 and Java scripting languages to speed up Java development. This presentation was split into two parts -- the first is the presentation itself, and the second is building a rss feed aggregator which presents the feeds in a Treemap. There are three pieces:

  • The presentation itself: PDF
  • Instructions for building the demo application: PDF
  • A set of working demo files. To run this you will need to follow steps 1-6 in the instructions above. oat_mash.tgz

Ruby2Ruby

Posted by Matt Williams

Ruby2Ruby is a gem which allows you to look at the code of a class. To install do:
gem install ruby2ruby
(you may need to do a sudo in front of it)

Here's an example of its use:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

irb(main):001:0> require 'rubygems'
=> true
irb(main):002:0> require 'ruby2ruby'
=> true
irb(main):003:0> class Foo
irb(main):004:1> def fud
irb(main):005:2> puts "groo"
irb(main):006:2> end
irb(main):007:1> end
=> nil
irb(main):008:0> Ruby2Ruby.translate Foo
=> "class Foo < Object\n  def fud\n    puts(\"groo\")\n  end\nend"
irb(main):009:0> class Foo
irb(main):010:1> def fi
irb(main):011:2> puts "fo"
irb(main):012:2> end
irb(main):013:1> end
=> nil
irb(main):014:0> Ruby2Ruby.translate Foo
=> "class Foo < Object\n  def fi\n    puts(\"fo\")\n  end\n  \n  def fud\n    puts(\"groo\")\n  end\nend"
irb(main):015:0> class Foo
irb(main):016:1> def fud
irb(main):017:2> puts "Hello World!"
irb(main):018:2> end
irb(main):019:1> end
=> nil
irb(main):020:0> Ruby2Ruby.translate Foo
=> "class Foo < Object\n  def fi\n    puts(\"fo\")\n  end\n  \n  def fud\n    puts(\"Hello World!\")\n  end\nend"
irb(main):021:0>

Notice how it changes the class output. One thing I have found is that if you create instance variables outside of a method they won't show up in the output. Otherwise, it works quite well and is a good addition to a metaprogramming toolkit.

sub vs sub!

Posted by Matt Williams

sub does not do the same thing as sub!:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

irb(main):001:0> a="something"
=> "something"
irb(main):002:0> b=a.sub(/e/,"E")
=> "somEthing"
irb(main):003:0> b
=> "somEthing"
irb(main):004:0> a
=> "something"
irb(main):005:0> c=a.sub!(/thing/,"one")
=> "someone"
irb(main):006:0> c
=> "someone"
irb(main):007:0> a
=> "someone"
irb(main):008:0> b=a.sub(/thing/,"body")
=> "someone"
irb(main):009:0> b
=> "someone"
irb(main):010:0> c=a.sub!(/thing/,"body")
=> nil

They behave the same when there is a pattern matched and a change, however, when there is not a pattern matched they behave differently. This can cause grief as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13

irb(main):011:0> a="something"
=> "something"
irb(main):012:0> b=a.tr("n-za-m","a-z")
=> "fbzrguvat"
irb(main):013:0> b=a.sub(/thing/,"one").tr("n-za-m","a-z")
=> "fbzrbar"
irb(main):014:0> a
=> "something"
irb(main):015:0> b=a.sub!(/body/,"one").tr("n-za-m","a-z")
NoMethodError: undefined method `tr' for nil:NilClass
        from (irb):15
        from :0

This is the general behaviour of any method ending in !, so be careful when you are using them.

Super!

Posted by Matt Williams

One common mistake people make with ruby's method_missing is to leave out a super. This means that if you don't handle all the cases which could cause an invocation of method_missing then the exception will be lost. So, always include super, unless you have a good reason not to do so.

ksh hash

Posted by Matt Williams

This describes a hashing implementation within ksh.

My Methods

Posted by Matt Williams

Ever want an easy way to know what methods a particular object supports in ruby? This article discusses how you can do so.

Spellchecker pt 1: Soundex 0

Posted by Matt Williams

This is the first in a series of articles working toward creating a pure ruby spellchecker. It starts out by investigating the Soundex algorithm, presenting a couple of implementations, then goes from there to create a bucket-hash implementation of a spellchecker using the soundex algorithm for the hash key. This is from a challenge posted to the Columbus Ruby Brigade Mailing list.

Honing in on Dollar Words and Hidden Costs of Code

Posted by Matt Williams

Dollar Words are ones in which you replace each letter with a number and add up the sum of the letters -- a==1, b==2, and so forth, and the word's total == 100. "CAT" == 24, for instance, and "BUZZY" is 100, so it is a dollar word. I'm going to talk about honing in on solutions, as well as hidden costs (and shortcomings!) associated with each one.

class_attr_lookup

Posted by Matt Williams

I had a situation where I had configuration and/or control values in a database and I didn't want to have to read them over and over again, so I've created the following.

Accessors in Javascript

Posted by Matt Williams

Tired of writing accessors for javascript objects? Here's a method for doing so. With metaprogramming, to boot.