DRY синглтон-классов по обслуживанию рельсов - PullRequest
5 голосов
/ 24 апреля 2020

Я работаю с моделью персистентности Elasticsearch, и у меня есть несколько общих методов для каждого индекса.

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

class EventSearchService
  class << self

    def with_index(index_name)
      old_repository = repository
      @repository = EventSearchService::ElasticsearchEventRepository.new(index_name: index_name)

      yield

    ensure
      @repository = old_repository
    end

    def index_name
      repository.index_name
    end

   def index_all(event_documents)
      return unless event_documents.present?

      actions = event_documents.map do |e|
        { index: { _index: index_name, _id: e.id, _type: "_doc", data: e.to_hash }}
      end

      repository.client.bulk(body: actions)
    end


    protected

    def repository
      @repository ||= EventSearchService::ElasticsearchEventRepository.new
    end
  end
end

Моя проблема в том, что я закончил создать файлы с одинаковыми методами. Когда я пытаюсь извлечь его непосредственно в абстрактный класс, я получаю сообщение об ошибке, исследование которого доходит до такой степени, что одноэлементные классы не могут быть унаследованы.

После поиска некоторых ответов я последовал за этот поток , и я попытался DRY его

require 'forwardable'
require 'singleton'

class ElasticsearchService
  include Singleton

  class << self
    extend Forwardable

    def_delegators(
      :with_index,
      :index_name,
      :index_all,
      :repository
    )
  end

  def with_index(index_name)
    old_repository = repository
    @repository = search_repository.new(index_name: index_name)
​
    yield
​
  ensure
    @repository = old_repository
  end
​
  def index_name
    repository.index_name
  end
​
  def index_all(documents)
    return unless documents.present?
​
    actions = documents.map do |d|
      { index: { _index: index_name, _id: d.id, _type: "_doc", data: e.to_hash }}
    end
​
    repository.client.bulk(body: actions)
  end
​
  def search_repository
    fail "Needs to be overriden"
  end
​
  protected
​
  def repository
    @repository ||= search_repository.new
  end
end

И я включил его как

class EventSearchService < ElasticsearchService
  def search_repository
    EventSearchService::ElasticsearchEventRepository
  end
end

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

Я получаю ошибку:

`<class:ElasticsearchService>': undefined local variable or method `​' for ElasticsearchService:Class (NameError)

1 Ответ

3 голосов
/ 28 апреля 2020

Этот очень подлый. В вашем коде есть несколько не-ASCII-пробелов, которые интерпретатор ruby распознает как имя вызываемого метода.

Я бросил ваш код в терминал, получая точно такая же ошибка, как и у вас, но после того, как вы написали ее вручную и выполнили метод по методу, он не получил ее.

Найден собеседник в сети и после копирования / вставки кода (вот ссылка на один, который я использовал ), код выполнялся без этой ошибки.

Поэтому правильное форматирование файла должно справиться с той конкретной ошибкой, с которой вы столкнулись.

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