[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