Передавать динамические типы в конвейерный контейнер - PullRequest
0 голосов
/ 17 сентября 2018

Я хочу сделать осколок, который поможет пошагово обрабатывать данные с рабочими, организованными в конвейер.Я добился определенного результата, но мне кажется, что это можно сделать проще и удобнее.В текущем решении мне не нравится, что нужно указывать тип каждого работника, даже если этот работник упакован в другой класс ( онлайн-пример ):

class Worker
  def do_it(data : String)
    puts "#{data} from #{self.class}"
  end
end

class Worker1 < Worker; end
class Worker2 < Worker; end
class Worker3 < Worker; end

class Wrapper(T)
  property item : T
  def initialize(@item : T); end
  def worker
    @item
  end
end

class Pipeline(T)
  @stack = [] of T

  def self.build
    with self.new yield
  end

  def add(wrapper : T)
    @stack << wrapper
  end

  def run(data : String)
    @stack.each do |wrapper|
      wrapper.worker.do_it(data)
    end
  end

end

alias WrapperObject = Wrapper(Worker1) | Wrapper(Worker2) | Wrapper(Worker3)

Pipeline(WrapperObject).build do
  add Wrapper(Worker1).new(Worker1.new)
  add Wrapper(Worker2).new(Worker2.new)
  add Wrapper(Worker3).new(Worker3.new)
  run("Some string data")
end

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

macro collect_types(workers)
  {% worker_types = workers.map{|k| k.id }.join(" | ") %}
  alias worker_types = {{ worker_types }}
  STACK = [] of {{ worker_types }}
end

, но потерял возможность наследования Pipeline ... В свете моих сновОсколки следует использовать так:

require 'pipeline'

class Worker < Pipeline::Worker
  def process(data : String)
    # some business logic
  end
end

pipeline = Pipeline::Line.build do
  add Worker1
  add Worker2
  add Worker3
end

result = pipeline.run(data)

Это возможно?

1 Ответ

0 голосов
/ 17 сентября 2018

Проблема была решена с помощью Шаблон команды для Crystal от @veelenga. Пример на carc.in

...