anise 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+