Forum: Ruby load a Ruby source with params

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
12e994280833d12c78f1e98e92850767?d=identicon&s=25 Sai S. (sai)
on 2009-02-16 14:19
Hello, Ruby world,

Do you know how loading a Ruby source with parameters?  I had try so by
using:
load(my_file my_arg)

but it do not seems to work...

Thank you.
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-02-16 17:07
Sai Hl wrote:
> Do you know how loading a Ruby source with parameters?  I had try so by
> using:
> load(my_file my_arg)
>
> but it do not seems to work...

I think you're confusing two things.

(1) Loading in more Ruby code to the currently-running Ruby interpreter.
This is done using "load" or "require". There is no concept of
"parameters" here. However you could set a global variable (e.g. $foo)
or a constant (Foo), which the code in the other file makes use of.

But it would be more normal for the other file just to define modules or
classes, and then after the load has completed you invoke one of those
modules or classes, at which point you can pass whatever parameters you
like.

(2) Forking and execing a new child process. This could be another
Ruby interpreter, but it could also be any other program on your system.
When you do this, you can pass command-line arguments (and/or
environment variables and open files)

The simplest way is with Kernel#system, e.g.

    system("/bin/prog","arg1","arg2")

but other options include backticks, IO.popen, the open3 and open4
libraries, and the low-level Kernel#fork and Kernel#exec calls.
12e994280833d12c78f1e98e92850767?d=identicon&s=25 Sai S. (sai)
on 2009-02-16 19:38
Brian Candler wrote:
> (1) Loading in more Ruby code to the currently-running Ruby interpreter.
> This is done using "load" or "require". There is no concept of
> "parameters" here. However you could set a global variable (e.g. $foo)
> or a constant (Foo), which the code in the other file makes use of.
>
> But it would be more normal for the other file just to define modules or
> classes, and then after the load has completed you invoke one of those
> modules or classes, at which point you can pass whatever parameters you
> like.
>
> (2) Forking and execing a new child process. This could be another
> Ruby interpreter, but it could also be any other program on your system.
> When you do this, you can pass command-line arguments (and/or
> environment variables and open files)
>
> The simplest way is with Kernel#system, e.g.
>
>     system("/bin/prog","arg1","arg2")
>
> but other options include backticks, IO.popen, the open3 and open4
> libraries, and the low-level Kernel#fork and Kernel#exec calls.

Many thanks for your detailled answer, Brian Candler.

until now I used those few lines:

# inc.test.rb
'Hello ' + subject

# inc.other_test.rb
'Hi, ' + subject

# main.rb
@files = []
subject = 'World'
Dir['inc.*.rb'].each do |file|
  open(file) { |f| @files << f.read }
end
@files.each { |f| puts "#{eval(f)}" }

But it's true that the eval function takes a lot of ressources and the
(1) solution is better, using global variables.

I am going to try to use the (2) solutions, with a module for any files
like:

# inc.test.rb
module Inc
  def say
    'Hello' + subject
  end
end

But is this possible in my case, because I don't know the name of each
module (which is depend of the name of its file)?

Regards
47b1910084592eb77a032bc7d8d1a84e?d=identicon&s=25 Joel VanderWerf (Guest)
on 2009-02-16 20:45
(Received via mailing list)
Cyril Beer wrote:
> Do you know how loading a Ruby source with parameters?  I had try so by
> using:
> load(my_file my_arg)

It's a bit awkward, but there's a way to do it with my script library:

http://redshift.sourceforge.net/script/

Quoting the docs:
==========
An "input" can be passed to the script before loading. Simply call
Script.new (or Script.load) with a block. The block is passed a single
argument, the Script module, and executed before the files are loaded
into the Script’s scope. Setting a constant in this block makes the
constant available to the script during loading. For example:
   script = Script.load("my-script.rb") { |script| script::INPUT = 3 }
==========

The file "my-script.rb" would simply refer to INPUT. You can pass any
number of args this way. See the "program2.rb" in the examples/ dir for
an example.

As a bonus, everything defined in "my-script.rb" is wrapped in a module,
returned by Script.load, and (in the case above) stored in a local
variable in the main file, which you can use to access the constants and
methods defined in my-script.rb.

HTH.
753dcb78b3a3651127665da4bed3c782?d=identicon&s=25 Brian Candler (candlerb)
on 2009-02-16 21:22
Sai Hl wrote:
> I am going to try to use the (2) solutions, with a module for any files
> like:
>
> # inc.test.rb
> module Inc
>   def say
>     'Hello' + subject
>   end
> end
>
> But is this possible in my case, because I don't know the name of each
> module (which is depend of the name of its file)?

If you are consistent in your naming, you can map the filename to the
module name (or vice versa). For example, look at the underscore and
camelize methods of ActiveSupport from Rails. These just convert FooBar"
to "foo_bar", and vice versa.

Then you can use const_get to convert the name "FooBar" to the actual
module instance on which to invoke the method. e.g.

  puts Object.const_get("Inc").say(subject)

A simpler solution is just to iterate over all the modules within an
enclosing module/namespace:

==> inc1.rb <==
module Extensions
  module Inc1
    def self.say(subject)
      "Hello #{subject}"
    end
  end
end

==> inc2.rb <==
module Extensions
  module Inc2
    def self.say(subject)
      "Goodbye #{subject}"
    end
  end
end

==> main.rb <==
Dir["inc*.rb"].each { |src| load src }
Extensions.constants.each do |k|
  puts Extensions.const_get(k).say("world")
end

Aside: if you strip off the .rb extension (look at File.basename) then
you can use 'require' instead of 'load'. This prevents loading the same
file multiple times.
12e994280833d12c78f1e98e92850767?d=identicon&s=25 Sai S. (sai)
on 2009-02-17 00:06
Thank you, Brian Candler!
Your help was very helpful. You should be a great teacher!

Regards.
149379873fe2cb70e550c6bff8fedd0c?d=identicon&s=25 Jeff Schwab (Guest)
on 2009-02-17 15:10
(Received via mailing list)
Sai Hl wrote:
>>
>> (2) Forking and execing a new child process. This could be another
>> Ruby interpreter, but it could also be any other program on your system.
>> When you do this, you can pass command-line arguments (and/or
>> environment variables and open files)

> I am going to try to use the (2) solutions

Out of curiosity, why wouldn't you just define a function in the "other"
file, then call it with whatever arguments you want?  This is the second
paragraph of (1).
A0235bc63a665cf3c08e0ed61e9572ba?d=identicon&s=25 Mklement 0. (michael_k44)
on 2014-07-11 19:20
Very late to the party, but thought I'add this:

If the file you're loading is designed to handle _command-line_
parameters, you can just fill the `ARGV` array before loading:

    ARGV[0] = my_arg
    load(my_file)   # my_file can then access my_arg as ARGV[0]
This topic is locked and can not be replied to.