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.