X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=lib%2Fsup%2Fhook.rb;fp=lib%2Fsup%2Fhook.rb;h=a2e88983cb3d7030abd845b83804828b9eb7b96b;hb=ffc8f7364d2e0c16ff908ec6ea5b1134effef348;hp=d0476dad95a78429513dfcb81a311d2a3cb72c86;hpb=ac2d27b230c0afc36eafddec1c387a6ab68a837d;p=sup diff --git a/lib/sup/hook.rb b/lib/sup/hook.rb index d0476da..a2e8898 100644 --- a/lib/sup/hook.rb +++ b/lib/sup/hook.rb @@ -1,33 +1,11 @@ module Redwood class HookManager - ## there's probably a better way to do this, but to evaluate a hook - ## with a bunch of pre-set "local variables" i define a function - ## per variable and then instance_evaluate the code. - ## - ## how does rails do it, when you pass :locals into a partial? - ## - ## i don't bother providing setters, since i'm pretty sure the - ## charade will fall apart pretty quickly with respect to scoping. - ## "fail-fast", we'll call it. class HookContext def initialize name @__say_id = nil @__name = name - @__locals = {} - end - - attr_writer :__locals - - def method_missing m, *a - case @__locals[m] - when Proc - @__locals[m] = @__locals[m].call(*a) # only call the proc once - when nil - super - else - @__locals[m] - end + @__cache = {} end def say s @@ -60,12 +38,24 @@ class HookManager HookManager.tags[tag] = value end - def __binding - binding - end - - def __cleanup + def __run __hook, __filename, __locals + __binding = binding + __lprocs, __lvars = __locals.partition { |k, v| v.is_a?(Proc) } + eval __lvars.map { |k, v| "#{k} = __locals[#{k.inspect}];" }.join, __binding + ## we also support closures for delays evaluation. unfortunately + ## we have to do this via method calls, so you don't get all the + ## semantics of a regular variable. not ideal. + __lprocs.each do |k, v| + self.class.instance_eval do + define_method k do + @__cache[k] ||= v.call + end + end + end + ret = eval __hook, __binding, __filename BufferManager.clear @__say_id if @__say_id + @__cache = {} + ret end end @@ -86,18 +76,16 @@ class HookManager def run name, locals={} hook = hook_for(name) or return context = @contexts[hook] ||= HookContext.new(name) - context.__locals = locals result = nil begin - result = context.instance_eval @hooks[name], fn_for(name) + result = context.__run hook, fn_for(name), locals rescue Exception => e log "error running hook: #{e.message}" log e.backtrace.join("\n") @hooks[name] = nil # disable it BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated? end - context.__cleanup result end @@ -127,15 +115,14 @@ private def hook_for name unless @hooks.member? name - @hooks[name] = - begin - returning IO.read(fn_for(name)) do - debug "read '#{name}' from #{fn_for(name)}" - end - rescue SystemCallError => e - #log "disabled hook for '#{name}': #{e.message}" - nil + @hooks[name] = begin + returning IO.read(fn_for(name)) do + debug "read '#{name}' from #{fn_for(name)}" end + rescue SystemCallError => e + #debug "disabled hook for '#{name}': #{e.message}" + nil + end end @hooks[name]