swenson
swenson

Reputation: 67

Ruby require modules, libraries

I'm new to ruby. I understand that, when I see a ruby script, it usually contains lines similar to this:

#!/usr/bin/env ruby
require 'rubyfunction1'
require 'rubyfunction2'

I understand that the require lines are basically (to put it in simple basic terms), calling other scripts. That is really all there is to it. These other scripts are functions.

Now, suppose, I put the content of the rubyfunction1 and rubyfunction2 scripts into two different variables. How do I require the content of a variable?

Or, suppose I want to be able to do something like this:

require '`/home/swenson/rubyfunction1.rb`'

I understand this is a roundabout way of requiring gems/ruby functions, but I'm curious to know if it is at all possible in this manner.

Basically, if I were to run the /home/swenson/rubyfunction1.rb script by itself on the command line, it will basically output to you the content of the script. It would be equivalent to doing "cat /home/swenson/rubyfunction1.rb".

I want to be able to do something like this:

require '`/home/swenson/rubyfunction1.rb`'
require '`/home/swenson/rubyfunction2.rb`'

or

specvar1 = `/home/swenson/rubyfunction1.rb`
specvar2 = `/home/swenson/rubyfunction2.rb`
require specvar1
require specvar2

Is this possible? Any suggestions I can apply to get it to work?

UPDATE:

So here's what I ended up doing.

Main Script called example.rb:

#!/usr/bin/env ruby

add = `./add.rb`     # for my purposes, this will serve as require
subtract = `./subtract.rb` # for my purposes, this will serve as require

eval add
puts "I can add: #{add(3, 2)}"

eval subtract
puts "I can now subtract #{subtract(3, 2)}"

Content of add.rb:

#!/usr/bin/env ruby
puts <<-function
#!/usr/bin/env ruby
def add(a, b)
  a + b
end
function

Content of subtract.rb:

#!/usr/bin/env ruby
puts <<-function
#!/usr/bin/env ruby
def subtract(a, b)
  a - b
end
function

When run from the command line, I get no errors:

# ./example.rb
I can add: 5
I can now subtract 1

Basically, what I want done is precisely this. However, I know there's probably a optimized way of doing this (without having to directly require the relative file). So please, feel free to help me update or optimize this.

Upvotes: 2

Views: 609

Answers (2)

Simple Lime
Simple Lime

Reputation: 11035

So, I think I understand your question correctly, let's say we have 3 files

add.rb

#!/usr/bin/env ruby

def add(a, b)
  a + b
end

subtract.rb

#!/usr/bin/env ruby

puts "def subtract(a, b)"
puts "  a - b"
puts "end"

example.rb

require './add.rb'
subtract = `./subtract.rb`

puts "I can add: #{add(3, 2)}"

# can't do `subtract`, yet, as we haven't `eval`ed the code even though we've run executed the file

eval subtract

puts "I can now subtract #{subtract(3, 2)}"

And the output of running ruby example.rb on the command line is:

$ ruby example.rb 
I can add: 5
I can now subtract 1

So, add.rb just defines a function add. When we require that file, it gets loaded in so we can use that function in our code with no problems.

But, subtract.rb doesn't define a function...it just outputs some code, so running it on the command line looks like:

$ ./subtract.rb 
def subtract(a, b)
  a - b
end

So now, in our third file example.rb, we require the add.rb and then we can start using add in our code as is, but then we want to execute the subtract.rb (using back ticks here) and capture the output of it. At this point, we can't subtract 2 numbers, because we haven't done anything with the output. Then we use eval to evaluate the output of the subtract method, which will define a method for us, then we can subtract the 2 numbers without a problem.

Note that eval is generally frowned upon because it allows arbitrary code to be executed. Never eval untrusted code unless you know how to tame it. In this case, as @JörgWMittag has pointed out in the comments, this code should be trusted, otherwise you just executed an un-trusted file to get this code. Be careful with user input, though, as that's not trusted.

Upvotes: 0

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369458

I understand that the require lines are basically (to put it in simple basic terms), calling other scripts. That is really all there is to it.

Yes. load, require, and require_relative simply run a Ruby file. That's it.

These other scripts are functions.

No. They are scripts. There is no such thing as a function in Ruby.

Now, suppose, I put the content of the rubyfunction1 and rubyfunction2 scripts into two different variables. How do I require the content of a variable?

You can't. require runs a file. It takes the name of a file (more precisely, a relative path) as an argument. Ruby code is not the name of a file.

Or, suppose i want to be able to do something like this:

require '`/home/swenson/rubyfunction1.rb`'

I understand this is a roundabout way of requiring gems/ruby functions, but im curious to know if it is at all possible in this manner.

This is possible. There's nothing special about this. It will simply run a file at the path `/home/swenson/rubyfunction1.rb`. That is a slightly unusual path, but there is nothing special about it. It's just a path like any other, with some funny characters in it.

so to iterate what im trying to do, i want to be able to do something like this:

require '`/home/swenson/rubyfunction1.rb`'
require '`/home/swenson/rubyfunction2.rb`'

or

specvar1 = `/home/swenson/rubyfunction1.rb`
specvar2 = `/home/swenson/rubyfunction2.rb`
require specvar1
require specvar2

Is this possible? Any suggestions I can apply to get it to work?

It's not quite clear what you want here. Those two code snippets are in no way equivalent, they do completely different things!

The first one passes the literal strings '`/home/swenson/rubyfunction1.rb`' and '`/home/swenson/rubyfunction2.rb`' as arguments to require. The second one executes two files named /home/swenson/rubyfunction1.rb and /home/swenson/rubyfunction2.rb using the default system shell (CMD.EXE on Windows, /bin/sh on POSIX), gets the standard output as String and passes those strings to require.

Note that in the first case, the backticks ` are part of the filename, whereas in the second case, they are Ruby syntax for calling the Kernel#` method.

Upvotes: 1

Related Questions