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
|
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.
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.
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.
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
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.
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.
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.
Posted by Matt Williams
This describes a hashing implementation within ksh.
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.
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.
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.
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.
Posted by Matt Williams
Tired of writing accessors for javascript objects? Here's a method for doing so. With metaprogramming, to boot.