sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit e459fc846862a1499f3acb2f8a2eb098344ee7ac
parent 1a3850da15b12880f355ef70f6bfc881a859874f
Author: William Morgan <wmorgan-sup@masanjin.net>
Date:   Sun, 23 Aug 2009 13:11:14 -0400

rewrite hookmanager to use eval for locals

This should fix all the issues that were cropping up when locals were faked
with method calls (the setter issue and the nil issue).

Diffstat:
M lib/sup/hook.rb | 52 +++++++++++++---------------------------------------
1 file changed, 13 insertions(+), 39 deletions(-)
diff --git a/lib/sup/hook.rb b/lib/sup/hook.rb
@@ -1,33 +1,10 @@
 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
     end
 
     def say s
@@ -60,12 +37,12 @@ class HookManager
       HookManager.tags[tag] = value
     end
 
-    def __binding 
-      binding
-    end
-
-    def __cleanup
+    def __run __hook, __filename, __locals
+      __binding = binding
+      eval __locals.map { |k, v| "#{k} = __locals[#{k.inspect}];" }.join, __binding
+      ret = eval __hook, __binding, __filename
       BufferManager.clear @__say_id if @__say_id
+      ret
     end
   end
 
@@ -88,18 +65,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
 
@@ -129,15 +104,14 @@ private
 
   def hook_for name
     unless @hooks.member? name
-      @hooks[name] =
-        begin
-          returning IO.read(fn_for(name)) 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
+          log "read '#{name}' from #{fn_for(name)}"
         end
+      rescue SystemCallError => e
+        #log "disabled hook for '#{name}': #{e.message}"
+        nil
+      end
     end
 
     @hooks[name]