From: "Simon Kröger" Date: 2006-02-10T05:42:54+09:00 Subject: Re: How to improve this kind of API? Lyle Johnson wrote: > I'm looking to make an API change for some methods in FXRuby and would > appreciate some suggestions about how to improve them. The pattern shows up > in several places in the code, but it always boils down to some widget > attribute that can have a combination of bit-flags. Well, i haven't used FXRuby very much, so i might miss the problem with the current interface, but from what i see below i think this new version doesn't justify breaking old code. > For example, the 4-way > splitter window can be configured to expand only its top-left pane: > > splitter1.expanded = TOP_LEFT Seems perfectly fine. Ok :top_left if more ruby'ish but also more dangerous. > or to expand both the top left and top right panes: > > splitter2.expanded = TOP_LEFT | TOP_RIGHT Also fine. Perhaps define a TOP constant for those who don't like binary operations. > And to check whether, say, the BOTTOM_LEFT pane is expanded: > > (splitter3.expanded & BOTTOM_LEFT) != 0 Ok, agreed, this isn't very nice. > Now, what I'm thinking of doing is replacing the symbolic constants with > Ruby symbols, and doing something like this instead: > > splitter1.expand(:top_left) > splitter2.expand(:top_left, :top_right) Well, i don't like using 2 parameters when it is only one logically. > and then having checks like: > > splitter3.expanded? :bottom_left I don't like that either. > I think that in order to "turn off" one of those bits, I'm probably also > going to need to add something like: > > splitter4.unexpand(:bottom_right) Oh, and i realy dislike this. > Now, the question is, is there some existing pattern in Ruby that this > reminds you of? In other words, what is the Ruby Way to handle this kind of > setting? The following isn't meant to be 'the soultion' but perhaps food for thoughts: ------------------------------------------------------------- require 'set' class Symbol def method_missing meth, *param set = Set[self] set.send meth, param.to_a if set.respond_to?(meth) end end class Splitter attr_accessor :expanded end TOP_LEFT = :top_left TOP_RIGHT = :top_right BOTTOM_LEFT = :bottom_right BOTTOM_RIGHT = :bottom_right splitter = Splitter.new splitter.expanded = TOP_LEFT p splitter.expanded #=> :top_left splitter.expanded = TOP_LEFT | TOP_RIGHT p splitter.expanded #=> p splitter.expanded.include?(BOTTOM_LEFT) #=> false p splitter.expanded.include?(TOP_LEFT) #=> true splitter.expanded = :bottom_left | :top_left p splitter.expanded #=> # splitter.expanded.delete(:top_left) p splitter.expanded #=> # ------------------------------------------------------------- cheers Simon