Требование нескольких модулей в одном проекте / гем - PullRequest
0 голосов
/ 23 мая 2018

У меня есть проект со следующей структурой:

Project
├── lib
│   ├── project.rb
│   └── thor_commands
│       ├── cli_starter.rb
│       ├── command1.rb
│       └── command2.rb
└── runme

runme

#!/usr/bin/env ruby

require_relative 'lib/project.rb'

project.rb:

Dir[File.dirname(__FILE__) + '/thor_commands/*.rb'].each { |file| require file }

cli_starter.rb

require_relative command1.rb  # Why do I need these
require_relative command2.rb  #

module MyThorCLI
  class Base < Thor
    Command1 ...
  end
end

Если я запускаю что-то вроде runme cmd1 без require_relative command1 и require_relative command2 в cli_starter.rb, я получаю ошибку:uninitialized constant MyThorCLI::Base::Command1.

Я пытаюсь понять, почему мне нужно require_relative command1 и require_relative command2, хотя в project.rb.

все уже требовалось. Мне кажется, что модули иклассы в этих модулях должны быть загружены во время выполнения, но это не удалось.

1 Ответ

0 голосов
/ 23 мая 2018

cli_starter.rb ссылается на Command1 в требуемое время, до того, как другие файлы были загружены: отдельный шаг разрешения отсутствует.

Дополнительные вызовы require_relative гарантируют, что эти файлы загружаются первыми, поэтому ихконстанты доступны, пока загружается cli_starter.rb.

Различные формы require по существу эквивалентны вставке содержимого файла в этот момент в коде (если это еще не требуется).

Таким образом (в зависимости от порядка Dir[] находит файлы из вашего глобуса), общее неудачное выполнение выглядит примерно так:

module MyThorCLI
  class Base < Thor
    Command1 ...
  end
end

class Command1
end

Без отдельного шага разрешения это происходит, когдаон попадает в ссылку Command1, потому что определение класса еще не встречалось - это несколько строк ниже.


Добавление этих требований - вполне разумное решение проблемы.Потенциально хитрый подход состоит в том, чтобы изменить содержимое cli_starter.rb, чтобы оно не ссылалось на другие константы до позднего времени (помещая эти ссылки в вызываемые позднее методы, а не непосредственно в тело класса).Будет ли это возможно, зависит от того, что делает с ними ваш класс.

class Base ..
  @@first_command = Command1 # this reference is evaluated when it's encountered
  def first_command
    @@first_command
  end

# -->

class Base ..
  def first_command
    Command1 # this one is evaluated when the method is called
  end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...