| Path: | DEMO.md |
| Last Update: | Sat Feb 23 07:13:29 +0000 2019 |
# 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!"]]
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.
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.