Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Thursday, March 19, 2009

Ruby class method extensions

I have developed a liking to Ruby since I first started using it for automation and now I even started to use it at work for one conversion process. Unfortunately, there are some set backs I've found with Ruby, such as using the Time class. I think my disliking of using it is probably because I've been spoiled with the well developed C# one. It lacks a lot of useful things. However, since Ruby is dynamic, I could make some of the necessary changes myself.

I had to do some extensive operations with the Time class and even though it had a lot of features, it lacked the ones I used the most. It got so bad that at a point, I had to start using Ruby's method extension feature which helped to solve my problem to a great extent.

I would however, like to ask the Ruby developers to clean up their Time class (I am not the only one saying that, just do a google on Ruby's Time class and see what I mean).

To insert class methods is easy. Let me show you:

class Time
class << self
def some_method()
end
end
end

So now I can do this: Time.some_method()

This allows me to insert custom Time creation methods where I can specify a time zone offset along with the time data I want.

What about some instance methods? How can I add for instance a date() method where I can tell Time.now to just give me the date component? Adding a class method won't help here. This requires a little hack (in my opinion).

First the Module:

module TimeInstance
# Converts the time to UTC and converts it
# into epoch in milliseconds
def to_epoch_millis()
(to_f() * 1000.0).to_i()
end

# Gets only the Date component of the current
# time instance
def date()
Time.local(year, month, day, 0, 0, 0, 0)
end
end


And in the Time class:

class Time
...
class << include TimeInstance
end
end


Now I can say: Time.now.date()

Now whatever you add in the TimeInstance module, will be added to the Time class's instance method list. The only catch is, you can only call public methods from the Time class in your module.

But this solves my problem greatly.

Hope this has helped you.

Friday, January 30, 2009

OpenDialog in Ruby

I have encountered some issues trying to get Ruby to open up an Open Dialog Box.
I tried doing it the DL route but apparently there is some problem with Ruby properly creating the struct to be passed to the 'GetOpenFileNameA' function (at least, that's what I've encountered). But I have found a different way...

Fortunately for me, I have delved into AutoIT scripting which allows me to create an Open Dialog Box. So I then decided to write a simple script to pass all the necessary params to this application from Ruby (i.e. Dialog message and filter) and the AutoIT application returns the filename that is selected or nil if canceled.

AutoIT code:

If $CmdLine[0] < 1 Then
ConsoleWriteError("No arguments given")
Exit
EndIf

$op = $CmdLine[1]

Switch($op)
Case "open"
If $CmdLine[0] < 3 Then
ConsoleWriteError("open command requires message and filter arguments.")
Exit
EndIf

$msg = $CmdLine[2]
$filter = $CmdLine[3]
$selected = FileOpenDialog($msg, "", $filter, 1)

If @error Then
ConsoleWriteError("Open Dialog problem")
Exit
EndIf

ConsoleWrite($selected)
EndSwitch


Ruby code:

f = IO.popen("controls.exe open \"Select a file\" \"Text File(*.txt)\"")

puts f.gets


This seems to work nicely. A bit of a round-trip but allows you to get what you need.
For those who don't know, AutoIT is a Windows-based automation scripting system (console and GUI wise, see some of my AutoIT posts).

Cheers!

Thursday, May 01, 2008

Ruby and Win32 API

If you are using Ruby as an automation process rather than a development tool, you sometimes might want to use some of Windows' GUI controls, such as a message box or folder browser box. In those cases, you might want to try the DL library.

Some of you have read this post about OLE Automation and DL. In a way it is quite simple but it can take a while to get right, especially if you're a beginner like me. However, after some time I have managed to get my folder browser to work and I haven't found Ruby code on the web that does this yet.
However, I feel like it is rather simple to do and to find out how to make your own version, all you need to do is to see how people who wrote VB code do it.
Why? Because it is that straight forward, in fact, Ruby reduces the amount of lines of code to do it.

I must warn and say that doing this kind of programming requires excessive use of the Win32API docs (one form or another) and some skilled programming, especially in the C-language area, because you are interfacing to the actual C-functions from Ruby.

Many VB code snippets that does this, have referenced these 2 c-functions (from the shell32 DLL):
  • SHGetPathFromIDListA

  • SHBrowseForFolderA

They also require a structure to send data to the BrowseForFolder function.
Here is a site to get you started.

Why don't I just paste the code? Well, actually the method I wrote to bring up the dialog box, requires a whole Module and I would like to write my own Ruby module before I publish anything.
Yeah, I might sound like a bugger but hey, I have posted lots of lines of code on this site before so... take it like a man! ;)
The hardest part is creating a Ruby C-like structure from the VB structure, so I think I'll help you out on that one:

ptr = DL.malloc(DL.sizeof('LLSSLLLL'))
ptr.struct!('LLSSLLLL', :br_hOwner, :br_pidRoot, :br_displayName, :br_title,
:br_flags, :br_fn, :br_lparam, :br_iImage)

Now don't say I didn't give you anything! :D

For those who still don't know what all those L's and S's are for, it is basically saying "This is a Long integer type" or "This is a string type". Its to determine the size of the structure, but you know that there are other data-types so you need to dig in on your own regarding that.

Now there is one thing I'm having trouble with and it is the Open/Save File Dialog box. Aparently if you take the exact same data-types as the prescribed docs say, Ruby fails to bring it up. After hours of struggling, I decided to skip the VB code and look on the web if someone already did this, and to my "surprise", nobody has posted any code on this. Bummer! So I decided to have a look on the MSDN site, and BAM! I found my answer. The reason why Ruby didn't bring up my dialog box was due to the fact that Ruby created a structure that had a different size than what the function was expecting! So now I am trying to find out where, how and why.

I might post my code and findings at a later stage, for this is a necessary thing for Windows Ruby Automation Programmers, like me! ;)

Monday, March 31, 2008

Ruby, ruby, ruby ...

Yeah it's been a while since the last posting. I was lacking some inspiration on what to blog on or I was just too lazy or too busy to actually log in and blog on something that I wanted to, that is until now...

You might ask, whats up with the title? Well I remember the song written by a band called Keizer Chiefs (spelling) named: Ruby. Now that reminds me of the Ruby scripting language which lots of people on the web is going on about. A dynamic typed language with multiple ways of saying one thing.

I was among those who agreed that Ruby was stupid, until I wanted to do a few things in Windows which Python nor other scripting languages could offer (or easily accomplish), except Ruby. Some of us would mock the guy who presented a brief crash course in Ruby, saying that it is too dynamic for our taste and it would make debugging a nightmare, etc. but doing some code delving and with the latest Netbeans language addition, which is Ruby and Ruby on Rails of course, I started to see how cool Ruby actually is.
Usually I despised dynamic typed languages until I saw how it can increase productivity and coding speed for smallish scripts, which is what I wanted for automation.

"What kind of automation?" you may ask. Well ordinary and OLE automation. Sure AutoIT is great for GUI and other windows automation but the scripting language is very BASIC (pun intended) lacking structure and (as in, I need structures as in C or C++'s structures or atleast...) object orientation. With Ruby we have good OO support and with the 'win32ole' lib, you can kick VBA and do MS Office automation via Ruby instead. A good starting site is Ruby on Windows which covers Ruby automation in MS Office. I managed to convert Powerpoint slides to somewhat formatted Word docs via Ruby, just to give you an idea.

I think I'll post a couple of script snippets later on, on what I worked on with Ruby and AutoIT for others to see and for future reference.

Just to go back to Python, some of you might say that Python does have OLE automation... I had a look at it and it looked very nasty! I wouldn't touch it, unless I looked at the wrong files, and you need to download a library for Python to have OLE automation ability. With Ruby you use the OLE objects exactly as in VBA but within your Ruby context.

Currently I am trying to implement a few operations in Ruby to have Browse-For-Folder ability, Open-Dialog, and so on functionality by doing Windows API calls via the DL lib in Ruby. You can catch a quick course on DL here.

I hope this will help you as much as it helped me.
God Bless!