agio 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,90 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ ##
4
+ # A simple wrapper around string data in an HTML document.
5
+ class Agio::Data
6
+ def initialize(value)
7
+ @value = value
8
+ end
9
+
10
+ attr_reader :value
11
+
12
+ def to_s
13
+ value
14
+ end
15
+
16
+ def to_str
17
+ value
18
+ end
19
+
20
+ def inspect
21
+ %Q(#<#{self.class} #{value.inspect}>)
22
+ end
23
+
24
+ ##
25
+ # Used mostly for testing.
26
+ def ==(other)
27
+ if other.kind_of? Agio::Data
28
+ self.class == other.class && value == other.value
29
+ else
30
+ value == other
31
+ end
32
+ end
33
+ end
34
+
35
+ ##
36
+ # A simple wrapper around CData in an HTML document.
37
+ class Agio::CData < Agio::Data; end
38
+
39
+ ##
40
+ # A simple wrapper around the string contents of an HTML comment.
41
+ class Agio::Comment < Agio::Data; end
42
+
43
+ ##
44
+ # A simple wrapper around the contents of an XML declaration in an
45
+ # XHTML document.
46
+ class Agio::XMLDecl
47
+ def initialize(options = {})
48
+ @version = options[:version]
49
+ @encoding = options[:encoding]
50
+ @standalone = options[:standalone]
51
+ end
52
+
53
+ attr_reader :version, :encoding, :standalone
54
+
55
+ def to_a
56
+ [ version, encoding, standalone ]
57
+ end
58
+
59
+ def to_s
60
+ s = %Q(<?xml )
61
+ s += %Q(version="#{version}" ) unless version.nil?
62
+ s += %Q(encoding="#{encoding}" ) unless encoding.nil?
63
+ s += %Q(standalone="#{!!standalone}" ) unless standalone.nil?
64
+ s += "?>"
65
+ s
66
+ end
67
+
68
+ def inspect
69
+ %Q(#<#{self.class} '#{to_s}'>)
70
+ end
71
+
72
+ def to_str
73
+ to_s
74
+ end
75
+
76
+ def ==(other)
77
+ case other
78
+ when String
79
+ to_s == other
80
+ when Array
81
+ to_a == other
82
+ when Agio::XMLDecl
83
+ to_s == other.to_s
84
+ else
85
+ false
86
+ end
87
+ end
88
+ end
89
+
90
+ # vim: ft=ruby
@@ -0,0 +1,317 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ ##
4
+ # Meta-programming methods to help create and manage the flags used to help
5
+ # keep track of processing state for Agio.
6
+ module Agio::Flags
7
+ ##
8
+ # When <tt>extend Agio::Flags</tt> is specified in a class, this will
9
+ # +extend+ the class methods with Agio::Flags::ClassMethods and +include+
10
+ # Agio::Flags.
11
+ def self.extend_object(object)
12
+ object.extend ClassMethods
13
+ object.__send__(:include, self)
14
+ end
15
+
16
+ ##
17
+ # Resets the flags to their default state. If +with_public+ is +false+,
18
+ # the default, only the internal flags will be reset to their initial
19
+ # state. If +with_public+ is a +true+ value, flags that were initialized
20
+ # with <tt>:public => true</tt> will also be reset.
21
+ #
22
+ # Calls the initializer methods created by the flag methods in
23
+ # ClassMethods.
24
+ def reset_flags(with_public = false)
25
+ self.class.flag_inits.each { |init| __send__ init }
26
+ self.class.public_flag_inits.each { |init| __send__ init } if with_public
27
+ end
28
+ private :reset_flags
29
+ end
30
+
31
+ ##
32
+ # Meta-programming methods to help create flags and accessor and test
33
+ # methods for those flags.
34
+ module Agio::Flags::ClassMethods
35
+ ##
36
+ # Creates a flag. This method is the core method for building flags. Flags
37
+ # must have a name and may specify one of two options, <tt>:default</tt>
38
+ # or <tt>:public</tt>.
39
+ #
40
+ # flag_builder returns a Hash describing the flag.
41
+ #
42
+ # === Options
43
+ # :default:: The default value for the flag. If not specified, or
44
+ # not overridden by one of the type helper methods, the
45
+ # default will be +nil+. If the default is not an immediate
46
+ # value, the default should be specified in a Proc, as is done
47
+ # for Array flags: <tt>lambda { [] }</tt>.
48
+ # :public:: If +true+, indicates that the flag is internal and should
49
+ # not be exposed to the user. The default is that flags are
50
+ # private (e.g., <tt>:public => false</tt>).
51
+ #
52
+ # === Methods Defined
53
+ # Four methods are always defined by +flag_builder+ or a type helper
54
+ # method. The type helper methods mentioned below may override the default
55
+ # behaviours described below.
56
+ #
57
+ # [Init] "init_<em>name</em>". This is always private, and should
58
+ # only be called through Flags#reset_flags. Sets the value of
59
+ # the flag to the default value. If the default value returns
60
+ # to #call, it will be called to provide the default value.
61
+ # Uses the flag's Setter.
62
+ # [Getter] "name". Returns the value of the flag.
63
+ # [Setter] "set_<em>name</em>" if private or "<em>name</em>=" if
64
+ # public. Sets the flag to the provided value.
65
+ # [Tester] "<em>name</em>?" Returns +true+ or +false+ for the value
66
+ # with double negation (e.g., <tt>!!value</tt>).
67
+ #
68
+ # When calling flag_builder from a helper method, you can provide a block
69
+ # that will allow the customization of the Setter or the Tester. The other
70
+ # methods cannot be overridden.
71
+ #
72
+ # === Type Helper Methods
73
+ #
74
+ # There are five type helpers defined:
75
+ #
76
+ # [string_flag] Creates a flag that works with String values. The
77
+ # default value is +nil+, unless otherwise specified. If a
78
+ # non-nil value is provided, the default value will be
79
+ # wrapped in a Proc that will create a new String object
80
+ # for every reset. The Setter converts all values (except
81
+ # +nil+) to a String using #to_s. The Tester will return
82
+ # +false+ if the value is +nil+ or the String is empty.
83
+ # [boolean_flag] Creates a flag that works with Boolean values (+true+ or
84
+ # +false+). The default value for a boolean_flag is
85
+ # +false+, unless otherwise specified. The Setter converts
86
+ # all values to +true+ or +false+ through double negation
87
+ # (e.g., <tt>!!value</tt>). The Tester forces the instance
88
+ # variable to +true+ or +false+ through double negation.
89
+ # [integer_flag] Creates a flag that works with integer values. The
90
+ # default value for an integer_flag is zero, unless
91
+ # otherwise specified. The Setter converts all values to
92
+ # integer with #to_i. The Tester returns +true+ if the
93
+ # value is non-zero. Private integer flags also define two
94
+ # additional methods, incr_<em>name</em> and
95
+ # decr_<em>name</em>, that will increment or decrement the
96
+ # integer value by the value provided.
97
+ # [hash_flag] Creates a flag that works with Hash values. The default
98
+ # value is a lambda that creates an empty Hash. The Tester
99
+ # returns +false+ if the value is +nil+ or the Hash is
100
+ # empty.
101
+ # [array_flag] Creates a flag that works with Array values. The default
102
+ # value is a lambda that creates an empty Array. The
103
+ # Tester returns +false+ if the value is +nil+ or the
104
+ # Array is empty.
105
+ def flag_builder(name, options = {})
106
+ raise SyntaxError, "Flag #{name} already defined" if flags.has_key? name.to_sym
107
+
108
+ default = options[:default]
109
+ type = options[:type]
110
+ is_public = options[:public]
111
+
112
+ flag = {
113
+ :ivar => "@flag_#{name}",
114
+ :init => "init_#{name}".to_sym,
115
+ :getter => name.to_sym,
116
+ :setter => (is_public ? "#{name}=" : "set_#{name}").to_sym,
117
+ :tester => "#{name}?".to_sym,
118
+ :public => is_public,
119
+ :type => type,
120
+ :default => default,
121
+ }
122
+
123
+ # Define the flag initializer
124
+ define_method(flag[:init]) do
125
+ value = if default.respond_to? :call
126
+ default.call
127
+ else
128
+ default
129
+ end
130
+ __send__(flag[:setter], value)
131
+ end
132
+ private flag[:init]
133
+
134
+ if is_public
135
+ public_flag_inits << flag[:init]
136
+ else
137
+ flag_inits << flag[:init]
138
+ end
139
+
140
+ # Define the flag getter
141
+ define_method(flag[:getter]) do
142
+ instance_variable_get(flag[:ivar])
143
+ end
144
+ private flag[:getter] unless is_public
145
+
146
+ # Define the flag setter
147
+ defined = yield :setter, flag[:setter], flag[:ivar] if block_given?
148
+
149
+ unless defined
150
+ define_method(flag[:setter]) do |value|
151
+ instance_variable_set(flag[:ivar], value)
152
+ end
153
+ end
154
+ private flag[:setter] unless is_public
155
+
156
+ # Define the flag tester
157
+ defined = yield :tester, flag[:tester], flag[:ivar] if block_given?
158
+
159
+ unless defined
160
+ define_method(flag[:tester]) do
161
+ !!instance_variable_get(ivar)
162
+ end
163
+ end
164
+ private flag[:tester] unless is_public
165
+
166
+ flags[name.to_sym] = flag
167
+ end
168
+
169
+ ##
170
+ # Defines a flag optimized for working with strings.
171
+ def string_flag(name, options = {})
172
+ options = { :default => nil }.merge(options).merge(:type => :string)
173
+
174
+ value = options[:default]
175
+ options[:default] = case value
176
+ when nil
177
+ nil
178
+ when String
179
+ lambda { value.dup }
180
+ else
181
+ lambda { value.to_s }
182
+ end
183
+
184
+ flag_builder(name, options) do |type, meth, ivar|
185
+ case type
186
+ when :setter
187
+ define_method(meth) do |value|
188
+ value = value.to_s unless value.nil?
189
+ instance_variable_set(ivar, value)
190
+ end
191
+ when :tester
192
+ define_method(meth) do
193
+ value = instance_variable_get(ivar)
194
+ !(value.nil? or value.empty?)
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ ##
201
+ # Defines a flag optimized for working with Boolean (+true+ or +false+)
202
+ # values.
203
+ def boolean_flag(name, options = {})
204
+ options = { :default => false }.merge(options).merge(:type => :boolean)
205
+ flag_builder(name, options) do |type, meth, ivar|
206
+ case type
207
+ when :setter
208
+ define_method(meth) do |value|
209
+ instance_variable_set(ivar, !!value)
210
+ end
211
+ when :tester
212
+ define_method(meth) do
213
+ !!instance_variable_get(ivar)
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ ##
220
+ # Defines a flag optimized for working with integer values.
221
+ def integer_flag(name, options = {})
222
+ options = { :default => 0 }.merge(options).merge(:type => :integer)
223
+
224
+ flag = flag_builder(name, options) do |type, meth, ivar|
225
+ case type
226
+ when :setter
227
+ define_method(meth) do |value|
228
+ instance_variable_set(ivar, value.to_i)
229
+ end
230
+ when :tester
231
+ define_method(meth) do
232
+ instance_variable_get(ivar).nonzero?
233
+ end
234
+ end
235
+ end
236
+
237
+ unless flag[:public]
238
+ incr = "incr_#{name}".to_sym
239
+ define_method(incr) do |value|
240
+ value = instance_variable_get(flag[:ivar]) + value.to_i
241
+ instance_variable_set(flag[:ivar], value)
242
+ end
243
+ private incr
244
+
245
+ decr = "decr_#{name}".to_sym
246
+ define_method(decr) do |value|
247
+ value = instance_variable_get(flag[:ivar]) - value.to_i
248
+ instance_variable_set(flag[:ivar], value)
249
+ end
250
+ private decr
251
+ end
252
+ end
253
+
254
+ ##
255
+ # Defines a flag optimized for working with arrays.
256
+ def array_flag(name, options = {})
257
+ options = { :default => lambda { [] } }.merge(options)
258
+ options = options.merge(:type => :array)
259
+ flag_builder(name, options) do |type, meth, ivar|
260
+ case type
261
+ when :setter
262
+ define_method(meth) do |value|
263
+ value = [ value ] unless value.nil? or value.kind_of? Array
264
+ instance_variable_set(ivar, value)
265
+ end
266
+ when :tester
267
+ define_method(meth) do
268
+ value = instance_variable_get(ivar)
269
+ !(value.nil? or value.empty?)
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ ##
276
+ # Defines a flag optimized for working with hashes.
277
+ def hash_flag(name, options = {})
278
+ options = { :default => lambda { {} } }.merge(options)
279
+ options = options.merge(:type => :hash)
280
+ flag_builder(name, options) do |type, meth, ivar|
281
+ case type
282
+ when :setter
283
+ define_method(meth) do |value|
284
+ raise ArgumentError unless value.nil? or value.kind_of? Hash
285
+ instance_variable_set(ivar, value)
286
+ end
287
+ when :tester
288
+ define_method(meth) do
289
+ value = instance_variable_get(ivar)
290
+ !(value.nil? or value.empty?)
291
+ end
292
+ end
293
+ end
294
+ end
295
+
296
+ ##
297
+ # An array of initializer method symbols created so that Flags#reset_flags
298
+ # can reset flags to their default values.
299
+ def flag_inits
300
+ @flag_inits ||= []
301
+ end
302
+
303
+ ##
304
+ # An array of initializer method symbols created so that Flags#reset_flags
305
+ # does its work appropriately for public flags.
306
+ def public_flag_inits
307
+ @public_flag_inits ||= []
308
+ end
309
+
310
+ ##
311
+ # The flags that have been defined.
312
+ def flags
313
+ @flags ||= {}
314
+ end
315
+ end
316
+
317
+ # vim: ft=ruby
@@ -0,0 +1,126 @@
1
+ # -*- ruby encoding: utf-8 -*-
2
+
3
+ require 'nokogiri'
4
+
5
+ ##
6
+ # Agio::HTMLElementDescription is a wrapper around
7
+ # Nokogiri::HTML::ElementDescription to work around a bug with LibXML2 prior
8
+ # to 2.7.7. In HTMLParser.c, the #define of INLINE didn't have commas,
9
+ # meaning that strings were concatenated instead of forming an
10
+ # array (e.g., what should have been <tt>[ "small", "em" ]</tt> ended up
11
+ # being <tt>[ "smallem" ]</tt>). This was fixed in libxml2 commit
12
+ # 4b41f15d... on 20 January 2010 by Eugene Pimenov.
13
+ #
14
+ # Nokogiri includes a DefaultDescription hash that contains the same basic
15
+ # information, so we will use that (with appropriate wrappers) if the
16
+ # version of LibXML2 is not sufficient to have this bug fixed.
17
+ class Agio::HTMLElementDescription
18
+ ver = Nokogiri::VERSION_INFO["libxml"]["loaded"]
19
+ ver = ver.split(%r{\.}).map { |e| e.to_i }
20
+
21
+ ok = ver[0] > 2
22
+ ok = ok || (ver[0] == 2 and ver[1] > 7)
23
+ ok = ok || (ver[0] == 2 and ver[1] == 7 and ver[2] >= 7)
24
+
25
+ if ok
26
+ def self.[](name)
27
+ Nokogiri::HTML::ElementDescription[name]
28
+ end
29
+ else
30
+ def self.[](name)
31
+ @cache ||= {}
32
+
33
+ name = name.downcase
34
+ desc = @cache[name]
35
+
36
+ if desc.nil?
37
+ desc = Nokogiri::HTML::ElementDescription::DefaultDescriptions[name]
38
+ desc = if desc.nil?
39
+ false
40
+ else
41
+ self.new(desc)
42
+ end
43
+
44
+ @cache[name] = desc
45
+ end
46
+
47
+ if desc
48
+ desc
49
+ else
50
+ nil
51
+ end
52
+ end
53
+ end
54
+
55
+ def initialize(desc)
56
+ @d = desc
57
+ @name = name.downcase
58
+ @d = Nokogiri::HTML::ElementDescription::DefaultDescriptions[@name]
59
+ end
60
+
61
+ def name
62
+ @d ? @d.name : @name
63
+ end
64
+
65
+ def to_s
66
+ "#{name}: #{description}"
67
+ end
68
+
69
+ def inspect
70
+ "#<#{self.class.name}: #{name} #{description}>"
71
+ end
72
+
73
+ def sub_elements
74
+ @d ? @d.subelts : []
75
+ end
76
+
77
+ def block?
78
+ !inline?
79
+ end
80
+
81
+ def inline?
82
+ @d ? @d.isinline : nil
83
+ end
84
+
85
+ def empty?
86
+ @d ? @d.empty : nil
87
+ end
88
+
89
+ def implied_start_tag?
90
+ @d ? @d.startTag : nil
91
+ end
92
+
93
+ def implied_end_tag?
94
+ @d ? @d.endTag : nil
95
+ end
96
+
97
+ def save_end_tag?
98
+ @d ? @d.saveEndTag : nil
99
+ end
100
+
101
+ def deprecated?
102
+ @d ? @d.depr : nil
103
+ end
104
+
105
+ def description
106
+ @d ? @d.desc : nil
107
+ end
108
+
109
+ def default_sub_element
110
+ @d ? @d.defaultsubelt : nil
111
+ end
112
+
113
+ def optional_attributes
114
+ @d ? @d.attrs_opt : []
115
+ end
116
+
117
+ def deprecated_attributes
118
+ @d ? @d.attrs_depr : []
119
+ end
120
+
121
+ def required_attributes
122
+ @d ? @d.attrs_req : []
123
+ end
124
+ end
125
+
126
+ # vim: ft=ruby