anise 0.4.0 → 0.5.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,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