RubyCOM Documentation

(such as it is)

 

License

RubyCOM was written by Ralph Mason (masonralph@yahoo.com) , it uses huge parts of Win32OLE by Masaki Suketa. You can find the latest information about this tool at www.oocities.org/masonralph

You are free to use RubyCOM how you like, just so long as you understand that anything bad that happens as a result of your use of this is entirely your fault and problem. If you don’t understand that please don’t use this software.

 

Install

An installer is coming, in the meantime copy all the files to a directory somewhere and then run regsvr32 RubyCOM.dll. You can also run install.bat do the same thing.

Overview.

RubyCOM allows ruby objects to be used from IDispatch hosting clients (eg VB) and Ruby to use IDispatch objects. Objects can be freely passed across the interface and created on either side (e.g. the VB side can create Ruby objects and Ruby can create com objects). Either side can hold and use objects from the other.

 

Creating Objects

Using RubyObjects from Com (example in VB)

The root object that RubyCOM exposes is the RubyCOM object.

You can use this object to Require ruby files and Create ruby object. The RubyCOM object has two functions and is a subclass of ‘Object’ These functions are CreateObject and Require

Eg

Set rc = CreateObject("RubyCOM.RubyCOM")

rc.Require("MyFile")

Set myObj = rc.CreateObject("MyObj")

You can also use other ruby style things like

Set myObj = rc.eval("MyObj.new") – This does the same thing

You can also pass parameters to CreateObject

? rc.CreateObject("String","This is passed to string.new!")

Creating Objects Directly

You can use the class registration tool to register your actual ruby classes as com objects in the registry. This automatically includes and creates an instance of the class by using a name from the register.

 

Eg

Set x = CreateObject("MyRubyApp.MyClass")

NOTE:Currently you need to add the registry entries by hand to support this, the tool is in progress.

Function Renaming.

Many Ruby functions are inaccessible to IDispatch clients due to their syntax. To allow access to these functions RubyCOM uses the following Rules

Is -> ?

If a function ends with a ? then you call it by preceding the name with Is

Thus empty? Becomes IsEmpty

Me -> !

If a function ends with and ! then you access it by using Me

Thus compact! Becomes compactMe

Uppercase first letters of a function or propertie name are always made lower.

Eg Empty becomes empty

There are many renamed functions

See Appendix A for More Rules - Search for 'Test Method Missing ( and function name conversion )

For any remaining functions that you can not access you can use ruby to help

Eg We want to call a function called _myfunc on myobj, so we ruby to create a proxy with a name we can use.

Myobj.instance_eval("def x_myfunc(*p) ; _myfunc(*p); end")

 

Win32OLE Compatibility

RubyCOM should be compatible with Win32OLE. However there will be cases where functions will work from RubyCOM that may not have worked from Win32OLE because RubyCOM fixes a method invocation bug that causes some IDispatch clients to fail the call with MEMBER NOT FOUND. Also as RubyCOM can pass objects across the interfaces there is no type that can not be marshalled by RubyCOM.

 

Other Notes

RubyCOM makes ‘inspect’ the default method for RubyObjects. This allow pretty simple debugging (from VB) using ? obj

 

Problems & Suggestions

I welcome all suggestions. I am interested also to know what you are using RubyCOM for and your experiences so I can improve it where necessary.

I may be able to assist with problems if I have time.

My email is masonralph@yahoo.com

 

Appendix A. Example code -

Dim rbyObject As Object
Private Sub Form_Load()

'RubyCom Test Harness
Dim obj1 As Object
Dim Obj2 As Object
Dim WinClass As Object
Dim MyClass As Object

Set obj1 = CreateObject("Ruby.Myclass")

obj1.x = 0
While (obj1.x < 1000)
    obj1.x = obj1.x + 1
Wend

a (obj1.x = 1000)

Set Obj2 = CreateObject("Ruby.Myclass")

a (obj1.Type = Obj2.Type) ' Call inspect on each type
a (obj1.Type Is Obj2.Type) ' Compare actual objects

'Test references & finding the same object
Set WinClass = obj1.eval("WIN32OLE")
Set MyClass = obj1.eval("Myclass")

a (WinClass.Type = MyClass.Type)
a (WinClass.Type Is MyClass.Type)
a (Not (WinClass Is MyClass))
a (obj1.Type Is MyClass)
a (Not (obj1.Type Is WinClass))

'Test calling back to other com objects Using Properties
obj1.x = Form1
a (obj1.instance_eval("@x.kind_of? WIN32OLE"))
Form1.Caption = ""
obj1.instance_eval ("@x.Caption='Test'")
a (Form1.Caption = "Test")
a (WinClass.IsKind_of(obj1.eval("Class")))
a (obj1.instance_eval("@x.Caption") = "Test")

'Test returned references
obj1.x = Obj2
obj1.x.x = "Test"
a (obj1.x.x = "Test")

'Test Is and Me and nil values
obj1.instance_eval ("def makexnil! ; @x=nil ; end")
a (Not obj1.x.IsNil)
a (Not (obj1.x Is Nothing))
obj1.MakexnilMe
a (obj1.x Is Nothing)
a (Not obj1.IsNil)

'Check out [] and []=
Set obj1 = obj1.eval("{}")
obj1("1") = True
obj1("2") = True
a (obj1("1") And obj1("2"))
a (obj1("3") Is Nothing)

'Test an array
k = obj1.eval("[1,2,3,3,4,5,5,5]")
a (k(0) = 1 And k(2) = 3 And k(4) = 4)
a (UBound(k) = 7)
obj1.instance_eval ("def a_test(x); x.uniq ; end")
k = obj1.a_test(k)
a (UBound(k) = 4)
a (k(0) = 1 And k(2) = 3 And k(4) = 5)

'Test multiple args
Set obj1 = obj1.instance_eval("Myclass.new()")
a (obj1.test(1, "test", 59) = "1 test 59")

'Test Calling back from Ruby to a local object using method calls
Set rbyObject = CreateObject("Ruby.Myclass")
rbyObject.instance_eval ("def add(x); @y=0 if @y.nil? ; @x.additem('Rby ' +x + (@y+=1).to_s ); end")
rbyObject.instance_eval ("def clear(); @x.Clear ; end")
rbyObject.x = List1 'List1 is a VB listbox object
rbyObject.Clear
rbyObject.Add ("1")
rbyObject.Add ("1")
rbyObject.Add ("1")
a (List1.ListCount = 3)
rbyObject.Clear
a (List1.ListCount = 0)


'Test Method Missing ( and function name conversion )
rbyObject.instance_eval ("def method_missing(x); x.id2name ; end ")
a (rbyObject.empty = "empty")
a (rbyObject.IsEmpty = "empty?")
a (rbyObject.EmptyMe = "empty!")
a (rbyObject.NoReallyEmptyMe = "noReallyEmpty!")

a (rbyObject.xor_ = "^")
a (rbyObject.and_ = "&")
a (rbyObject.or_ = "|")
a (rbyObject.plus_ = "+")
a (rbyObject.minus_ = "-")
a (rbyObject.times_ = "*")
a (rbyObject.div_ = "/")
a (rbyObject.mod_ = "%")
a (rbyObject.greater_ = ">")
a (rbyObject.less_ = "<")
a (rbyObject.greatereql_ = ">=")
a (rbyObject.lesseql_ = "<=")
a (rbyObject.compare_ = "<=>")
a (rbyObject.insert_ = "<<")
a (rbyObject.extract_ = ">>")
a (rbyObject.match_ = "~")

rbyObject.instance_eval ("def ==(x); '==' ; end ")
rbyObject.instance_eval ("def ===(x); '===' ; end ")
rbyObject.instance_eval ("def =~(x); '=~' ; end ")

a (rbyObject.eqleql_(1) = "==")
a (rbyObject.eqleqleql_(1) = "===")
a (rbyObject.eqlmatch_(1) = "=~")


'Call renamed method on a real class
Set obj1 = obj1.eval("/regex/")
a (obj1.eqlmatch_("regex") = 0)

'Setup for the button push test
Set rbyObject = CreateObject("Ruby.Myclass")
rbyObject.x = List1
rbyObject.instance_eval ("def add(x); @y=0 if @y.nil? ; @x.additem('Rby ' +x + (@y+=1).to_s ); end")

End Sub


Sub a(x As Boolean)
    If Not x Then
        MsgBox "Assertion Failed"
        Debug.Assert (False)
    End If
End Sub



Private Sub Command1_Click()
    rbyObject.Add Text1.Text
End Sub