Ruby автозагрузка выдает ошибку при первом упоминании константы - PullRequest
0 голосов
/ 22 июля 2011

Я пытаюсь настроить автозагрузку для моих классов в новом проекте, используя Module#autoload. Это почти работает - проблема в том, что при первом использовании константы для автозагрузки происходит ошибка с «неинициализированной константой», но при втором использовании константа работает, как и ожидалось.

Код, иллюстрирующий проблему:

init.rb:

# Load lib, other directories will be autoloaded
APPLICATION_ROOT=File.expand_path(File.dirname(__FILE__))
$:.unshift(APPLICATION_ROOT)
Dir.glob("#{APPLICATION_ROOT}/patches/*").each {|p| require p}
Dir.glob("#{APPLICATION_ROOT}/lib/*").each {|p| require p}

# Test autoloading
include Autoload
begin
  puts Sprite.new.inspect
rescue
  puts "Caught an error"
end
puts Sprite.new.inspect # will not error

пластыри / string.rb:

class String
  def camelize
    self.split("_").map{|word| word.capitalize}.join
  end
end

Библиотека / autoload.rb:

module Autoload
  Dir.glob("#{APPLICATION_ROOT}/app/*/*").each do |path|
    classname = File.basename(path).gsub(/.rb$/,'').camelize
    autoload classname.to_sym, path
  end
end

приложение / модели / sprite.rb:

puts "Sprite Required!"
class Sprite
  puts "Sprite Defining!"
  def initialize
    puts "Sprite Initialized!"
  end
end
puts "Sprite Defined!"

Выход:

Sprite Required!
Sprite Defining!
Sprite Defined!
Caught an error
Sprite Initialized!
#<Sprite:0x000000024ee920>

Как мне получить желаемое поведение (без первоначальной ошибки)?

1 Ответ

2 голосов
/ 22 июля 2011

Проблема в том, что вы звоните autoload в области действия модуля Autoload. В этом случае Ruby ожидает или создает автозагрузку для символа Autoload::Sprite, когда вам нужно просто Sprite.

К счастью, это просто:

module Autoload
  def self.included(mod)
    # ...
    # Call autoload on the scope of the includer
    mod.autoload ...
  end
end

Или вы также можете явно вызвать автозагрузку на Object, поскольку именно здесь ваша «целевая область» для автозагрузки классов, скорее всего, будет:

Object.autoload ...
...