<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -149,6 +149,12 @@ function_p(VALUE self)
   JRETURN_RUBY(JS_TypeOfValue(context, proxy_value) == JSTYPE_FUNCTION ? Qtrue : Qfalse);
 }
 
+static VALUE
+callable_test_p(VALUE self, VALUE proxy)
+{
+  return function_p(proxy);
+}
+
 /*
  * call-seq:
  *   respond_to?(symbol)
@@ -501,12 +507,19 @@ static void finalize(RubyLandProxy* proxy)
 
 bool ruby_value_is_proxy(VALUE maybe_proxy)
 {
-  return proxy_class == CLASS_OF(maybe_proxy) || script_class == CLASS_OF(maybe_proxy);
+  return rb_obj_is_kind_of(maybe_proxy, proxy_class);
 }
 
 bool ruby_value_is_script_proxy(VALUE maybe_proxy)
 {
-  return script_class == CLASS_OF(maybe_proxy);
+  return rb_obj_is_kind_of(maybe_proxy, script_class);
+}
+
+VALUE apply_wrappers(VALUE proxy)
+{
+  VALUE johnson = rb_const_get(rb_mKernel, rb_intern(&quot;Johnson&quot;));
+  VALUE johnson_proxy = rb_const_get(johnson, rb_intern(&quot;RubyLandProxy&quot;));
+  return rb_funcall(johnson_proxy, rb_intern(&quot;apply_wrappers&quot;), 1, proxy);
 }
 
 JSBool unwrap_ruby_land_proxy(JohnsonRuntime* runtime, VALUE wrapped, jsval* retval)
@@ -542,6 +555,9 @@ VALUE make_ruby_land_proxy(JohnsonRuntime* runtime, jsval value, const char cons
     PREPARE_RUBY_JROOTS(context, 1);
     JROOT(value);
 
+    VALUE rb_runtime = (VALUE)JS_GetRuntimePrivate(runtime-&gt;js);
+    rb_iv_set(proxy, &quot;@runtime&quot;, rb_runtime);
+
     our_proxy-&gt;runtime = runtime;
     our_proxy-&gt;key = (void *)value;
     our_proxy-&gt;self = proxy;
@@ -552,10 +568,11 @@ VALUE make_ruby_land_proxy(JohnsonRuntime* runtime, jsval value, const char cons
     // put the proxy OID in the id map
     JCHECK(JS_HashTableAdd(runtime-&gt;jsids, (void *)value, (void *)our_proxy));
 
-    VALUE rb_runtime = (VALUE)JS_GetRuntimePrivate(runtime-&gt;js);
-    rb_iv_set(proxy, &quot;@runtime&quot;, rb_runtime);
+    VALUE final_proxy = JPROTECT(apply_wrappers, proxy);
 
-    JRETURN_RUBY(proxy);
+    our_proxy-&gt;self = final_proxy;
+
+    JRETURN_RUBY(final_proxy);
   }
 }
 
@@ -580,11 +597,15 @@ void init_Johnson_SpiderMonkey_Proxy(VALUE spidermonkey)
   rb_define_method(proxy_class, &quot;length&quot;, length, 0);
   rb_define_method(proxy_class, &quot;to_s&quot;, to_s, 0);
 
-  rb_define_private_method(proxy_class, &quot;native_call&quot;, native_call, -1);
   rb_define_private_method(proxy_class, &quot;runtime&quot;, runtime, 0);
   rb_define_private_method(proxy_class, &quot;function_property?&quot;, function_property_p, 1);
   rb_define_private_method(proxy_class, &quot;call_function_property&quot;, call_function_property, -1);
 
+  VALUE callable = rb_define_module_under(proxy_class, &quot;Callable&quot;);
+  rb_define_singleton_method(callable, &quot;test?&quot;, callable_test_p, 1);
+  rb_define_private_method(callable, &quot;native_call&quot;, native_call, -1);
+
+  rb_funcall(johnson_proxy, rb_intern(&quot;insert_wrapper&quot;), 1, callable);
 
   script_class = rb_define_class_under(spidermonkey, &quot;RubyLandScript&quot;, proxy_class);
 }</diff>
      <filename>ext/spidermonkey/ruby_land_proxy.c</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,47 @@
 module Johnson #:nodoc:
   class RubyLandProxy
+    class &lt;&lt; self
+      def apply_wrappers(proxy)
+        wrappers.each do |(wrapper, test)|
+          next if test &amp;&amp; !test.call(proxy)
+          next if wrapper.respond_to?(:test?) &amp;&amp; !wrapper.test?(proxy)
+
+          if wrapper.respond_to?(:call)
+            proxy = wrapper.call(proxy)
+            break unless Johnson::RubyLandProxy === proxy
+          else
+            proxy.send :extend, wrapper
+          end
+        end
+        proxy
+      end
+      def add_wrapper(wrapper, &amp;test)
+        wrappers.push [wrapper, test]
+      end
+      def insert_wrapper(wrapper, &amp;test)
+        wrappers.unshift [wrapper, test]
+      end
+      def wrappers
+        @wrappers ||= []
+      end
+    end
+
+    module Callable
+      def self.test?(proxy)
+        proxy.respond_to?(:call_using)
+      end
+
+      def to_proc
+        @proc ||= Proc.new { |*args| call(*args) }
+      end
+
+      def call(*args)
+        call_using(runtime.global, *args)
+      end
+    end
+
+    add_wrapper Callable
+
     include Enumerable
 
     # FIXME: need to revisit array vs non-array proxy, to_a/to_ary semantics, etc.
@@ -11,14 +53,6 @@ module Johnson #:nodoc:
     end
     private :initialize
 
-    def to_proc
-      @proc ||= Proc.new { |*args| call(*args) }
-    end
-
-    def call(*args)
-      call_using(runtime.global, *args)
-    end
-
     def inspect
       toString
     end</diff>
      <filename>lib/johnson/ruby_land_proxy.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,10 @@
 module Johnson #:nodoc:
   module SpiderMonkey #:nodoc:
     class RubyLandProxy &lt; Johnson::RubyLandProxy # native
-      def call_using(this, *args)
-        native_call(this, *args)
+      module Callable
+        def call_using(this, *args)
+          native_call(this, *args)
+        end
       end
     end
     class RubyLandScript &lt; Johnson::SpiderMonkey::RubyLandProxy # native</diff>
      <filename>lib/johnson/spidermonkey/ruby_land_proxy.rb</filename>
    </modified>
    <modified>
      <diff>@@ -63,7 +63,9 @@ module Johnson
       end
       
       def test_calling_non_functions_complains
-        assert_raise(RuntimeError) { @runtime.evaluate(&quot;new Object()&quot;).call }
+        o = @runtime.evaluate(&quot;new Object()&quot;)
+        assert_equal(false, o.respond_to?(:call))
+        assert_raise(NoMethodError) { o.call }
       end
       
       def test_functions_can_be_called</diff>
      <filename>test/johnson/spidermonkey/ruby_land_proxy_test.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>46d4f089f34a90a0a4e2305de7a57e2cf903dd4f</id>
    </parent>
  </parents>
  <author>
    <name>Matthew Draper</name>
    <email>matthew@trebex.net</email>
  </author>
  <url>http://github.com/jbarnette/johnson/commit/1df39ce9780f1b24dfd49716c99abe909781be46</url>
  <id>1df39ce9780f1b24dfd49716c99abe909781be46</id>
  <committed-date>2009-10-03T20:55:00-07:00</committed-date>
  <authored-date>2009-10-03T20:47:56-07:00</authored-date>
  <message>Apply wrappers during RubyLandProxy creation.

This allows pure-ruby code to control how different JS values are
presented to the rest of ruby-land. Such wrappers provide for the most
common case, but there's also a need to be able to define a conversion
to be applied each time the proxy is required, too. And then we need
corresponding functionality in js-land.</message>
  <tree>3ebf7cec40693a5084236a1490b3b866c3074fd1</tree>
  <committer>
    <name>Matthew Draper</name>
    <email>matthew@trebex.net</email>
  </committer>
</commit>
