[Nitro] Serious discussion on Annotaitons - Part I

transfire at gmail.com transfire at gmail.com
Sun Oct 29 06:37:51 EST 2006


First of all here is the code for the annotations system in the latest
Facets. If you compare it to the old version you'll see it's a lot less
complex. Now appearently something doesn't work right in Nitro with it
but as of yet no one has been able to give me one concrete error as to
what is going wrong. Off the top of my head I know that some
meta-information methods (like #inheritance) is no longer there so that
would break things, or if one were trying to jerry things using
inheritor which is no longer used. But in using it normally it should
work, I have a bunch of test cases and they all work --so I really need
to get some concerete idea about what the problem is so I can fix it.

Thanks,
T.

(P.S. I'm going to follow this up with a discussion of annotations in
general).

# --- annotations.rb

class Annotations

  def initialize( base )
    @base, @ann = base, {}
  end

  def [](key)
    key = :self if key == @base
    @ann[key] ||= Annotation.new(@base, key)
  end

  def []=(key, note)
    raise ArgumentError unless Annotation === note
    @ann[key] = note
  end

  def ==(other) @ann == other.to_h end

  def to_h() @ann end

  def key?(key) @ann.key?(key) end

  def each(&yld)
    @ann.each(&yld)
  end

  def update( other )
    @ann.update( other.to_h )
    self
  end
  private :update

  def self
    self[:self]
  end

  def annotated_base() @base end

  def method_missing( key, *args, &blk )
    if key?(key)
      self[key] #.heritage
    else
      if @base.ancestors.any?{|anc| anc.annotations.key?(key)}
        return self[key].heritage
        #ann[name].heritage
      end
      super
    end
  end

end

#

class Annotation < OpenObject

  def initialize( base, key, orig=nil )
    @base = base
    @key  = key
    @orig = orig || self
    super()
  end

  def original
    @orig
  end

  #def class
  #  self[:class]
  #end

  def inspect
    "#<#{object_class.name}(#{@base}##{@key}) #{super}>"
  end

  def annotation_key
    @key
  end

  def heritage( orig=nil )
    ah = {}
    @base.ancestors.reverse_each do |anc|
      if anc.annotations.key?(@key)
        anc.annotations[@key].each { |k,v|
          case v
          when Module
            ah[k] = v
          else
            ah[k] = v.dup rescue v
          end
        }
      end
    end
    a = Annotation.new( @base, @key, orig || @orig )
    a.send(:replace, ah)
    a
  end

  def method_missing( sym, *args, &blk )
    type = sym.to_s[-1,1]
    key = sym.to_s.gsub(/[=!?]$/, '').to_sym

    case type
    when '='
      @orig[key] = args[0] #, *args, &blk )
    when '!'
      #r = super( key, *args, &blk )
      if key?(key)
        self[key]
      else
        self[key] = heritage(self)[key]
      end
    else
      heritage[sym]
    end
  end

end

class Module

  def annotations
    @annotations ||= Annotations.new(self)
  end

  def ann( key=nil, *options )
    return annotations unless key
    return name.collect{|k,v| ann k,*v} if Hash === key
    return annotations[key] if options.empty?
    opt = {}
    opt.update options.pop if Hash === options.last
    opt[:class] = options.pop if Class === options.last
    keys = [key].concat options
    keys.each do |key|
      note = annotations[key]
      #unless options.empty?
      #  (hopt[:tags] ||= []) << options
      #end
      note.send(:update,opt)
    end
    keys
  end

end

module Kernel
  # Any object can be annotated.
  #--
  # Not sure about this.
  #++
  def ann( *args )
    #if singleton_class?
      (class << self; self; end).ann( *args )
    #else
    #  self.class.ann( *args )
    #end
  end
end



More information about the Nitro-general mailing list