anise 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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
|
-
|