anise 0.6.0 → 0.7.0

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