Ruby

Using Ruby Classes In C# With IronRuby

9 commentsWritten on September 6th, 2010 by
Categories: IronRuby, Ruby

I wanted to see how easy or difficult it would be to use your own Ruby classes from C# through IronRuby. Turns out it's pretty easy to do so.

Suppose we have the following simple Ruby classes:

class Customer
  attr_reader :name
  attr_reader :email
  
  def initialize(name, email)
    @name = name
    @email = email
  end
end

class Product
  attr_reader :name
  attr_reader :price

  def initialize(name, price)
    @name = name
    @price = price
  end
end

class OrderItem
  attr_reader :product
  attr_reader :count

  def initialize(product, count)
    @product = product
    @count = count
  end
end

class Order
  attr_reader :customer
  attr_reader :date
  attr_reader :discount
  attr_reader :items
  
  def initialize(customer, discount, date)
    @customer = customer
    @discount = discount
    @date = date
    @items = []
  end
  
  def add_item(item)
    @items << item
  end
end

Each of those classes is located in its own file, but i've listed all of the code together here. Now, how hard or easy would it be to say, create an Order instance in C#?

It turns out to be pretty easy. It's pretty easy to start up a Ruby engine in .NET and have it execute some Ruby files. Now, i don't want to tell it to execute each file, so i create a bootstrap.rb file which contains the following code:

load 'product.rb'
load 'customer.rb'
load 'orderitem.rb'
load 'order.rb'

Obviously, this just loads each entity's file into the current scope.

Now, i can just do this in C#:

            var engine = Ruby.CreateEngine();
            engine.ExecuteFile("bootstrap.rb");
            dynamic ruby = engine.Runtime.Globals;

            dynamic customer = ruby.Customer.@new("Davy Brion", "davy@gmail.com");
            dynamic product1 = ruby.Product.@new("product1", 50);
            dynamic product2 = ruby.Product.@new("product2", 60);
            dynamic order = ruby.Order.@new(customer, null, DateTime.Now);

            order.add_item(ruby.OrderItem.@new(product1, 5));
            order.add_item(ruby.OrderItem.@new(product2, 5));

            var total = 0;
            foreach (dynamic item in order.items)
            {
                total += item.count * item.product.price;
            }

            Console.WriteLine("order total: " + total);
            Console.WriteLine();
            Console.WriteLine(order.inspect());

And the output of that is this:

order total: 550

#<Order:0x000005c @customer=#<Customer:0x0000056 @name='Davy Brion', @email='davy@gmail.com'>, @discount=nil, @date=9/5/2010 22:36:14, @items=[#<OrderItem:0x000005e @product=#<Product:0x0000058 @name='product1', @price=50>, @count=5>, #<OrderItem:0x0000060 @product=#<Product:0x000005a @name='product2', @price=60>, @count=5>]>

Not sure what you think of that, but i thought it was pretty impressive. I'd hoped that this would be possible, but i wasn't sure since most of the examples you see about IronRuby seem to be focused on using .NET types from Ruby code that is interpreted by IronRuby's interpreter. But given the flexibility that you have in Ruby when it comes to designing classes, i'm much more interested in using Ruby classes from C# code instead of the other way around.

Let's go over some parts of the code...

            var engine = Ruby.CreateEngine();
            engine.ExecuteFile("bootstrap.rb");
            dynamic ruby = engine.Runtime.Globals;

This is all you need to do to start the Ruby engine (no idea why they call it that but whatever) and execute our bootstrap.rb file so that our classes are defined. We then have access to IronRuby's top-level binding through the engine.Runtime.Globals property.

So now we can simply create instances of these classes like this:

            dynamic customer = ruby.Customer.@new("Davy Brion", "davy@gmail.com");
            dynamic product1 = ruby.Product.@new("product1", 50);
            dynamic product2 = ruby.Product.@new("product2", 60);
            dynamic order = ruby.Order.@new(customer, null, DateTime.Now);

It's too bad that we have to escape the 'new' method because the C# compiler should be capable of figuring out that we aren't using the new operator there. But other than that, i'm pretty happy with how this works.

            order.add_item(ruby.OrderItem.@new(product1, 5));
            order.add_item(ruby.OrderItem.@new(product2, 5));

As you can see, calling methods on the instances of our Ruby classes looks normal as well, except for the fact that those classes use the typical Ruby naming conventions instead of offering a typical .NET-looking AddItem method. We'll fix that later though ;)

            var total = 0;
            foreach (dynamic item in order.items)
            {
                total += item.count * item.product.price;
            }

Now this is actually cooler than it might appear on first sight. First of all, notice the lack of parentheses when we call order.items, item.count and item.product.price. Big deal, you use properties all the time right? Well, Ruby doesn't have properties... it just has methods and due to some of its rules you can write this in Ruby:

  count = item.count
  item.count = 5

Which is actually only syntactical sugar for what it really is:

  count = item.count()
  item.count=(5) # the method name actually is 'count='

The fact that using these methods as if they are properties in C# is a nice touch, though it only works for accessor methods which were defined with the attr_reader, attr_accessor and attr_writer methods in your Ruby classes. If you defined your own accessor methods, you will have to use parentheses when you call them in C#.

The other thing that i find pretty cool about that piece of code is that you can use the foreach statement to loop through the return value of the order.items method, which is a Ruby array. Not sure whether IronRuby implicitly wraps Ruby arrays as IEnumerables or if it does that with all Ruby types which mix in the Enumerable module, but whatever it is, it's cool.

All in all, it's pretty nice that we can easily create and use these instances of classes that we defined in Ruby. But i'm a big fan of sticking to the accepted naming guidelines for each language. In Ruby, each method is lowercased and optionally uses underscores instead of the capitalized pascal cased method names that we typically use in C#. And when you use CLR types in Ruby code that is running in IronRuby, you can indeed stick to Ruby's naming conventions and IronRuby will automatically 'translate' method calls like write_line to WriteLine. It would be cool if, for instance, we could do order.AddItem in the example above and that it would just be 'translated' to order.add_item. And of course, if we could use capitalized versions of the accessor methods then it would look like pretty typical .NET code apart from the call to the @new method.

With Ruby code, pretty much everything is possible so it shouldn't be a surprise that we can easily 'fix' the naming convention issue. Keep in mind though that the approach i'm going to show is quite crude, and there most likely is a better way that i haven't thought of yet. I just added the following code at the bottom of the bootstrap.rb file:

if defined? IronRuby
  def add_dotnet_friendly_method_aliases_for(klass)
    klass.public_instance_methods.each do |method|
      klass.instance_eval do
        dotnet_friendly_name = IronRuby::Clr::Name.unmangle(method)  
        alias_method dotnet_friendly_name, method unless dotnet_friendly_name.nil? # in this case, it's already a dotnet friendly name
      end
    end
  end

  add_dotnet_friendly_method_aliases_for Product
  add_dotnet_friendly_method_aliases_for Customer
  add_dotnet_friendly_method_aliases_for OrderItem
  add_dotnet_friendly_method_aliases_for Order
end

Since we only need to do this if we're running in IronRuby, we first check whether the IronRuby constant is defined. If it isn't there's no point in adding the .NET-friendly method aliases. If we are running in IronRuby, we just add a method alias for each public instance method of our 4 classes. Again, it's a crude solution, but it does enable us to write the following C# code:

            var engine = Ruby.CreateEngine();
            engine.ExecuteFile("bootstrap.rb");
            dynamic ruby = engine.Runtime.Globals;

            dynamic customer = ruby.Customer.@new("Davy Brion", "davy@gmail.com");
            dynamic product1 = ruby.Product.@new("product1", 50);
            dynamic product2 = ruby.Product.@new("product2", 60);
            dynamic order = ruby.Order.@new(customer, null, DateTime.Now);

            order.AddItem(ruby.OrderItem.@new(product1, 5));
            order.AddItem(ruby.OrderItem.@new(product2, 5));

            var total = 0;
            foreach (dynamic item in order.Items)
            {
                total += item.Count * item.Product.Price;
            }

            Console.WriteLine("order total: " + total);
            Console.WriteLine();
            Console.WriteLine(order.Inspect());

And it works just like you'd expect it to. So far, i'm pretty happy, and very impressed with IronRuby :)

Writing A Simple DSL

3 commentsWritten on September 4th, 2010 by
Categories: DSL, Ruby

Creating a DSL seems like a hard thing to do, right? While there are various interesting challenges that you'll need to deal with if you want to build and use a real DSL, the initial step of getting it working is actually a lot easier than you might think it is. I'm gonna walk you through the creation of a simple DSL, suitable for a domain that all of us have experience with. The domain is quite simple: describing entities, their properties and their relationships. Forget for a second that you could obviously get the exact same information from a set of class definitions. It's merely a technical exercise using a domain that we all know :)

One of the key questions that we need to ask ourselves is: what kind of concepts do we want to be able to describe with our DSL? In our case, we want to describe a model consisting of entities. Disregarding behavior for now, we can say that each entity will consist of properties. Properties could be regular properties, references to other Entities, or collections of other entities. Here's one way (of many, obviously) to model that in Ruby (since that language makes it very easy to define a DSL):

require 'forwardable'

class Model
  extend Forwardable
  
  def initialize
    @entities = []
  end

  def add_entity(entity)
    @entities << entity
  end
  
  def entity_for(name)
    @entities.detect { |entity| entity.name == name }
  end

  def_delegator :@entities, :each, :each_entity  
end

class Entity
  extend Forwardable

  attr_reader :name

  def initialize(name)
    @name = name
    @collections = []
    @properties = []
    @references = []
  end
  
  def add_collection(collection)
    @collections << collection
  end
  
  def add_property(property)
    @properties << property
  end
  
  def add_reference(reference)
    @references << reference
  end
  
  def identifier
    @properties.detect { |property| property.is_identifier? }
  end

  def_delegator :@collections, :each, :each_collection
  def_delegator :@properties, :each, :each_property
  def_delegator :@references, :each, :each_reference  
end

class Property
  attr_reader :name
  attr_reader :required
  attr_reader :type
  
  def self.new_identifier(name, type)
    self.new(name, type, false, true)
  end
  
  def initialize(name, type, required=false, is_identifier=false)
    @name = name
    @type = type
    @required = required
    @is_identifier = is_identifier
  end
  
  def is_identifier?
    @is_identifier
  end
end

class Reference
  attr_reader :name
  attr_reader :entity
  attr_reader :is_required
  
  def initialize(name, entity, is_required)
    @name = name
    @entity = entity
    @is_required = is_required
  end
end

class Reference
  attr_reader :name
  attr_reader :entity
  attr_reader :is_required
  
  def initialize(name, entity, is_required)
    @name = name
    @entity = entity
    @is_required = is_required
  end
end

class Collection
  attr_reader :name
  attr_reader :entity

  def initialize(name, entity)
    @name = name
    @entity = entity
  end
end

That gives us a simple, yet complete object model to describe entities, their properties and their relationships. The next question is: how do we define the DSL? Considering an Invoice entity, suppose we'd like to describe it in our DSL like this:

entity "Invoice"
identified_by "Id", :guid
must_reference "Customer"
must_have "Date", :date
can_have "Discount", :double
contains "Lines", "InvoiceLine"

This really tells us anything we need to know about this entity, and we could use this data for pretty much everything we want. There is no explicit or implicit link to any specific kind of technology, like say, a relational database, a document database, or some kind of databinding technology. We could transform or extend this data to suit whichever purpose we deem fit.

So now that we know how we want to describe our entities and their relationships, we can implement the language. As mentioned in the title of this post, this is the implementation of a simple DSL. It's just to illustrate an idea, and not an approach that is guaranteed to stand up to the real-world requirements that a DSL could face (and that depends on a case by case basis). So in this case, we're going to go with an implementation where each entity is described in its own file, and its filename must end with '_def.rb'. With that limitation in mind, we can do this:

require_relative 'application.rb'
require_relative 'entity.rb'
require_relative 'collection.rb'
require_relative 'property.rb'
require_relative 'reference.rb'

@model = Model.new

def entity(name)
  entity = Entity.new(name)
  @model.add_entity entity
  @current_entity = entity
end

def identified_by(name, type)
  @current_entity.add_property Property.new_identifier(name, type)
end

def must_have(name, type)
  has name, type, true
end

def can_have(name, type)
  has name, type, false
end

def must_reference(entity_name, name=nil)
  references entity_name, true, name
end

def can_reference(entity_name, name=nil)
  references entity_name, false, name
end

def contains(name, entity_name)
  referred_entity = @model.entity_for entity_name
  @current_entity.add_collection Collection.new(name, referred_entity)
end

def has(name, type, required=false)
  @current_entity.add_property Property.new(name, type, required)
end

def references(entity_name, is_required=false, name=nil)
  referred_entity = @model.entity_for entity_name
  name = entity_name if name.nil?
  @current_entity.add_reference Reference.new(name, entity_name, is_required)
end

Dir.glob('*_def.rb').each do |file| 
  @current_entity = nil
  load file
end

@model.each_entity do |entity|
  puts entity.name
  print_name = Proc.new { |item| puts "\t\t#{item.name}"}
  puts "\t has the following properties:"
  entity.each_property &print_name
  puts "\t has the following references:"
  entity.each_reference &print_name
  puts "\t has the following collections:"
  entity.each_collection &print_name
end

As you can see, we have 'global' method definitions (they're actually implicitly added to the Object class) which correspond with our language 'keywords'. Those method implementations use the model that we defined earlier to build a nice object graph based on what we describe through our DSL.

You'll notice that after the method definitions, you can see the following code:

Dir.glob('*_def.rb').each do |file| 
  @current_entity = nil
  load file
end

And that's the clue to this simple DSL: it loops through each file that matches the '*_def.rb' pattern, sets an instance variable named @current_entity (implicitly added to the current Object instance in this case) to nil, and then loads the current file in the loop. The load method (it might look like a keyword, but it's a method) executes the ruby code in the given file in place, meaning that it shares the same scope. In other words, the methods that we've defined here are accessible to our DSL declarations since those are executed within the same scope. And since those method implementations manipulate our domain model, we just built a simple 'language' to describe our entities, their properties and their relations.

Suppose we've got the following entity definitions (each would be in a separate file, but they are just listed all at once here):

entity "Customer"
identified_by "Id", :guid
must_have "Name", :string
can_have "Email", :string

entity "Product"
identified_by "Id", :guid
must_have "Name", :string
must_have "Price", :integer

entity "InvoiceLine"
identified_by "Id", :guid
must_reference "Product"
must_have "Count", :integer

entity "Invoice"
identified_by "Id", :guid
must_reference "Customer"
must_have "Date", :date
can_have "Discount", :double
contains "Lines", "InvoiceLine"

This describes a very small domain model consisting of 4 entities. In the code listed above, you may have noticed the following piece at the end:

@model.each_entity do |entity|
  puts entity.name
  print_name = Proc.new { |item| puts "\t\t#{item.name}"}
  puts "\t has the following properties:"
  entity.each_property &print_name
  puts "\t has the following references:"
  entity.each_reference &print_name
  puts "\t has the following collections:"
  entity.each_collection &print_name
end

Given the 4 described entities, running the code above results in the following output:

Customer
     has the following properties:
        Id
        Name
        Email
     has the following references:
     has the following collections:
Invoice
     has the following properties:
        Id
        Date
        Discount
     has the following references:
        Customer
     has the following collections:
        Lines
InvoiceLine
     has the following properties:
        Id
        Count
     has the following references:
        Product
     has the following collections:
Product
     has the following properties:
        Id
        Name
        Price
     has the following references:
     has the following collections:

So there you have it, we described our entities, their properties and their relationships in a very simple manner and those descriptions were interpreted and the data has been put into an object model that we can use for a variety of purposes if we wanted to. And there really are a lot of interesting things we can do with this, especially when keeping IronRuby in mind :)

First Impressions Of The Ruby Community

48 commentsWritten on August 31st, 2010 by
Categories: Opinions, Ruby

It's been about 3 weeks since i've started my Ruby journey. Obviously, i still have a lot to learn. And in order to keep learning, i'm subscribing to more Ruby-related blogs and i'm starting to follow more Ruby-related folks on Twitter. At the same time, i'm gradually unsubscribing from a lot of .NET blogs and have even un-followed some people on Twitter that i only followed for .NET related stuff.

The biggest difference that i've noticed so far is that the Ruby community is pretty much a lot like what the ALT.NET community always wanted to be. As far as i can tell so far, knowledge is being shared all the time. And this is generally done in good spirits without negativity or flamewars (save a few exceptions obviously). People genuinely seem to care about helping other people out and making sure that everyone improves. I privately contacted a few Ruby people out of the blue. They don't know me, and i didn't know them. I just happened to stumble upon their blogs or twitter profiles and i figured "what the hell... i'll just bother them with some questions". And you know what? Every single one of them has responded in a remarkably friendly way.

When i asked them about interesting resources to follow as a newbie Rubyist, they all gladly shared their suggestions. When i thanked them for it, they all replied stating that i should feel free to contact them if i had any more questions about whatever Ruby related. Seriously, can you imagine the few .NET heroes that we have responding to questions through email from people they don't even know like that? I can't. Hell, i know most of them don't respond like that. The few that do are still trying to earn their MVP award or are too worried about renewing their MVP status.

Now, i'm not saying that all is well in the Ruby/Rails world and that there are no arguments or that there isn't any negativity or anything like that. Because the negativity and the arguments are definitely there. The thing is, it just seems to happen at a much lower frequency than it does in the .NET world. Granted, the .NET world is probably one of the most unfriendliest of all but still, the difference is striking IMO.

A part of me hopes that i'm wrong about this and that in the end, there isn't really a substantial difference between the ruby community and the (previously ALT).NET community. Then again, another part of me hopes that what i'm seeing so far is indeed true and real. If only because that would mean that what i consider to be the ideal developer community indeed exists somewhere.

To summarize the difference: i'm sure some of you remember the infamous "Rails Is A Ghetto"-rant. Well, from what i can tell so far... if Ruby/Rails is a ghetto, then .NET is the trailer park.

‘eventpublisher’ Gem Now Available

No Comments »Written on August 28th, 2010 by
Categories: Ruby

For those of you liked the EventPublisher module that i've been talking about recently, it's now available as a gem. The code is hosted on github under the MIT license and you can download/install it with the following command:

gem install eventpublisher

After that, you just need to add the following to your ruby files in order to use it:

require 'eventpublisher'

First Experiences With RSpec/BDD

2 commentsWritten on August 27th, 2010 by
Categories: Ruby, testing

I wanted to write some tests for the EventPublisher Ruby module i've been playing around with, so i figured i'd just use RSpec for it since that appears to be the most popular testing library in the Ruby world. Now, in the .NET world i never really got into the whole BDD thing and i stuck with TDD because i was quite happy with the coverage that it gave me. In Ruby however, due to the whole dynamic environment i think it's more important to test functionality as completely as possible with as little knowledge as possible of implementation details while mocking/stubbing/faking as little as possible. That doesn't mean i wouldn't mock anything in Ruby tests... it just means that i would try to follow my own rules on the subject as much as possible, whereas in the .NET world many of us (myself included) probably go a little overboard with the whole mocking/stubbing/faking thing.

Something to keep in mind for the rest of this post: i did not write my tests first for this thing. I know, i know, test-first is better. I generally prefer to write my tests before my real code as well, but in this case, the EventPublisher code was the result of just some first time Ruby experiments, and since i'm pretty happy with the code i don't want to get rid of it just so i could do it "right" by re-writing it test-first. So these tests were not meant to drive the design, only to verify the correctness of the code. Also note that the tests are not complete yet. More should be added, but i thought i had enough to post here and hopefully collect some feedback from you guys/gals.

When i started with these tests for the EventPublisher module, i instinctively wanted to test on a too technical level, like i often do in .NET. For instance, i wrote a test that proved that when you called the subscribe method, that the passed in method was actually added to the Event instance that the EventPublisher uses. The thing is: if you use the EventPublisher, you never directly use Event instances. So why on earth should i even know about them in my tests, right? After all, they are an implementation detail. I had to switch my reasoning from "is the code doing what i, a software developer, think it should do?" to something along the lines of "what needs to happen when i trigger an event?". For instance, if i trigger an event, all i should care about is that the subscribed methods are called correctly and that they receive their arguments correctly. How that actually happens is something that i probably shouldn't care about at all in these tests.

I eventually ended up with the following:

class Publisher
    include EventPublisher
    event :my_first_event
    event :my_second_event
    
    def trigger_first_event(args)
        trigger :my_first_event, args
    end
    
    def trigger_second_event(arg1, arg2)
        trigger :my_second_event, arg1, arg2
    end
end

describe EventPublisher, ": triggering event" do
    before(:each) do
      @publisher = Publisher.new
    end

    it "should not fail without any subscribers" do
      @publisher.trigger_first_event "testing"
    end

    it "should pass single event arg correctly to subscribed method with one argument" do
        @args = nil
      def my_first_event_handler(args);
            @args = args
        end

        @publisher.subscribe :my_first_event, method(:my_first_event_handler)
        @publisher.trigger_first_event "testing!"
        @args.should == "testing!"
    end
    
    it "should pass multiple event args correctly to subscribed method with multiple arguments" do
        @args2_1, @args2_2 = nil, nil
        def my_second_event_handler(arg1, arg2)
            @args2_1, @args2_2 = arg1, arg2
        end
        
        @publisher.subscribe :my_second_event, method(:my_second_event_handler)
        @publisher.trigger_second_event "second", "event"
        @args2_1.should == "second"
        @args2_2.should == "event"
    end

    it "should pass single event arg correctly to subscribed block with one argument" do
        event_args = nil
        @publisher.subscribe(:my_first_event) { |args| event_args = args }
        @publisher.trigger_first_event "test"
      event_args.should == "test"
    end
    
    it "should pass multiple event args correctly to subscribed block with two arguments" do
      first_arg, second_arg = nil, nil
        @publisher.subscribe(:my_second_event) { |arg1,arg2| first_arg, second_arg = arg1, arg2 }
        @publisher.trigger_second_event "first", "second"
        first_arg.should == "first"
        second_arg.should == "second"
    end
    
    it "should call subscribed method once for each time it was subscribed" do
      @counter1 = 0
        def my_first_event_handler(args)
            @counter1 += 1
        end
        
        2.times { @publisher.subscribe :my_first_event, method(:my_first_event_handler) }
        @publisher.trigger_first_event "test"
        @counter1.should == 2
    end
    
    it "should call all subscribed methods" do
        @counter1, @counter2 = 0, 0
        def handler1(args)
            @counter1 += 1
        end
        
        def handler2(args)
            @counter2 += 1
        end
        
        @publisher.subscribe :my_first_event, method(:handler1)
        @publisher.subscribe :my_first_event, method(:handler2)
        @publisher.trigger_first_event "first_event"
        @counter1.should == 1
        @counter2.should == 1
    end
    
end

There are a couple of things i like about this. For starters, the output of running this code looks like this:

EventPublisher: triggering event should not fail without any subscribers should pass single event arg correctly to subscribed method with one argument should pass multiple event args correctly to subscribed method with multiple arguments should pass single event arg correctly to subscribed block with one argument should pass multiple event args correctly to subscribed block with two arguments should call subscribed method once for each time it was subscribed should call all subscribed methods

Anyone can read that and understand what kind of functionality is supported.

Another big benefit of these tests is that they contain zero knowledge of the actual implementation of the EventPublisher module. They merely initiate its functionality, and verify whether the expected behavior in the given functional context occurred. I could seriously refactor (or even rewrite) the actual EventPublisher code and i wouldn't have to change my tests as long as i don't change the name and arguments of the subscribe and trigger methods.

For now, i'm pretty happy with this style and organization of tests and will probably stick with it for a while in my Ruby coding. Unless one (or some) of you tell me how i can improve it :)