George Moschovitis wrote:
> > harp:~ > cat a.rb
> > ...
> > :baz}
> >
> > Now this implementatin leaves out some of the needed shortcuts (like
> > implied class annotation) and it also leaves out the BIG issue of
> > inheritance, but those can of course can be worked in. The main thing
> > here is the simplicty of the interface. I realize it's a big change but
> > I think Ara has a point. The simplicy, uniformity and consistancy has
> > it's own merits over the elegance of the magic dot notation.
>> Well I like this simplicity as well. Could you introduce the
> inheritance feature?
> And what is implied class annotation? I would like to replace nitro's
> annotation with this simpler version. If you remember, I was always
> worried about the performance (and complexity) issues of the current
> implementation.
Your wish is my command. Here it is. The just about the most
straight-foward and concise implementation of Annotations possible. I
have only two outstanding issues with it. 1) Whether to use the global
variable or not (see remarks for the difference); and 2) Whether
#heritage should remain it's own method or be integrated into #ann
itself, or perhaps just rename it? FYI heritage returns the complete
inheritance chain of annotations.
I'm sure other improvments are possible. Please let me know it you have
any suggestions. Thanks.
# --- ann.rb
require 'facets/core/hash/to_h'
require 'facets/core/hash/symbolize_keys'
require 'facets/core/hash/op_add'
# By using a global veriable rather the definining a class instance
variable
# for each class/module, it is possible to quicky scan all annotations
for the
# entire system. To do the same without this would require scanning
through
# the ObjectSpace. (Still which is better?)
#$annotations = Hash.new { |h,k| h[k] = {} }
class Module
def annotations
#$annotations[self] # global?
@annotations ||= {}
end
def heritage(ref)
ref = ref.to_sym
ancestors.inject({}) { |memo, ancestor|
ancestor.annotations[ref] ||= {}
ancestor.annotations[ref] + memo
}
end
# Set or read annotations.
def ann( ref, keys_or_class=nil, keys=nil )
return heritage(ref) unless keys_or_class or keys
if Class === keys_or_class
keys ||= {}
keys[:class] = keys_or_class
else
keys = keys_or_class
end
if Hash === keys
ref = ref.to_sym
annotations[ref] ||= {}
annotations[ref].update(keys.symbolize_keys)
else
key = keys.to_sym
heritage(ref)[key]
end
end
# To change an annotation's value in place for a given class or
module
# it first must be duplicated, otherwise the change may effect
annotations
# in the class or module's ancestors.
def ann!( ref, keys_or_class=nil, keys=nil )
return heritage(ref) unless keys_or_class or keys
if Class === keys_or_class
keys ||= {}
keys[:class] = keys_or_class
else
keys = keys_or_class
end
if Hash === keys
ref = ref.to_sym
annotations[ref] ||= {}
annotations[ref].update(keys.symbolize_keys)
else
key = keys.to_sym
annotations[ref][key] = heritage(ref)[key].dup
end
end
end