Reputation: 425
This works:
class MyAwesomeClass
variable_of_doom = ["things", "stuff", "chunky_bacon"]
variable_of_doom.each do |name|
define_method("#{name}") do
puts name
end
end
end
puts (MyAwesomeClass.instance_methods - Object.instance_methods).inspect
# => ["things", "stuff", "chunky_bacon"]
This does not, but this is what I need:
variable_of_doom = ["things", "stuff", "chunky_bacon"]
class MyAwesomeClass
variable_of_doom.each do |name|
define_method("#{name}") do
puts name
end
end
end
puts (MyAwesomeClass.instance_methods - Object.instance_methods).inspect
# => NameError: undefined local variable or method ‘variable_of_doom’ for MyAwesomeClass:Class
# => method <class:MyAwesomeClass> in untitled 4 at line 9
# => method <main> in untitled 4 at line 7
Upvotes: 0
Views: 437
Reputation: 19
It is not a good idea to make glabal variables, instead, moving variable_of_doom into Class scopes would be a god idea.
Upvotes: 0
Reputation: 42411
Your question boils down to this failing example:
variable_of_doom = %w(famine plague flood war pestilence drought television)
class MyAwesomeClass
# undefined local variable or method `variable_of_doom' for MyAwesomeClass:Class
puts variable_of_doom
end
Are the variables of doom constant? If so, the following works, because classes have access to constants declared outside their own class definition:
VARIABLE_OF_DOOM = %w(famine plague flood war pestilence drought dos)
class MyAwesomeClass
puts VARIABLE_OF_DOOM
end
If you need the doom-worthy variables to be dynamic, you could create a module or class with a method that knows how to deliver them.
module VarsOfDoom
VOD = %w(famine plague flood war pestilence drought computer-mouse)
def self.dynamic
VOD.shuffle
end
end
class MyAwesomeClass
# Works because the module VarsOfDoom is itself a constant.
puts VarsOfDoom::VOD
puts
puts VarsOfDoom.dynamic
end
I would not resort to making $variables_of_doom
a global. It's not necessary and should be avoided on principle.
Upvotes: 2
Reputation: 30445
In Ruby, a class
(or def
) block demarcates a new, separate scope in which local variables from surrounding scopes are not accessible. If you need surrounding local variables to be in scope, you can get around this using blocks, like:
variable_of_doom = ["things", "stuff", "chunky_bacon"]
MyAwesomeClass.class_eval do
variable_of_doom.each do |var|
# do whatever you need here
end
end
In Pragmatic Bookshelf's Ruby Metaprogramming, they describe the use of this technique as "scope gates": use class
or def
blocks when you want to create a new scope for local variables, use blocks when you don't.
Upvotes: 1
Reputation: 118261
How to resolve the issue has been told in other answer. I would like to suggest you to do such instropection
as below to check the scope rule :
variable_of_doom = ["things", "stuff", "chunky_bacon"]
defined? variable_of_doom # => "local-variable"
local_variables.include? :variable_of_doom # => true
class MyAwesomeClass
p defined?(variable_of_doom)
p local_variables.include?(:variable_of_doom )
end
# >> nil
# >> false
Upvotes: 0
Reputation: 25537
In Ruby, global variables need are indicated by $
just like instance variables are indicated with @
. So this works:
$variable_of_doom = ["things", "stuff", "chunky_bacon"]
class MyAwesomeClass
$variable_of_doom.each do |name|
define_method("#{name}") do
puts name
end
end
end
puts (MyAwesomeClass.instance_methods - Object.instance_methods).inspect
# => [:things, :stuff, :chunky_bacon]
Upvotes: 0