anise 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby +59 -38
- data/.yardopts +7 -0
- data/DEMO.md +242 -0
- data/{HISTORY.rdoc → HISTORY.md} +28 -7
- data/LICENSE.txt +27 -0
- data/README.md +129 -0
- data/demo/01_annotations.md +81 -0
- data/demo/03_attributes.md +14 -0
- data/demo/04_methods.md +50 -0
- data/demo/05_variables.md +45 -0
- data/{qed → demo}/applique/ae.rb +0 -0
- data/demo/applique/anise.rb +1 -0
- data/{qed/toplevel/01_annotations.qed → demo/toplevel/01_annotations.md} +5 -9
- data/demo/toplevel/03_attributes.md +20 -0
- data/lib/anise.rb +28 -45
- data/lib/anise.yml +59 -38
- data/lib/anise/annotations.rb +132 -0
- data/lib/anise/annotations/store.rb +136 -0
- data/lib/anise/annotative.rb +7 -0
- data/lib/anise/annotative/attributes.rb +147 -0
- data/lib/anise/annotative/methods.rb +131 -0
- data/lib/anise/annotative/variables.rb +99 -0
- data/lib/anise/{module.rb → core_ext.rb} +30 -0
- data/lib/anise/universal.rb +6 -0
- data/lib/anise/version.rb +17 -0
- data/test/case_annotations.rb +173 -0
- data/test/case_attributes.rb +46 -0
- data/test/case_combined_usage.rb +341 -0
- data/test/case_methods.rb +36 -0
- data/test/case_variables.rb +22 -0
- data/test/helper.rb +2 -0
- metadata +99 -98
- data/APACHE2.txt +0 -204
- data/COPYING.rdoc +0 -17
- data/README.rdoc +0 -107
- data/lib/anise/annotation.rb +0 -175
- data/lib/anise/annotator.rb +0 -82
- data/lib/anise/attribute.rb +0 -138
- data/qed/01_annotations.qed +0 -26
- data/qed/02_annotation_added.rdoc +0 -60
- data/qed/03_attributes.rdoc +0 -16
- data/qed/04_annotator.rdoc +0 -49
- data/qed/toplevel/03_attributes.rdoc +0 -20
- data/test/suite.rb +0 -8
- data/test/test_anise.rb +0 -193
- data/test/test_anise_toplevel.rb +0 -194
- data/test/test_annotations.rb +0 -136
- data/test/test_annotations_module.rb +0 -132
- data/test/test_annotations_toplevel.rb +0 -131
- data/test/test_annotator.rb +0 -26
- data/test/test_annotator_toplevel.rb +0 -28
- data/test/test_attribute.rb +0 -37
- data/test/test_attribute_toplevel.rb +0 -65
data/README.md
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# Anise
|
2
|
+
|
3
|
+
[Hompage](http://rubyworks.github.com/anise) /
|
4
|
+
[Report Issue](http://github.com/rubyworks/anise/issues) /
|
5
|
+
[Source Code](http://github.com/rubyworks/anise) /
|
6
|
+
[Mailing List](http://groups.google.com/group/rubyworks-mailinglist) /
|
7
|
+
[IRC Channel](http://chat.us.freenode.new/rubyworks)
|
8
|
+
|
9
|
+
[![Build Status](https://secure.travis-ci.org/rubyworks/anise.png)](http://travis-ci.org/rubyworks/anise)
|
10
|
+
|
11
|
+
|
12
|
+
## Introduction
|
13
|
+
|
14
|
+
Anise is an Annotation System for the Ruby programming language.
|
15
|
+
Unlike most other annotations systems it is not a comment-based or
|
16
|
+
macro-based system that sits over-and-above the rest of the code.
|
17
|
+
Rather, Anise is a dynamic annotations system operating at runtime.
|
18
|
+
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
To install with RubyGems simply open a console and type:
|
23
|
+
|
24
|
+
gem install anise
|
25
|
+
|
26
|
+
To manually install you will need Setup.rb (see http://setup.rubyforge.org).
|
27
|
+
Then download the tarball package and do:
|
28
|
+
|
29
|
+
$ tar -xvzf anise-0.2.0.tgz
|
30
|
+
$ cd anise-0.2.0
|
31
|
+
$ sudo setup.rb all
|
32
|
+
|
33
|
+
|
34
|
+
## Instruction
|
35
|
+
|
36
|
+
The following example briefly demonstrates all three major features. To use
|
37
|
+
any of them first require the `anise` library.
|
38
|
+
|
39
|
+
require 'anise'
|
40
|
+
|
41
|
+
General annotations are provided by the `Anise::Annotations` module.
|
42
|
+
|
43
|
+
class X
|
44
|
+
extend Anise::Annotations
|
45
|
+
|
46
|
+
ann :grape, :class=>String
|
47
|
+
end
|
48
|
+
|
49
|
+
X.ann(:grape, :class) #=> String
|
50
|
+
|
51
|
+
Annotated attributes can be easily added to a class via the `Annotative::Attributes`
|
52
|
+
module.
|
53
|
+
|
54
|
+
class X
|
55
|
+
extend Anise::Annotative::Attributes
|
56
|
+
|
57
|
+
attr :baz, Integer, :max => 10
|
58
|
+
end
|
59
|
+
|
60
|
+
X.ann(:baz) #=> {:class=>Integer, :max=>10}
|
61
|
+
|
62
|
+
Mewthod annotations can be had via the `AnnotatedMethods` module.
|
63
|
+
|
64
|
+
class X
|
65
|
+
extend Anise::Annotative::Methods
|
66
|
+
|
67
|
+
def self.doc(string)
|
68
|
+
method_annotation(:doc=>string)
|
69
|
+
end
|
70
|
+
|
71
|
+
doc "This is an entry."
|
72
|
+
|
73
|
+
def bar
|
74
|
+
# ...
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
X.ann(:bar) #=> {:doc=>"This is an entry."}
|
79
|
+
|
80
|
+
Any of these modules can be used in conjunction. Since both `AnnotatedMethods`
|
81
|
+
and `AnnotatedAttributes` preclude `Annotations` all three can be used by simply
|
82
|
+
using the later two.
|
83
|
+
|
84
|
+
class X
|
85
|
+
extend Anise::Annotative::Attributes
|
86
|
+
extend Anise::Annotative::Methods
|
87
|
+
|
88
|
+
...
|
89
|
+
end
|
90
|
+
|
91
|
+
Note also that the `Anise` module is clean and contains only modules and classes
|
92
|
+
with detailed names starting the "Annotat-", so it is prefectly convenient for
|
93
|
+
inclusion in the toplevel namespace or your own applications namespace.
|
94
|
+
|
95
|
+
module MyApp
|
96
|
+
include Anise
|
97
|
+
|
98
|
+
class Foo
|
99
|
+
extend Annotative::Attributes
|
100
|
+
|
101
|
+
...
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
## Development
|
107
|
+
|
108
|
+
### Test Instructions
|
109
|
+
|
110
|
+
Ainse has two test suites, one using [QED](http://rubyworks.github.com/qed) and
|
111
|
+
the other using [Citron](http://rubyworks.github.com/citron) which is built on
|
112
|
+
[RubyTest](http://rubyworks.github.com/rubytest).
|
113
|
+
|
114
|
+
To run the QED demonstrations simple run:
|
115
|
+
|
116
|
+
$ qed
|
117
|
+
|
118
|
+
To run the Citron-based unit tests use:
|
119
|
+
|
120
|
+
$ rubytest
|
121
|
+
|
122
|
+
|
123
|
+
## Copyrights
|
124
|
+
|
125
|
+
Copyright (c) 2008 Rubyworks. All rights reserved.
|
126
|
+
|
127
|
+
This program is distributed under the terms of the **BSD-2-Clause** license.
|
128
|
+
|
129
|
+
See LICNESE.txt file for details.
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Annotations
|
2
|
+
|
3
|
+
## Creating and Reading Annotations
|
4
|
+
|
5
|
+
Load the Anise library.
|
6
|
+
|
7
|
+
require 'anise'
|
8
|
+
|
9
|
+
Given an example class X we can apply annotations to it using the #ann method.
|
10
|
+
|
11
|
+
class X
|
12
|
+
extend Anise::Annotations
|
13
|
+
|
14
|
+
ann :x1, :a=>1
|
15
|
+
ann :x1, :b=>2
|
16
|
+
end
|
17
|
+
|
18
|
+
We can then use #ann to lookup the set annotations.
|
19
|
+
|
20
|
+
X.ann(:x1,:a).should == 1
|
21
|
+
|
22
|
+
The #ann method is a public interface, so we can define annotation externally as well.
|
23
|
+
|
24
|
+
X.ann :x1, :a => 2
|
25
|
+
X.ann(:x1, :a).should == 2
|
26
|
+
|
27
|
+
## Annotation Added Callback
|
28
|
+
|
29
|
+
Given a sample class Y, we can use a standard callback method #annotation_added().
|
30
|
+
|
31
|
+
class Y
|
32
|
+
extend Anise::Annotations
|
33
|
+
|
34
|
+
class << self
|
35
|
+
attr :last_callback
|
36
|
+
|
37
|
+
def annotation_added(ref, ns)
|
38
|
+
@last_callback = [ns, ref, ann(ref/ns)]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Now if we add an annotation, we will see the callback catches it.
|
44
|
+
|
45
|
+
Y.ann :x1, :a=>1
|
46
|
+
Y.last_callback.should == [:ann, :x1, {:a => 1}]
|
47
|
+
|
48
|
+
We will do it again to be sure.
|
49
|
+
|
50
|
+
Y.ann :x1, :b=>2
|
51
|
+
Y.last_callback.should == [:ann, :x1, {:a => 1, :b => 2}]
|
52
|
+
|
53
|
+
## Using Callbacks for Attribute Defaults
|
54
|
+
|
55
|
+
class ::Module
|
56
|
+
def annotation_added(key, ns)
|
57
|
+
return unless ns == :ann
|
58
|
+
base = self
|
59
|
+
if value = ann(key, :default)
|
60
|
+
define_method(key) do
|
61
|
+
instance_variable_set("@#{key}", value) unless instance_variable_defined?("@#{key}")
|
62
|
+
base.module_eval{ attr key }
|
63
|
+
instance_variable_get("@#{key}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Try it out.
|
70
|
+
|
71
|
+
class Z
|
72
|
+
extend Anise::Annotations
|
73
|
+
|
74
|
+
attr :a
|
75
|
+
ann :a, :default => 10
|
76
|
+
end
|
77
|
+
|
78
|
+
z = Z.new
|
79
|
+
z.a.should == 10
|
80
|
+
z.a.should == 10
|
81
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Annotative Attributes
|
2
|
+
|
3
|
+
Create a class that uses the `Annotative::Attributes` mixin.
|
4
|
+
|
5
|
+
class X
|
6
|
+
extend Anise::Annotative::Attributes
|
7
|
+
|
8
|
+
attr :a, :count => 1
|
9
|
+
end
|
10
|
+
|
11
|
+
Then we can see tht the attribute method `:a` has an annotation entry.
|
12
|
+
|
13
|
+
X.ann(:a, :count) #=> 1
|
14
|
+
|
data/demo/04_methods.md
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Method Annotations
|
2
|
+
|
3
|
+
Create a class that uses the `Annotative::Methods` mixin.
|
4
|
+
|
5
|
+
class X
|
6
|
+
extend Anise::Annotative::Methods
|
7
|
+
|
8
|
+
def self.doc(string)
|
9
|
+
method_annotation(:doc=>string.to_s)
|
10
|
+
end
|
11
|
+
|
12
|
+
doc "See what I mean?"
|
13
|
+
|
14
|
+
def see
|
15
|
+
puts "Yes, I see!"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
See that it is set.
|
20
|
+
|
21
|
+
X.ann(:see, :doc) #=> "See what I mean?"
|
22
|
+
|
23
|
+
Method Annotators can override the standard annotation procedure
|
24
|
+
with a custom procedure. In such case no annotations will actually
|
25
|
+
be created unless the `#ann` is called in the procedure.
|
26
|
+
|
27
|
+
class Y
|
28
|
+
extend Anise::Annotative::Methods
|
29
|
+
|
30
|
+
def self.list
|
31
|
+
@list ||= []
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.doc(string)
|
35
|
+
method_annotation do |method|
|
36
|
+
list << [method, string]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
doc "See here!"
|
41
|
+
|
42
|
+
def see
|
43
|
+
puts "Yes, I see!"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
See that it is set.
|
48
|
+
|
49
|
+
Y.list #=> [[:see, "See here!"]]
|
50
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# Variable Annotations
|
2
|
+
|
3
|
+
Create a class that uses the `Annotative::Variables` mixin.
|
4
|
+
|
5
|
+
class X
|
6
|
+
extend Anise::Annotative::Variables
|
7
|
+
|
8
|
+
variable_annotator :@doc
|
9
|
+
|
10
|
+
@doc = "See what I mean?"
|
11
|
+
|
12
|
+
def see
|
13
|
+
puts "Yes, I see!"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
See that it is set.
|
18
|
+
|
19
|
+
X.ann(:see, :@doc).should == "See what I mean?"
|
20
|
+
|
21
|
+
Variable annotations can override the standard annotation procedure with a
|
22
|
+
custom procedure.
|
23
|
+
|
24
|
+
class Y
|
25
|
+
extend Anise::Annotative::Variables
|
26
|
+
|
27
|
+
def self.list
|
28
|
+
@list ||= []
|
29
|
+
end
|
30
|
+
|
31
|
+
variable_annotator :@doc do |method, value|
|
32
|
+
list << [method, value]
|
33
|
+
end
|
34
|
+
|
35
|
+
@doc = "See here!"
|
36
|
+
|
37
|
+
def see
|
38
|
+
puts "Yes, I see!"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
See that it is set.
|
43
|
+
|
44
|
+
Y.list #=> [[:see, "See here!"]]
|
45
|
+
|
data/{qed → demo}/applique/ae.rb
RENAMED
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'anise'
|
@@ -1,13 +1,9 @@
|
|
1
|
-
=
|
1
|
+
= TOPLEVEL Annotations
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require 'anise/annotation'
|
6
|
-
|
7
|
-
Including Annotations at the toplevel should make them available to all classes.
|
3
|
+
Extending Object with `Annotations` should make them available to all classes.
|
8
4
|
|
9
5
|
class ::Object
|
10
|
-
|
6
|
+
extend Anise::Annotations
|
11
7
|
end
|
12
8
|
|
13
9
|
Given a example class X we can apply annotations to it using the #ann method.
|
@@ -19,12 +15,12 @@ Given a example class X we can apply annotations to it using the #ann method.
|
|
19
15
|
|
20
16
|
We can then use #ann to lookup the set annotations.
|
21
17
|
|
22
|
-
|
18
|
+
X.ann(:x1,:a).should == 1
|
23
19
|
|
24
20
|
The #ann method is a public interface, so we can define annotation externally as well.
|
25
21
|
|
26
22
|
X.ann :x1, :a => 2
|
27
23
|
X.ann(:x1, :a).should == 2
|
28
24
|
|
29
|
-
|
25
|
+
Alternatively the `Annotations` module could be included into the `Module` class.
|
30
26
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
= TOPLEVEL Annotated Attributes
|
2
|
+
|
3
|
+
Including `AnnotatedAttributes` at the toplevel, i.e. Object, will make
|
4
|
+
annotated attributes univerally available.
|
5
|
+
|
6
|
+
class ::Object
|
7
|
+
extend Anise::Annotative::Attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
Create a class that uses it.
|
11
|
+
|
12
|
+
class X
|
13
|
+
attr :a, :count=>1
|
14
|
+
end
|
15
|
+
|
16
|
+
X.ann(:a, :count) #=> 1
|
17
|
+
|
18
|
+
Alternatively the `Annotative::Attributes` module could be included into
|
19
|
+
the `Module` class.
|
20
|
+
|
data/lib/anise.rb
CHANGED
@@ -1,62 +1,45 @@
|
|
1
|
-
require 'anise/annotation'
|
2
|
-
require 'anise/attribute'
|
3
|
-
require 'anise/annotator'
|
4
|
-
|
5
|
-
# = Anise
|
6
|
-
#
|
7
1
|
# Dynamic Annotations for Ruby.
|
8
2
|
#
|
9
3
|
# require 'anise'
|
10
4
|
#
|
5
|
+
# Provides annotations:
|
6
|
+
#
|
11
7
|
# class X
|
12
|
-
#
|
8
|
+
# extend Anise::Annotations
|
13
9
|
#
|
14
|
-
# # Provides annotations
|
15
10
|
# ann :foo, :class=>String
|
11
|
+
# end
|
16
12
|
#
|
17
|
-
#
|
18
|
-
#
|
13
|
+
# Provides method annotations:
|
14
|
+
#
|
15
|
+
# class Y
|
16
|
+
# extend Anise::Annotator::Method
|
17
|
+
#
|
18
|
+
# def self.doc(string)
|
19
|
+
# method_annotation(:doc=>string)
|
20
|
+
# end
|
19
21
|
#
|
20
|
-
# # Provides method annotators.
|
21
|
-
# annotator :doc
|
22
22
|
# doc "foo is cool"
|
23
23
|
# def foo
|
24
24
|
# # ...
|
25
25
|
# end
|
26
26
|
# end
|
27
27
|
#
|
28
|
+
# Provides annotated attributes:
|
29
|
+
#
|
30
|
+
# class Z
|
31
|
+
# extend Anise::Annotator::Attribute
|
32
|
+
#
|
33
|
+
# attr :bar, Integer, :max=>10
|
34
|
+
# end
|
35
|
+
#
|
28
36
|
module Anise
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
#module ClassMethods
|
39
|
-
# def append_features(base)
|
40
|
-
# super(base)
|
41
|
-
# Attribute.append_features(base)
|
42
|
-
# Annotator.append_features(base)
|
43
|
-
# base.extend ClassMethods
|
44
|
-
# end
|
45
|
-
#end
|
46
|
-
|
47
|
-
#
|
48
|
-
def self.metadata
|
49
|
-
@metadata ||= (
|
50
|
-
require 'yaml'
|
51
|
-
YAML.load(File.new(File.dirname(__FILE__) + '/anise.yml'))
|
52
|
-
)
|
53
|
-
end
|
54
|
-
|
55
|
-
#
|
56
|
-
def self.const_missing(name)
|
57
|
-
metadata[name.to_s.downcase] || super(name)
|
58
|
-
end
|
59
|
-
|
60
|
-
VERSION = metadata['version'] # becuase Ruby 1.8~ gets in the way :(
|
37
|
+
require 'anise/version'
|
38
|
+
require 'anise/core_ext'
|
39
|
+
require 'anise/annotations'
|
40
|
+
require 'anise/annotations/store'
|
41
|
+
require 'anise/annotative'
|
42
|
+
require 'anise/annotative/methods'
|
43
|
+
require 'anise/annotative/attributes'
|
44
|
+
require 'anise/annotative/variables'
|
61
45
|
end
|
62
|
-
|