faithfulgeek.org

Agile web development

Evil Fun With IronRuby

June 17th, 2008

I was playing with IronRuby a bit last night while driving back from Columbus Ruby Brigade with Ken Adair. It started with wondering if it’s possible to .each on a .NET ArrayList (System.Collections.ArrayList) and iterate via a closure ala Ruby arrays. Here’s the result of my testing (testing/output via IR.cmd – IronRuby’s IRB – comments added later):


# Create a Ruby variable a and set it to a new instance of a .NET ArrayList
>>> $a = System::Collections::ArrayList.new
=> []
# Add the string "j" to the list
>>> $a << "j" 
=> ["j"]
# Add the number 1 to the list
>>> $a << 1
=> ["j", 1]
# Add the string "joe" to the list using ArrayList.
>>> $a.Add("joe")
=> 2
# Call each and print out each element using a closure
>>> $a.each { |i| puts i }
j
1
joe
=> ["j", 1, "joe"]

So to answer the question, yes, it does iterate via a closure just like in Ruby! As an added bonus, we also found out that the add operator (<<) works with ArrayList too! Very cool. The question is, how does this work? Is there a layer that adds these methods to ArrayList or is ArrayList simply mapped to a Ruby array under the covers?

So we decided to take this experiment one step further: one of the awesome features of Ruby is open classes. So, what happens when I try to open a .NET type?


>>> class System::String
... def say_hello
... "Hello " + self
... end
... end

In the above snippet we opened up System.String and defined a say_hello method. So what happens when we try to call it:


>>> "joe".say_hello
:0:in `Initialize': undefined local variable or method `say_hello' for joe:String (NoMethodError)

At first glance you might think that it didn’t work. However, this is actually expected because “joe” is an instance of a Ruby String not a .NET string. Now if we do this:


>>> "joe".ToString.say_hello
=> "Hello joe" 

Much better! So, somehow I can open System.String and add methods to it. Seems kind of evil to me. I wonder what the guidance will be around opening up .NET classes. Especially when you can’t even inherit from some of them in C#!

How to allow users to enter a dollar sign in money fields on a form using Rails

January 16th, 2008

Long title, but well worth the article:

[Update (3/27/2008): I have released this code as a plugin. Please see my entry announcing the acts_as_currency plugin.]

I’m still newbieish to Ruby on Rails. I recently had a form in which I had a field that took a monetary amount (let’s say, hourly rate). In the database (and therefore in ActiveRecord), we want to store that as a decimal type so we can perform calculations on it. However, on the front end we want the user to be able to enter $55. Unfortunately, this is not completely straightforward. Since ActiveRecord sees the type as a decimal, it will rip out the ’$’ and set anything after it to zero (0). Therefore, $55 becomes 0. That is no good! I played around with a few different ideas, trying to modify the validation of the attribute. While it seemed a good idea at the time, it did not work; this is because at the time we start validating, the salary attribute has already been cast to a decimal and we lost our data. After that I tried using a before_validation callback (thanks to Nate Klaiber for the idea), but that caused problems with my rspec test, because when I set the hourly_pay attribute it doesn’t revalidate, therefore the before_validation callback never fires.

meh.

Then I decided to consult my good friend, Google. I came across this gem from one of my tweeps, Joe O’Brien. After reading that, I was able to write:


    def hourly_pay=(hourly_pay)
        hourly_pay.gsub!(/^\$/, '') if hourly_pay =~ /^\$/
        write_attribute(:hourly_pay, hourly_pay)
    end

I reran my rspec tests, and all passed! Yay! However, I could have more currency fields in the future. Not to mention, this was a huge pain in the ass for me to figure out, and I want to save everyone else the hassle that I went through. Therefore, I used a little metaprogramming to create an acts_as_currency method for the model class:


1    class ActiveRecord::Base
2    
3           def self.acts_as_currency(*args)
4
5            args.each do |arg|
6                define_method arg.to_s + '=' do |currency_string|
7                    currency_string.gsub!(/^\$/, '') if currency_string =~ /^\$/
8                  write_attribute(arg, currency_string)
9             end
10                
11               end
12
13      end
14
15  end

Here is the line-by-line explanation, due to popular demand:

So line 1 redefines the ActiveRecord::Base class from which all ActiveRecord objects inherit.

Line 3 defines the acts_as_currency method as an instance method on the ActiveRecord::Base class. *args allows multiple arguments to be passed in a comma-delimited format.

Line 5 Loops through each argument, running the code inside do…end, with arg being the current argument in the loop.

Line 6 This is the real magic! define_method allows you to dynamically define a new method on whatever class you are currently working with. Here we use arg.to_s + '=', so in the case of our acts_as_currency :hourly_pay we are defining hourly_pay=(currency_string), which is a custom setter for the hourly_pay attribute. If we add more symbols ala acts_as_currency :hourly_pay, :tax_withheld then we’ll get more setters defined (tax_withheld=(currency_string)).

Line 7 This is the body of the method you are defining. In this case, we check if currency_string starts with $, and if so, strip it out.

Line 8 We then write this new value to the attribute already defined in the ActiveRecord model.

That’s it! Six (you read that right: 6! [that’s for you, Corso]) lines of code is all it took to add an innumerable amount of currency attributes to any ActiveRecord model. If you think you’ll have a need for it, download the code here (right-click | Save Link As…) and drop in the ‘lib’ folder of your Rails project. Eventually I may make a plugin out of it. Please note: I am not responsible for the behavior of this code in your environment; it is provided merely to help you if you can use it; if you have questions I will try to answer, but no promises :).

Anyway, with that out of the way, enjoy! If you have any suggestions, questions, whatever on this code, please comment!

Fun with Ruby.NET!

December 26th, 2007

I started really playing with the Gardens Point Ruby.NET compiler. I wrote a little script that shows the true coolness of Ruby.NET:


require 'mscorlib.dll'

#Using System.Console.WriteLine to print to the screen
System::Console.WriteLine "Hello World!" 

names = ['Joe', 'Katie', 'Bob', 'Sue', 'Ann']

names.each do |name| puts "Hello #{name}!" end

# Create a .NET ArrayList
list = System::Collections::ArrayList.new

# Add the Ruby array to the .NET ArrayList
list.AddRange names

# Iterate through ArrayList and print Hello, name to the screen using System.Console.WriteLine
0.upto list.Count-1 do |i|
  System::Console.WriteLine "Hello {0}!", list[i]
end

Enjoy!

Fun with method_missing

December 14th, 2007

If you know me, you probably know I’m learning Ruby. It’s an amazing language that just keeps getting better as I learn more. I recently started playing with method_missing, which is a method that is called when the message you are passing to a class does not exist. I wrote the following Hello World example tonight to print “Hello, ” followed by a name, in a unique way.


Hello.Joe # Prints Hello, Joe
Hello.Tom # Prints Hello, Tom
Hello.Katie # Prints Hello, Katie

The code that makes it work:


class Hello
    def self.method_missing(id, *args)
        return "Hello, #{id}" 
    end
end

Hope you and find this at least somewhat useful. If not, at least as much fun as I had writing it!

CLR String.Format in Ruby

December 8th, 2007

I love using String.Format instead of string concatenation in C#. It’s become one of my favorite functions. For those who don’t know C#, String.Format works like this:


String.Format("Hello, {0}, today's date is {1}!", "Joe", 
    DateTime.Now.ToShortDateString());  
    // <-- This will return "Hello, Joe, today's date is 12/8/2007!" 

I’ve been coding in Ruby quite a bit lately. I couldn’t find a similar function, so I wrote my own:

class String

    def self.format(format, *args)
        index = 0
        args.each do |arg|
            format.sub!("{#{index}}", arg)
            index = index + 1
        end
        format
    end

end
The most beautiful part of this is I can still type String.format as I did before. The Ruby String.format actually redefines the String class, allowing it to define the class method I created. This feature is included in C# 3.0, known as Extension Methods (I’m not sure what they call it in Ruby). I guess I should mention it’s been in Ruby since the beginning.

Anyway, now in my Ruby classes, I can type:

String.format "Hello, {0}, today's date is {1}", "Joe", Date::today 
    # <-- Returns "Hello, Joe, today's date is 12/8/2007", just like before

If you would like to be able to use String.Format in Ruby, feel free to add this method to your Ruby project! Also, if you have any questions or comments, please feel free to leave them in the comments section!

Update [12/10/2007]: I have since learned that I can use variables directly in strings with Ruby, for example “Hello, ${name}, today’s date is ${Date::today}”. This is yet another example of where the beauty of Ruby makes a major feature in .NET completely obsolete. I’ll definitely be doing some refactoring to get rid of my String.format.

A Mini Publishing Engine in Ruby

December 7th, 2007

Last weekend I wrote a mini publishing engine in Ruby. It’s very small, very basic, but it works, and that’s the important part. Best of all, it’s only 12 lines of code (including whitespace)! Check out the code, below:

Template:

<html>
    <head>
        <title>Test Page</title>
    </head>
    <body>
        ${body}    
    </body>
</html>

Publisher:

require 'ftools'

template = File.red('template.html').to_s

page_body = ARGV[0]

content = template.gsub(/\$\{body\}/, page_body)

File.open('index.html', File::CREAT|File::RDWR) {
    |f|
    f << content
}

So running

ruby RbPublisher.rb This is the body!
yeilds:

Output:

<html>
    <head>
        <title>Test Page</title>
    </head>
    <body>
        This is the body!    
    </body>
</html>

Pretty self explanatory. Takes in the body content on the command line, and pushes it into the template where I put the ${body} tag. This was a fun experiment, and we may use it on the CWSA website.

Questions/comments? Please leave any constructive criticism you may have! Enjoy!