2015-03-17 2 views
1

У меня есть гем проект со следующей структурой:RSpec поднимает NameErrors для кода в подкаталоге/Lib

foo-bar 
├── lib 
│   └── foo 
│    ├── bar 
│    │   └── qux.rb 
│    └── bar.rb 
└── spec 
    ├── spec_helper.rb 
    └── unit 
     ├── baz_spec.rb 
     └── qux_spec.rb 

В lib/foo, bar.rb определяет модуль Foo::Bar, и внутри этого класса Foo::Bar::Baz. Внутри lib/foo/bar, qux.rb определяется класс Foo::Bar::Qux.

spec_helper.rb устанавливает RSpec и Simplecov и заканчивается require 'foo/bar'. Оба baz_spec.rb и qux_spec.rb начинаются с require 'spec_helper'.

baz_spec.rb имеет характеристики для Foo::Bar::Baz, и он отлично работает. qux_spec.rb, однако, который имеет спецификации для Foo::Bar::Qux, терпит неудачу с:

/Users/me/foo-bar/spec/unit/qux_spec.rb:6:in `<module:Bar>': uninitialized constant Foo::Bar::Qux (NameError) 
    from /Users/me/foo-bar/spec/unit/qux_spec.rb:4:in `<module:Foo>' 
    from /Users/me/foo-bar/spec/unit/qux_spec.rb:3:in `<top (required)>' 
    from /Users/me/.rvm/gems/ruby-2.2.0/gems/rspec-core-3.2.2/lib/rspec/core/configuration.rb:1226:in `load' 
    ... 
    (etc.) 

Я подтвердил, что это не просто опечатка, перемещая код Foo::Bar::Baz из lib/foo/bar.rb и в свой собственный файл, lib/foo/bar/baz.rb, после чего baz_spec.rb также перестает работать.

Это также, кажется, не делают разницы объявить ли я класс как

class Foo::Bar::Qux 
    ... 

или

module Foo 
    module Bar 
    class Qux 
     ... 

Я использую рубин 2.2.0 с RSpec 3.2.2 на Mac OS X Yosemite.

Ясно, что что-то не так с моим requires, но, как новичок в Ruby, я этого не вижу. Есть идеи?

+0

Возможное решение зависит от того, какие рамки вы используете. Итак, используете ли вы Rails или ActiveSupport? – jack

+0

Ничего. Ну, я полагаю, что ActiveSupport там, потому что у меня есть ActiveJob в моем gemspec, но он пока не используется. –

ответ

0

Решенный: после более пристального изучения других проектов я был cargo-culting от, я понял, что неправильно понял require.

В отличие от (по-видимому) эквивалента Rails, готовый Kernel.require загружает только файлы .rb (и библиотеки расширений). Таким образом, в приведенном выше примере require 'foo/bar' не загружает файлы из каталога foo/bar, он просто загружает foo/bar.rb.

Для того, чтобы загрузить файлы в foo/bar, в том числе qux.rb, я должен был пойти в bar.rb и явно загрузить эти файлы в верхней части объявления модуля:

module Foo 
    module Bar 
    Dir.glob(File.expand_path('../bar/*.rb', __FILE__), &method(:require)) 

    # ...module declaration continues... 

Только один из многих сценариев языка -Изличные ловушки, ожидающие тех, кто приезжает в Руби из других более тяжеловесных языков, я полагаю.

1

Если вы используете ActiveSupport одной линии, как это поможет вам:

ActiveSupport::Dependencies.autoload_paths << "./lib" 

Если вы теперь пытается использовать Foo::Bar::Qux, ActiveSupport будет искать файл с именем foo/bar/qux.rb внутри папки lib.

+0

Я бы не рекомендовал использовать функцию автозагрузки ActiveSupport, поскольку она вводит зависимость, которая вам может не понадобиться, а также не дает вам контроля над порядком загрузки файлов. Кроме того, рассмотрите возможность использования встроенной функции автозагрузки Ruby (http://ruby-doc.org/core-2.1.0/Module.html#method-i-autoload), если вы используете последнюю версию –

2

необходимо добавить файл foo.rb под номером ./lib и добавить необходимые заявления для каждого файла, чтобы вы могли загрузить их. Вы можете посмотреть образец драгоценного камня для справки: dogeify и статью, в которой вы видите создание драгоценного камня build your first gem.

 Смежные вопросы

  • Нет связанных вопросов^_^