]> git.cworth.org Git - sup/blob - lib/sup/hook.rb
rewrite hookmanager to use eval for locals
[sup] / lib / sup / hook.rb
1 module Redwood
2
3 class HookManager
4   class HookContext
5     def initialize name
6       @__say_id = nil
7       @__name = name
8     end
9
10     def say s
11       if BufferManager.instantiated?
12         @__say_id = BufferManager.say s, @__say_id
13         BufferManager.draw_screen
14       else
15         log s
16       end
17     end
18
19     def log s
20       Redwood::log "hook[#@__name]: #{s}"
21     end
22
23     def ask_yes_or_no q
24       if BufferManager.instantiated?
25         BufferManager.ask_yes_or_no q
26       else
27         print q
28         gets.chomp.downcase == 'y'
29       end
30     end
31
32     def get tag
33       HookManager.tags[tag]
34     end
35
36     def set tag, value
37       HookManager.tags[tag] = value
38     end
39
40     def __run __hook, __filename, __locals
41       __binding = binding
42       eval __locals.map { |k, v| "#{k} = __locals[#{k.inspect}];" }.join, __binding
43       ret = eval __hook, __binding, __filename
44       BufferManager.clear @__say_id if @__say_id
45       ret
46     end
47   end
48
49   include Singleton
50
51   def initialize dir
52     @dir = dir
53     @hooks = {}
54     @descs = {}
55     @contexts = {}
56     @tags = {}
57
58     Dir.mkdir dir unless File.exists? dir
59
60     self.class.i_am_the_instance self
61   end
62
63   attr_reader :tags
64
65   def run name, locals={}
66     hook = hook_for(name) or return
67     context = @contexts[hook] ||= HookContext.new(name)
68
69     result = nil
70     begin
71       result = context.__run hook, fn_for(name), locals
72     rescue Exception => e
73       log "error running hook: #{e.message}"
74       log e.backtrace.join("\n")
75       @hooks[name] = nil # disable it
76       BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated?
77     end
78     result
79   end
80
81   def register name, desc
82     @descs[name] = desc
83   end
84
85   def print_hooks f=$stdout
86 puts <<EOS
87 Have #{@descs.size} registered hooks:
88
89 EOS
90
91     @descs.sort.each do |name, desc|
92       f.puts <<EOS
93 #{name}
94 #{"-" * name.length}
95 File: #{fn_for name}
96 #{desc}
97 EOS
98     end
99   end
100
101   def enabled? name; !hook_for(name).nil? end
102
103 private
104
105   def hook_for name
106     unless @hooks.member? name
107       @hooks[name] = begin
108         returning IO.read(fn_for(name)) do
109           log "read '#{name}' from #{fn_for(name)}"
110         end
111       rescue SystemCallError => e
112         #log "disabled hook for '#{name}': #{e.message}"
113         nil
114       end
115     end
116
117     @hooks[name]
118   end
119
120   def fn_for name
121     File.join @dir, "#{name}.rb"
122   end
123
124   def log m
125     Redwood::log("hook: " + m)
126   end
127 end
128
129 end