Как получить доступ к классу, определенному в модуле B, из модуля A - PullRequest
0 голосов
/ 08 мая 2020

Сообщение об ошибке:

NameError: uninitialized constant FinancialFunctions::ComputationSteps::TwoBranchesPerPeriod::Strategy1

Я бы хотел, чтобы Rails автоматически просматривал включенный модуль Strategies и видел класс, определенный в нем, а не просто просматривал TwoBranchesPerPeriod.

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

Есть два c решения, которые я не ищу:

  • require или load в верхней части файла, так как я хочу, чтобы автозагрузка Rails была основным решением этой проблемы и не требовала наличия нескольких файлов.
  • Явно укажите область видимости при инициализации класса. . Я знаю, что простой вызов Strategies::Strategy1.new будет работать, но это решение не работает для меня из-за длины нескольких классов. Я хотел бы просто определить зависимости в верхней части файла с помощью операторов include и иметь доступ к методам / классам, определенным во включенных модулях.
  • Я открыт для операторов autoload в файле, таком как strategy.rb, но из того, что я тестировал, это тоже не работает.

app / lib / financial_functions / computation_steps / two_branches_per_period.rb:

module FinancialFunctions
  module ComputationSteps
   module TwoBranchesPerPeriod
      include Strategies
      def a_method
        #The below line is resulting in the error
        # NameError: uninitialized constant FinancialFunctions::ComputationSteps::TwoBranchesPerPeriod::Strategy1
        a=Strategy1.new
      end
   end
  end
end 

/ приложение / lib / financial_functions / computation_steps / strategy1.rb:

module FinancialFunctions
  module ComputationSteps
   module Strategies
    class Strategy1
      def initialize
        puts "this should work"
      end
    end
  end
end

1 Ответ

0 голосов
/ 08 мая 2020

Я хотел бы просто определить зависимости в верхней части файла с помощью операторов include и получить доступ к методам / классам, определенным во включенных модулях.

Ваши ожидания не реальны c в Ruby. Ruby не имеет системы пакетов, а includes не эквивалентен imports на таких языках, как Python или ES6.

Как указано в комментариях @maxpleaner, включает только копии методов модуль.

Итак, чтобы сделать это, вам нужно будет определить новые константы в потребляющем классе / модуле:

module FinancialFunctions
  module ComputationSteps
    module TwoBranchesPerPeriod
      include Strategies
      Strategy1 = ComputationSteps::Strategies::Strategy1

      def a_method
        Strategy1.new
      end
    end
  end
end

Вы можете сделать это динамически с помощью Module#included hook:

module Foo
  module Bar
  end

  module Baz
  end

  def self.included(base)
    self.constants.each do |c|
      base.constant_set(c, self.constant_get(c))
    end
  end
end
module X
  includes Foo
end
irb(main):002:0> X::Bar
=> Foo::Bar

Но помимо того, что это забавный пример метапрограммирования, я не думаю, что это настолько мудро, поскольку нет способа справиться с конфликтами пространств имен. Вы также можете создать импровизированный эквивалент конструкции импорта:

module Importer
  def import(*constants, from:)
    constants.each do |c|
      const_set(c, from.const_get(c))
    end
  end
end
module Foo
  module Bar
    module A
    end
    module B
    end
  end
end
class Thing
  extend Importer
  import :A, :B, from: Foo::Bar
end
irb(main):001:0> Thing::A
=> Foo::Bar::A
irb(main):002:0> Thing::B
=> Foo::Bar::B

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...