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.
Files changed (53) hide show
  1. data/.ruby +59 -38
  2. data/.yardopts +7 -0
  3. data/DEMO.md +242 -0
  4. data/{HISTORY.rdoc → HISTORY.md} +28 -7
  5. data/LICENSE.txt +27 -0
  6. data/README.md +129 -0
  7. data/demo/01_annotations.md +81 -0
  8. data/demo/03_attributes.md +14 -0
  9. data/demo/04_methods.md +50 -0
  10. data/demo/05_variables.md +45 -0
  11. data/{qed → demo}/applique/ae.rb +0 -0
  12. data/demo/applique/anise.rb +1 -0
  13. data/{qed/toplevel/01_annotations.qed → demo/toplevel/01_annotations.md} +5 -9
  14. data/demo/toplevel/03_attributes.md +20 -0
  15. data/lib/anise.rb +28 -45
  16. data/lib/anise.yml +59 -38
  17. data/lib/anise/annotations.rb +132 -0
  18. data/lib/anise/annotations/store.rb +136 -0
  19. data/lib/anise/annotative.rb +7 -0
  20. data/lib/anise/annotative/attributes.rb +147 -0
  21. data/lib/anise/annotative/methods.rb +131 -0
  22. data/lib/anise/annotative/variables.rb +99 -0
  23. data/lib/anise/{module.rb → core_ext.rb} +30 -0
  24. data/lib/anise/universal.rb +6 -0
  25. data/lib/anise/version.rb +17 -0
  26. data/test/case_annotations.rb +173 -0
  27. data/test/case_attributes.rb +46 -0
  28. data/test/case_combined_usage.rb +341 -0
  29. data/test/case_methods.rb +36 -0
  30. data/test/case_variables.rb +22 -0
  31. data/test/helper.rb +2 -0
  32. metadata +99 -98
  33. data/APACHE2.txt +0 -204
  34. data/COPYING.rdoc +0 -17
  35. data/README.rdoc +0 -107
  36. data/lib/anise/annotation.rb +0 -175
  37. data/lib/anise/annotator.rb +0 -82
  38. data/lib/anise/attribute.rb +0 -138
  39. data/qed/01_annotations.qed +0 -26
  40. data/qed/02_annotation_added.rdoc +0 -60
  41. data/qed/03_attributes.rdoc +0 -16
  42. data/qed/04_annotator.rdoc +0 -49
  43. data/qed/toplevel/03_attributes.rdoc +0 -20
  44. data/test/suite.rb +0 -8
  45. data/test/test_anise.rb +0 -193
  46. data/test/test_anise_toplevel.rb +0 -194
  47. data/test/test_annotations.rb +0 -136
  48. data/test/test_annotations_module.rb +0 -132
  49. data/test/test_annotations_toplevel.rb +0 -131
  50. data/test/test_annotator.rb +0 -26
  51. data/test/test_annotator_toplevel.rb +0 -28
  52. data/test/test_attribute.rb +0 -37
  53. data/test/test_attribute_toplevel.rb +0 -65
@@ -1,175 +0,0 @@
1
- module Anise
2
-
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.
9
- #
10
- # == Synopsis
11
- #
12
- # require 'anise/annotation'
13
- #
14
- # class X
15
- # include Anise::Annotation
16
- #
17
- # attr :a
18
- #
19
- # ann :a, :desc => "A Number"
20
- # end
21
- #
22
- # X.ann(:a, :desc) #=> "A Number"
23
- #
24
- # As stated, annotations need not only annotate methods, they are
25
- # arbitrary, so they can be used for any purpose. For example, we
26
- # may want to annotate instance variables.
27
- #
28
- # class X
29
- # include Anise::Annotation
30
- #
31
- # ann :@a, :valid => lambda{ |x| x.is_a?(Integer) }
32
- #
33
- # def validate
34
- # instance_variables.each do |iv|
35
- # if validator = self.class.ann(iv)[:valid]
36
- # value = instance_variable_get(iv)
37
- # unless validator.call(value)
38
- # raise "Invalid value #{value} for #{iv}"
39
- # end
40
- # end
41
- # end
42
- # end
43
- # end
44
- #
45
- # Or, we could even annotate the class itself.
46
- #
47
- # class X
48
- # include Anise::Annotate
49
- #
50
- # ann self, :valid => lambda{ |x| x.is_a?(Enumerable) }
51
- # end
52
- #
53
- # Although annotations are arbitrary they are tied to the class or
54
- # module they are defined against.
55
- #
56
- #--
57
- # TODO: By using a global variable rather the definining a class
58
- # instance variable for each class/module, it is possible to
59
- # quicky scan all annotations for the entire system. To do
60
- # the same without this would require scanning through
61
- # the ObjectSpace. Should we do this?
62
- # $annotations = Hash.new { |h,k| h[k] = {} }
63
- #
64
- # TODO: The ann(x).name notation is kind of nice. Would like to add that
65
- # back-in if reasonable. This would require @annotations to be an
66
- # OpenHash or OpenObject rather than just a Hash though.
67
- #++
68
- module Annotation
69
-
70
- #
71
-
72
- def self.included(base)
73
- base.extend Aid
74
- end
75
-
76
- # Anise::Annotations Domain Language.
77
-
78
- module Aid
79
-
80
- # Lookup an annotation. Unlike +annotations[ref]+
81
- # this provides a complete annotation <i>heritage</i>,
82
- # pulling annotations of the same reference name
83
- # from ancestor classes and modules.
84
-
85
- def annotation(ref=nil)
86
- return(@annotations ||= {}) if ref.nil?
87
-
88
- ref = ref.to_sym
89
- ann = {}
90
- ancestors.reverse_each do |anc|
91
- next unless anc < Annotation
92
- if h = anc.annotations[ref]
93
- ann.merge!(h)
94
- end
95
- end
96
- return ann
97
- end
98
-
99
- # Plural alias for #annotation.
100
-
101
- alias_method :annotations, :annotation
102
-
103
- # Set or read annotations.
104
-
105
- def ann(ref, keys_or_class=nil, keys=nil)
106
- return annotation(ref) unless keys_or_class or keys
107
-
108
- if Class === keys_or_class
109
- keys ||= {}
110
- keys[:class] = keys_or_class
111
- else
112
- keys = keys_or_class
113
- end
114
-
115
- if Hash === keys
116
- ref = ref.to_sym
117
- keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
118
- annotations[ref] ||= {}
119
- annotations[ref].update(keys)
120
- # callback
121
- annotation_added(ref) #if method_defined?(:annotation_added)
122
- else
123
- key = keys.to_sym
124
- annotation(ref)[key]
125
- end
126
- end
127
-
128
- # To change an annotation's value in place for a given class or module
129
- # it first must be duplicated, otherwise the change may effect annotations
130
- # in the class or module's ancestors.
131
-
132
- def ann!(ref, keys_or_class=nil, keys=nil)
133
- #return annotation(ref) unless keys_or_class or keys
134
- unless keys_or_class or keys
135
- return annotations[ref] ||= {}
136
- end
137
-
138
- if Class === keys_or_class
139
- keys ||= {}
140
- keys[:class] = keys_or_class
141
- else
142
- keys = keys_or_class
143
- end
144
-
145
- if Hash === keys
146
- ref = ref.to_sym
147
- keys = keys.inject({}){ |h,(k,v)| h[k.to_sym] = v; h} #rekey
148
- annotations[ref] ||= {}
149
- annotations[ref].update(keys)
150
- # callback
151
- annotation_added(ref) #if method_defined?(:annotation_added)
152
- else
153
- key = keys.to_sym
154
- annotations[ref] ||= {}
155
- begin
156
- annotations[ref][key] = annotation(ref)[key].dup
157
- rescue TypeError
158
- annotations[ref][key] = annotation(ref)[key]
159
- end
160
- end
161
- end
162
-
163
- # Callback method. This method is called for each new annotation.
164
-
165
- def annotation_added(name)
166
- super if defined?(super)
167
- end
168
-
169
- end
170
-
171
- end
172
-
173
- end
174
-
175
- # Copyright (c) 2006-11-07 Thomas Sawyer
@@ -1,82 +0,0 @@
1
- module Anise
2
- require 'anise/annotation'
3
-
4
- # = Annotator
5
- #
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.
12
- #
13
- # require 'anise/annotator'
14
- #
15
- # class X
16
- # include Anise::Annotator
17
- #
18
- # annotator :doc
19
- #
20
- # doc "See what I mean?"
21
- #
22
- # def see
23
- # puts "Yes, I see!"
24
- # end
25
- # end
26
- #
27
- # X.ann(:see, :doc) #=> "See what I mean?"
28
- #
29
- # Note that the library uses the #method_added callback, so be sure to
30
- # respect good practices of calling +super+ if you need to override
31
- # this method while using Annotator.
32
- #
33
- #--
34
- # TODO: Allow annotators to be inherited via module mixins.
35
- #
36
- # TODO: Ensure thread-safety of <code>@_pending_annotations</code> variable.
37
- #++
38
- module Annotator
39
-
40
- #
41
- def self.included(base)
42
- base.send(:include, Annotation) #unless base.is_a?(Annotation)
43
- base.extend Aid
44
- end
45
-
46
- module Aid
47
-
48
- # Define an annotator.
49
- def annotator(name, &block)
50
- (class << self; self; end).module_eval do
51
- define_method(name) do |*args|
52
- @_pending_annotations ||= []
53
- @_pending_annotations << [name, args, block]
54
- end
55
- end
56
- end
57
-
58
- # When a method is added, run all pending annotations.
59
- def method_added(sym)
60
- @_pending_annotations ||= []
61
- @_pending_annotations.each do |name, args, block|
62
- if block
63
- block.call(sym, *args)
64
- else
65
- if args.size == 1
66
- ann(sym, name=>args.first)
67
- else
68
- ann(sym, name=>args)
69
- end
70
- end
71
- end
72
- @_pending_annotations = []
73
- super if defined?(super)
74
- end
75
-
76
- end
77
-
78
- end
79
-
80
- end
81
-
82
- # Copyright (c) 2005,2011 Thomas Sawyer
@@ -1,138 +0,0 @@
1
- module Anise
2
- #require 'facets/inheritor' # removed dependency
3
- require 'anise/annotation'
4
- require 'anise/module'
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 be added to them directly rather than requiring
12
- # a separate #ann statement.
13
- #
14
- # require 'anise/attribute'
15
- #
16
- # class X
17
- # include Anise::Attribute
18
- #
19
- # attr :a, :valid => lambda{ |x| x.is_a?(Integer) }
20
- # end
21
- #
22
- # See annotation.rb for more information.
23
- #
24
- # NOTE: This library was designed to be backward compatible with
25
- # the standard versions of the same methods.
26
- #
27
- module Attribute
28
-
29
- #
30
- def self.included(base)
31
- base.send(:include, Annotation) #.append_features(base)
32
- base.extend Aid
33
-
34
- #inheritor :instance_attributes, [], :|
35
- base_class = (class << base; self; end)
36
- base_class.attribute_methods.each do |attr_method|
37
- annotatable_attribute_method(base_class, attr_method)
38
- end
39
- end
40
-
41
- #
42
- def self.annotatable_attribute_method(base, attr_method_name)
43
- base.module_eval do
44
- define_method(attr_method_name) do |*args|
45
- args.flatten!
46
-
47
- harg={}; while args.last.is_a?(Hash)
48
- harg.update(args.pop)
49
- end
50
-
51
- raise ArgumentError if args.empty? and harg.empty?
52
-
53
- if args.empty? # hash mode
54
- harg.each { |a,h| __send__(attr_method_name,a,h) }
55
- else
56
- klass = harg[:class] = args.pop if args.last.is_a?(Class)
57
-
58
- #attr_method.call(*args)
59
- super(*args)
60
-
61
- args.each{|a| ann(a.to_sym,harg)}
62
-
63
- instance_attributes!.concat(args) #merge!
64
-
65
- # Use this callback to customize for your needs.
66
- if respond_to?(:attr_callback)
67
- attr_callback(self, args, harg)
68
- end
69
-
70
- # return the names of the attributes created
71
- return args
72
- end
73
- end
74
- end
75
- end
76
-
77
- # Anise::Attributes Doman Language.
78
- module Aid
79
-
80
- # Instance attributes, including inherited attributes.
81
- def instance_attributes
82
- a = []
83
- ancestors.each do |anc|
84
- next unless anc < Attribute
85
- if x = anc.instance_attributes!
86
- a |= x
87
- end
88
- end
89
- return a
90
- end
91
-
92
- # Local instance attributes.
93
- def instance_attributes!
94
- @instance_attributes ||= []
95
- end
96
-
97
- # Return list of attributes that have a :class annotation.
98
- #
99
- # class MyClass
100
- # attr_accessor :test
101
- # attr_accessor :name, String, :doc => 'Hello'
102
- # attr_accessor :age, Fixnum
103
- # end
104
- #
105
- # MyClass.instance_attributes # => [:test, :name, :age, :body]
106
- # MyClass.classified_attributes # => [:name, :age]
107
- #
108
- def classified_attributes
109
- instance_attributes.find_all do |a|
110
- self.ann(a, :class)
111
- end
112
- end
113
-
114
- # This define a simple adjustment to #attr to allow it to handle the boolean argument and
115
- # to be able to accept attributes. It's backward compatible and is not needed for Ruby 1.9
116
- # which gets rid of the secondary argument.
117
- #
118
- def attr(*args)
119
- args.flatten!
120
- case args.last
121
- when TrueClass
122
- args.pop
123
- attr_accessor(*args)
124
- when FalseClass, NilClass
125
- args.pop
126
- attr_reader(*args)
127
- else
128
- attr_reader(*args)
129
- end
130
- end
131
-
132
- end
133
-
134
- end
135
-
136
- end
137
-
138
- # Copyright (c) 2005, 2008 Thomas Sawyer
@@ -1,26 +0,0 @@
1
- = Creating and Reading Annotations
2
-
3
- Load the primary annotations library.
4
-
5
- require 'anise/annotation'
6
-
7
- Given a example class X we can apply annotations to it using the #ann method.
8
-
9
- class X
10
- include Anise::Annotation
11
-
12
- ann :x1, :a=>1
13
- ann :x1, :b=>2
14
- end
15
-
16
- We can then use #ann to lookup the set annotations.
17
-
18
- X.ann(:x1,:a).should == 1
19
-
20
- The #ann method is a public interface, so we can define annotation externally as well.
21
-
22
- X.ann :x1, :a => 2
23
- X.ann(:x1, :a).should == 2
24
-
25
- QED.
26
-
@@ -1,60 +0,0 @@
1
- = Annotation Added Callback
2
-
3
- Load the annotations, which supports callbacks out of the box.
4
-
5
- require 'anise/annotation'
6
-
7
- Given a sample class X, we can use a standard callback method #annotation_added().
8
-
9
- class X
10
- include Anise::Annotation
11
-
12
- class << self
13
- attr :last_callback
14
-
15
- def annotation_added(name)
16
- @last_callback = [name, ann(name)]
17
- end
18
- end
19
- end
20
-
21
- Now if we add an annotation, we will see the callback catches it.
22
-
23
- X.ann :x1, :a=>1
24
- X.last_callback.should == [:x1, {:a => 1}]
25
-
26
- We'll do it again to be sure.
27
-
28
- X.ann :x1, :b=>2
29
- X.last_callback.should == [:x1, {:a => 1, :b => 2}]
30
-
31
- == Using Callbacks for Attribute Defaults
32
-
33
- class ::Module
34
- def annotation_added(key)
35
- base = self
36
- if value = ann(key, :default)
37
- define_method(key) do
38
- instance_variable_set("@#{key}", value) unless instance_variable_defined?("@#{key}")
39
- base.module_eval{ attr key }
40
- instance_variable_get("@#{key}")
41
- end
42
- end
43
- end
44
- end
45
-
46
- Try it out.
47
-
48
- class Y
49
- include Anise::Annotation
50
-
51
- attr :a
52
- ann :a, :default => 10
53
- end
54
-
55
- x = Y.new
56
- x.a.should == 10
57
- x.a.should == 10
58
-
59
- QED.
60
-