anise 0.1.1 → 0.2.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.
@@ -0,0 +1,60 @@
1
+ module Anise
2
+ require 'anise/annotation.rb'
3
+
4
+ # = Annotator
5
+ #
6
+ # Annotator allows for the creation of dynamic method
7
+ # annotations which attach to the next method defined.
8
+ #
9
+ # class X
10
+ # include Anise::Annotator
11
+ #
12
+ # annotator :doc
13
+ #
14
+ # doc "See what I mean?"
15
+ #
16
+ # def see
17
+ # puts "Yes, I see!"
18
+ # end
19
+ # end
20
+ #
21
+ # X.ann(:see, :doc) #=> "See what I mean?"
22
+ #
23
+ #--
24
+ # TODO: Thread safety of @pending_annotations.
25
+ #++
26
+ module Annotator
27
+
28
+ def self.append_features(base)
29
+ #if base == Object
30
+ # Module.send(:include, self) # FIXME: Module ?
31
+ #else
32
+ base.extend Annotation #unless base.is_a?(Annotation)
33
+ base.extend self
34
+ #end
35
+ end
36
+
37
+ def annotator(name)
38
+ (class << self; self; end).module_eval do
39
+ define_method(name) do |*args|
40
+ @pending_annotations ||= []
41
+ @pending_annotations << [name, args]
42
+ end
43
+ end
44
+ end
45
+
46
+ def method_added(sym)
47
+ @pending_annotations ||= []
48
+ @pending_annotations.each do |name, args|
49
+ ann sym, name => args
50
+ end
51
+ @pending_annotations = []
52
+ super if defined?(super)
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ # Copyright (c) 2005, 2008 TigerOps
60
+
@@ -0,0 +1,135 @@
1
+ #require 'facets/inheritor' # remove dependency
2
+
3
+ module Anise
4
+ require 'anise/annotation'
5
+
6
+ # = Annotated Attributes
7
+ #
8
+ # This framework modifies the major attr_* methods to allow easy
9
+ # addition of annotations. It modifies the built in attribute methods
10
+ # (attr, attr_reader, attr_writer and attr_accessor), to allow
11
+ # annotations to added to them directly rather than requireing a
12
+ # separate #ann statement.
13
+ #
14
+ # class X
15
+ # include Anise::Attribute
16
+ #
17
+ # attr :a, :valid => lambda{ |x| x.is_a?(Integer) }
18
+ # end
19
+ #
20
+ # See annotation.rb for more information.
21
+ #
22
+ # NOTE: This library was designed to be backward compatible with
23
+ # the standard versions of the same methods.
24
+ #
25
+ module Attribute
26
+
27
+ def self.append_features(base)
28
+ base.extend Annotation
29
+ base.extend Attribute
30
+ base.module_eval do
31
+ #inheritor :instance_attributes, [], :|
32
+ annotatable_attribute_method(:attr_reader)
33
+ annotatable_attribute_method(:attr_writer)
34
+ annotatable_attribute_method(:attr_accessor)
35
+ annotatable_attribute_method(:attr_setter) if defined?(attr_setter)
36
+ end
37
+ end
38
+
39
+ #
40
+ def annotatable_attribute_method(attr_method_name)
41
+ (class << self; self; end).module_eval do
42
+
43
+ define_method(attr_method_name) do |*args|
44
+ args.flatten!
45
+
46
+ harg={}; while args.last.is_a?(Hash)
47
+ harg.update(args.pop)
48
+ end
49
+
50
+ raise ArgumentError if args.empty? and harg.empty?
51
+
52
+ if args.empty? # hash mode
53
+ harg.each { |a,h| __send__(attr_method_name,a,h) }
54
+ else
55
+ klass = harg[:class] = args.pop if args.last.is_a?(Class)
56
+
57
+ #attr_method.call(*args)
58
+ super(*args)
59
+
60
+ args.each{|a| ann(a.to_sym,harg)}
61
+
62
+ instance_attributes!.concat(args) #merge!
63
+
64
+ # Use this callback to customize for your needs.
65
+ if respond_to?(:attr_callback)
66
+ attr_callback(self, args, harg)
67
+ end
68
+
69
+ # return the names of the attributes created
70
+ return args
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+ end
77
+
78
+ # Instance attributes, including inherited attributes.
79
+ def instance_attributes
80
+ a = []
81
+ ancestors.each do |anc|
82
+ next unless anc.is_a?(Attribute)
83
+ if x = anc.instance_attributes!
84
+ a |= x
85
+ end
86
+ end
87
+ return a
88
+ end
89
+
90
+ # Local instance attributes.
91
+ def instance_attributes!
92
+ @instance_attributes ||= []
93
+ end
94
+
95
+ # Return list of attributes that have a :class annotation.
96
+ #
97
+ # class MyClass
98
+ # attr_accessor :test
99
+ # attr_accessor :name, String, :doc => 'Hello'
100
+ # attr_accessor :age, Fixnum
101
+ # end
102
+ #
103
+ # MyClass.instance_attributes # => [:test, :name, :age, :body]
104
+ # MyClass.classified_attributes # => [:name, :age]
105
+ #
106
+ def classified_attributes
107
+ instance_attributes.find_all do |a|
108
+ self.ann(a, :class)
109
+ end
110
+ end
111
+
112
+ # This define a simple adjustment to #attr to allow it to handle the boolean argument and
113
+ # to be able to accept attributes. It's backward compatible and is not needed for Ruby 1.9
114
+ # which gets rid of the secondary argument.
115
+ #
116
+ def attr(*args)
117
+ args.flatten!
118
+ case args.last
119
+ when TrueClass
120
+ args.pop
121
+ attr_accessor(*args)
122
+ when FalseClass, NilClass
123
+ args.pop
124
+ attr_reader(*args)
125
+ else
126
+ attr_reader(*args)
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
134
+ # Copyright (c) 2005, 2008 TigerOps
135
+
data/lib/anise.rb CHANGED
@@ -1 +1,38 @@
1
- require 'anise/annotatable'
1
+ require 'anise/annotator'
2
+ require 'anise/attribute'
3
+
4
+ # = Anise
5
+ #
6
+ # Dynamic Annotations system for Ruby.
7
+ #
8
+ # class X
9
+ #
10
+ # include Anise
11
+ #
12
+ # # Provides annotations:
13
+ #
14
+ # ann :foo, :class=>String
15
+ #
16
+ # # Provides annotators:
17
+ #
18
+ # annotator :doc
19
+ # doc "Underdog is here!"
20
+ # def underdog
21
+ # UnderDog.new
22
+ # end
23
+ #
24
+ # # Provides annotated attributes:
25
+ #
26
+ # attr :bar, Integer, :max => 10
27
+ #
28
+ # end
29
+ #
30
+ module Anise
31
+
32
+ def self.append_features(base)
33
+ Attribute.append_features(base)
34
+ Annotator.append_features(base)
35
+ end
36
+
37
+ end
38
+
@@ -0,0 +1,195 @@
1
+ require 'anise'
2
+
3
+ class Test_Anise_Annotation_0 < Test::Unit::TestCase
4
+ class X
5
+ include Anise
6
+
7
+ attr :a
8
+
9
+ ann :@a, :valid => lambda{ |x| x.is_a?(Integer) }
10
+
11
+ ann :a, :class => Integer
12
+
13
+ def initialize(a)
14
+ @a = a
15
+ end
16
+
17
+ def validate
18
+ instance_variables.each do |iv|
19
+ if validator = self.class.ann(iv)[:valid]
20
+ value = instance_variable_get(iv)
21
+ unless validator.call(value)
22
+ raise "Invalid value #{value} for #{iv}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def test_annotation_class
30
+ assert_equal(Integer, X.ann(:a, :class))
31
+ end
32
+
33
+ def test_annotation_validate
34
+ x = X.new(1)
35
+ assert_nothing_raised{ x.validate }
36
+ end
37
+ end
38
+
39
+ class Test_Anise_Annotation_1 < Test::Unit::TestCase
40
+ class X
41
+ include Anise
42
+ def x1 ; end
43
+ ann :x1, :a=>1
44
+ ann :x1, :b=>2
45
+ end
46
+
47
+ def test_1_01
48
+ assert_equal( X.ann(:x1,:a), X.ann(:x1,:a) )
49
+ assert_equal( X.ann(:x1,:a).object_id, X.ann(:x1,:a).object_id )
50
+ end
51
+ def test_1_02
52
+ X.ann :x1, :a => 2
53
+ assert_equal( 2, X.ann(:x1,:a) )
54
+ end
55
+ end
56
+
57
+ class Test_Anise_Annotation_2 < Test::Unit::TestCase
58
+ class X
59
+ include Anise
60
+ def x1 ; end
61
+ ann :x1, :a=>1
62
+ ann :x1, :b=>2
63
+ end
64
+ class Y < X ; end
65
+
66
+ def test_2_01
67
+ assert_equal( Y.ann(:x1,:a), Y.ann(:x1,:a) )
68
+ assert_equal( Y.ann(:x1,:a).object_id, Y.ann(:x1,:a).object_id )
69
+ end
70
+ def test_2_02
71
+ assert_equal( 1, Y.ann(:x1,:a) )
72
+ assert_equal( 2, Y.ann(:x1,:b) )
73
+ end
74
+ def test_2_03
75
+ Y.ann :x1,:a => 2
76
+ assert_equal( 2, Y.ann(:x1,:a) )
77
+ assert_equal( 2, Y.ann(:x1,:b) )
78
+ end
79
+ end
80
+
81
+ class Test_Anise_Annotation_3 < Test::Unit::TestCase
82
+ class X
83
+ include Anise
84
+ ann :foo, Integer
85
+ end
86
+ class Y < X
87
+ ann :foo, String
88
+ end
89
+
90
+ def test_3_01
91
+ assert_equal( Integer, X.ann(:foo, :class) )
92
+ end
93
+ def test_3_02
94
+ assert_equal( String, Y.ann(:foo, :class) )
95
+ end
96
+ end
97
+
98
+ class Test_Anise_Annotation_4 < Test::Unit::TestCase
99
+ class X
100
+ include Anise
101
+ ann :foo, :doc => "hello"
102
+ ann :foo, :bar => []
103
+ end
104
+ class Y < X
105
+ ann :foo, :class => String, :doc => "bye"
106
+ end
107
+
108
+ def test_4_01
109
+ assert_equal( "hello", X.ann(:foo,:doc) )
110
+ end
111
+ def test_4_02
112
+ assert_equal( X.ann(:foo), { :doc => "hello", :bar => [] } )
113
+ end
114
+ def test_4_03
115
+ X.ann(:foo,:bar) << "1"
116
+ assert_equal( ["1"], X.ann(:foo,:bar) )
117
+ end
118
+ def test_4_04
119
+ assert_equal( "bye", Y.ann(:foo,:doc) )
120
+ end
121
+ def test_4_05
122
+ #assert_equal( nil, Y.ann(:foo,:bar) )
123
+ assert_equal( ["1"], Y.ann(:foo,:bar) )
124
+ end
125
+ def test_4_06
126
+ Y.ann(:foo, :doc => "cap")
127
+ assert_equal( "cap", Y.ann(:foo, :doc) )
128
+ end
129
+ def test_4_07
130
+ Y.ann!(:foo,:bar) << "2"
131
+ assert_equal( ["1", "2"], Y.ann(:foo,:bar) )
132
+ assert_equal( ["1", "2"], Y.ann(:foo,:bar) )
133
+ assert_equal( ["1"], X.ann(:foo,:bar) )
134
+ end
135
+ end
136
+
137
+ class Test_Anise_Annotator < Test::Unit::TestCase
138
+ class X
139
+ include Anise
140
+
141
+ annotator :req
142
+
143
+ req 'r'
144
+
145
+ def a ; "a"; end
146
+
147
+ req 's'
148
+
149
+ attr :b
150
+ end
151
+
152
+ def test_annotated
153
+ assert_equal( {:req=>['r']}, X.ann(:a) )
154
+ end
155
+
156
+ def test_annotated
157
+ assert_equal( {:req=>['s']}, X.ann(:b) )
158
+ end
159
+ end
160
+
161
+ class Test_Anise_Attribute < Test::Unit::TestCase
162
+ class X
163
+ include Anise
164
+ attr :q
165
+ attr :a, :x => 1
166
+ end
167
+
168
+ def test_attr_a
169
+ assert_equal( {:x=>1}, X.ann(:a) )
170
+ end
171
+ end
172
+
173
+ class Test_Anise_Attribute_Using_Attr < Test::Unit::TestCase
174
+ class A
175
+ include Anise
176
+ attr :x, :cast=>"to_s"
177
+ end
178
+
179
+ def test_01
180
+ assert_equal( "to_s", A.ann(:x,:cast) )
181
+ end
182
+ end
183
+
184
+ class Test_Anise_Attribute_Using_Attr_Accessor < Test::Unit::TestCase
185
+ class A
186
+ include Anise
187
+ attr_accessor :x, :cast=>"to_s"
188
+ end
189
+
190
+ def test_instance_attributes
191
+ a = A.new
192
+ assert_equal( [:x], A.instance_attributes )
193
+ end
194
+ end
195
+
@@ -0,0 +1,196 @@
1
+ require 'anise'
2
+
3
+ include Anise
4
+
5
+ class Test_Anise_Toplevel_Annotation_0 < Test::Unit::TestCase
6
+ class X
7
+ attr :a
8
+
9
+ ann :@a, :valid => lambda{ |x| x.is_a?(Integer) }
10
+
11
+ ann :a, :class => Integer
12
+
13
+ def initialize(a)
14
+ @a = a
15
+ end
16
+
17
+ def validate
18
+ instance_variables.each do |iv|
19
+ if validator = self.class.ann(iv)[:valid]
20
+ value = instance_variable_get(iv)
21
+ unless validator.call(value)
22
+ raise "Invalid value #{value} for #{iv}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def test_annotation_class
30
+ assert_equal(Integer, X.ann(:a, :class))
31
+ end
32
+
33
+ def test_annotation_validate
34
+ x = X.new(1)
35
+ assert_nothing_raised{ x.validate }
36
+ end
37
+ end
38
+
39
+ class Test_Anise_Toplevel_Annotation_1 < Test::Unit::TestCase
40
+ class X
41
+ def x1 ; end
42
+ ann :x1, :a=>1
43
+ ann :x1, :b=>2
44
+ end
45
+
46
+ def test_1_01
47
+ assert_equal( X.ann(:x1,:a), X.ann(:x1,:a) )
48
+ assert_equal( X.ann(:x1,:a).object_id, X.ann(:x1,:a).object_id )
49
+ end
50
+ def test_1_02
51
+ X.ann :x1, :a => 2
52
+ assert_equal( 2, X.ann(:x1,:a) )
53
+ end
54
+ end
55
+
56
+ class Test_Anise_Toplevel_Annotation_2 < Test::Unit::TestCase
57
+ class X
58
+ def x1 ; end
59
+ ann :x1, :a=>1
60
+ ann :x1, :b=>2
61
+ end
62
+ class Y < X ; end
63
+
64
+ def test_2_01
65
+ assert_equal( Y.ann(:x1,:a), Y.ann(:x1,:a) )
66
+ assert_equal( Y.ann(:x1,:a).object_id, Y.ann(:x1,:a).object_id )
67
+ end
68
+ def test_2_02
69
+ assert_equal( 1, Y.ann(:x1,:a) )
70
+ assert_equal( 2, Y.ann(:x1,:b) )
71
+ end
72
+ def test_2_03
73
+ Y.ann :x1,:a => 2
74
+ assert_equal( 2, Y.ann(:x1,:a) )
75
+ assert_equal( 2, Y.ann(:x1,:b) )
76
+ end
77
+ end
78
+
79
+ class Test_Anise_Toplevel_Annotation_3 < Test::Unit::TestCase
80
+ class X
81
+ ann :foo, Integer
82
+ end
83
+ class Y < X
84
+ ann :foo, String
85
+ end
86
+
87
+ def test_3_01
88
+ assert_equal( Integer, X.ann(:foo, :class) )
89
+ end
90
+ def test_3_02
91
+ assert_equal( String, Y.ann(:foo, :class) )
92
+ end
93
+ end
94
+
95
+ class Test_Anise_Toplevel_Annotation_4 < Test::Unit::TestCase
96
+ class X
97
+ ann :foo, :doc => "hello"
98
+ ann :foo, :bar => []
99
+ end
100
+ class Y < X
101
+ ann :foo, :class => String, :doc => "bye"
102
+ end
103
+
104
+ def test_4_01
105
+ assert_equal( "hello", X.ann(:foo,:doc) )
106
+ end
107
+ def test_4_02
108
+ assert_equal( X.ann(:foo), { :doc => "hello", :bar => [] } )
109
+ end
110
+ def test_4_03
111
+ X.ann(:foo,:bar) << "1"
112
+ assert_equal( ["1"], X.ann(:foo,:bar) )
113
+ end
114
+ def test_4_04
115
+ assert_equal( "bye", Y.ann(:foo,:doc) )
116
+ end
117
+ def test_4_05
118
+ #assert_equal( nil, Y.ann(:foo,:bar) )
119
+ assert_equal( ["1"], Y.ann(:foo,:bar) )
120
+ end
121
+ def test_4_06
122
+ Y.ann(:foo, :doc => "cap")
123
+ assert_equal( "cap", Y.ann(:foo, :doc) )
124
+ end
125
+ def test_4_07
126
+ Y.ann!(:foo,:bar) << "2"
127
+ assert_equal( ["1", "2"], Y.ann(:foo,:bar) )
128
+ assert_equal( ["1", "2"], Y.ann(:foo,:bar) )
129
+ assert_equal( ["1"], X.ann(:foo,:bar) )
130
+ end
131
+ end
132
+
133
+ class Test_Anise_Toplevel_Annotator < Test::Unit::TestCase
134
+ class X
135
+ annotator :req
136
+
137
+ req 'r'
138
+
139
+ def a ; "a"; end
140
+
141
+ req 's'
142
+
143
+ attr :b
144
+
145
+ def initialize
146
+ @b = "b"
147
+ end
148
+ end
149
+
150
+ def test_normal
151
+ x = X.new
152
+ assert_equal("a", x.a)
153
+ assert_equal("b", x.b)
154
+ end
155
+
156
+ def test_annotated_a
157
+ assert_equal( {:req=>['r']}, X.ann(:a) )
158
+ end
159
+
160
+ def test_annotated_b
161
+ assert_equal( {:req=>['s']}, X.ann(:b) )
162
+ end
163
+ end
164
+
165
+ class Test_Anise_Toplevel_Attribute < Test::Unit::TestCase
166
+ class X
167
+ attr :q
168
+ attr :a, :x => 1
169
+ end
170
+
171
+ def test_attr_a
172
+ assert_equal( {:x=>1}, X.ann(:a) )
173
+ end
174
+ end
175
+
176
+ class Test_Anise_Toplevel_Attribute_Using_Attr < Test::Unit::TestCase
177
+ class A
178
+ attr :x, :cast=>"to_s"
179
+ end
180
+
181
+ def test_01
182
+ assert_equal( "to_s", A.ann(:x,:cast) )
183
+ end
184
+ end
185
+
186
+ class Test_Anise_Toplevel_Attribute_Using_Attr_Accessor < Test::Unit::TestCase
187
+ class A
188
+ attr_accessor :x, :cast=>"to_s"
189
+ end
190
+
191
+ def test_instance_attributes
192
+ a = A.new
193
+ assert_equal( [:x], A.instance_attributes )
194
+ end
195
+ end
196
+