tags:

views:

89

answers:

4

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!

+1  A: 

Choose from these great answers in SO on loading the files: http://stackoverflow.com/questions/735073/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.

Jesse Wolgamott
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
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
I think, You are right. Thanks for advice of using global hash. I will post news solution below.
Pavel Chernov
+1  A: 

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ć
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
A: 

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
This assumes that naming of modules follows naming of the ruby files they are contained within, which was not mentioned in the question.
Mladen Jablanović
A: 

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