RubyCLR and Visual Basic - Part 1

 

Over the last week I've had a chance to play around with RubyCLR (John Lam is the brains behind it - what an awesome project!). I thought that I would post some thoughts around it and some "tutorial" like articles since the documentation was a bit scarce and it took me a while to figure out certain things that I hope will help you in your quest to connect Ruby with CLR objects.

 

I'll be working with Visual Basic since I think there are some really cool things in VB that should make it easier to work with Ruby classes, but John hasn't implemented them yet; I will have a separate post with some requests to follow.

 

I will assume that you have downloaded RubyCLR and Ruby itself, and followed the instructions to get it to work. I was able to get it to work by using Ruby 1.8.4 and the 1.8.4 sources.

 

I've also included a zip file with the VB sources and the ruby source.

 

The application that we are going to build (trivial application, just to demonstrate how things work) will have the ruby script call a method in a class in VB. Then, the ruby script will create an instance of it's own class, pass it to VB, and have VB call a method on it.

 

Calling a VB function

 

This first part is pretty trivial. The following code is the VB method we will call:

 

Public Sub DoAction( x as String, i as Integer )

    Console.WriteLine( "You gave me a string {0} and an integer {1}", x, i )

End Sub

 

In Ruby, we simply do the following:

 

vbclass = Sample::Sample.new

vbclass.DoAction( "tim", 10 )

 

Getting VB to call a method in a Ruby class

 

This part was more challenging. I had to dig through a bunch of stuff in order to figure it out. The current implementation of RubyCLR only exposes Ruby methods that match an interface declared in .NET. This s one of the things I will ask John about in my next post.

 

Here's the .NET interface I compiled with my VB assembly:

 

Public Interface IRubyCallable

    sub Go()

    sub Go2(x)

End Interface

 

Here's the Ruby class. I will comment on it below.

 

class RubyClass

    include RubyClr::Bindable

 

    def clr_interfaces

        ['Sample.IRubyCallable']

    end

 

    def get_binding_context

        ['X']

    end

 

    def X

    end

 

    def go

        puts 'We are go!'

    end

 

    def go2( x )

        print 'We are go with x = ', x

    end

end

 

First of all, you need to include the RubyClr::Bindable mixin. This will cause the RubyCLR to consider this class for .NET bridging.

 

You need a method called "clr_interfaces" which returns an array of qualified interface names that this class implements. RubyCLR will expose the methods on these interfaces to the .NET object.

 

You need a method called "get_binding_context" which returns an array of property names in the current class. The current implementation of RubyCLR requires this even if you don't want a property exposed; I just put a dummy property name.

 

Finally, you implement the two interface methods.

 

Here's the VB code to consume:

 

Public Sub CallRuby( x as Object )

    Console.WriteLine( "Try to call a method on object..." )

    x.Go()

    x.Go2( 10 )

End Sub

 

Notice that I'm using the late binding feature in VB, rather then typing to the interface. This is one thing that I think John can do to make the VB experience better; exposing all methods in any Bindable Ruby class, and letting the VB late binder resolve method calls at runtime. I will post more on these thoughts later.

 

Now, if you run the Ruby script, you should see the two statements outputted to your console. It took me way too long to get this working, so I hope that this will help you on your way to Ruby+VB+C# bliss.

sample.zip