0

I'm new to Ruby - I'm having troubles on every step...

Imagine a Ruby script main.rb and a lot of unknown script files script1.rb ... scriptN.rb. Each scriptX.rb contains unique module with one procedure needs to be executed:

Module X  
  def some_procedure(i)  
    puts "{#i} Module X procedure executed successfully!"  
  end  
end

All I need is to:

  1. iterate over all files in current directory
  2. if current file has name like /^script.*?\.rb$/
  3. then load it and execute some_procedure

How can I do it in main.rb ?

Thank you in advance!

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Pavel Chernov
  • 1,807
  • 1
  • 16
  • 15

4 Answers4

1

Choose from these great answers in SO on loading the files: Best way to require all files from a directory in ruby?

Then in your files, just have them execute on load, rather than on a method call.

Community
  • 1
  • 1
Jesse Wolgamott
  • 40,197
  • 4
  • 83
  • 109
  • Thank You, but it is not what is required. Now I want to execute **some_procedure()** - so I have to put it to each module to execute on load. What if later I will need to execute **another_procedure()** ? Do I have to rewrite all these modules?! – Pavel Chernov Aug 15 '10 at 18:08
  • Personally, I think when you have too many assumptions on the naming of each module. Instead, I would a) follow my guidelines able b) have each module insert the names of the methods to be executes into a global hash. Then c) execute all methods in the hash. Yours feels very un-ruby (to me. but obviously if it works, that's all that REALLY matters). – Jesse Wolgamott Aug 15 '10 at 20:13
  • I think, You are right. Thanks for advice of using global hash. I will post news solution below. – Pavel Chernov Aug 17 '10 at 04:18
1

The problem might be that, when a file is required, it doesn't return the list of modules (or, in general, constants) which it defines. So, unless you don't know which module a script has defined, you will not know where to pass your some_procedure message.

As a workaround, you may try getting the list of defined constants before and after the script was required, find a difference, i.e. list of constants during require, and iterate through all of them, checking which one implements the method you need.

Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113
  • Yes, this is the problem I've encountered. I've almost broke my brains, but think I've found solution! Look my solution below... – Pavel Chernov Aug 15 '10 at 18:11
0

First, we need to put some restriction:

  • Every file script_my1.rb will have the module named Script_my1. I.e. first letter capitalized, all other letters - lowercase.

Create two files script_my1.rb and script_my2.rb as follows:

---script_my1.rb:

module Script_my1  
  @value = 0  

  def self.some_procedure(i)  
    puts "#{i} my1 executed!"  
    @value = i  
  end  

  def self.another_procedure()  
    return @value  
  end  
end  

---script_my2.rb:

module Script_my2  
  @value = 0

  def self.some_procedure(i)  
    puts "#{i} my2 executed!"  
    @value = i  
  end  

  def self.another_procedure()  
    return @value  
  end  
end  

Now the main script, that loads and executes some_procedure() in each module, and then another_procedure().

Please notice, that each module can have separated variables with the same name @value.

Moreover, I think every module can be executed in a separate thread and have access to global variables, but I have not tested it yet.

---main.rb:

# Load all files from the current directory  
# with name like script_xxx.rb  
i = 1  
result = nil  
Dir['./script_*.rb'].each { |f|  
  next if File.directory?(f)  

  require (f)  
  moduleName = f[2,f.length].rpartition('.rb')[0].capitalize  
  eval ( "#{moduleName}.some_procedure(%d)" % i )  
  eval ( "result = #{moduleName}.another_procedure()" )  
  puts result  
  i = i + 1  
}  

Output of this program is:

1 my1 executed!
1
2 my2 executed!
2

That is all!

Pavel Chernov
  • 1,807
  • 1
  • 16
  • 15
0

Some improvement to previous solution can be made. If we want to avoid special naming, we can use global hash to store procedure's names. Each loaded script_xx.rb file would register it's own procedures in this global hash.

Please notice, that in this case we make two cycles:

  1. first we load all files script_xx.b

    every file while loading will register it's procedures in $global_procs array.

  2. then iterate over all entries in $global_procs to execute all registered procedures via eval()

Hope, this is a more 'ruby-like' solution!

---script_my1.rb

module My1  
  @value = 0  

  def self.some_procedure(i)  
    puts "#{i} my1 executed!"  
    @value = i  
  end  

  def self.another_procedure()  
    return @value  
  end  
end 

$global_procs << { 'module' => 'My1',
  'some_procedure' => 'My1.some_procedure',
  'another_procedure' => 'My1.another_procedure' }

---script_my2.rb

module MMM2  
  @value = 0

  def self.some_procedure(i)  
    puts "#{i} MMM2 executed!"  
    @value = i  
  end  

  def self.another_procedure()  
    return @value  
  end  
end  

$global_procs << { 'module' => 'MMM2',
  'some_procedure' => 'MMM2.some_procedure',
  'another_procedure' => 'MMM2.another_procedure' }

---main.rb

# Create global array for holding module's info
$global_procs = []

Dir['./script_*.rb'].each { |f|  
  next if File.directory?(f)  
  require (f)  
}

i = 1  
result = nil  

$global_procs.each { |p|
  puts "Module name: " + p['module']
  eval(p['some_procedure']+'(i)')
  result = eval(p['another_procedure']+'()')
  puts result  
  i = i + 1  
}
Pavel Chernov
  • 1,807
  • 1
  • 16
  • 15