lib/cuts/cut.rb in cuts-0.0.4 vs lib/cuts/cut.rb in cuts-0.1.0

- old
+ new

@@ -23,27 +23,27 @@ # # class X # def x; "x"; end # end # -# cut :C < X do +# cut :Z < X do # def x; '{' + super + '}'; end # end # # X.new.x #=> "{x}" # -# To use this in an AOP fashion you can define an Aspect, as a class +# One way to use this in an AOP fashion is to define an aspect as a class # or function module, and tie it together with the Cut. # # module LogAspect # extend self # def log(meth, result) # ... # end # end # -# cut :C < X do +# cut :Z < X do # def x # LogAspect.log(:x, r = super) # return r # end # end @@ -55,101 +55,74 @@ # ACut < AClass < ASuperClass # # Instantiating AClass effecively instantiates ACut instead, # but that action is effectively transparent. # -# This is the basic model of this particluar implementation: +# This particular implementation create a module for each cut +# and extends objects as they are created. Given the following example: # # class Klass # def x; "x"; end # end # # cut KlassCut < Klass # def x; '{' + super + '}'; end # end # -# We cut it like so: +# The effect is essentially: # -# Klass = KlassCut +# k = Klass.new +# k.extend KlassCut # -# p Klass.new.x +# p k.x # -# This is simple and relatvely robust, but not 100% transparent. -# So we add some redirection methods to the cut to improve the -# transparency. -# -# Due to limitation in meta-programming Ruby as this level, the -# transparency isn't perfect, but it's fairly close. +# The downside to this approach is a limitation in dynamicism. -class Cut +class Cut < Module + def initialize(klass, &block) + klass.cuts.unshift(self) + module_eval(&block) + end +end - def self.new(klass, &block) - cut = Class.new(klass, &block) # <-- This is the actual cut. - - #cut.class_eval(&block) - - cut.send(:include, Transparency) - cut.extend MetaTransparency - - v = $VERBOSE - $VERBOSE = false - klass.modspace::const_set(klass.basename, cut) - $VERBOSE = v - - return cut +class Class + def cuts + @cuts ||= [] end +end - # These methods are needed to emulate full transparancy as - # closely as possible. +class Object + class << self + alias_method :_new, :new - module Transparency - def methods(all=true) - self.class.superclass.instance_methods(all) + def new(*a, &b) + o = _new(*a, &b) + if !cuts.empty? + o.extend *cuts + end + o end - def public_methods(all=true) - self.class.superclass.public_instance_methods(all) - end - def private_methods(all=true) - self.class.superclass.private_instance_methods(all) - end - def protected_methods(all=true) - self.class.superclass.protected_instance_methods(all) - end - end - # These methods are needed to emulate full transparancy as - # closely as possible. - - module MetaTransparency - #def instance_method(name) ; p "XXXX"; superclass.instance_method(name) ; end - def define_method(*a,&b) ; superclass.define_method(*a,&b) ; end - def module_eval(*a,&b) ; superclass.module_eval(*a,&b) ; end - def class_eval(*a,&b) ; superclass.class_eval(*a,&b) ; end end - end - class Symbol #alias :_op_lt_without_cuts :< # A little tick to simulate subclassing literal syntax. - def <(klass) if Class === klass - [self,klass] + [self, klass] else raise NoMethodError, "undefined method `<' for :#{self}:Symbol" #_op_lt_without_cuts(cut_class) end end end - module Kernel # Cut convienence method. - def cut(klass, &block) case klass when Array name, klass = *klass else @@ -159,54 +132,12 @@ cut = Cut.new(klass, &block) # How to handle main, but not other instance spaces? #klass.modspace::const_set(klass.basename, cut) mod = (Module === self ? self : Object) - mod.const_set(cutname, cut) # <<- this is what we don't have in Cut.new + mod.const_set(name, cut) if name # <<- this is what we don't have in Cut.new return cut end end -class Module - # Returns the root name of the module/class. - # - # module Example - # class Demo - # end - # end - # - # Demo.name #=> "Example::Demo" - # Demo.basename #=> "Demo" - # - # For anonymous modules this will provide a basename - # based on Module#inspect. - # - # m = Module.new - # m.inspect #=> "#<Module:0xb7bb0434>" - # m.basename #=> "Module_0xb7bb0434" - # - def basename - if name and not name.empty? - name.gsub(/^.*::/, '') - else - nil #inspect.gsub('#<','').gsub('>','').sub(':', '_') - end - end - - # Returns the module's container module. - # - # module Example - # class Demo - # end - # end - # - # Example::Demo.modspace #=> Example - # - # See also Module#basename. - # - def modspace - space = name[ 0...(name.rindex( '::' ) || 0)] - space.empty? ? Object : eval(space) - end -end