From: "Florian Groß" Date: 2005-04-04T09:31:36+09:00 Subject: Re: Hash::MixIn and Python style Object#dict Mathieu Bouchard wrote: > class MyHash; include HollowHash; include SimpleStringP # (3) > def each_key(&b) > # blah blah blah > end > # further blah > end > class MyVerifiedHash < MyHash; include SimpleHashP::Contract; end > > SimpleHashP is the "declarator" module, that asserts that a given module > supports a feature set. SimpleHashP::Contract is a "verifier" module. > However there is currently still no hint that a given module _wants_ an > implementation of a given feature set in the way that HollowHash wants a > SimpleHashP without providing a default implementation of it. This sounds a lot like something that could be done with the Contracts and implications in ruby-contract: (http://ruby-contract.rubyforge.org) # You called this a declarator module module Hash::MixIn def each_keys(&block) keys.each(&block) end def each(&block) each_keys do |key| block.call(key, self.fetch(key)) end end # ... and all the other methods end # You called this a verifier class Hash::Contract < Contract # My set again, though I wonder if .each_keys would not be a more # efficient primitive than .keys. I'm still not sure about the # difference between .remove and .delete. provides :fetch, :store, :keys, :delete # Here's a sample for a more complex provides: provides :fetch do @object.keys.each do |key| # Contracts are really just disguised test suites assert_no_exception { @object.fetch(key) } end end implies Hash::MixIn end class MyHash fulfills Hash::Contract end This contract does not yet do any detailed implementation testing, but it ought to be easy to add. Regarding FileAsString, that could be done like this: class Object adapt :to => String, :via => :read end Which would automatically add type adaption routes for all Objects that implement #read. If there were a method like this expecting a string: def open(string) # implementation snipped... end signature :open, String, :result => File And you were to call it as open(aFile) it would automatically read the filename from aFile and then pass open() that as a String. As you can see this is implicit type conversion which can be dangerous if you do it too much. Therefore I think it should really only be used in cases where the source and target are /very/ closely equivalent. One case would be two libraries providing classes for passing around Colors with incompatible interfaces. The other things you wrote about also sounded very interesting. Perhaps we can continue talking about these things via private mail or IRC as I seem to be good at forgetting about slightly old threads on the ML...