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.