From: Robert Dober Date: 2008-08-27T19:28:00+09:00 Subject: Re: Difficult Inheritance Problem On Wed, Aug 27, 2008 at 11:08 AM, Toby Clemson wrote: I am currently working on a new release of Labardor, but there still is sooo much to do, however, you might be interested in the following code of Labrador. I am however aware that this implies a rethink of your strategy, however one of my goals is to explore different behavior based OO approaches than inheritance and mixins, in case you find that a useful paradigm shift. And I appologize for the long post but Labrador just is in no shape for a new release to Rubyforge. HTH Robert Skip the rest if you are not particularily interested in different OO approaches. ----------------------------- 8< ------------------------ #-- # vim: sts=2 sw=2 tw=0 expandtab nu: #* #* Labrador, The Lazy Programmer's Best Friend. #* #* Distributed under the terms of the BSD License. #* Copyright (c) 2007 Robert Dober #* All rights reserved. #* #* Redistribution and use in source and binary forms, with or without #* modification, are permitted provided that the following conditions are met: #* * Redistributions of source code must retain the above copyright #* notice, this list of conditions and the following disclaimer. #* * Redistributions in binary form must reproduce the above copyright #* notice, this list of conditions and the following disclaimer in the #* documentation and/or other materials provided with the distribution. #* * Neither the name of the Labrador packahe nor the #* names of its contributors may be used to endorse or promote products #* derived from this software without specific prior written permission. #* #* THIS SOFTWARE IS PROVIDED BY Robert Dober ``AS IS'' AND ANY #* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED #* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE #* DISCLAIMED. IN NO EVENT SHALL Robert Dober BE LIABLE FOR ANY #* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES #* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; #* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND #* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT #* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS #* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # #++ class Array def ivar_names_to_strings map { |ele| ele.to_s.sub("@","") } end def ivar_names_to_symbols map { |ele| ele.to_s.sub("@","").to_sym } end def names_to_ivar_strings map { |ele| "@#{ele.to_s.sub("@","")}" } end def names_to_ivar_symbols map { |ele| "@#{ele.to_s.sub("@","")}".to_sym } end end # class Array class Object def get_ivars *ivars ivars = instance_variables if ivars.empty? ivars.ivar_names_to_symbols. inject( {} ) { |h, ivar| h.update ivar => instance_variable_get( "@#{ivar}" ) } end def pop_ivars set_ivars! @__ivar_stack__.pop end def push_ivars hash ( @__ivar_stack__ ||= [] ). push( get_ivars( *hash.keys ) ) set_ivars! hash end def set_ivars hash hash.keys.each do | ivar | ivar_name = "@#{ivar}".sub( /^@@/, "@" ) instance_variable_set ivar_name, hash[ ivar ] unless instance_variables.include? ivar_name end end def set_ivars! hash hash.keys.each do | ivar | ivar_name = "@#{ivar}".sub( /^@@/, "@" ) instance_variable_set ivar_name, hash[ ivar ] end end def set_only_ivars hash, *keys set_ivars hash.keys.inject( {} ){ |h, k| keys.include?( k ) ? h.update( k => hash[k] ) : h } end # def set_only_ivars hash, *keys def set_only_ivars! hash, *keys set_ivars! hash.keys.inject( {} ){ |h, k| keys.include?( k ) ? h.update( k => hash[k] ) : h } end # def set_only_ivars hash, *keys end # class Object class Behavior attr_reader :block def initialize &blk @block = blk end end module Kernel def Behavior &blk Behavior::new &blk end end class Module def empty?; instance_methods.empty? end def empty!; instance_methods.each do |im| remove_method im end end end module Pushable CannotPopException = Class::new RuntimeError ArgumentError = Class::new ::ArgumentError def pop_behavior @__bsp__ -= 1 raise CannotPopException, "empty entity #{self}" if @__bsp__ < 0 @__behavior_stack__[@__bsp__].empty! end def push_behavior *behaviors, &blk @__behavior_stack__ ||= [] @__bsp__ ||= 0 raise ArgumentError, "push_behavior takes at least one behavior or block" if behaviors.empty? and blk.nil? behaviors.each do |behavior| _push_behavior behavior end _push_behavior blk if blk self end private def _push_behavior behavior m = @__behavior_stack__[@__bsp__] @__behavior_stack__ << ( m = Module::new ) unless m include m rescue extend m # this is autoprotected against double inclusion; so finally turns out it is a feature ;) m.empty! m.module_eval &(behavior.block rescue behavior) @__bsp__ += 1 end end # module Pushable class << Pushable def new *args, &blk c = Class::new( *args, &blk ) c.extend self c end end # class << Pushable class << PushableModule = Module::new def new *args, &blk m = Module::new( *args, &blk ) m.extend Pushable m end end ------------------------------------ 8< -----------------------------------------