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/masonralphYou 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 -
DimrbyObject 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
Suba(x As Boolean) If Not x Then MsgBox "Assertion Failed" Debug.Assert (False) End If End Sub
Private SubCommand1_Click() rbyObject.Add Text1.Text End Sub