anise 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,41 @@
1
+ ---
2
+ spec_version: 1.0.0
3
+ replaces: []
4
+
5
+ loadpath:
6
+ - lib
7
+ name: anise
8
+ repositories: {}
9
+
10
+ conflicts: []
11
+
12
+ engine_check: []
13
+
14
+ title: Anise
15
+ contact: trans <transfire@gmail.com>
16
+ resources:
17
+ code: http://github.com/rubyworks/anise
18
+ mail: http://groups.google.com/group/rubyworks-mailinglist
19
+ home: http://rubyworks.github.com/anise
20
+ maintainers: []
21
+
22
+ requires:
23
+ - group:
24
+ - test
25
+ name: qed
26
+ version: 0+
27
+ - group:
28
+ - build
29
+ name: syckle
30
+ version: 0+
31
+ manifest: MANIFEST
32
+ version: 0.5.0
33
+ licenses:
34
+ - Apache 2.0
35
+ copyright: Copyright (c) 2008 Thomas Sawyer
36
+ authors:
37
+ - Thomas Sawyer
38
+ organization: Rubyworks
39
+ description: Anise is an Annotation System for the Ruby programming language. Unlike most other annotations systems it is not a comment-based or macro-based system that sits over-and-above the rest of the code. Rather, Anise is a dynamic annotations system operating at runtime.
40
+ summary: Dynamic Annotation System
41
+ created: "2008-02-21"
@@ -1,14 +1,11 @@
1
1
  module Anise
2
2
 
3
- # = Runtime Annotations
4
- #
5
- # The Annotation module is the heart of the Anise system.
6
- # It provides the framework for annotating class or module related
7
- # objects, typically symbols representing methods, with arbitrary
8
- # metadata. These annotations do not do anything in themselves.
9
- # They are simply data. But you can put them to use. For instance
10
- # an attribute validator might check for an annotation called
11
- # :valid and test against it.
3
+ # The Annotate module is the core of the Anise system. It provides the
4
+ # framework for annotating class or module related objects, typically
5
+ # symbols representing methods, with arbitrary metadata. These annotations
6
+ # do not do anything in themselves. They are simply data. But they can be
7
+ # put to good use. For instance an attribute validator might check for an
8
+ # annotation called :valid and test against it.
12
9
  #
13
10
  # == Synopsis
14
11
  #
@@ -48,12 +45,12 @@ module Anise
48
45
  # Or, we could even annotate the class itself.
49
46
  #
50
47
  # class X
51
- # include Anise::Annotation
48
+ # include Anise::Annotate
52
49
  #
53
50
  # ann self, :valid => lambda{ |x| x.is_a?(Enumerable) }
54
51
  # end
55
52
  #
56
- # Altough annotations are arbitrary they are tied to the class or
53
+ # Although annotations are arbitrary they are tied to the class or
57
54
  # module they are defined against.
58
55
  #
59
56
  #--
@@ -66,125 +63,114 @@ module Anise
66
63
  #
67
64
  # TODO: The ann(x).name notation is kind of nice. Would like to add that
68
65
  # back-in if reasonable. This would require @annotations to be an
69
- # OpenHash or OpenObject rather than just a Hash.
66
+ # OpenHash or OpenObject rather than just a Hash though.
70
67
  #++
71
68
  module Annotation
72
69
 
70
+ #
71
+
73
72
  def self.append_features(base)
74
- if base == ::Object
75
- append_features(::Module)
76
- elsif base == ::Module
77
- unless ::Module < Annotation
78
- super
79
- end
80
- else
81
- base.extend self
82
- end
73
+ base.extend ClassMethods
74
+ super(base)
83
75
  end
84
76
 
85
- # Lookup an annotation. Unlike +annotations[ref]+
86
- # this provides a complete annotation <i>heritage</i>,
87
- # pulling annotations of the same reference name
88
- # from ancestor classes and modules.
89
- #
90
- def annotation(ref=nil)
91
- return(@annotations ||= {}) if ref.nil?
92
-
93
- ref = ref.to_sym
94
- ann = {}
95
- ancestors.reverse_each do |anc|
96
- next unless anc.is_a?(Annotation)
97
- #anc.annotations[ref] ||= {}
98
- if anc.annotations[ref]
99
- ann.update(anc.annotations[ref]) #.merge(ann)
77
+ # Anise::Annotations Domain Language.
78
+
79
+ module ClassMethods
80
+
81
+ # Lookup an annotation. Unlike +annotations[ref]+
82
+ # this provides a complete annotation <i>heritage</i>,
83
+ # pulling annotations of the same reference name
84
+ # from ancestor classes and modules.
85
+
86
+ def annotation(ref=nil)
87
+ return(@annotations ||= {}) if ref.nil?
88
+
89
+ ref = ref.to_sym
90
+ ann = {}
91
+ ancestors.reverse_each do |anc|
92
+ next unless anc < Annotation
93
+ if h = anc.annotations[ref]
94
+ ann.merge!(h)
95
+ end
100
96
  end
97
+ return ann
101
98
  end
102
- return ann
103
- #ancs = ancestors.select{ |a| a.is_a?(Annotations) }
104
- #ancs.inject({}) do |memo, ancestor|
105
- # ancestor.annotations[ref] ||= {}
106
- # ancestor.annotations[ref].merge(memo)
107
- #end
108
- end
109
99
 
110
- # Plural alias for #annotation.
111
- alias_method :annotations, :annotation
100
+ # Plural alias for #annotation.
112
101
 
113
- # Stores this class' or module's annotations.
114
- #
115
- #def annotations
116
- # #$annotations[self]
117
- # @annotations ||= {}
118
- #end
102
+ alias_method :annotations, :annotation
119
103
 
120
- # Set or read annotations.
121
- #
122
- def ann(ref, keys_or_class=nil, keys=nil)
123
- return annotation(ref) unless keys_or_class or keys
124
-
125
- if Class === keys_or_class
126
- keys ||= {}
127
- keys[:class] = keys_or_class
128
- else
129
- keys = keys_or_class
130
- end
104
+ # Set or read annotations.
131
105
 
132
- if Hash === keys
133
- ref = ref.to_sym
134
- keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
135
- annotations[ref] ||= {}
136
- annotations[ref].update(keys)
137
- # callback
138
- annotation_added(ref)
139
- else
140
- key = keys.to_sym
141
- annotation(ref)[key]
142
- end
143
- end
106
+ def ann(ref, keys_or_class=nil, keys=nil)
107
+ return annotation(ref) unless keys_or_class or keys
144
108
 
145
- # To change an annotation's value in place for a given class or module
146
- # it first must be duplicated, otherwise the change may effect annotations
147
- # in the class or module's ancestors.
148
- #
149
- def ann!(ref, keys_or_class=nil, keys=nil)
150
- #return annotation(ref) unless keys_or_class or keys
151
- unless keys_or_class or keys
152
- return annotations[ref] ||= {}
153
- end
109
+ if Class === keys_or_class
110
+ keys ||= {}
111
+ keys[:class] = keys_or_class
112
+ else
113
+ keys = keys_or_class
114
+ end
154
115
 
155
- if Class === keys_or_class
156
- keys ||= {}
157
- keys[:class] = keys_or_class
158
- else
159
- keys = keys_or_class
116
+ if Hash === keys
117
+ ref = ref.to_sym
118
+ keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
119
+ annotations[ref] ||= {}
120
+ annotations[ref].update(keys)
121
+ # callback
122
+ annotation_added(ref) #if method_defined?(:annotation_added)
123
+ else
124
+ key = keys.to_sym
125
+ annotation(ref)[key]
126
+ end
160
127
  end
161
128
 
162
- if Hash === keys
163
- ref = ref.to_sym
164
- keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
165
- annotations[ref] ||= {}
166
- annotations[ref].update(keys)
167
- # callback
168
- annotation_added(ref) if method_defined?(:annotation_added)
169
- else
170
- key = keys.to_sym
171
- annotations[ref] ||= {}
172
- begin
173
- annotations[ref][key] = annotation(ref)[key].dup
174
- rescue TypeError
175
- annotations[ref][key] = annotation(ref)[key]
129
+ # To change an annotation's value in place for a given class or module
130
+ # it first must be duplicated, otherwise the change may effect annotations
131
+ # in the class or module's ancestors.
132
+
133
+ def ann!(ref, keys_or_class=nil, keys=nil)
134
+ #return annotation(ref) unless keys_or_class or keys
135
+ unless keys_or_class or keys
136
+ return annotations[ref] ||= {}
137
+ end
138
+
139
+ if Class === keys_or_class
140
+ keys ||= {}
141
+ keys[:class] = keys_or_class
142
+ else
143
+ keys = keys_or_class
144
+ end
145
+
146
+ if Hash === keys
147
+ ref = ref.to_sym
148
+ keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
149
+ annotations[ref] ||= {}
150
+ annotations[ref].update(keys)
151
+ # callback
152
+ annotation_added(ref) #if method_defined?(:annotation_added)
153
+ else
154
+ key = keys.to_sym
155
+ annotations[ref] ||= {}
156
+ begin
157
+ annotations[ref][key] = annotation(ref)[key].dup
158
+ rescue TypeError
159
+ annotations[ref][key] = annotation(ref)[key]
160
+ end
176
161
  end
177
162
  end
178
- end
179
163
 
180
- # callback method
181
- def annotation_added(name)
182
- super if defined?(super)
164
+ # Callback method. This method is called for each new annotation.
165
+
166
+ def annotation_added(name)
167
+ super if defined?(super)
168
+ end
169
+
183
170
  end
184
171
 
185
172
  end
186
173
 
187
174
  end
188
175
 
189
- # 2006-11-07 trans Created this ultra-concise version of annotations.
190
- # Copyright (c) 2005, 2008 TigerOps
176
+ # Copyright (c) 2006-11-07 Thomas Sawyer
@@ -1,10 +1,14 @@
1
1
  module Anise
2
- require 'anise/annotation.rb'
2
+ require 'anise/annotation'
3
3
 
4
4
  # = Annotator
5
5
  #
6
- # Annotator allows for the creation of dynamic <i>method
7
- # annotations</i> which attach to the next method defined.
6
+ # The Annotator module allows for the creation of <i>method annotations</i>
7
+ # which attach to the next method defined.
8
+ #
9
+ # This idiom of annotator-before-definition was popularized by
10
+ # Rake's desc/task pair. The Annotator module makes it very easy
11
+ # to add similar capabilites to any program.
8
12
  #
9
13
  # require 'anise/annotator'
10
14
  #
@@ -22,66 +26,58 @@ module Anise
22
26
  #
23
27
  # X.ann(:see, :doc) #=> "See what I mean?"
24
28
  #
25
- # This idiom of annotator before definition was popularized by
26
- # Rake's desc/task pair. Annotator makes it very easy to add
27
- # similar capabilites to any program.
28
- #
29
- # The library uses the #method_added callback, so be sure to
29
+ # Note that the library uses the #method_added callback, so be sure to
30
30
  # respect good practices of calling +super+ if you need to override
31
31
  # this method while using Annotator.
32
32
  #
33
- # TODO: Ensure thread safety of the internal <code>@pending_annotations</code> variable.
33
+ #--
34
+ # TODO: Allow annotators to be inherited via module mixins.
34
35
  #
36
+ # TODO: Ensure thread-safety of <code>@_pending_annotations</code> variable.
37
+ #++
35
38
  module Annotator
36
39
 
40
+ #
37
41
  def self.append_features(base)
38
- if base == Object
39
- append_features(::Module)
40
- elsif base == ::Module
41
- unless Module < Annotator
42
- ::Module.module_eval do
43
- include Annotation
44
- end
45
- # can't include b/c it seem Module intercetps the call.
46
- ::Module.module_eval do
47
- def method_added(sym)
48
- @pending_annotations ||= []
49
- @pending_annotations.each do |name, args|
50
- ann sym, name => args
51
- end
52
- @pending_annotations = []
53
- #super if defined?(super)
54
- end
42
+ Annotation.append_features(base) #unless base.is_a?(Annotation)
43
+ base.extend ClassMethods
44
+ super(base)
45
+ end
46
+
47
+ module ClassMethods
48
+
49
+ # Define an annotator.
50
+ def annotator(name, &block)
51
+ (class << self; self; end).module_eval do
52
+ define_method(name) do |*args|
53
+ @_pending_annotations ||= []
54
+ @_pending_annotations << [name, args, block]
55
55
  end
56
- super
57
56
  end
58
- else
59
- base.extend Annotation #unless base.is_a?(Annotation)
60
- base.extend self
61
57
  end
62
- end
63
58
 
64
- def annotator(name)
65
- (class << self; self; end).module_eval do
66
- define_method(name) do |*args|
67
- @pending_annotations ||= []
68
- @pending_annotations << [name, args]
59
+ # When a method is added, run all pending annotations.
60
+ def method_added(sym)
61
+ @_pending_annotations ||= []
62
+ @_pending_annotations.each do |name, args, block|
63
+ if block
64
+ block.call(sym, *args)
65
+ else
66
+ if args.size == 1
67
+ ann(sym, name=>args.first)
68
+ else
69
+ ann(sym, name=>args)
70
+ end
71
+ end
69
72
  end
73
+ @_pending_annotations = []
74
+ super if defined?(super)
70
75
  end
71
- end
72
76
 
73
- def method_added(sym)
74
- @pending_annotations ||= []
75
- @pending_annotations.each do |name, args|
76
- ann sym, name => args
77
- end
78
- @pending_annotations = []
79
- super if defined?(super)
80
77
  end
81
78
 
82
79
  end
83
80
 
84
81
  end
85
82
 
86
- # Copyright (c) 2005, 2008 TigerOps
87
-
83
+ # Copyright (c) 2005,2011 Thomas Sawyer
@@ -1,7 +1,7 @@
1
- #require 'facets/inheritor' # remove dependency
2
-
3
1
  module Anise
2
+ #require 'facets/inheritor' # removed dependency
4
3
  require 'anise/annotation'
4
+ require 'anise/module'
5
5
 
6
6
  # = Annotated Attributes
7
7
  #
@@ -22,35 +22,20 @@ module Anise
22
22
  # See annotation.rb for more information.
23
23
  #
24
24
  # NOTE: This library was designed to be backward compatible with
25
- # the standard versions of the same methods.
25
+ # the standard versions of the same methods.
26
26
  #
27
27
  module Attribute
28
28
 
29
+ #
29
30
  def self.append_features(base)
30
- if base == ::Object
31
- append_features(::Module)
32
- elsif base == ::Module
33
- unless ::Module <= self
34
- ::Module.module_eval do
35
- include Annotation
36
- super(::Module)
37
- end
38
- annotatable_attribute_method_for_module(:attr)
39
- annotatable_attribute_method_for_module(:attr_reader)
40
- annotatable_attribute_method_for_module(:attr_writer)
41
- annotatable_attribute_method_for_module(:attr_accessor)
42
- annotatable_attribute_method_for_module(:attr_setter) if defined?(attr_setter)
43
- end
44
- else
45
- base.extend Annotation
46
- base.extend Attribute
47
- base = (class << base; self; end)
48
- #inheritor :instance_attributes, [], :|
49
- annotatable_attribute_method(base, :attr)
50
- annotatable_attribute_method(base, :attr_reader)
51
- annotatable_attribute_method(base, :attr_writer)
52
- annotatable_attribute_method(base, :attr_accessor)
53
- annotatable_attribute_method(base, :attr_setter) if defined?(attr_setter)
31
+ super(base)
32
+ Annotation.append_features(base)
33
+ base.extend ClassMethods #Attribute
34
+
35
+ #inheritor :instance_attributes, [], :|
36
+ base_class = (class << base; self; end)
37
+ base_class.attribute_methods.each do |attr_method|
38
+ annotatable_attribute_method(base_class, attr_method)
54
39
  end
55
40
  end
56
41
 
@@ -90,99 +75,65 @@ module Anise
90
75
  end
91
76
  end
92
77
 
93
- #
94
- def self.annotatable_attribute_method_for_module(attr_method_name)
95
- ::Module.module_eval do
96
- alias_method "__#{attr_method_name}", attr_method_name
97
-
98
- define_method(attr_method_name) do |*args|
99
-
100
- args.flatten!
101
-
102
- harg={}; while args.last.is_a?(Hash)
103
- harg.update(args.pop)
104
- end
105
-
106
- raise ArgumentError if args.empty? and harg.empty?
107
-
108
- if args.empty? # hash mode
109
- harg.each { |a,h| __send__(attr_method_name,a,h) }
110
- else
111
- klass = harg[:class] = args.pop if args.last.is_a?(Class)
112
-
113
- __send__("__#{attr_method_name}", *args)
114
-
115
- args.each{|a| ann(a.to_sym,harg)}
116
-
117
- instance_attributes!.concat(args) #merge!
118
-
119
- # Use this callback to customize for your needs.
120
- if respond_to?(:attr_callback)
121
- attr_callback(self, args, harg)
122
- end
78
+ # Anise::Attributes Doman Language.
79
+ module ClassMethods
123
80
 
124
- # return the names of the attributes created
125
- return args
81
+ # Instance attributes, including inherited attributes.
82
+ def instance_attributes
83
+ a = []
84
+ ancestors.each do |anc|
85
+ next unless anc < Attribute
86
+ if x = anc.instance_attributes!
87
+ a |= x
126
88
  end
127
89
  end
90
+ return a
128
91
  end
129
- end
130
92
 
131
- # Instance attributes, including inherited attributes.
132
- def instance_attributes
133
- a = []
134
- ancestors.each do |anc|
135
- next unless anc.is_a?(Attribute)
136
- if x = anc.instance_attributes!
137
- a |= x
138
- end
93
+ # Local instance attributes.
94
+ def instance_attributes!
95
+ @instance_attributes ||= []
139
96
  end
140
- return a
141
- end
142
97
 
143
- # Local instance attributes.
144
- def instance_attributes!
145
- @instance_attributes ||= []
146
- end
147
-
148
- # Return list of attributes that have a :class annotation.
149
- #
150
- # class MyClass
151
- # attr_accessor :test
152
- # attr_accessor :name, String, :doc => 'Hello'
153
- # attr_accessor :age, Fixnum
154
- # end
155
- #
156
- # MyClass.instance_attributes # => [:test, :name, :age, :body]
157
- # MyClass.classified_attributes # => [:name, :age]
158
- #
159
- def classified_attributes
160
- instance_attributes.find_all do |a|
161
- self.ann(a, :class)
98
+ # Return list of attributes that have a :class annotation.
99
+ #
100
+ # class MyClass
101
+ # attr_accessor :test
102
+ # attr_accessor :name, String, :doc => 'Hello'
103
+ # attr_accessor :age, Fixnum
104
+ # end
105
+ #
106
+ # MyClass.instance_attributes # => [:test, :name, :age, :body]
107
+ # MyClass.classified_attributes # => [:name, :age]
108
+ #
109
+ def classified_attributes
110
+ instance_attributes.find_all do |a|
111
+ self.ann(a, :class)
112
+ end
162
113
  end
163
- end
164
114
 
165
- # This define a simple adjustment to #attr to allow it to handle the boolean argument and
166
- # to be able to accept attributes. It's backward compatible and is not needed for Ruby 1.9
167
- # which gets rid of the secondary argument.
168
- #
169
- def attr(*args)
170
- args.flatten!
171
- case args.last
172
- when TrueClass
173
- args.pop
174
- attr_accessor(*args)
175
- when FalseClass, NilClass
176
- args.pop
177
- attr_reader(*args)
178
- else
179
- attr_reader(*args)
115
+ # This define a simple adjustment to #attr to allow it to handle the boolean argument and
116
+ # to be able to accept attributes. It's backward compatible and is not needed for Ruby 1.9
117
+ # which gets rid of the secondary argument.
118
+ #
119
+ def attr(*args)
120
+ args.flatten!
121
+ case args.last
122
+ when TrueClass
123
+ args.pop
124
+ attr_accessor(*args)
125
+ when FalseClass, NilClass
126
+ args.pop
127
+ attr_reader(*args)
128
+ else
129
+ attr_reader(*args)
130
+ end
180
131
  end
132
+
181
133
  end
182
134
 
183
135
  end
184
136
 
185
137
  end
186
138
 
187
- # Copyright (c) 2005, 2008 TigerOps
188
-
139
+ # Copyright (c) 2005, 2008 Thomas Sawyer