David Garamond <davegaramond / icqmail.com> writes:

> if a client wants interface 1, then she will get the methods foo and bar 
> (which is actually C#bar1). if he picks interface 2, then she will get 
> the methods foo and bar (which is actually C#bar2). for all she cares, 
> she just wants to know/deal with a single [versatile] class, C. and from 
> that single class, she can pick several sets of features/interfaces she 
> needs/wants.
> 
> i know that, in ruby, modules are usually used for things like this, but 
> in my case many of the method names are the same so i don't think 
> modules are approriate for this. for example, interface1 consists of 
> foo, bar, baz, abc, and abd. interface2 consists of foo, bar, baz, bab, 
> bac. in most of the cases all of the interfaces provide the same set of 
> features, just in a different style or different revision.
> 
> any pointers of how i might do something like this in ruby?

I know that you're avoiding inheritance on purpose, but I'd do it like
this:


class C
  def self.new(facet = 1, *args)
    if self == C
      case facet
      when 1 then C1.new(*args)
      when 2 then C2.new(*args)
      end
    else      
      super(*args)
    end
  end

  def foo 
    puts "foo"
  end

  def bar1 
    puts "bar version 1"
  end

  def bar2 
    puts "bar version 2"
  end
end


class C1 < C
  alias_method :bar, :bar1
end

class C2 < C
  alias_method :bar, :bar2
end


c1 = C.new(1) # cilent1 picks interface as defined in C1
c1.foo        # prints "foo"
c1.bar        # prints "bar version 1"

c2 = C.new(2) # client2 picks interface as defined in C2
c2.foo        # prints "foo"
c2.bar        # prints "bar version 2"


You can define a class method in C named .facet if you don't want to
touch .new for this purpose, just rename .new.


  def self.facet(facet = 1, *args)
    if self == C
      case facet
      when 1 then C1.new(*args)
      when 2 then C2.new(*args)
      end
    else      
      super(*args)
    end
  end


And can easily take away the ugly case statement, too:


  def self.facet(facet = 1, *args)
    if self == C
      Object.const_get("#{self}#{facet}").new(*args)
    else      
      super(*args)
    end
  end


Finally, you might want to make it generally useful by stuffing it
into a mixin:


module Facetable
  def facet(facet = 1, *args)
    if self == C
      Object.const_get("#{self}#{facet}").new(*args)
    else      
      super(*args)
    end
  end
end

class C
  extend Facetable

  ...
end

class C1 < C
  ...
end

class C_something < C
  ...
end

c1 = C.facet(1)
csth = C.facet("_something")


....and so on.



Massimiliano