Annotated Attributes
This framework modifies the attr_* methods to allow easy addition of annotations. It the built in attribute methods (attr, attr_reader, attr_writer and attr_accessor), to allow annotations to added to them directly rather than requireing a separate ann statement.
class X attr :a, :valid => lambda{ |x| x.is_a?(Integer) } end
See annotation.rb for more information.
NOTE This library was designed to be backward compatible with the standard versions of the same methods.
- ann
- annotated?
- annotated_methods
- annotation
- append_features
- attr
- class_inherit
- class_methods
- define_annotation
- extend
- include
- method_annotation
- method_overloads
- mixin_parameters
- overload
[ show source ]
# File lib/facets/more/annotation.rb, line 232 def ann(*args) harg = args.last.is_a?(Hash) ? args.pop : {} #return annotator if args.empty? and harg.empty? return @_ann ||= Annotator.new( self ) if args.empty? and harg.empty? # for array of "mini-hashes" format if harg.empty? and Hash === args[0] args.each{|e| e.each{|k,v| harg[k]=v}} args = [] end # querying a single annotation if harg.empty? and args.size == 1 return annotation if self == args[0] or :self == args[0] #return args[0].annotation unless args[0].is_a?(Symbol) or args[0].is_a?(String) return method_annotation( args[0] ) #.inherit end # if last element is a class (and there are more then just the one element) harg[:class] = args.pop if args.last.is_a?(Class) and args.size > 1 if args.empty? # hash format harg.each do |key,hsh| if key == :self annotation.__update__( hsh ) next end note = annotated?( key ) if note and null != note note.__update__( hsh ) else define_annotation( key, hsh ) end end return harg.keys else # name, hash format args.each do |key| if key == :self annotation.__update__( harg ) next end note = annotated?( key ) if note and null != note note.__update__( harg ) else define_annotation( key, harg ) end end return args end end
Does this module/class or its ancestors have any annotation for a given method?
[ show source ]
# File lib/facets/more/annotation.rb, line 204 def annotated?( key ) return annotation if self == key r = method_annotation( key ) null == r ? nil : r end
Returns a list of all annotated methods.
[ show source ]
# File lib/facets/more/annotation.rb, line 211 def annotated_methods(include_ancestors=true) annlist = [] if include_ancestors ancestors.inject([]){ |memo, anc| memo | anc.method_annotation.keys } else method_annotation.keys end end
def annotation
@_annotation ||= Annotation.new.inherits( self ){ |anc| anc.annotation }
end
[ show source ]
# File lib/facets/more/annotation.rb, line 183 def annotation( harg=nil ) @_annotation ||= Annotation.new.inherits( self ){ |anc| anc.annotation } return @_annotation unless harg @_annotation.__update__( harg ) if harg end
[ show source ]
# File lib/facets/more/classmethods.rb, line 106 def append_features( base ) result = append_features_without_classmethods( base ) if const_defined?( :ClassMethods ) base.extend( self::ClassMethods ) unless base.is_a?( Class ) unless base.const_defined?( :ClassMethods ) base.const_set( :ClassMethods, Module.new ) end my = self base::ClassMethods.class_eval do include my::ClassMethods end end end result end
[ show source ]
# File lib/facets/more/annattr.rb, line 45 def attr( *args ) args.flatten! case args.last when TrueClass args.pop attr_accessor( *args ) when FalseClass args.pop attr_reader( *args ) else attr_reader( *args ) end end
Alias for class_methods
[ show source ]
# File lib/facets/more/classmethods.rb, line 123 def class_methods( &yld ) if const_defined?( :ClassMethods ) self::ClassMethods.class_eval( &yld ) else self.const_set( :ClassMethods, Module.new( &yld ) ) end extend( self::ClassMethods ) self::ClassMethods end
[ show source ]
# File lib/facets/more/paramix.rb, line 117 def extend(*args) params = args.last.is_a?(Hash) ? args.pop : {} args.each do |mod| (class << self; self; end).class_eval do mixin_parameters[mod] = params if mod.basename define_method( mod.basename ) do |key| if params.key?(key) params[key] else super if defined?( super ) end end end end end r = extend_without_parameters(*args) for mod in args if mod.method_defined?(:extended_with_parameters) mod.extended_with_parameters( self, params ) end end r end
[ show source ]
# File lib/facets/more/paramix.rb, line 92 def include(*args) params = args.last.is_a?(Hash) ? args.pop : {} args.each do |mod| mixin_parameters[mod] = params if mod.basename define_method( mod.basename ) do |key| if params.key?(key) params[key] else super if defined?( super ) end end end end r = include_without_parameters(*args) for mod in args if mod.respond_to?(:included_with_parameters) mod.included_with_parameters( self, params ) end end r end
[ show source ]
# File lib/facets/more/annotation.rb, line 189 def method_annotation( key=nil ) @_method_annotation ||= {} return @_method_annotation unless key key = key.to_sym if a = @_method_annotation[key] return a elsif ancestors.any? { |anc| anc.method_annotation[key] } @_method_annotation[key] = Annotation.new.inherits( self ){ |anc| anc.method_annotation[key] } else null end end
[ show source ]
# File lib/facets/more/overload.rb, line 43 def method_overloads @method_overloads ||= {} end
Store for module parameters. This is local per module and indexed on module/class included-into.
[ show source ]
# File lib/facets/more/paramix.rb, line 88 def mixin_parameters ; @mixin_parameters ||= {} ; end
[ show source ]
# File lib/facets/more/overload.rb, line 47 def overload( name, *signiture, &block ) name = name.to_sym if method_overloads.key?( name ) method_overloads[name][signiture] = block else method_overloads[name] = {} method_overloads[name][signiture] = block if method_defined?( name ) #method_overloads[name][nil] = instance_method( name ) #true alias_method( "#{name}Generic", name ) has_generic = true else has_generic = false end define_method( name ) do |*args| ovr = self.class.method_overloads["#{name}".to_sym] sig = args.collect{ |a| a.class } hit = nil faces = ovr.keys.sort { |a,b| b.size <=> a.size } faces.each do |cmp| next unless cmp.size == sig.size cmp.size.times { |i| next unless cmp[i] < sig[i] } hit = cmp end if hit ovr[hit].call(*args) else if has_generic #ovr[nil] send( "#{name}Generic", *args ) #ovr[nil].bind(self).call(*args) else raise NoMethodError end end end end end
[ show source ]
# File lib/facets/more/annotation.rb, line 225 def define_annotation( key, note ) key = key.to_sym method_annotation[key] = Annotation.new(note).inherits(self){ |anc| anc.method_annotation[key] } method_annotation[key] end