I have an external file: path_to_external_file.rb
with some class definition:
class A
some_definitions
end
And I want to load that within module B
so that the class A
defined above can be referred to as B::A
. I tried:
class B
load('path_to_external_file.rb')
end
but A
is defined in the main environment, not in B
:
A #=> A
B.constants # => []
How can I load external files within some class/module?
Edit
Should I read the external files as strings, and evaluate them within Class.new{...}
, and include
that class within B
?
You cannot. At least using load
or require
, the Ruby files will always be evaluated in a top context.
You can work around that problem in two ways:
class B::A
directly (but you are probably trying to avoid that)eval(File.read("path_to_external_file.rb"))
within your B
classEdit: Maybe, this library is interesting for you: https://github.com/dreamcat4/script/blob/master/intro.txt
Generally, it's a bad idea to define a class as "class A" but then "magically" make it contained by module B. If you want to refer to class A as B::A, you should define it using either:
module B
class A
# contents
end
end
or:
class B::A
# contents
end
Otherwise anyone who reads your code will be confused. In this case, you don't gain anything in clarity, brevity, or convenience by using "tricks", so straightforward code is better. There is a lesson here: the metaprogramming features of Ruby are great, but there is no need to use them gratuitously. Only use them when you really gain something from doing so. Otherwise you just make your code hard to understand.
BUT, having read your comment, it looks like there is really a good reason to do something like this in your case. I suggest that the following solution would be even better than what you are envisioning:
m = Module.new
m.module_eval("class C; end")
m.constants
=> [:C]
m.const_get(:C)
=> #<Module:0xfd0da0>::C
You see? If you want a "guaranteed unique" namespace, you can use an anonymous module. You could store these modules in a hash or other data structure, and pull the classes out of them as needed. This solves the problem you mentioned, that the users of your app are going to be adding their own classes, and you don't want the names to collide.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With