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, sinceself
is the default receiver, andself
is an object whose class inherits fromObject
.So, this:
is actually equivalent to
Now you have a "global procedure" called
foo
, which you can call just like this:The reason why you can call it like this, is that this call is actually equivalent to
and
self
is an object that includesObject
in its ancestry chain, thus it inherits the privatefoo
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 toself.send(:foo)
and notself.foo
.]The
A.new.foo
in yourfile2.rb
is a red herring: you could just as well tryObject.new.foo
or[].foo
or42.foo
and get the same result.By the way:
puts
andrequire
are themselves examples of such "global procedures", which are actually private methods onObject
(or more precisely, they are private methods onKernel
which is mixed intoObject
).On a sidenote: it is really bad style to put calls to
require
inside a class definition, because it makes it look like therequire
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
is perfectly valid code, it is also very confusing. It is much better to use the following, semantically equivalent, code:
That way it is perfectly clear to the reader of the code that
file1.rb
is in no way scoped or namespaced insideA
.Also, it is generally preferred to leave off the file extension, i.e. to use
require 'file1'
instead ofrequire '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 yourrequire
calls.One last comment: the idiomatic way to circumvent access protection is to use
send
, notinstance_eval
, i.e. useA.new.send(:foo)
instead ofA.new.instance_eval {foo}
.