2014-11-22 2 views
0

Я играю с некоторыми концепциями метапрограммирования и задаюсь вопросом, возможно ли что-то, что я хочу сделать, просто.Как загрузить файл в контексте объекта

Там просто DLS для событий,

//test_events.rb 
event 'monthly events are suspiciously high' do 
    true 
end 

и сценарий должен кричать, когда событие возвращает истину, я пытаюсь сделать это, не загрязняя глобальное пространство имен методы события, и любой переменный экземпляр. Так что я пытаюсь что-то вроде этого:

Dir.glob('*_events.rb').each do |file| 

    MyClass = Class.new do 
    define_method :event do |name, &block| 
     @events[name] = block 
    end 
    end 

    env = MyClass.new 

    env.instance_eval{@events = {}} 

    env.instance_eval{load(file)} 

end 

Таким образом, для каждого * _events.rb файла Я хотел бы, чтобы загрузить его в контексте MyClass (я знаю, что с 2-ой петле Dir.glob # каждый будет жаловаться уже определенный const - не важно сейчас).

Проблема с env.instance_eval{load(file)} кода в test_events.rb выполняется в контексте объекта, потому что я получаю

undefined method `event' for main:Object (NoMethodError) 

Есть ли способ сделать это? (Я стараюсь сейчас в 1.9.3, но изменения версии вверх не является проблемой, так как это просто упражнения)

+0

вы можете захотеть взглянуть на эту BlogPost для пошагового о том, как создать пользовательский DSL в Ruby: http://robots.thoughtbot.com/writing-a-domain-specific-language-in-ruby –

+0

Спасибо, это действительно интересно читать. Тем не менее мне не удалось найти ответ на мой вопрос. Дело в том, что я знаю, как сделать DSL, который будет работать следующим образом: «Redflag.register do Событие« Месячные события подозрительно высокие »do true end end ' Это довольно просто. Но позвольте мне перефразировать мой вопрос: как вызвать Kernel # load в контексте любого экземпляра объекта. Из всех моих попыток похоже, что он всегда будет вызван в контексте объекта объекта. Является ли это возможным? – meta

+1

AFAIK no, 'load' не зависит от контекста - он загружает код в глобальную область. –

ответ

2

instance_eval может занять String в качестве аргумента вместо блока, так что вместо load (который, как вы предлагаете загрузит файл на верхнем уровне), вам необходимо прочитать содержимое файла в строку, чтобы передать, что-то вроде:

env.instance_eval(File.read(file)) 
Смежные вопросы