- From: Ben Lavender <ben@dydra.com>
- Date: Fri, 20 May 2011 12:11:10 -0500
- To: Christoph Badura <bad@bsd.de>
- Cc: public-rdf-ruby@w3.org
This is a quirk of Promise. In Ruby 1.8, there is no BasicObject, so Promise fakes it by undefining all of the non-critical methods on Object. When you monkey-patch Object to have a to_zorch, Promise does not pass the method through to the underlying promised thunk, and you get Object's version. In Ruby 1.9 (which I tested, which is why I did not see the same behavior), Promise uses BasicObject, which did not get #to_zorch added to it by adding it to Object. I do not imagine this behavior would happen in any case other than monkey-patching Object itself. Easy repro in 1.8.7: require 'promise' class Object def to_zorch "promises can't be zorched!" end end class Fixnum def to_zorch to_s end end x = promise { 15 } x.to_zorch # => "promises can't be zorched!" in 1.8.7, "15" in 1.9.2 There are two immediate workarounds: * Upgrade to 1.9 already ;) RVM makes it easy. * Remove to_zorch from Promise: x.to_zorch # => "promises can't be inspected!" in 1.8.7, "15" in 1.9.2 Promise.__send__(:undef_method, :to_zorch) x.to_zorch # => "15" everywhere I'm not sure that this is worth fixing in promise proper; it's slow enough already. But I will try and think of a way to document this gotcha. Ben On Fri, May 20, 2011 at 10:57 AM, Christoph Badura <bad@bsd.de> wrote: > On Thu, May 19, 2011 at 05:28:46PM -0500, Ben Lavender wrote: >> > Run the following example in irb to see what is happening. While >> > writing that test case I also discovered that >> > SomeModel.for('123', :has_many_property => other_model_instance) >> > messes up the subject of the object recoded in the has_many_property. >> >> That's to be expected; it wants a Set or Array. Try :has_many_property >> => [ other_instance] > > You expect it not to fail but to mess up the object it is storing? > I'd expect it to fail or to do something sensible. If I read the rspec > specs right you expect it to do something sensible for > > some_model_instance.has_many_property = other_model_instance > > Check my irb output below. ab.subject ends up as "http://example.com/a/A" > >> > c.bar.first.super >> > c.bar.first.to_zorch >> > c.reload >> > c.bar.first.super >> > c.bar.first.to_zorch # XXX fails > >> What fails? What is the expected behavior? For me, c.bar.first is an >> A, which has a defined #to_zorch. When I call it, I get A's subject? > > I get different output for both invocations of c.bar.first.to_zorch. > The first one returns A's subject, the second one "boom!". > > The calls to super are just to provoke a backtrace to demonstrate that > the after the reload c.bar.first.to_zorch goes through the promise's > method_missing handler. > > I guess I was already to tired yesterday. I wanted to mention that I ran > this under ruby 1.8.7 and Spira 0.0.12. > > Here is the relevant output from my system's irb after the initialisations: > > xxx.rb(main):037:0* x = A.for('123', :foo => 'a foo').save! > => <A:-579815178 @subject: http://example.com/a/123> > xxx.rb(main):038:0> B.for('456', :foo => 'b foo', :bar => x).save! > => <B:-579595548 @subject: http://example.com/b/456> > xxx.rb(main):039:0> > xxx.rb(main):040:0* a = A.for '123' > => <A:-578851808 @subject: http://example.com/a/123> > xxx.rb(main):041:0> a.attributes > => {:foo=>"a foo"} > xxx.rb(main):042:0> b = B.for '456' > => <B:-578860798 @subject: http://example.com/b/456> > xxx.rb(main):043:0> b.attributes > => {:bar=>#<Set: {<A:-578865728 @subject: http://example.com/a/A>}>, :foo=>"b foo"} > xxx.rb(main):044:0> ab = b.bar.first > => <A:-578865728 @subject: http://example.com/a/A> > xxx.rb(main):045:0> puts 'boom!' if a.subject != ab.subject # XXX @subject wrong > boom! > => nil > xxx.rb(main):046:0> c = B.for '789' > => <B:-578885038 @subject: http://example.com/b/789> > xxx.rb(main):047:0> c.foo = 'c foo' > => "c foo" > xxx.rb(main):048:0> c.bar << x > => #<Set: {<A:-579815178 @subject: http://example.com/a/123>}> > xxx.rb(main):049:0> c.save! > => <B:-578885038 @subject: http://example.com/b/789> > xxx.rb(main):050:0> c.attributes > => {:bar=>#<Set: {<A:-579815178 @subject: http://example.com/a/123>}>, :foo=>"c foo"} > xxx.rb(main):051:0> c.bar.first.super > NoMethodError: undefined method `super' for <A:-579815178 @subject: http://example.com/a/123>:A > from xxx.rb:51 > xxx.rb(main):052:0> c.bar.first.to_zorch > => "http://example.com/a/123" > xxx.rb(main):053:0> c.reload > => {:bar=>#<Set: {<A:-578916598 @subject: http://example.com/a/123>}>, :foo=>"c foo"} > xxx.rb(main):054:0> c.bar.first.super > NoMethodError: undefined method `super' for <A:-578916598 @subject: http://example.com/a/123>:A > from /usr/pkg/lib/ruby/gems/1.8/gems/promise-0.3.0/lib/promise.rb:89:in `__send__' > from /usr/pkg/lib/ruby/gems/1.8/gems/promise-0.3.0/lib/promise.rb:89:in `method_missing' > from xxx.rb:54 > xxx.rb(main):055:0> c.bar.first.to_zorch # XXX fails > => "boom!" > xxx.rb(main):056:0> > > --chris > -- Ben Lavender | ben@dydra.com | http://dydra.com twitter/github: bhuga | +15047221016
Received on Friday, 20 May 2011 17:11:57 UTC