Ruby namespaces and require


#1

Hi all,

There have been a few threads recently both here and on the Rails list
where the problem of namespace collisions has come up. It seems to my
untutored eye that they’ve come about simply because the original
authors didn’t apply their namespacing universally. From memory, an
example is htmltools and ActionPack both defining an HTML::Tag class.

A possible solution sprung to mind: how does the following syntax look?

require ‘foo’, :into => ‘Bar’
require ‘qux’, :into => ‘Wibble::Spang’

What that would do is require the named file such that all its code was
executed in the context of the named module. My meta-fu isn’t quite up
to giving even a simple example, but I’d envisage the result looking
something like this:

$ cat bar.rb
class Bar
end
$ cat test.rb
require ‘bar’, :into => ‘Foo’
p Foo.constants
$ ruby test.rb
[“Bar”]

With the htmltools and ActionPack example, this:

require ‘htmltools’, :into => ‘MyHtmltoolsModule’
require ‘actionpack’, :into => ‘MyCollisionModule’

would result in MyHtmlToolsModule::HTML::Tag and
MyCollisionModule::HTML::Tag existing side-by-side.

Would this require help from the interpreter? require and load both
execute the code at the top level of the namespace (unless I’ve missed
something) and without overloading them to actually eval() the code
differently, I’m not sure what’s best.

Any thoughts? Has this been discussed to death before my time? Is it
obviously stupid?

It’s just struck me that if we’re getting help from the interpreter
anyway, this might be possible:

require ‘foo’ into Bar

which I think is quite neat. In case I haven’t quite made it clear, the
main advantage I can see from this is that modules can be protected from
each other without the original author needing to care how their module
is going to be used, and it can be retrospectively applied to existing
code (give or take any meta- or cleverer-than-me-programming that makes
this void, of course :slight_smile: ) to fix exactly the sort of collision problems
that are already occurring.


#2

It should be better and more elegant to have a STD NS like in Java
or in C#.

Then use for all non official applications an ext//
prefix.

Like:

require "skp/ifc/users"


Upper reality >oftware.
Dave - Skp Core (skp-it.eu).


Email.it, the professional e-mail, gratis per te: http://www.email.it/f

Sponsor:
Refill srl il paradiso della tua stampante - cartucce e toner
compatibili, inchiostri e accessori per la ricarica, carta speciale.
Tutto a prezzi scontatissimi!
Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid=5187&d=19-5


#3

dave wrote:

It should be better and more elegant to have a STD NS like in Java
or in C#.
Alternative, certainly. I’m not so sure about better or more elegant.
Having a standard namespace and having a system that applies it are two
separate concerns. It’s semantics versus syntax.

Then use for all non official applications an ext//
prefix.

Like:

require "skp/ifc/users"

There’s nothing stopping that from happening as well, except for the
large body of code that already exists without it. In fact, this would
be quite a nice way of adapting the existing codebase to a standard
namespace if that was what Matz wanted, without needing an extensive
rewrite.

To take your example:
require ‘users’, :into => ‘Skp::Ifc’
would have a similar effect, without the requirement that the ‘users.rb’
file was written with a namespace in mind, or a directory structure to
mirror it.


#4

In Rolls (roll.rubyforge.org) I added the import method which works
like this:

module Bar
import ‘foo’
end

I can’t say which sytax is better, but either works, but there are some
gotchyas in doing this that one must be careful about. For instance,
importing any code with extensions to built in classes will not work
unless the class name is prefixed with ‘::’.

T.


#5

On Fri, May 19, 2006 at 04:23:45PM +0900, Alex Y. wrote:
} There have been a few threads recently both here and on the Rails list
} where the problem of namespace collisions has come up. It seems to my
} untutored eye that they’ve come about simply because the original
} authors didn’t apply their namespacing universally. From memory, an
} example is htmltools and ActionPack both defining an HTML::Tag class.
}
} A possible solution sprung to mind: how does the following syntax
look?
}
} require ‘foo’, :into => ‘Bar’
} require ‘qux’, :into => ‘Wibble::Spang’
[…]
} Any thoughts? Has this been discussed to death before my time? Is it
} obviously stupid?

I don’t care for the :into => syntax, myself.

} It’s just struck me that if we’re getting help from the interpreter
} anyway, this might be possible:
}
} require ‘foo’ into Bar
[…]

Nicer, but I consider the whole into thing superfluous. Consider the
following implementation:

def qualified_const_get(str)
path = str.to_s.split("::")
from_root = path[0].empty?
if from_root
path = path[1…-1]
else
from_root = (self == Object) || (self.class == Object)
end
if not from_root
begin
start_ns = (Class === self) ? self : self.class
return path.inject(start_ns) { |ns,name| ns.const_get(name) }
rescue NameError
#noop
end
end
path.inject(Object) { |ns,name| ns.const_get(name) }
end

module RequireWithinNamespace
AlreadyRequired = Hash.new { |h,k| h[k] = [] }

def self.find_requirable_file(filename)
filename = “#{filename}.rb” unless /.rb$/ === filename
$LOAD_PATH.each { |dir|
path = File.join(dir, filename)
return path if File.exists?(path)
}
raise “Could not find #{filename} in #{$LOAD_PATH.inspect}”
end

def self.require_within(filename, context = nil, base_require =
:require)
if context
if not ((Module === context) || (Class === context))
context = Object::qualified_const_get(context)
end
filename = find_requirable_file(filename)
context_list = AlreadyRequired[filename]
if not (context_list.index context)
context_list << context
context.instance_eval { eval File.read(filename) }
return true
else
return false
end
else
send(base_require, filename)
end
end

def require(filename, context = nil)
RequireWithinNamespace.require_within(filename, context)
end

end

You can then use…

RequireWithinNamespace::require ‘qux’, ‘Wibble::Spang’

…or even…

no need for quotes around the namespace

RequireWithinNamespace::require_within ‘qux’, Wibble::Spang

…or, since it is a drop-in replacement for require, you can add…

module Kernel
alias :require_no_namespace :require

def require(filename, context = nil)
RequireWithinNamespace.require_within(filename,
context,
:require_no_namespace)
end
end

…so you can use it for your normal requires or to require in a
namespace.

By the way, I decided that it was time to take the Ruby tricks and
techniques I’ve discovered or developed and make them publicly
available. I
am starting to post them on a blog for people to take and use freely.
See
http://redcorundum.blogspot.com/ (There is only oe post so far, but I
have
a bunch of stuff that will gradually go up there.) Once I’ve done a bit
more testing of this, it will go up there as well.

} Alex
–Greg


#6

Gregory S. wrote:

On Fri, May 19, 2006 at 04:23:45PM +0900, Alex Y. wrote:

} A possible solution sprung to mind: how does the following syntax look?
}
} require ‘foo’, :into => ‘Bar’
} require ‘qux’, :into => ‘Wibble::Spang’
[…]
} Any thoughts? Has this been discussed to death before my time? Is it
} obviously stupid?

I don’t care for the :into => syntax, myself.
Fair enough :slight_smile:

} It’s just struck me that if we’re getting help from the interpreter
} anyway, this might be possible:
}
} require ‘foo’ into Bar
[…]

Nicer, but I consider the whole into thing superfluous. Consider the
following implementation:
<snip implementation I’ll have to go away and Study…>

I’ve got a bit of a soft spot for natural language-ish syntax, but
that’s just personal preference talking.

You can then use…

RequireWithinNamespace::require ‘qux’, ‘Wibble::Spang’
Given that my plan was to alias away (or somehow supplement) the
existing Kernel#require, I didn’t want to hijack the second parameter
because I don’t know what’s going on with require_gem. As I understand
it, require_gem is being deprecated in favour of plain-old require, but
require_gem handles version requirements which (I imagine) could get
tacked on to require. Passing named parameters with a hash seems to be
the cleanest way to please everyone :slight_smile:

…or even…

no need for quotes around the namespace

RequireWithinNamespace::require_within ‘qux’, Wibble::Spang
That’s a neat trick - the only reason I had the quotes there in the
first place was because I wasn’t sure it was possible to get rid of them
without triggering warnings.

…or, since it is a drop-in replacement for require, you can add…

module Kernel
alias :require_no_namespace :require

def require(filename, context = nil)
RequireWithinNamespace.require_within(filename,
context, :require_no_namespace)
end
end
And that is what I think I’ll be using from here on in. Very cool.

> See > http://redcorundum.blogspot.com/ Bookmarked!

Thanks for that, good to know I’m not entirely barking.


#7

On 5/19/06, Alex Y. removed_email_address@domain.invalid wrote:

There have been a few threads recently both here and on the Rails list
where the problem of namespace collisions has come up. It seems to my
untutored eye that they’ve come about simply because the original
authors didn’t apply their namespacing universally. From memory, an
example is htmltools and ActionPack both defining an HTML::Tag class.

A possible solution sprung to mind: how does the following syntax look?

require ‘foo’, :into => ‘Bar’
require ‘qux’, :into => ‘Wibble::Spang’

Awful and unworkable. Remember that in Ruby, a filename does not
necessarily correspond to a created or loaded class. Furthermore, with
dynamic code generation, that would end up meaning nothing at all in
the end.

So, I would oppose this heartily.

-austin


#8

removed_email_address@domain.invalid wrote:

unless the class name is prefixed with ‘::’.
I can’t say I like the syntax (I came up with :into for precisely that
reason - your way is more natural, but rather verbose), but it’s
different strokes for different folks. I’ll take a look at your
implementation… It’d be good to have something standard to point to
as a solution.


#9

Austin Z. wrote:

On 5/19/06, Alex Y. removed_email_address@domain.invalid wrote:

A possible solution sprung to mind: how does the following syntax look?

require ‘foo’, :into => ‘Bar’
require ‘qux’, :into => ‘Wibble::Spang’

Awful and unworkable.
Really? There’s already been one implementation posted that could
support exactly this. Is it the concept you object to, or how it looks
in this case? Would you prefer the:
module Bar
import(‘foo’)
end
syntax that was also suggested? Or maybe
require ‘foo’, Bar
?

Remember that in Ruby, a filename does not
necessarily correspond to a created or loaded class.
I’m not assuming that. I’m just supplying a module context within which
arbitrary code can be imported and executed. I’d want this system to be
circumventable too, by the way - as long as the author knew they were
doing it.

Furthermore, with
dynamic code generation, that would end up meaning nothing at all in
the end.
This is where it gets interesting. Can you give me an example?

So, I would oppose this heartily.
Fair enough :slight_smile: Bear in mind, though, that this offers a way to fix a
current problem without breaking anything.


#10

| require ‘foo’, Bar

What about:

require_in Bar, "foo" ?


Upper reality >oftware.
Dave - Skp Core (skp-it.eu).


Email.it, the professional e-mail, gratis per te: http://www.email.it/f

Sponsor:
Cerchi l?amore? Allora iscriviti gratis a Meetic: troverai migliaia di
single in linea e potrai chattare con loro.
Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?mid@49&d -5


#11

| Alternative, certainly. I’m not so sure about better or more elegant.

It is a necessary evolution, i think. To control the entropy :slight_smile:

| Having a standard namespace and having a system that applies it are
two
| separate concerns.

A good and adpreciated standard would help users to:

- Find projects they need.
  (like "ext/devel/deploy/gem" or "ext/net/http/rails")
- Understand the nature of the project.
- Avoid collisions.
- Keep order.

Long paths can be avoided with and intelligent optimization
on require:

If the find returns just one matching file in the repository
like:

require “rails” it becomes -> require “ext/net/http/rails”.

Then the file is sourced.

So if there is a Conflict:

require “http/rails” would be fine.


Upper reality >oftware.
Dave - Skp Core (skp-it.eu).


Email.it, the professional e-mail, gratis per te: http://www.email.it/f

Sponsor:
Refill s.r.l. - Prodotti per TUTTE le stampanti sul mercato a prezzi
sempre convenienti. Dal 1993, leader nel compatibile di qualità in Italia.
Clicca qui: http://adv.email.it/cgi-bin/foclick.cgi?midQ88&d -5


#12

dave wrote:

| Alternative, certainly. I’m not so sure about better or more elegant.

It is a necessary evolution, i think. To control the entropy :slight_smile:
There’s more than one way to skin that cat :slight_smile:

| Having a standard namespace and having a system that applies it are two
| separate concerns.

A good and adpreciated standard would help users to:

- Find projects they need. 
  (like "ext/devel/deploy/gem" or "ext/net/http/rails")
- Understand the nature of the project.
- Avoid collisions.
- Keep order.

Yes. However, we don’t have that, nor is there any project to impose
such a structure on the community, which would need to take into account
the large amounts of existing code.

Then the file is sourced.

So if there is a Conflict:

require “http/rails” would be fine.
That doesn’t actually solve the original problem, although it does
reduce it: what happens when http/rails and http/roads both define a
top-level Wheel class?


#13

Austin may be right that there are too many problems with doing this
effectively as a standard. But I’m not yet sure of that. All I have
seen for sure is the problem of core extensions, which like I said can
be resolved using a prefix ‘::’. Of course one should be careful not to
reference things in the absolute but rather in the relative. For
instance, never do:

class X
def X.foo

but always

class X
def self.foo

Following some simple guidelines should make importing feasible. NAd of
course, it’s okay if something is not importable --one can decument
that fact too.

But perhaps Austin you have a better solution?

T.


#14

removed_email_address@domain.invalid wrote:

Austin may be right that there are too many problems with doing this
effectively as a standard. But I’m not yet sure of that. All I have
seen for sure is the problem of core extensions, which like I said can
be resolved using a prefix ‘::’.
That does feel clumsy. It’s a simple fix, I know, but it’s still
clumsy.

def self.foo

Why?

irb(main):001:0> class X; end
=> nil
irb(main):002:0> module Y; class X; def X.foo; end; end; end
=> nil
irb(main):003:0> Y::X.methods - X.methods
=> [“foo”]


#15

On 5/20/06, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

But perhaps Austin you have a better solution?

Yes. Complain to developers who step on each others classes/namespaces.

This is a solution looking for a real problem.

-austin


#16

On 5/24/06, removed_email_address@domain.invalid removed_email_address@domain.invalid wrote:

namespaces will arrive soon and provide the proper solution.
True namespaces exist, Trans. Selector namespaces are something
different entirely.
I’m not convinced that selector namespaces are useful, but Matz is.
I’m absolutely convinced that this isn’t useful.

-austin


#17

Austin wrote:

Yes. Complain to developers who step on each others classes/namespaces.

This is a solution looking for a real problem.

The problem has been expirenced many times. I think your just looking
at the one piece of it. The whole issue includes the practice of core
extensions and that’s come up a good a lot. If extensions never occured
then it would be easy enough to ecapsulate libraries at load time w/o
issue. But with extensions, not even being cooperative with regards to
class/namspaces can’t completely avoid the problems. Hopefully true
namespaces will arrive soon and provide the proper solution.

T.