From: Trans Date: 2007-10-22T22:15:41+09:00 Subject: Re: Conflicts between using respond_to? and extending Ruby On Oct 22, 7:29 am, "David A. Black" wrote: > Hi -- > > > > On Mon, 22 Oct 2007, Trans wrote: > > Hi-- > > > I recently cam across an interesting conflict between open-uri.rb and > > Facets rendition of kernel/metaid.rb. Facets defines a general > > extension Kernel#meta, and open-uri defines OpenURI::Meta#meta. open- > > uri uses OpenURI::Meta to extend StringIO via singleton. This is all > > fine, but then open-uri checks to see if a StringIO object has been > > extended by doing: > > > io.respond_to? :meta > > > And that's where the problem lies, b/c if you've loaded 'facets/kernel/ > > metaid' you're going to get a false positive here. Now the best remedy > > is open-uri to be more precise: > > > io.is_a? OpenURI::Meta > > > That fixes the the problem. But it raises an interesting question. > > I've used #respond_to? myself from time to time thinking it was oh, so > > duck-type kosher; never realizing that it might clash with general > > extensions. > > > So where lies the fault in this conflict? Are extensions the bad guy, > > or is respond_to? really not a good oop concept? Or..? > > I think this is just the age-old issue about adding methods to > existing classes and hitting conflicts. #respond_to? is relatively > dumb; it can't tell you what the method actually does. I think of it > as an important tool for "soft" duck typing, in contrast with "hard" > duck typing where you just send the object the message. That's interesting. It makes me wonder if it's worth "hardening" with something like: respond_to?(:meta, OpenURI::Meta) So that Ruby will check that it would respond to a #meta that's defined in OpenURI. But yea, really, I agree with you. I never really realized it before, but respond_to? is pretty weak. > What does your Kernel#meta do? If it's what's usually called > #singleton_class, you might change it to #singleton_class :-) Or > something like that (#metaclass, if you're into that terminology) -- a > little more descriptive and less likely to clash. Sort-of, but it wraps the singleton in a Functor, so you can call methods against it as if you had opened it up yourself. For example: class X meta.attr :x end Defines a class attribute. > There's no perfect solution, though. Using #extend on specific objects, instead of adding > methods to Kernel, could make clashes much less likely, though if you > happened to add #meta to a StringIO object via #extend, you'd still > have the same problem. Indeed. T.