Execute ruby method from command-line - ruby

I have the following class in Ruby in the file test_class.rb:
class TestClass
def test_verify_one
# DO SOME
end
def test_verify_two
# DO SOME
end
end
To execute this class I send two parameters to the terminal, ENVIRONMENT and LANGUAGE.
So... to call from terminal I use:
ruby test_class.rb ENVIRONMENT LANGUAGE
This executes both methods.
I want to execute only one.
I tried the following:
ruby -r "test_class.rb" -e "TestClass.test_verify_one" ENVIRONMENT LANGUAGE
but it is not working.
Can you help me?

Within the same folder as test_class.rb, run the ruby command with the following command syntax:
ruby -I . -r "test_class" -e "TestClass.test_verify_one" arg1 arg2
Breaking this command down we get:
-I . Include current directory in $LOAD_PATH so we can use require
-r Require a file named test_class within the $LOAD_PATH. This is possible because we included the current directory in our load path above (.rb extension is optional here).
-e Same as you've provided, evaluates the following code.
Now, if we call ARGV within that method we should get arg1 and arg2 on separate lines:
#...
def self.test_verify_one
puts ARGV
end
#...

If you want your first method to take the variables you're passing to it you need to define your first method to take two variables, like so:
class TestClass
def test_verify_one (var1, var2)
# DO SOME
end
def test_verify_two
# DO SOME
end
end
You will then need to put a condition into your second which causes it to only execute under the conditions you want it to... or just comment it out if you don't need it at the moment. So, for example, if you only wanted test 2 to fire when variables were not passed in, your code would look something like this:
class TestClass
def test_verify_one (var1, var2)
# DO SOME
end
def test_verify_two (var1, var2)
if (var1 and var2) defined? nil
# DO SOME
end
end

Related

Stop execution of code when requiring another file in Ruby

I have a file foo.rb that has the following:
class Foo
def do_stuff
puts "Doing stuff"
end
def do_other_stuff
puts "Doing other stuff"
end
end
f = Foo.new
f.do_stuff
I want require this file in another file bar.rb and access to the methods in the Foo class without executing the instructions in foo.rb.
Expecting to output just:
Doing other stuff
I tried the following in bar.rb:
require 'foo'
f = Foo.new
f.do_other_stuff
However, requiring the file executes the code of foo.rb, and my output is this:
Doing stuff
Doing other stuff
Is there a good way to get around this execution?
requiring a file will execute the code. I think its a bad design, what you are trying to achieve. However you can still circumvent it by putting the code in if __FILE__ == $0 block:
if __FILE__ == $0
f = Foo.new
f.do_stuff
end
if __FILE__ == $0 will make sure the code inside the block is executed only when run directly and not when required, as in your example.
If you just want to block the outputs, do something like this:
stdout_old = $stdout.dup
stderr_old = $stderr.dup
$stderr.reopen(IO::NULL)
$stdout.reopen(IO::NULL)
require "foo"
$stdout.flush
$stderr.flush
$stdout.reopen(stdout_old)
$stderr.reopen(stderr_old)
I want require this file in another file bar.rb and access to the methods in the Foo class without executing the instructions in foo.rb.
Since the methods in the Foo class are defined by executing the instructions in foo.rb, this is obviously non-sensical and impossible: either you want Foo, then you have to execute the instructions, or you don't execute the instructions, but then you don't get Foo.

Command line and argument processing

Good morning...evening.
The problem is about calling method with given argument straightaway after typing in command line:
$ ruby my_class.rb someString
I have got a file my_class.rb with code:
class MyClass
p ARGV
end
and that works, but I would like to use a method to print that input:
class MyClass
def print_me(string)
p string
end
end
Is it even possible to do it without specifying class and method in command line and keep it that way?
$ ruby my_class.rb someString
Yes, just define your class and then call it with the arguments like this:
class MyClass
def print_me(string)
p string
end
end
MyClass.new.print_me(ARGV[0])
You can put the last line in a different file that requires your class definition. But this just changes how you manage your code.

How to access constant value from spec file?

I get a uninitialized constant error, when I run this rspec by rspec foo_spec.rb.
# foo.rb
class Foo
FILENAME = "filename.txt"
def filename
FILENAME
end
end
# foo_spec.rb
require_relative 'foo'
describe Foo do
describe "#filename" do
it "should have right filename" do
foo = Foo.new
expect(foo.filename).to eq FILENAME
end
end
end
I confirmed if I change FILENAME to "filename.txt", the test passes.
How should I use constant value with rspec?
This isn't an rspec problem, it's a Ruby problem. You need to qualify the constant with the class in which its declared. FILENAME should be Foo::FILENAME.
You can only refer to it by FILENAME within the context of Foo. Otherwise, supposing I had a class Bar which also defined a constant called FILENAME, how could Ruby figure out which one I was referring to?

How to call or activate a class?

In my lib folder I have billede.rb:
class Billede
require 'RMagick'
#some code that creates a watermark for a image
image.write(out)
end
How do I call/activate the class? Is the only way to change it to a Rake task?
You can't call a class directly. You have to call a method on that class. For example:
class Billede
def self.foobar
# some kind of code here...
end
end
Then you can call it via Billede.foobar
Perhaps you should read some documentation on basic ruby syntax before trying to do more complex things (such as manipulating images w/ Rmagick).
Code 'inside a class' is run just like any other code. If you have a Ruby file like this:
puts "Hello from #{self}"
class Foo
puts "Hello from #{self}"
end
and you run the file (either via ruby foo.rb on the command line or require "./foo" or load "foo.rb" in a script) it then you will see the output:
Hello from main
Hello from Foo
If you want to load a utility that 'does something' that you can then invoke from a REPL like IRB or the Rails console, then do this:
module MyStuff
def self.do_it
# your code here
end
end
You can require "./mystuff" to load the code, and when you're ready to run it type MyStuff.do_it
And, as you may guess, you can also create methods that accept arguments.
If you want to define a file that can be included in others (with no immediate side effects) but which also "does its thing" whenever the file is run by itself, you can do this:
module MyStuff
def self.run!
# Go
end
end
MyStuff.run! if __FILE__==$0
Now if you require or load this file the run! method won't be invoked, but if you type ruby mystuff.rb from the command line it will.
# in /lib/billede.rb
class Billede
def self.do_something(arg)
# ...
end
def do_anotherthing(arg)
# ...
end
end
# inside a model or controller
require 'billede'
Billede::do_something("arg")
# or
billede_instance = Billede.new
billede_instance.do_anotherthing("arg")

How to execute a method only once in Ruby? Are there static variables?

I wrote a script that contains a few method definitions, no classes and some public code. Some of these methods execute some pretty time-consuming shell programs. However, these shell programs only need to be executed the first time the method is invoked.
Now in C, I would declare a static variable in each method to make sure those programs are only executed once. How could I do that in Ruby?
There is an idiom in ruby: x ||= y.
def something
#something ||= calculate_something
end
private
def calculate_something
# some long process
end
But there is a problem with this idiom if your 'long running utility' may return a false value (false or nil), since the ||= operator will still cause the right side to be evaluated.
If you expect false values then use an additional variable, in a way similar to the proposed by DigitalRoss:
def something
return #something if #something_calculated
#something = calculate_something
#something_calculated = true
return #something
end
Don't try to save a line of code by setting the #something_calculated variable first, an then running calculate_something. If your calculate function raises an exception your function will always return nil and will never call the calculate again.
More generally, in Ruby you use instance variables. Note however, that they are visible in all the methods of given object - they are not local to the method.
If you need a variable shared by all instances, define the method in the class object, and in every instance call self.class.something
class User
def self.something
#something ||= calculate_something
end
def self.calculate_something
# ....
end
def something
self.class.something
end
end
The "memoize" gem might be good here. When you memoize a method, it is called no more than once:
require 'memoize'
include Memoize
def thing_that_should_happen_once
puts "foo"
end
memoize :thing_that_should_happen_once
thing_that_should_happen_once # => foo
thing_that_should_happen_once # =>
def f
system "echo hello" unless #justonce
#justonce = true
end
And, hmm, if you want it to run a shell command on invocation until it succeeds, you might try:
def f x
#justonce = system x unless #justonce
end
Unlike the other solutions in this thread, this solution doesn't require you to hold onto any state:
Get the method to remove itself after invocation or to overwrite itself with an empty method:
def hello
puts "hello"
define_singleton_method(:hello) {}
end
OR:
def hello
puts "hello"
singleton_class.send(:undef_method, __method__)
end
def my_time_consuming_method
#result ||= begin
sleep 5
true
end
end
my_time_consuming_method # true after 5 secs
my_time_consuming_method # true directly
Making sure shell commands are run only once is a recurring pattern. One solution I wrote, makes a checksum on the input files on the command line and only executes it when the shell command has not run before. It also executes again when input files have changed. See
https://github.com/pjotrp/once-only
Simply use it by prepending 'once-only' to the shell command. E.g.
bowtie -t e_coli reads/e_coli_1000.fq e_coli.map
becomes
once-only bowtie -t e_coli reads/e_coli_1000.fq e_coli.map
For PBS add a --pbs switch.

Resources