Scripting in Ruby - ruby

I've developed a set of Ruby scripts. Each of them should be 'self-contained', so a user can run it on its own. But also I would like to use them to build other scripts, I mean for example to use its methods but also to run it as a whole, without doing ` script.rb`.
So far what I have is just a couple of scripts (separate files) where I have no classes, just a couple of methods. The processing of taking user input and running those methods is outside of any functions. I see that this model may be not right.
My question is, what should I do now to keep every script self contained but also to allow other scripts to use it? Should every script just contain a class with a main method that I would run object.main?
Or maybe my approach of writing a simple scripts, no classes is also good?
If I start a new script, should I always go the objective way?

When I write a one off script, I often wrap it in a class. You've pointed out some advantages of doing this including reuse and cleaner documentation.
I find that there are several levels of polish for scripts depending on how they are going to be used. If the script is run once and never used again, I may not wrap it in a class. If it's important (taking backups of production systems), it's probably worth putting it in full gem form and writing tests. Somewhere in the middle is the single purpose class. Generally this means you're taking the code that's not in a method and putting it in the class constructor.
This:
#!ruby
def amethod(i)
i+1
end
ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end
Becomes:
#!ruby
class OneAdder
def amethod(i)
i+1
end
def initialize
ARGF.each do |l|
if l.chomp.to_i > 0
puts amethod(l.chomp.to_i)
end
end
end
end
OneAdder.new

Related

How is called the feature that let's ruby execute code inside classes while interpreting the file

When I have the following ruby code
#file a.rb
class A
puts '2'
end
if I execute rb a.rb I get 2 printed onto the screen. This is because of the way ruby interprets the code, but, what is the name of this behavior?
The reason it prints something is because in the course of defining class A you asked it to. Anything inside a class block is treated as regular Ruby code, it's not special, so printing, exiting, making network connections, opening files, that all works as it would anywhere else.
This is in stark contrast to things like JavaScript and C++ where that is absolutely not allowed.
Ruby, being a dynamic programming language, has a lot more latitude. This permits things like defining methods based on input from files, or pretty much anything you can imagine.
The name of this behaviour is basically "evaluation", as in when Ruby evaluates that code, that is it parses and runs it.
This allows you to do things in Ruby not possible in other languages without employing macros, pre-processor tricks, or other techniques:
class A
if (Date.today.saturday? or Date.today.sunday?)
def party!
:on
end
end
end
Where that will only define the party! method when the code is run on a weekend.

Ruby require multiple files without knowing their class names

Let's say I have an Application that requires different files. Each file contains a single purpose "thing". I call it "thing" because I'm unsure if it will be a class or a module.
The First Thing
# things/one.rb
class One
def self.do_it
"I'm the one"
end
end
And the second
# things/two.rb
class Two
def self.do_it
"I'm not the only one!"
end
end
Now I wanna require all files in the thingsdirectory and execute the do_it method. But I wanna do this dynamically - for every thing in things folder without even knowing their Classname.
# app.rb
Dir["things/*.rb"].each {|file| require file }
Keep in Mind: I simply wanna execute the code in the things files - it's not necessary that they are Classes or Modules
You can't reliably do this for a number of reasons, but the most important is that you're under no obligations to declare a single class in any given file, or a class at all. You've got the right idea with loading in all files in a particular directory, but if you need to operate on those there's two ways to crack that nut.
The easiest way is to declare these classes as a subclass of some already known parent. ActiveSupport has the descendents method to reflect on a particular class, that's part of Rails, but you can also do it the hard way if you have to.
The second easiest way is to correlate the names with the classes in them, and then convert filenames to class-names algorithmically. This is how the Rails autoloader works. cat.rb contains Cat, bad_dog.rb contains BadDog and so on.
If you look more closely at how things like Test::Unit work they take the first approach, any declared test subclasses are executed before the Ruby process terminates. It's a fairly simple system that puts no constraints on what the files are called or where and how the classes are declared.
Rails leans towards the second approach where the path communicates intent. This makes finding files more predictable but requires more discipline on the part of the developer to conform to that standard.
They both have merit. Pick the one that works for your use case.

if __FILE__ == $0 break program when it's placed before any methods

I'm new to Ruby and am trying to understand a behavior that I've run into. I'm writing a class that needs some constants initialized before it can run, but when its run from another class, as it sometimes will be, I get warnings about constants already being defined. So I placed the following at the end of my file:
if __FILE__ == $0
constant_initialiation
ReviewScraper.new.getReviews($testing, $getWeekendReviews, $clearWorksheet, $getAll)
end
The constant_initialization is just a bunch of constants being set, nothing interesting. Anyway, this works great for me -- so long as its at the end of the file. If I move this up to the top and try running, I get an error: unitialized constant ReviewScraper (NameError). Almost as if it compiles sequentially for just this part of the file and isn't finding the ReviewScraper class definition when its run.
Can any Ruby geniuses explain this behavior to me? It's no big issue other than for styling purposes (I like having my list of constants up top), but it would be nice to understand what's going on here.
First off, I'll expand on my comments above as to what is going on. Secondly, I'll suggest perhaps a better way of setting your constants in code that avoids setting them multiple times.
As I mentioned, a Ruby script reads from top to bottom. So, if you try to instantiate a class before you define it, they the Ruby script won't know what it is.
cat = Cat.new # NameError
class Cat
# Code
end
cat = Cat.new # Works fine
The script first reads the line where you make a new Cat object. However, it doesn't know what a Cat is yet. Once it is done processing the code for what a Cat is, then it can create one. I used the example of talking to someone about Darth Vader but it is probably more akin to asking a construction company to build your building before you've ever handed them a blueprint. It is only after they have the blueprint that they can build a your building.
Now, in regards to initializing constants, there are a couple different things you could do. One is, you could put the initializations in a if block much like you did at the top but leave out the instantiating of the class until the end of the script. (Two if statements.) Another would be to put the constants in a module in its own file.
module Names
Dog = "Spot"
Cat = "Sparkles"
end
Now you just require that file wherever you need it. In file_one.rb you put
require_relative './modules/names_module.rb' # Or wherever it is
include Names
You put the same thing in your Review Scraper file. Here's the cool part: if you require the Names module once, it'll be brought into the code. However, if you require it a second time nothing will happen. You won't get warnings. It'll just quietly not require it a second time. One top of that, all your constants are in their own namespace.
Just a thought.

Guard Ruby classes with class-level metaprogramming against multiple loads

A quirk of Ruby's require is that, while in general, it will only load a file once, if that file is accessible via multiple paths (e.g. symlinks), it can be required multiple times. This causes problems when there are things like class-level metaprogramming, or in general a code that should only be executed once on file loading, getting executed multiple times.
Is there any way, from inside a Ruby class definition, to tell whether the class has been defined before? I thought defined? or Object.const_get might tell me, but from those it looks like the class is defined as soon as it's opened.
This is not an answer to your question in the second paragraph, but a solution to the issue in your first paragraph. Actually, you cannot avoid multiple file loads by checking whether a class was defined already.
Instead of doing:
require some_file_name
do:
require File.realpath(some_file_name)
By doing so, different symbolic links pointing to the same real file would be normalized to the same real file name, and hence multiple loading of them would be correctly filtered by require.
Cf. this question and the answer given there.
The real solution is that requiring that a piece of code is only executed once is bad design and you should fix that.
However, what you could do is simply set some flag that the code has already been executed and check that flag. E.g.:
class Foo
unless #__executed__
def bla; end
puts 'Test'
end
#__executed__ = true
end

Structure of Ruby Programs

I need some insight into the construction of Ruby programs. I'm trying to learn how to write Ruby (independent of Rails) so I'm translating some Perl scripts I wrote in a bioinformtatics project into Ruby code. Basically creating classes where useful and whatnot.
My issue is how do I execute it? The Perl scripts are just long blocks of commands, one after the other. What's appropriate in Ruby? Should I define my classes in their own .rb files and call those and their methods in a sepearate rb file that sort of uses them to execute my program?
What is normally done? Any examples would be greatly apreciated. I'd also appreciate any tips in general on how to go about learning this kind of thing.
Ruby does have what's usually called the top level execution environment, and so a long string of commands will execute immediately just like Perl. Or, you can define classes and modules and go all OOP on your problem if you want, or you can mix the approaches.
You will need at least one line at the top level or top level of a class to start everything off. So:
p :hello
or
class A
p :hello
end
or
class A
def run
p :hello
end
end
A.new.run
or, my favorite:
class A
def run
p :hello
end
self
end.new.run
I'd highly recommend looking at some of your other favorite gems to see how their code is structured (like on Github). That's how I found my start. Thinking of your project as a "gem", being released or not, is a good way to wrap your mind around the problem.

Resources