X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=lib%2Fsup%2Fhook.rb;h=0212c6bc9dfe26c738cab3d7f8b90929b7dc981a;hb=cdb10174bbb4f11f9e01ea3e683b3ad128fcfd2f;hp=dae2ce575f756b106a6277f4692ba548e0e28a14;hpb=dcd480edbf6f50a0c86298fd61ee8d517da53d0c;p=sup diff --git a/lib/sup/hook.rb b/lib/sup/hook.rb index dae2ce5..0212c6b 100644 --- a/lib/sup/hook.rb +++ b/lib/sup/hook.rb @@ -1,53 +1,61 @@ 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. - ## this is basically fail-fast. class HookContext def initialize name + @__say_id = nil @__name = name - @__locals = {} + @__cache = {} end - attr_writer :__locals - - def method_missing m, *a - case @__locals[m] - when Proc - @__locals[m].call(*a) - when nil - super + def say s + if BufferManager.instantiated? + @__say_id = BufferManager.say s, @__say_id + BufferManager.draw_screen else - @__locals[m] + log s end end - def say s - @__say_id = BufferManager.say s, @__say_id - BufferManager.draw_screen - end - def log s - Redwood::log "hook[#@__name]: #{s}" + info "hook[#@__name]: #{s}" end def ask_yes_or_no q - BufferManager.ask_yes_or_no q + if BufferManager.instantiated? + BufferManager.ask_yes_or_no q + else + print q + gets.chomp.downcase == 'y' + end end - def __binding - binding + def get tag + HookManager.tags[tag] end - def __cleanup + def set tag, value + HookManager.tags[tag] = value + end + + 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 @@ -58,26 +66,26 @@ class HookManager @hooks = {} @descs = {} @contexts = {} - - Dir.mkdir dir unless File.exists? dir + @tags = {} - self.class.i_am_the_instance self + Dir.mkdir dir unless File.exists? dir end + attr_reader :tags + 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") - BufferManager.flash "Error running hook: #{e.message}" + @hooks[name] = nil # disable it + BufferManager.flash "Error running hook: #{e.message}" if BufferManager.instantiated? end - context.__cleanup result end @@ -101,19 +109,22 @@ EOS end end + def enabled? name; !hook_for(name).nil? end + + def clear; @hooks.clear; end + private def hook_for name unless @hooks.member? name - @hooks[name] = - begin - returning IO.readlines(fn_for(name)).join do - log "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 + #log "disabled hook for '#{name}': #{e.message}" + nil + end end @hooks[name] @@ -124,7 +135,7 @@ private end def log m - Redwood::log("hook: " + m) + info("hook: " + m) end end