Is there a "main" method in Ruby like in C? - ruby

I'm new to Ruby, so apologies if this sounds really silly.
I can't seem to figure out how to write a "main" code and have methods in the same file (similar to C). I end up with a "main" file which loads a seperate file that has all the methods. I appreciate any guidance on this.
I spotted the following SO post but I don't understand it:
Should I define a main method in my ruby scripts?
While it's not a big deal, it's just easier being able to see all the relevant code in the same file. Thank you.
[-EDIT-]
Thanks to everyone who responded - turns out you just need to define all the methods above the code. An example is below:
def callTest1
puts "in test 1"
end
def callTest2
puts "in test 2"
end
callTest1
callTest2
I think this makes sense as Ruby needs to know all methods beforehand. This is unlike C where there is a header file which clearly list the available functions and therefore, can define them beneath the main() function
Again, thanks to everyone who responded.

#Hauleth's answer is correct: there is no main method or structure in Ruby. I just want to provide a slightly different view here along with some explanation.
When you execute ruby somefile.rb, Ruby executes all of the code in somefile.rb. So if you have a very small project and want it to be self-contained in a single file, there's absolutely nothing wrong with doing something like this:
# somefile.rb
class MyClass
def say_hello
puts "Hello World"
end
end
def another_hello
puts "Hello World (from a method)"
end
c = MyClass.new
c.say_hello
another_hello
It's not that the first two blocks aren't executed, it's just that you don't see the effects until you actually use the corresponding class/method.
The if __FILE__ == $0 bit is just a way to block off code that you only want to run if this file is being run directly from the command line. __FILE__
is the name of the current file, $0 is the command that was executed by the shell (though it's smart enough to drop the ruby), so comparing the two tells you precisely that: is this the file that was executed from the command line? This is sometimes done by coders who want to define a class/module in a file and also provide a command-line utility that uses it. IMHO that's not very good project structure, but just like anything there are use cases where doing it makes perfect sense.
If you want to be able to execute your code directly, you can add a shebang line
#!/usr/bin/env ruby
# rest of somefile.rb
and make it executable with chmod +x somefile.rb (optionally rename it without the .rb extension). This doesn't really change your situation. The if __FILE__ == $0 still works and still probably isn't necessary.
Edit
As #steenslag correctly points out, the top-level scope in Ruby is an Object called main. It has slightly funky behavior, though:
irb
>> self
=> main
>> self.class
=> Object
>> main
NameError: undefined local variable or method `main' for main:Object
from (irb):8
Don't worry about this until you start to dig much deeper into the language. If you do want to learn lots more about this kind of stuff, Metaprogramming Ruby is a great read :)

No there isn't such structure. Of course you can define main function but it won't be called until you do so. Ruby execute line by line so if you want to print 'Hello World' you simply write:
puts 'Hello World'
The question that you mentioned is about using one file as module and executable, so if you write
if __FILE__ == $0
# your code
end
It will be called only if you run this file. If you only require it in other file then this code will never run. But IMHO it's bad idea, better option is using RubyGems and there add executables.

Actually there is a main, but it is not a method; it's the top-level object that is the initial execution context of a Ruby program.
class Foo
p self
end
#=> Foo
p self
#=> main
def foo
p self
end
foo
#=> main

There is no magic main function in Ruby. See http://en.wikipedia.org/wiki/Main_function#Ruby

If you wish to run Ruby scripts like C compiled files, do the following:
#!/usr/bin/env ruby
puts "Hello"
and then chmod a+x file_name.rb. Everything that is below the first line will be run, as if it was contents of main in C. Of course class and function definitions won't give you any results until they are instantiated/invoked (although the code inside class definitions is actually evaluated, so you could get some output but this is not expected in normal circumstances).

Another way to write main() method is:
class HelloWorld
def initialize(name)
#name = name
end
def sayHello()
print "Hello ##name!"
end
end
def main()
helloWorld = HelloWorld.new("Alice")
helloWorld.sayHello
end
main

Related

Is it possible to explicitly include sub-modules or classes in Ruby?

I want to be able to statically analyze my code. That is, to know from the plain text of the file where every function and variable comes from. IDEs and text editor plugins work better when they can trace the origin of every symbol as well.
So for example, if I have application code like this:
#...
Y.some_method()
#...
Then I want to see Y in an include/import/require/extend/def statement somewhere on the page.
In other languages I use, one can explicitly choose which sub-parts of a namespace to bring in to the current context.
Python:
from X import Y
Haskell:
import X (Y)
Elixir:
alias X.Y, as: Y
And while it's possible to import all contained names in Python, the "wildcard import" is frowned upon:
from X import *
". . . they make it unclear which names are present in the namespace, confusing both readers and many automated tools."
In Ruby, it seems that this fully implicit "wildcard" way is the only way to bring in a contained name:
include X
This makes Y available, but is there some way to make this explicit? The docs for Ruby include don't show any options.
What I'd really like to do in Ruby is something like one of these:
from X include Y
include X::Y as Y
The best I've come up with so far is:
require 'x/y' ; Y = X::Y
Here's a crazy hack in the answer to another question which would enable this.
Try this. But I agree with #tadman that you should consider doing it in the Ruby way.
Object.define_singleton_method(:include) do |*mths, from: nil|
mod = from || mths.first
mod = mod.dup
if from
all_mths = mod.instance_methods
(all_mths - mths).each { |mth| mod.send :undef_method, mth }
end
super(mod)
end
module Foobar
def foo
puts :foo
end
def bar
puts :bar
end
end
class Abc
include Foobar
end
Abc.new.foo # => 'foo'
Abc.new.bar # => 'foo'
class AbcWithoutBar
include :foo, from: Foobar
end
AbcWithoutBar.new.foo # => 'foo'
AbcWithoutBar.new.bar # => NoMethodError
Ruby always executes the code that you require
And since there is no partial execution of a file there cannot be partial require.
When you require a feature Ruby locates the corresponding file using the load paths in $: and then double checks against the list of loaded files in $" and if the file has not yet been loaded executes the file.
Ruby is a dynamic language, the best way to reason about its source code is halting a running program rather than statically. In fact even class and def are not declarations but just method calls that are executed at runtime. Consider for example this contrived example
class Surprise < [Array, Hash, Fixnum, Object].sample
end
If you want to know where a method or class has been defined best use pry. You can require pry and then use binding.pry to stop anywhere in your source code and spelunk around to inspect objects and source code. Two of the most useful commands are ls and $
ls prints all methods of an object or class
$ prints the file location and source code of a method

How can I "require" code from another .rb file like in PHP?

Coming to Ruby from a PHP background, I'm used to being able to use require, require_once, include, or include_once which all have a similar effect, but the key being they continue to process code in the same scope where the include / require command was invoked.
Example:
sub.php
<?php
echo $foo;
main.php
<?php
$foo = 1234;
include('sub.php'); // outputs '1234'
When I first started using Ruby I tried to include / require / require_relative / load other .rb files, and after becoming a little frustrated with not having it work how I would expect it to I decided that there were better ways to go about breaking up large files and that Ruby didn't need to behave in the same way PHP did.
However, occasionally I feel that for testing purposes it would be nice to to load code from another .rb file in the way PHP does - in the same scope with access to all the same variables - without having to use class / instance variables or constants. Is this possible? Maybe somehow using a proc / binding / or eval command?
Again, I'm not advocating that this should be used during development - but I am curious if it is possible - and if so, how?
Yes, this is possible, although certainly not something I'd recommend doing. This works:
includer.rb:
puts var
include.rb:
var = "Hello!"
eval(File.read("include.rb"), binding)
Running this (Ruby 2.2.1, Ruby 1.9.3) will print Hello!. It works simply: eval takes an optional binding with which to evaluate the code it is passed, and Kernel#binding returns the current binding.
To have code run in same binding, you could simply eval the file contents as follows:
example.rb
class Example
def self.called_by_include
"value for bar"
end
def foo
puts "Called foo"
end
eval( File.read( 'included.rb' ) )
end
Example.new.bar
included.rb
BAR_CONSTANT = called_by_include
def bar
puts BAR_CONSTANT
end
Running ruby example.rb produces output
value for bar
The important thing is the eval( File.read( 'included.rb' ) ) code, which if you really wanted you could define as a class method on Object, to allow arbitrary source to be included with a convenience function*. The use of constants, class variables etc just shows influences working in both directions between the two pieces of source code.
It would be bad practice to use this in any production code. Ruby gives you much better tools for meta-programming, such as ability to use mix-ins, re-open classes, define methods from blocks etc.
* Something like this
class Object
def self.include_source filename
eval( File.read( filename ) )
end
end
And the line in example.rb would become just
include_source 'included.rb'
Again I have to repeat this is not such a great idea . . .
To import external .rb file in your code, I'm not sure but I think it have to be a gem.
Use require followed by the name of the gem you want to import.
Example
require 'foobar'
# do some stuff
Or you can use load to import entire rb file
load 'foobar.rb'
# do some stuff
Good luck and sorry for my english

Find path to file that required this one

I'll show an example of what I'm trying to do.
child.rb
require 'parent'
class Child < Parent
...
end
parent.rb
class Parent
puts __FILE__
...
end
running this (e.g. in IRB):
require 'child'
child=Child.new
returns this:
/path/to/parent.rb
but i'm really trying to get the file child.rb instead.
How can i do this without moving the puts __FILE__ in to the child class directly?
There is no way in Ruby to get what you are asking for. Perhaps if you explained why you want this—what you are trying to accomplish—then I (or someone else) could help you further. As it stands you seem to be asking an XY problem.
Although it's not always the "file that required me", you can use $0 in this case instead of __FILE__ to get "the root file that is running" in the case when you have done ruby parent.rb. Note that this will not work with IRB, however. (Inside IRB $0 is always "irb" or something equally unhelpful.)
Redefine require to output caller_locations.first.absolute_path before calling the original require.
you can use some backtrace method like caller_locations(1,1)[0].path or caller

Call ruby function from command-line

How can I directly call a ruby function from the command-line?
Imagine, I would have this script test.rb:
class TestClass
def self.test_function(some_var)
puts "I got the following variable: #{some_var}"
end
end
If this script is run from the command-line (ruby test.rb), nothing happens (as intended).
Is there something like ruby test.rb TestClass.test_function('someTextString')?
I want to get the following output: I got the following variable: someTextString.
First the name of the class needs to start with a capital letter, and since you really want to use a static method, the function name definition needs to start with self..
class TestClass
def self.test_function(someVar)
puts "I got the following variable: " + someVar
end
end
Then to invoke that from the command line you can do:
ruby -r "./test.rb" -e "TestClass.test_function 'hi'"
If you instead had test_function as an instance method, you'd have:
class TestClass
def test_function(someVar)
puts "I got the following variable: " + someVar
end
end
then you'd invoke it with:
ruby -r "./test.rb" -e "TestClass.new.test_function 'hi'"
Here's another variation, if you find that typing ruby syntax at the command line is awkward and you really just want to pass args to ruby. Here's test.rb:
#!/usr/bin/env ruby
class TestClass
def self.test_function(some_var)
puts "I got the following variable: #{some_var}"
end
end
TestClass.test_function(ARGV[0])
Make test.rb executable and run it like this:
./test.rb "Some Value"
Or run it like this:
ruby test.rb "Some Value"
This works because ruby automatically sets the ARGV array to the arguments passed to the script. You could use ARGV[0] or ARGV.first to get the first argument, or you could combine the args into a single string, separated by spaces, using ARGV.join(' ').
If you're doing lots of command-line stuff, you may eventually have a use for Shellwords, which is in the standard ruby lib.
If you have multiple arguments to call in a example like this:
class TestClass
def self.test_function(some_var1, some_var2)
puts "I got the following variables: #{some_var1}, #{some_var2}"
end
end
run it like this (the arguments need to be comma separated in this case)
ruby -r "./test.rb" -e "TestClass.new.test_function 'hi','Mike'"
#!/usr/bin/env ruby
class A
def run
p :Hello_world
end
self
end.new.run
The usual way to script Ruby is to just use the top level execution environment called main. You can just start defining methods and code you write outside of a class, and these will be executed directly. (BTW, code inside a class but outside any method will run "by itself" also.)
Anyway, I'm with you ... I like writing all code in a named class and instantiating that class, so you can combine the techniques .. have the class return its own object .. and then use just a little of that top level code to allocate, initialize, and then dot into the class.
With this, you can just type $ ruby test.rb and it will do what you want. Or you can chmod +x test.rb; ./test.rb since we did add a shebang.
If you are working on a command line interface, then I would suggest to have a look at thor.
Thor directly maps your commands to methods within the defined class, see the thor wiki for an example.
Just an extension to Ingenu's answer for the case that the function does not print something out, but does return something.
We would have the following test.rb
class TestClass
def self.test_function(some_var)
return "I got the following variable: " + some_var
end
end
Then to invoke that from the command line and get the return value:
ruby -r "./test.rb" -e "puts TestClass.test_function('hi')"
If you know that how to call an rb file from commandline
ruby yourfile.rb
This can do the whole trick for you.
What you have done is, just defined your methods in the class. Now you can call it below the definition. If you still want to read, wide open your eyes
class TestClass
def self.test_function(some_var)
puts "I got the following variable: #{some_var}"
end
test_function(var)
end

Can I write Ruby code that is executed only when my script is run, but not when it is required?

I want to write a Ruby script something like this:
class Foo
# instance methods here
def self.run
foo = Foo.new
# do stuff here
end
end
# This code should only be executed when run as a script, but not when required into another file
unless required_in? # <-- not a real Kernel method
Foo.run
end
# ------------------------------------------------------------------------------------------
I want to be able to unit test it, which is why I don't want the code outside of the class to run unless I execute the script directly, i.e. ruby foo_it_up.rb.
I know I can simply put the Foo class in another file and require 'foo' in my script. In fact, that is probably a better way to do it, just in case Foo's functionality is needed somewhere else. So my question is more academic than anything, but I'd still be interested in knowing how to do this in Ruby.
This is usually done with
if __FILE__ == $0
Foo.run
end
but I prefer
if File.identical?(__FILE__, $0)
Foo.run
end
because programs like ruby-prof can make $0 not equal __FILE__ even when you use --replace-progname.
$0 refers to the name of the program ($PROGRAM_NAME), while __FILE__ is the name of the current source file.

Resources