如何将简单的DSL添加到Ruby类?

Rom*_*man 2 ruby ruby-on-rails

如何实现一个允许我使用DSL注册其他类的类,并且可以在实例化后访问它们,如下例所示:

module Google
  class Search
    def self.run 
      puts :search
    end
  end

  class Map
    def self.run 
      puts :map
    end
  end

  class Calendar
    def self.run 
      puts :calendar
    end
  end
end

class One
  has Google::Search
  has Google::Map

  def perform
    # run through all registered classes, instantiate and then call run on each
  end
end

class Two
  has Google::Calendar

  def perform
    # run through all registered classes, instantiate and then call run on each
  end
end

One.new.peform 
# => 'search'
# => 'map'

One.new.peform 
# => 'calendar'
Run Code Online (Sandbox Code Playgroud)

Ale*_*kin 5

你的初始代码包含几个错误,它甚至不会通过ruby解释器.

首先,您需要实现DSL处理程序:

module DSLHandler
  @@classes = {}
  def classes
    @@classes[self.name] ||= []
  end
  def has clazz
    classes << clazz
    puts "registered #{clazz} in #{classes}"
  end
  extend self
end
Run Code Online (Sandbox Code Playgroud)

现在需要理解,因为has在类级别上调用,必须在同一级别上调用perform .总结:

class Google ; end

class Google::Search
  def self.run
    puts :search
  end
end

class Google::Map
  def self.run
    puts :map
  end
end

class Google
  extend DSLHandler

  has Google::Search
  has Google::Map

  def self.perform
    classes.each { |clazz| clazz.run }
  end
end

Google.perform
Run Code Online (Sandbox Code Playgroud)

结果如预期:

# ? registered Google::Search in [Google::Search]
# ? registered Google::Map in [Google::Search, Google::Map]
# ? search
# ? map
Run Code Online (Sandbox Code Playgroud)