Annotations

Creating and Reading Annotations

Load the Anise library.

require 'anise'

Given an example class X we can apply annotations to it using the #ann method.

class X
  extend Anise::Annotations

  ann :x1, :a=>1
  ann :x1, :b=>2
end

We can then use #ann to lookup the set annotations.

X.ann(:x1,:a).should == 1

The #ann method is a public interface, so we can define annotation externally as well.

X.ann :x1, :a => 2
X.ann(:x1, :a).should == 2

Annotation Added Callback

Given a sample class Y, we can use a standard callback method #annotation_added().

class Y
  extend Anise::Annotations

  class << self
    attr :last_callback

    def annotation_added(ref, ns)
      @last_callback = [ns, ref, ann(ref/ns)]
    end
  end
end

Now if we add an annotation, we will see the callback catches it.

Y.ann :x1, :a=>1
Y.last_callback.should == [:ann, :x1, {:a => 1}]

We will do it again to be sure.

Y.ann :x1, :b=>2
Y.last_callback.should == [:ann, :x1, {:a => 1, :b => 2}]

Using Callbacks for Attribute Defaults

class ::Module
  def annotation_added(key, ns)
    return unless ns == :ann
    base = self
    if value = ann(key, :default)
      define_method(key) do
        instance_variable_set("@#{key}", value) unless instance_variable_defined?("@#{key}")
        base.module_eval{ attr key }
        instance_variable_get("@#{key}")
      end 
    end
  end
end

Try it out.

class Z
  extend Anise::Annotations

  attr :a
  ann :a, :default => 10
end

z = Z.new
z.a.should == 10
z.a.should == 10

Annotative Attributes

Create a class that uses the Annotative::Attributes mixin.

class X
  extend Anise::Annotative::Attributes

  attr :a, :count => 1
end

Then we can see tht the attribute method :a has an annotation entry.

X.ann(:a, :count) #=> 1

Method Annotations

Create a class that uses the Annotative::Methods mixin.

class X
  extend Anise::Annotative::Methods

  def self.doc(string)
    method_annotation(:doc=>string.to_s)
  end

  doc "See what I mean?"

  def see
    puts "Yes, I see!"
  end
end

See that it is set.

X.ann(:see, :doc)  #=> "See what I mean?"

Method Annotators can override the standard annotation procedure with a custom procedure. In such case no annotations will actually be created unless the #ann is called in the procedure.

class Y
  extend Anise::Annotative::Methods

  def self.list
    @list ||= []
  end

  def self.doc(string)
    method_annotation do |method|
      list << [method, string]
    end
  end

  doc "See here!"

  def see
    puts "Yes, I see!"
  end
end

See that it is set.

Y.list #=> [[:see, "See here!"]]

Variable Annotations

Create a class that uses the Annotative::Variables mixin.

class X
  extend Anise::Annotative::Variables

  variable_annotator :@doc

  @doc = "See what I mean?"

  def see
    puts "Yes, I see!"
  end
end

See that it is set.

X.ann(:see, :@doc).should == "See what I mean?"

Variable annotations can override the standard annotation procedure with a custom procedure.

class Y
  extend Anise::Annotative::Variables

  def self.list
    @list ||= []
  end

  variable_annotator :@doc do |method, value|
    list << [method, value]
  end

  @doc = "See here!"

  def see
    puts "Yes, I see!"
  end
end

See that it is set.

Y.list #=> [[:see, "See here!"]]

= TOPLEVEL Annotations

Extending Object with Annotations should make them available to all classes.

class ::Object

extend Anise::Annotations

end

Given a example class X we can apply annotations to it using the #ann method.

class X

ann :x1, :a=>1
ann :x1, :b=>2

end

We can then use #ann to lookup the set annotations.

X.ann(:x1,:a).should == 1

The #ann method is a public interface, so we can define annotation externally as well.

X.ann :x1, :a => 2 X.ann(:x1, :a).should == 2

Alternatively the Annotations module could be included into the Module class.

= TOPLEVEL Annotated Attributes

Including AnnotatedAttributes at the toplevel, i.e. Object, will make annotated attributes univerally available.

class ::Object

extend Anise::Annotative::Attributes

end

Create a class that uses it.

class X

attr :a, :count=>1

end

X.ann(:a, :count) #=> 1

Alternatively the Annotative::Attributes module could be included into the Module class.