[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Object not missing constant... what am I doing wrong?

Teleolurian

6/17/2008 11:50:00 PM

Background: I'm using ActiveRecord to handle some bulk uploads. I
decided it would be a good idea to put all my models into subfolders,
then load them with autoload [essentially, so I can namespace
everything into a module]. Here's the relevant code (i'm using
MODULENAMEBase.rb as the naming convention for the class that does
establish_connection):

module DBNamespace
def self.included(m)
@models_path = "models/#{m}"
require "#{@models_path}/#{m}Base.rb"
Dir.new(@models_path).entries.grep(/\.rb$/).collect do |fn|
cname = fn.sub(/\.rb$/, '')
cname[0] = cname[0].chr.upcase
m.autoload(cname, "#{@models_path}/#{fn}") unless fn ==
"#{m}Base.rb"
end
end

end

module PL
include DBNamespace
end

----
Right now, I can check PL.autoload?(:Agent) and get the correct path;
I can even load the constant with PL.const_get(:Agent). However,
trying PL::Agent gives me a:

/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/
dependencies.rb:278:in `load_missing_constant': uninitialized constant
PL::Agent (NameError)
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
active_support/dependencies.rb:467:in `const_missing'

And doing an include PL; Agent gives me the odder:

/usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/
dependencies.rb:252:in `load_missing_constant': Object is not missing
constant Agent! (ArgumentError)
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
active_support/dependencies.rb:467:in `const_missing'
from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
active_support/dependencies.rb:479:in `const_missing'
from header.rb:7


Can anybody clear this up?
3 Answers

Bryan JJ Buckley

6/18/2008 4:51:00 AM

0

Hi,

Looks like you're trying to reinvent something that Rails already
tries to do for you, and the two mechanisms aren't playing nicely
together.

2008/6/18 Teleolurian <teleolurian@gmail.com>:
> Background: I'm using ActiveRecord to handle some bulk uploads. I
> decided it would be a good idea to put all my models into subfolders,
> then load them with autoload [essentially, so I can namespace
> everything into a module]. Here's the relevant code (i'm using
> MODULENAMEBase.rb as the naming convention for the class that does
> establish_connection):
>
> module DBNamespace
> def self.included(m)
> @models_path = "models/#{m}"
> require "#{@models_path}/#{m}Base.rb"
> Dir.new(@models_path).entries.grep(/\.rb$/).collect do |fn|
> cname = fn.sub(/\.rb$/, '')
> cname[0] = cname[0].chr.upcase
> m.autoload(cname, "#{@models_path}/#{fn}") unless fn ==
> "#{m}Base.rb"
> end
> end
>
> end
>
> module PL
> include DBNamespace
> end
>
> ----
> Right now, I can check PL.autoload?(:Agent) and get the correct path;
> I can even load the constant with PL.const_get(:Agent). However,
> trying PL::Agent gives me a:
>
> /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/
> dependencies.rb:278:in `load_missing_constant': uninitialized constant
> PL::Agent (NameError)
> from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
> active_support/dependencies.rb:467:in `const_missing'

This happens because when you try to access PL::Agent directly, your
PL module hasn't been explicitely included into anything, and
therefore your `included` block was never called. Hence, no constant
PL::Agent.

>
> And doing an include PL; Agent gives me the odder:
>
> /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/
> dependencies.rb:252:in `load_missing_constant': Object is not missing
> constant Agent! (ArgumentError)
> from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
> active_support/dependencies.rb:467:in `const_missing'
> from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
> active_support/dependencies.rb:479:in `const_missing'
> from header.rb:7

This is where you're tripping over Rails's ActiveSupport autoloading.
First you include PL, which includes DBNamespace, and calls
DBNamespace::included, and that terminates properly. At this point,
you have added Agent as autoloadable... That would (probably) be fine
in a pure Ruby application. But Rails already has an autoloading
mechanism, which is based on overriding Class#const_missing, and which
is apparently called as soon as you reference the (as yet unknown)
constant Agent. This apparantly is already known (probably due to your
manual addition of it to the autoload map).

>
>
> Can anybody clear this up?
>
>

I would recommend that if you want to namespace models like this, let
Rails to the work its own way for you. Put files in a hierarchical
structure under app/models or lib/ (which are both in the load path
anyway), and name those files consistently. For example, in
db_namespace.rb, just have

Dir["#{File.basename(__FILE__, 'rb')}/**/*.rb"].each do |requirement|
require requirement
end

and in db_namespace/agent.rb, do something like

module DBNamespace
class Agent
# stuff
end
end

Then Agent is autoloaded the first time ruby sees DBNamespace::Agent.

Apologies if I've missed some of the point of what you were trying to
do, but I do recommend that you stick to Rails conventions when doing
something like this, as trying to second-guess all the ActiveSupport
core extensions to Module and Class are almost guaranteed to cause
headaches.

--
JJ

Bryan JJ Buckley

6/18/2008 4:55:00 AM

0

oops, didn't mean to double-post, sowwy.

Teleolurian

6/18/2008 4:27:00 PM

0

On Jun 17, 9:50 pm, Bryan JJ Buckley <jjbuck...@gmail.com> wrote:
> Hi,
>
> Looks like you're trying to reinvent something that Rails already
> tries to do for you, and the two mechanisms aren't playing nicely
> together.
>
> 2008/6/18 Teleolurian <teleolur...@gmail.com>:
>
>
>
> > Background: I'm using ActiveRecord to handle some bulk uploads. I
> > decided it would be a good idea to put all my models into subfolders,
> > then load them with autoload [essentially, so I can namespace
> > everything into a module]. Here's the relevant code (i'm using
> > MODULENAMEBase.rb as the naming convention for the class that does
> > establish_connection):
>
> > module DBNamespace
> >  def self.included(m)
> >    @models_path = "models/#{m}"
> >    require "#{@models_path}/#{m}Base.rb"
> >    Dir.new(@models_path).entries.grep(/\.rb$/).collect do |fn|
> >      cname = fn.sub(/\.rb$/, '')
> >      cname[0] = cname[0].chr.upcase
> >      m.autoload(cname, "#{@models_path}/#{fn}") unless fn ==
> > "#{m}Base.rb"
> >    end
> >  end
>
> > end
>
> > module PL
> >  include DBNamespace
> > end
>
> > ----
> > Right now, I can check PL.autoload?(:Agent) and get the correct path;
> > I can even load the constant with PL.const_get(:Agent). However,
> > trying PL::Agent gives me a:
>
> > /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/
> > dependencies.rb:278:in `load_missing_constant': uninitialized constant
> > PL::Agent (NameError)
> >        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
> > active_support/dependencies.rb:467:in `const_missing'
>
> This happens because when you try to access PL::Agent directly, your
> PL module hasn't been explicitely included into anything, and
> therefore your `included` block was never called. Hence, no constant
> PL::Agent.
>
>
>
> > And doing an include PL; Agent gives me the odder:
>
> > /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/
> > dependencies.rb:252:in `load_missing_constant': Object is not missing
> > constant Agent! (ArgumentError)
> >        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
> > active_support/dependencies.rb:467:in `const_missing'
> >        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/
> > active_support/dependencies.rb:479:in `const_missing'
> >        from header.rb:7
>
> This is where you're tripping over Rails's ActiveSupport autoloading.
> First you include PL, which includes DBNamespace, and calls
> DBNamespace::included, and that terminates properly. At this point,
> you have added Agent as autoloadable... That would (probably) be fine
> in a pure Ruby application. But Rails already has an autoloading
> mechanism, which is based on overriding Class#const_missing, and which
> is apparently called as soon as you reference the (as yet unknown)
> constant Agent. This apparantly is already known (probably due to your
> manual addition of it to the autoload map).
>
>
>
> > Can anybody clear this up?
>
> I would recommend that if you want to namespace models like this, let
> Rails to the work its own way for you. Put files in a hierarchical
> structure under app/models or lib/ (which are both in the load path
> anyway), and name those files consistently. For example, in
> db_namespace.rb, just have
>
>   Dir["#{File.basename(__FILE__, 'rb')}/**/*.rb"].each do |requirement|
>     require requirement
>   end
>
>  and in db_namespace/agent.rb, do something like
>
>   module DBNamespace
>     class Agent
>       # stuff
>     end
>   end
>
> Then Agent is autoloaded the first time ruby sees DBNamespace::Agent.
>
> Apologies if I've missed some of the point of what you were trying to
> do, but I do recommend that you stick to Rails conventions when doing
> something like this, as trying to second-guess all the ActiveSupport
> core extensions to Module and Class are almost guaranteed to cause
> headaches.
>
> --
> JJ

Thank you very much! Adding module namespaces around the model classes
was what I needed to do. Probably should have been obvious, but I've
just come back to ruby after a bit of a hiatus :)