This is best explained with an example:
file1.rb:
def foo
puts 123
end
file2.rb:
class A
require 'file1'
end
A.new.foo
will give an error "': private method 'foo' called".
I can get around this by doing A.new.send("foo")
but is there a way to make the imported methods public?
Edit: To clarify, I am not confusing include and require. Also, the reason why I cannot use normal inclusion (as many have rightly pointed out) is that this is part of a meta-programming setup. I need to allow the user to add functionality at run-time; eg he can say "run-this-app --include file1.rb" and the app will behave differently based on the code he wrote in file1.rb. Sorry should have explained clearer.
Edit: After reading Jorg's answer I realized my code does not behave exactly as intended, and he answers my (misguided) question perfectly. I am trying to do something more akin to str=(entire file1.rb as string); A.class_exec(str)
.
Global procedures in Ruby aren't really global procedures. They are methods, like everything else. In particular, when you define what looks like a global procedure, you are actually defining a private instance method of Object
. Since every piece of code in Ruby is evaluated in the context of an object, this allows you to use those methods as if they were global procedures, since self
is the default receiver, and self
is an object whose class inherits from Object
.
So, this:
# file1.rb
def foo
puts 123
end
is actually equivalent to
# file1.rb
class Object
private
def foo
puts 123
end
end
Now you have a "global procedure" called foo
, which you can call just like this:
foo
The reason why you can call it like this, is that this call is actually equivalent to
self.foo
and self
is an object that includes Object
in its ancestry chain, thus it inherits the private foo
method.
[Note: to be precise, private methods cannot be called with an explicit receiver, even if that explicit receiver is self
. So, to be really pedantic, it is actually equivalent to self.send(:foo)
and not self.foo
.]
The A.new.foo
in your file2.rb
is a red herring: you could just as well try Object.new.foo
or [].foo
or 42.foo
and get the same result.
By the way: puts
and require
are themselves examples of such "global procedures", which are actually private methods on Object
(or more precisely, they are private methods on Kernel
which is mixed into Object
).
On a sidenote: it is really bad style to put calls to require
inside a class definition, because it makes it look like the require
d code is somehow scoped or namespaced inside the class, which is of course false. require
simply runs the code in the file, nothing more.
So, while
# file2.rb
class A
require 'file1.rb'
end
is perfectly valid code, it is also very confusing. It is much better to use the following, semantically equivalent, code:
# file2.rb
require 'file1.rb'
class A
end
That way it is perfectly clear to the reader of the code that file1.rb
is in no way scoped or namespaced inside A
.
Also, it is generally preferred to leave off the file extension, i.e. to use require 'file1'
instead of require 'file1.rb'
. This allows you to replace the Ruby file with, for example, native code (for MRI, YARV, Rubinius, MacRuby or JRuby), JVM byte code in a .jar
or .class
file (for JRuby), CIL byte code in .dll
file (for IronRuby) and so on, without having to change any of your require
calls.
One last comment: the idiomatic way to circumvent access protection is to use send
, not instance_eval
, i.e. use A.new.send(:foo)
instead of A.new.instance_eval {foo}
.