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.