ruby / Передача аргументов динамически созданному классу - PullRequest
2 голосов
/ 26 октября 2019

Вероятно, есть много других лучших способов;но имея следующий фрагмент кода:

class ApplicationService
  def self.build(*args, &block)
    new(*args, &block).build
  end
end

class BaseClass; end

class Fetcher < ApplicationService
  attr_reader :resource_name

  def initialize(resource_name)
    @resource_name = resource_name
  end

  def build
    resource_name = @resource_name

    Class.new(BaseClass) do
      @@resource_name = resource_name

      class << self
        def all
          "http://some.remote.resource/#{@@resource_name}/all"
        end
      end
    end
  end
end


, чтобы получить начальный resource_name в методе self.all, я придумал определение @@resource_name = resource_name. Я абсолютно не уверен, что это хороший путь.

Я бы хотел использовать такой «генератор», чтобы обеспечить следующий интерфейс:

## In some kind of initializers :
Xyz = Fetcher.build('xyz')

## Final use :
Xyz.all

Будет ли лучший шаблон для динамического создания класса при передаче аргументов при создании этого класса?

1 Ответ

1 голос
/ 26 октября 2019

Неясно, почему вы хотите создать класс в первую очередь. Если для этого есть веские причины, мой ответ является недействительным.

Вы можете вести себя желаемым образом, используя «стандартные» методы ООП и работая с экземплярами

class Fetcher
  def initialize(resource_name)
    @resource_name = resource_name
  end

  def all
    "http://some.remote.resource/#{@resource_name}/all"
  end
end

xyz_fetcher = Fetcher.new('xyz')
xyz_fetcher.all

В противном случае ваш кодэто более или менее то, что вы бы / должны сделать, я думаю. Просто я бы позволил классу Fetcher выступать в роли одиночного (не использовать экземпляр Fetcher):

class Fetcher < ApplicationService
  # make a singleton by privatizing initialize (read this up somewhere else)

  def self.build(resource_name)
    Class.new(BaseClass) do
      @@resource_name = resource_name

      class << self
        def all
          "http://some.remote.resource/#{@@resource_name}/all"
        end
      end
    end
  end
end

Тогда

Xyz = Fetcher.build('xyz')
Xyz.all

Теперь у вас есть материалс ApplicationService, который более или менее достигает этого (и пропускает блок), так что, вероятно, мы читатели пропускаем некоторые части общей картины ... пожалуйста, уточните, если это так.

Помимо синглетонизации, вы могли бывместо этого также работайте с модулями (спасибо @max за комментарий).

...