Рубин Метапрограммирование - PullRequest
4 голосов
/ 29 мая 2010

Я пытаюсь написать DSL, который позволяет мне делать

Policy.name do
 author "Foo"
 reviewed_by "Bar"
end

Следующий код может почти обработать его:

class Policy
  include Singleton
  def self.method_missing(name,&block)
      puts name
      puts "#{yield}"
  end
  def self.author(name)
   puts name
  end
  def self.reviewed_by(name)
   puts name
  end
end

Определяя мой метод как методы класса (self.method_name), я могу получить к нему доступ, используя следующий синтаксис:

Policy.name do
 Policy.author "Foo"
 Policy.reviewed_by "Bar"
end

Если я удаляю «self» из имен методов и пытаюсь использовать свой желаемый синтаксис, то я получаю ошибку «Method not Found» в Main, поэтому он не может найти мою функцию до ядра модуля. Хорошо, я понимаю ошибку. Но как я могу это исправить? Как я могу исправить свой класс, чтобы он работал с моим желаемым синтаксисом, что?

Ответы [ 2 ]

4 голосов
/ 29 мая 2010

Чтобы контролировать, что self находится в области действия блока (поскольку author разрешается в self.author), вы можете использовать instance_eval.

class Policy
  def self.name(&block)
    PolicyNameScope.new(block)
  end

  class PolicyNameScope
    def initialize(block)
      instance_eval(&block)     
    end

    def author(author)
      @author = author
    end

    def reviewed_by(reviewed_by)
      @reviewed_by = reviewed_by
    end
  end
end

policy = Policy.name do
  author "Dawg"
  reviewed_by "Dude"
end

p policy
# => #<Policy::PolicyNameScope:0x7fb81ef9f910 @reviewed_by="Dude", @author="Dawg">

Класс PolicyNameScope имеет методы экземпляра, которые разрешены в блоке name. Это связано с тем, что методы из Policy недоступны внутри блока, что делает DSL намного более тесным.

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

1 голос
/ 13 июля 2010

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

class Policy

  def self.method_missing(name,&block)
    self.class_eval(&block)
  end
  def self.author(name)
    p name
  end
  def self.reviewed_by(name)
    p name
  end

end

Policy.name do
  author "Foo"
  reviewed_by "Bar"
end

Это не оптимизированное решение, а решение вашей заявленной проблемы.

...