[macruby-changes] [3915] MacRuby/trunk

source_changes at macosforge.org source_changes at macosforge.org
Wed Apr 7 12:45:55 PDT 2010


Revision: 3915
          http://trac.macosforge.org/projects/ruby/changeset/3915
Author:   eloy.de.enige at gmail.com
Date:     2010-04-07 12:45:53 -0700 (Wed, 07 Apr 2010)
Log Message:
-----------
Once any framework is loaded, send KVO notifications from attr writers.

That is, loaded through Kernel#framework.

Modified Paths:
--------------
    MacRuby/trunk/compiler.cpp
    MacRuby/trunk/compiler.h
    MacRuby/trunk/objc.h
    MacRuby/trunk/objc.m
    MacRuby/trunk/spec/macruby/core/kvc_spec.rb
    MacRuby/trunk/spec/macruby/core/kvo_spec.rb

Added Paths:
-----------
    MacRuby/trunk/spec/macruby/fixtures/kvo_wrapper.rb

Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp	2010-04-07 07:34:31 UTC (rev 3914)
+++ MacRuby/trunk/compiler.cpp	2010-04-07 19:45:53 UTC (rev 3915)
@@ -100,6 +100,7 @@
     prepareIvarSlotFunc = NULL;
     getIvarFunc = NULL;
     setIvarFunc = NULL;
+    setKVOIvarFunc = NULL;
     definedFunc = NULL;
     undefFunc = NULL;
     aliasFunc = NULL;
@@ -5988,7 +5989,7 @@
 RoxorCompiler::compile_write_attr(ID name)
 {
     Function *f = cast<Function>(module->getOrInsertFunction("",
-		RubyObjTy, RubyObjTy, PtrTy, RubyObjTy, NULL));
+	RubyObjTy, RubyObjTy, PtrTy, RubyObjTy, NULL));
 
     Function::arg_iterator arg = f->arg_begin();
     current_self = arg++;
@@ -5997,14 +5998,19 @@
 
     bb = BasicBlock::Create(context, "EntryBlock", f);
 
-    // This disables ivar slot generation.
-    // TODO: make it work
-    const bool old_current_instance_method = current_instance_method;
-    current_instance_method = false;
+    std::vector<Value *> params;
+    params.push_back(current_self);
+    params.push_back(compile_id(name));
+    params.push_back(new_val);
 
-    Value *val = compile_ivar_assignment(name, new_val);
+    if (setKVOIvarFunc == NULL) {
+	    setKVOIvarFunc =
+	    cast<Function>(module->getOrInsertFunction("rb_vm_set_kvo_ivar",
+	            RubyObjTy, RubyObjTy, RubyObjTy, RubyObjTy, NULL));
+    }
 
-    current_instance_method = old_current_instance_method;
+    Value *val = CallInst::Create(setKVOIvarFunc,
+	params.begin(), params.end(), "", bb);
 
     ReturnInst::Create(context, val, bb);
 

Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h	2010-04-07 07:34:31 UTC (rev 3914)
+++ MacRuby/trunk/compiler.h	2010-04-07 19:45:53 UTC (rev 3915)
@@ -151,6 +151,7 @@
 	Function *prepareIvarSlotFunc;
 	Function *getIvarFunc;
 	Function *setIvarFunc;
+	Function *setKVOIvarFunc;
 	Function *definedFunc;
 	Function *undefFunc;
 	Function *aliasFunc;

Modified: MacRuby/trunk/objc.h
===================================================================
--- MacRuby/trunk/objc.h	2010-04-07 07:34:31 UTC (rev 3914)
+++ MacRuby/trunk/objc.h	2010-04-07 19:45:53 UTC (rev 3915)
@@ -19,6 +19,7 @@
 	bs_element_method_t *bs_method, char *buf, size_t buflen);
 
 void rb_objc_define_kvo_setter(VALUE klass, ID mid);
+VALUE rb_vm_set_kvo_ivar(VALUE obj, ID name, VALUE val);
 
 static inline IMP
 rb_objc_install_method(Class klass, SEL sel, IMP imp)

Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m	2010-04-07 07:34:31 UTC (rev 3914)
+++ MacRuby/trunk/objc.m	2010-04-07 19:45:53 UTC (rev 3915)
@@ -338,6 +338,8 @@
 #endif
 }
 
+static bool enable_kvo_notifications = false;
+
 VALUE
 rb_require_framework(VALUE recv, SEL sel, int argc, VALUE *argv)
 {
@@ -450,6 +452,8 @@
     reload_class_constants();
     reload_protocols();
 
+    enable_kvo_notifications = true;
+
     return Qtrue;
 }
 
@@ -505,6 +509,21 @@
 }
 
 VALUE
+rb_vm_set_kvo_ivar(VALUE obj, ID name, VALUE val)
+{
+    NSString *key = NULL;
+    if (enable_kvo_notifications) {
+	key = [(NSString *)rb_id2str(name) substringFromIndex:1]; // skip '@' prefix
+	[(id)obj willChangeValueForKey:key];
+    }
+    rb_ivar_set(obj, name, val);
+    if (enable_kvo_notifications) {
+	[(id)obj didChangeValueForKey:key];
+    }
+    return val;
+}
+
+VALUE
 rb_mod_objc_ib_outlet(VALUE recv, SEL sel, int argc, VALUE *argv)
 {
     int i;

Modified: MacRuby/trunk/spec/macruby/core/kvc_spec.rb
===================================================================
--- MacRuby/trunk/spec/macruby/core/kvc_spec.rb	2010-04-07 07:34:31 UTC (rev 3914)
+++ MacRuby/trunk/spec/macruby/core/kvc_spec.rb	2010-04-07 19:45:53 UTC (rev 3915)
@@ -221,3 +221,15 @@
     manipulateUnorderedCollection(w)
   end
 end
+
+class Wrapper
+  attr_accessor :whatever
+end
+
+describe "Module::attr_writer" do
+  it "defines an Objective-C style setter method" do
+    w = Wrapper.new
+    w.setWhatever(42)
+    w.whatever.should == 42
+  end
+end
\ No newline at end of file

Modified: MacRuby/trunk/spec/macruby/core/kvo_spec.rb
===================================================================
--- MacRuby/trunk/spec/macruby/core/kvo_spec.rb	2010-04-07 07:34:31 UTC (rev 3914)
+++ MacRuby/trunk/spec/macruby/core/kvo_spec.rb	2010-04-07 19:45:53 UTC (rev 3915)
@@ -1,33 +1,6 @@
-require File.dirname(__FILE__) + "/../spec_helper"
+require File.expand_path("../../spec_helper", __FILE__)
+require File.join(FIXTURES, "kvo_wrapper")
 
-class Wrapper
-  attr_accessor :whatever
-
-  def initialize(value)
-    super()
-    @wrapped = value
-    @whatever= 'like, whatever'
-  end
-
-  def wrappedValue
-    @wrapped
-  end
-end
-
-class FancyWrapper < NSValue
-  attr_accessor :whatever
-
-  def initialize(value)
-    super()
-    @wrapped = value
-    @whatever= 'like, whatever'
-  end
-
-  def wrappedValue
-    @wrapped
-  end
-end
-
 describe "An Object being observed through NSKeyValueObservation" do
   it "retains the values for its instance variables" do
     #
@@ -86,3 +59,40 @@
     lambda { w.inspect }.should_not raise_error
   end
 end
+
+describe "An accessor defined with Module::attr_writer" do
+  it "does not send any KVO notifications unless a framework has been loaded" do
+    expected_output = "Manfred is very happy with himself"
+
+    example = %{delegate = Object.new
+                def delegate.wrapperWillChangeValueForKey(key)
+                  raise "did not expect a KVO notification!"
+                end
+                w = Wrapper.new
+                w.kvoDelegate = delegate
+                w.whatever = "#{expected_output}"
+                puts w.whatever}.gsub("\n", ";")
+
+    output = ruby_exe(example, :options => "-r #{File.join(FIXTURES, "kvo_wrapper.rb")}")
+    output.chomp.should == expected_output
+  end
+  
+  it "sends KVO notifications, around assigning the new value, once a framework has been loaded" do
+    @w = Wrapper.new
+    @w.kvoDelegate = self
+    @w.whatever = "oh come on"
+    (@ranBefore && @ranAfter).should == true
+  end
+  
+  def wrapperWillChangeValueForKey(key)
+    key.should == "whatever"
+    @w.whatever.should == "like, whatever"
+    @ranBefore = true
+  end
+  
+  def wrapperDidChangeValueForKey(key)
+    key.should == "whatever"
+    @w.whatever.should == "oh come on"
+    @ranAfter = true
+  end
+end
\ No newline at end of file

Added: MacRuby/trunk/spec/macruby/fixtures/kvo_wrapper.rb
===================================================================
--- MacRuby/trunk/spec/macruby/fixtures/kvo_wrapper.rb	                        (rev 0)
+++ MacRuby/trunk/spec/macruby/fixtures/kvo_wrapper.rb	2010-04-07 19:45:53 UTC (rev 3915)
@@ -0,0 +1,43 @@
+class Wrapper
+  attr_accessor :whatever
+
+  def initialize(value = nil)
+    super()
+    @wrapped = value
+    @whatever= 'like, whatever'
+  end
+
+  def wrappedValue
+    @wrapped
+  end
+end
+
+class FancyWrapper < NSValue
+  attr_accessor :whatever
+
+  def initialize(value)
+    super()
+    @wrapped = value
+    @whatever= 'like, whatever'
+  end
+
+  def wrappedValue
+    @wrapped
+  end
+end
+
+class Wrapper
+  attr_accessor :whatever
+  
+  def kvoDelegate=(delegate)
+    @kvoDelegate = delegate
+  end
+  
+  def willChangeValueForKey(key)
+    @kvoDelegate.wrapperWillChangeValueForKey(key) if @kvoDelegate
+  end
+  
+  def didChangeValueForKey(key)
+    @kvoDelegate.wrapperDidChangeValueForKey(key) if @kvoDelegate
+  end
+end
\ No newline at end of file
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100407/e3d76c8a/attachment.html>


More information about the macruby-changes mailing list