"James B. Byrne" <ByrneJB / Harte-Lyne.ca> writes: > I have written my first live ruby script that actually performs useful > work as an exercise in syntax discovery. It is very much a straight > line utility that could just as easily be written in bash. What I would > like is for someone to look at the code reproduced below and guide me > through the steps to convert this into something approximating the ruby > OOP idiom. I come from a 4GL universe working on mid-range and high end > iron and OS rather than unix/linux and OOP. So, I have a major > challenge getting my head out of first gear. OOP is a different mindset. But given that you work on big iron, you might have an advantage that you don't know about. I find that when I describe OOP to people unfamiliar with it, it's easiest to understand if you start with the data, and add the methods later. Given that your universe revolves around data, this might not be so hard. > Looking at this I wondered what can be placed into separate classes. It > seems to me that the check for environment variables and defaluts and > then creating the resulting directory strings and regexp objects is > either one functional group or two, depending if one considers the > search for environmental settings totally separate from the directory > validation process or not. I tend to see two classes; GetDirs and > CheckDirs. Here, your focus is on what your code is *doing*. Think, instead, about what it *is*. That is, what data are you collecting, and what are you doing with it? I would argue that instead what you need is a Configuration object that stores data like, "What directories should I be fetching from which machines, and where should I put them?", and give that object methods like validate_directories() and so on. Then think of what other things you want to store data about. Say, your machines. You could define a Machine class that stored generic data, such as its name, location, and other generic info. You then could subclass that into HP3000, ZOS_box, and so on. Each of those would contain methods like get_file(), which would fetch a file from that machine to the local directory, and maybe reboot(), which would annoy everybody else using that machine. ;-) A very loose description might be something like this: class Configuration def initialize() # set all variables to their default values, # overriding with ENV vars as required. end def validate_directories() # ensure all directories you rely on are present end end class Machine def intialize(name, location) # set generic info about Machine here end end class HP3000 def initialize(name, location) super(); # let Machine handle this end def get_file(filename, destination) # do stuff to put filename on the hp3000 into # destination end end Notice again how my focus is on the nouns (what things *are*) as opposed to the verbs (what things *do*). Also notice that the verbs are attached to the thing that does them in most cases. You could make an argument that get_file doesn't belong with the HP3000, that it should be its own top-level subroutine. My reason for placing it there is this: there is probably a different procedure for each type of machine you deal with for getting files off of it. By putting the get_file() method in the machine-specific class, you are putting all the machine class-specific information in one place, instead of scattering it all around. My two major principles when breaking things down are: * What is the data? * What does it do? (In that order) > My difficulty is that I do not see how all this hangs together after the > classes and methods are written. Does the script end up as a ruby > module? A module is a chunk of code you want to re-use elsewhere. If this script is supposed to be invoked on its own, then no, you don't want to make it a module. You may, however, want to put the various classes you create into their own files so you can re-use them elsewhere. > Then what do I do? Do I have a "main" procedure below the class > definitions in the module? Any code you do not put in a method or other limited scope gets executed in the order you see it. So basically, there is no main(), you just start doing stuff (much as in a shell script). > I would really appreciate it if someone could invest the time to > walk me through this because once I see how to map what I presently > do to the ruby way I expect that many things I am unsure about will > suddenly become clear. I am particularly interested in how to redo > this so that Test::Unit can be used to drive it for testing. I'm in a bit of a rush right now, but maybe someone else will explain how a method such as I proposed makes it easy to test using Test::Unit-- otherwise, I'll get back to you later and try and explain it. -=Eric