]> git.cworth.org Git - sup/blob - lib/sup/hook.rb
hook system
[sup] / lib / sup / hook.rb
1 module Redwood
2
3 class HookManager
4
5   ## there's probably a better way to do this, but to evaluate a hook
6   ## with a bunch of pre-set "local variables" i define a function
7   ## per variable and then instance_evaluate the code.
8   ##
9   ## i don't bother providing setters, since i'm pretty sure the
10   ## charade will fall apart pretty quickly with respect to scoping.
11   ## this is basically fail-fast.
12   class HookContext
13     def initialize name, hash
14       @__name = name
15       hash.each do |k, v|
16         self.class.instance_eval { define_method(k) { v } }
17       end
18     end
19
20     def say s
21       @__say_id = BufferManager.say s, @__say_id
22     end
23
24     def log s
25       Redwood::log "hook[#@__name]: #{s}"
26     end
27
28     def __binding 
29       binding
30     end
31
32     def __cleanup
33       BufferManager.clear @__say_id if @__say_id
34     end
35   end
36
37   include Singleton
38
39   def initialize dir
40     @dir = dir
41     @hooks = {}
42     @descs = {}
43     Dir.mkdir dir unless File.exists? dir
44
45     self.class.i_am_the_instance self
46   end
47
48   def run name, locals={}
49     hook = hook_for(name) or return
50     context = HookContext.new name, locals
51
52     begin
53       result = eval @hooks[name], context.__binding, fn_for(name)
54       if result.is_a? String
55         log "got return value: #{result.inspect}"
56         BufferManager.flash result 
57       end
58     rescue Exception => e
59       log "error running hook: #{e.message}"
60       BufferManager.flash "Error running hook: #{e.message}"
61     end
62     context.__cleanup
63   end
64
65   def register name, desc
66     @descs[name] = desc
67   end
68
69   def print_hooks f=$stdout
70 puts <<EOS
71 Have #{@descs.size} registered hooks:
72
73 EOS
74
75     @descs.sort.each do |name, desc|
76       f.puts <<EOS
77 #{name}
78 #{"-" * name.length}
79 File: #{fn_for name}
80 #{desc}
81 EOS
82     end
83   end
84
85 private
86
87   def hook_for name
88     unless @hooks.member? name
89       @hooks[name] =
90         begin
91           returning IO.readlines(fn_for(name)).join do
92             log "read '#{name}' from #{fn_for(name)}"
93           end
94         rescue SystemCallError => e
95           nil
96         end
97     end
98
99     @hooks[name]
100   end
101
102   def fn_for name
103     File.join @dir, "#{name}.rb"
104   end
105
106   def log m
107     Redwood::log("hook: " + m)
108   end
109 end
110
111 end