opal-builder 3.2.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
5
+ # All rights reserved.
6
+
7
+ # Permission is granted for use, copying, modification, distribution,
8
+ # and distribution of modified versions of this work as long as the
9
+ # above copyright notice is included.
10
+ #++
11
+
12
+ require 'builder/xmlmarkup'
13
+
14
+ module Builder
15
+
16
+ # Create a series of SAX-like XML events (e.g. start_tag, end_tag)
17
+ # from the markup code. XmlEvent objects are used in a way similar
18
+ # to XmlMarkup objects, except that a series of events are generated
19
+ # and passed to a handler rather than generating character-based
20
+ # markup.
21
+ #
22
+ # Usage:
23
+ # xe = Builder::XmlEvents.new(hander)
24
+ # xe.title("HI") # Sends start_tag/end_tag/text messages to the handler.
25
+ #
26
+ # Indentation may also be selected by providing value for the
27
+ # indentation size and initial indentation level.
28
+ #
29
+ # xe = Builder::XmlEvents.new(handler, indent_size, initial_indent_level)
30
+ #
31
+ # == XML Event Handler
32
+ #
33
+ # The handler object must expect the following events.
34
+ #
35
+ # [<tt>start_tag(tag, attrs)</tt>]
36
+ # Announces that a new tag has been found. +tag+ is the name of
37
+ # the tag and +attrs+ is a hash of attributes for the tag.
38
+ #
39
+ # [<tt>end_tag(tag)</tt>]
40
+ # Announces that an end tag for +tag+ has been found.
41
+ #
42
+ # [<tt>text(text)</tt>]
43
+ # Announces that a string of characters (+text+) has been found.
44
+ # A series of characters may be broken up into more than one
45
+ # +text+ call, so the client cannot assume that a single
46
+ # callback contains all the text data.
47
+ #
48
+ class XmlEvents < XmlMarkup
49
+ def text!(text)
50
+ @target.text(text)
51
+ end
52
+
53
+ def _start_tag(sym, attrs, end_too=false)
54
+ @target.start_tag(sym, attrs)
55
+ _end_tag(sym) if end_too
56
+ end
57
+
58
+ def _end_tag(sym)
59
+ @target.end_tag(sym)
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,339 @@
1
+ #!/usr/bin/env ruby
2
+ #--
3
+ # Copyright 2004, 2005 by Jim Weirich (jim@weirichhouse.org).
4
+ # All rights reserved.
5
+
6
+ # Permission is granted for use, copying, modification, distribution,
7
+ # and distribution of modified versions of this work as long as the
8
+ # above copyright notice is included.
9
+ #++
10
+
11
+ # Provide a flexible and easy to use Builder for creating XML markup.
12
+ # See XmlBuilder for usage details.
13
+
14
+ require 'builder/xmlbase'
15
+
16
+ module Builder
17
+
18
+ # Create XML markup easily. All (well, almost all) methods sent to
19
+ # an XmlMarkup object will be translated to the equivalent XML
20
+ # markup. Any method with a block will be treated as an XML markup
21
+ # tag with nested markup in the block.
22
+ #
23
+ # Examples will demonstrate this easier than words. In the
24
+ # following, +xm+ is an +XmlMarkup+ object.
25
+ #
26
+ # xm.em("emphasized") # => <em>emphasized</em>
27
+ # xm.em { xm.b("emp & bold") } # => <em><b>emph &amp; bold</b></em>
28
+ # xm.a("A Link", "href"=>"http://onestepback.org")
29
+ # # => <a href="http://onestepback.org">A Link</a>
30
+ # xm.div { xm.br } # => <div><br/></div>
31
+ # xm.target("name"=>"compile", "option"=>"fast")
32
+ # # => <target option="fast" name="compile"\>
33
+ # # NOTE: order of attributes is not specified.
34
+ #
35
+ # xm.instruct! # <?xml version="1.0" encoding="UTF-8"?>
36
+ # xm.html { # <html>
37
+ # xm.head { # <head>
38
+ # xm.title("History") # <title>History</title>
39
+ # } # </head>
40
+ # xm.body { # <body>
41
+ # xm.comment! "HI" # <!-- HI -->
42
+ # xm.h1("Header") # <h1>Header</h1>
43
+ # xm.p("paragraph") # <p>paragraph</p>
44
+ # } # </body>
45
+ # } # </html>
46
+ #
47
+ # == Notes:
48
+ #
49
+ # * The order that attributes are inserted in markup tags is
50
+ # undefined.
51
+ #
52
+ # * Sometimes you wish to insert text without enclosing tags. Use
53
+ # the <tt>text!</tt> method to accomplish this.
54
+ #
55
+ # Example:
56
+ #
57
+ # xm.div { # <div>
58
+ # xm.text! "line"; xm.br # line<br/>
59
+ # xm.text! "another line"; xmbr # another line<br/>
60
+ # } # </div>
61
+ #
62
+ # * The special XML characters <, >, and & are converted to &lt;,
63
+ # &gt; and &amp; automatically. Use the <tt><<</tt> operation to
64
+ # insert text without modification.
65
+ #
66
+ # * Sometimes tags use special characters not allowed in ruby
67
+ # identifiers. Use the <tt>tag!</tt> method to handle these
68
+ # cases.
69
+ #
70
+ # Example:
71
+ #
72
+ # xml.tag!("SOAP:Envelope") { ... }
73
+ #
74
+ # will produce ...
75
+ #
76
+ # <SOAP:Envelope> ... </SOAP:Envelope>"
77
+ #
78
+ # <tt>tag!</tt> will also take text and attribute arguments (after
79
+ # the tag name) like normal markup methods. (But see the next
80
+ # bullet item for a better way to handle XML namespaces).
81
+ #
82
+ # * Direct support for XML namespaces is now available. If the
83
+ # first argument to a tag call is a symbol, it will be joined to
84
+ # the tag to produce a namespace:tag combination. It is easier to
85
+ # show this than describe it.
86
+ #
87
+ # xml.SOAP :Envelope do ... end
88
+ #
89
+ # Just put a space before the colon in a namespace to produce the
90
+ # right form for builder (e.g. "<tt>SOAP:Envelope</tt>" =>
91
+ # "<tt>xml.SOAP :Envelope</tt>")
92
+ #
93
+ # * XmlMarkup builds the markup in any object (called a _target_)
94
+ # that accepts the <tt><<</tt> method. If no target is given,
95
+ # then XmlMarkup defaults to a string target.
96
+ #
97
+ # Examples:
98
+ #
99
+ # xm = Builder::XmlMarkup.new
100
+ # result = xm.title("yada")
101
+ # # result is a string containing the markup.
102
+ #
103
+ # buffer = ""
104
+ # xm = Builder::XmlMarkup.new(buffer)
105
+ # # The markup is appended to buffer (using <<)
106
+ #
107
+ # xm = Builder::XmlMarkup.new(STDOUT)
108
+ # # The markup is written to STDOUT (using <<)
109
+ #
110
+ # xm = Builder::XmlMarkup.new
111
+ # x2 = Builder::XmlMarkup.new(:target=>xm)
112
+ # # Markup written to +x2+ will be send to +xm+.
113
+ #
114
+ # * Indentation is enabled by providing the number of spaces to
115
+ # indent for each level as a second argument to XmlBuilder.new.
116
+ # Initial indentation may be specified using a third parameter.
117
+ #
118
+ # Example:
119
+ #
120
+ # xm = Builder.new(:indent=>2)
121
+ # # xm will produce nicely formatted and indented XML.
122
+ #
123
+ # xm = Builder.new(:indent=>2, :margin=>4)
124
+ # # xm will produce nicely formatted and indented XML with 2
125
+ # # spaces per indent and an over all indentation level of 4.
126
+ #
127
+ # builder = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2)
128
+ # builder.name { |b| b.first("Jim"); b.last("Weirich) }
129
+ # # prints:
130
+ # # <name>
131
+ # # <first>Jim</first>
132
+ # # <last>Weirich</last>
133
+ # # </name>
134
+ #
135
+ # * The instance_eval implementation which forces self to refer to
136
+ # the message receiver as self is now obsolete. We now use normal
137
+ # block calls to execute the markup block. This means that all
138
+ # markup methods must now be explicitly send to the xml builder.
139
+ # For instance, instead of
140
+ #
141
+ # xml.div { strong("text") }
142
+ #
143
+ # you need to write:
144
+ #
145
+ # xml.div { xml.strong("text") }
146
+ #
147
+ # Although more verbose, the subtle change in semantics within the
148
+ # block was found to be prone to error. To make this change a
149
+ # little less cumbersome, the markup block now gets the markup
150
+ # object sent as an argument, allowing you to use a shorter alias
151
+ # within the block.
152
+ #
153
+ # For example:
154
+ #
155
+ # xml_builder = Builder::XmlMarkup.new
156
+ # xml_builder.div { |xml|
157
+ # xml.stong("text")
158
+ # }
159
+ #
160
+ class XmlMarkup < XmlBase
161
+
162
+ # Create an XML markup builder. Parameters are specified by an
163
+ # option hash.
164
+ #
165
+ # :target => <em>target_object</em>::
166
+ # Object receiving the markup. +target_object+ must respond to
167
+ # the <tt><<(<em>a_string</em>)</tt> operator and return
168
+ # itself. The default target is a plain string target.
169
+ #
170
+ # :indent => <em>indentation</em>::
171
+ # Number of spaces used for indentation. The default is no
172
+ # indentation and no line breaks.
173
+ #
174
+ # :margin => <em>initial_indentation_level</em>::
175
+ # Amount of initial indentation (specified in levels, not
176
+ # spaces).
177
+ #
178
+ # :quote => <em>:single</em>::
179
+ # Use single quotes for attributes rather than double quotes.
180
+ #
181
+ # :escape_attrs => <em>OBSOLETE</em>::
182
+ # The :escape_attrs option is no longer supported by builder
183
+ # (and will be quietly ignored). String attribute values are
184
+ # now automatically escaped. If you need unescaped attribute
185
+ # values (perhaps you are using entities in the attribute
186
+ # values), then give the value as a Symbol. This allows much
187
+ # finer control over escaping attribute values.
188
+ #
189
+ def initialize(options={})
190
+ indent = options[:indent] || 0
191
+ margin = options[:margin] || 0
192
+ @quote = (options[:quote] == :single) ? "'" : '"'
193
+ @explicit_nil_handling = options[:explicit_nil_handling]
194
+ super(indent, margin)
195
+ @target = options[:target] || ""
196
+ end
197
+
198
+ # Return the target of the builder.
199
+ def target!
200
+ @target
201
+ end
202
+
203
+ def comment!(comment_text)
204
+ _ensure_no_block ::Kernel::block_given?
205
+ _special("<!-- ", " -->", comment_text, nil)
206
+ end
207
+
208
+ # Insert an XML declaration into the XML markup.
209
+ #
210
+ # For example:
211
+ #
212
+ # xml.declare! :ELEMENT, :blah, "yada"
213
+ # # => <!ELEMENT blah "yada">
214
+ def declare!(inst, *args, &block)
215
+ _indent
216
+ @target << "<!#{inst}"
217
+ args.each do |arg|
218
+ case arg
219
+ when ::String
220
+ @target << %{ "#{arg}"} # " WART
221
+ when ::Symbol
222
+ @target << " #{arg}"
223
+ end
224
+ end
225
+ if ::Kernel::block_given?
226
+ @target << " ["
227
+ _newline
228
+ _nested_structures(block)
229
+ @target << "]"
230
+ end
231
+ @target << ">"
232
+ _newline
233
+ end
234
+
235
+ # Insert a processing instruction into the XML markup. E.g.
236
+ #
237
+ # For example:
238
+ #
239
+ # xml.instruct!
240
+ # #=> <?xml version="1.0" encoding="UTF-8"?>
241
+ # xml.instruct! :aaa, :bbb=>"ccc"
242
+ # #=> <?aaa bbb="ccc"?>
243
+ #
244
+ # Note: If the encoding is setup to "UTF-8" and the value of
245
+ # $KCODE is "UTF8", then builder will emit UTF-8 encoded strings
246
+ # rather than the entity encoding normally used.
247
+ def instruct!(directive_tag=:xml, attrs={})
248
+ _ensure_no_block ::Kernel::block_given?
249
+ if directive_tag == :xml
250
+ a = { :version=>"1.0", :encoding=>"UTF-8" }
251
+ attrs = a.merge attrs
252
+ @encoding = attrs[:encoding].downcase
253
+ end
254
+ _special(
255
+ "<?#{directive_tag}",
256
+ "?>",
257
+ nil,
258
+ attrs,
259
+ [:version, :encoding, :standalone])
260
+ end
261
+
262
+ # Insert a CDATA section into the XML markup.
263
+ #
264
+ # For example:
265
+ #
266
+ # xml.cdata!("text to be included in cdata")
267
+ # #=> <![CDATA[text to be included in cdata]]>
268
+ #
269
+ def cdata!(text)
270
+ _ensure_no_block ::Kernel::block_given?
271
+ _special("<![CDATA[", "]]>", text.gsub(']]>', ']]]]><![CDATA[>'), nil)
272
+ end
273
+
274
+ private
275
+
276
+ # NOTE: All private methods of a builder object are prefixed when
277
+ # a "_" character to avoid possible conflict with XML tag names.
278
+
279
+ # Insert text directly in to the builder's target.
280
+ def _text(text)
281
+ @target << text
282
+ end
283
+
284
+ # Insert special instruction.
285
+ def _special(open, close, data=nil, attrs=nil, order=[])
286
+ _indent
287
+ @target << open
288
+ @target << data if data
289
+ _insert_attributes(attrs, order) if attrs
290
+ @target << close
291
+ _newline
292
+ end
293
+
294
+ # Start an XML tag. If <tt>end_too</tt> is true, then the start
295
+ # tag is also the end tag (e.g. <br/>
296
+ def _start_tag(sym, attrs, end_too=false)
297
+ @target << "<#{sym}"
298
+ _insert_attributes(attrs)
299
+ @target << "/" if end_too
300
+ @target << ">"
301
+ end
302
+
303
+ # Insert an ending tag.
304
+ def _end_tag(sym)
305
+ @target << "</#{sym}>"
306
+ end
307
+
308
+ # Insert the attributes (given in the hash).
309
+ def _insert_attributes(attrs, order=[])
310
+ return if attrs.nil?
311
+ order.each do |k|
312
+ v = attrs[k]
313
+ @target << %{ #{k}=#{@quote}#{_attr_value(v)}#{@quote}} if v
314
+ end
315
+ attrs.each do |k, v|
316
+ @target << %{ #{k}=#{@quote}#{_attr_value(v)}#{@quote}} unless order.member?(k) # " WART
317
+ end
318
+ end
319
+
320
+ def _attr_value(value)
321
+ case value
322
+ when ::Symbol
323
+ value.to_s
324
+ else
325
+ _escape_attribute(value.to_s)
326
+ end
327
+ end
328
+
329
+ def _ensure_no_block(got_block)
330
+ if got_block
331
+ ::Kernel::raise IllegalBlockError.new(
332
+ "Blocks are not allowed on XML instructions"
333
+ )
334
+ end
335
+ end
336
+
337
+ end
338
+
339
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ #--
4
+ # Copyright 2004 by Jim Weirich (jim@weirichhouse.org).
5
+ # All rights reserved.
6
+
7
+ # Permission is granted for use, copying, modification, distribution,
8
+ # and distribution of modified versions of this work as long as the
9
+ # above copyright notice is included.
10
+ #++
11
+
12
+ require 'builder/xmlmarkup'
13
+ require 'builder/xmlevents'
data/config.ru ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler.require
3
+
4
+ Opal::Processor.source_map_enabled = false
5
+
6
+ run Opal::Server.new { |s|
7
+ s.main = 'opal/rspec/sprockets_runner'
8
+ s.append_path 'spec'
9
+ s.debug = false
10
+ }
@@ -0,0 +1,8 @@
1
+ require 'opal'
2
+
3
+ # Our fixes, need to go first so that require 'builder' is caught by us first
4
+ Opal.append_path File.expand_path('../../opal', __FILE__).untaint
5
+ # builder source itself
6
+ Opal.append_path File.expand_path('../../builder/lib', __FILE__).untaint
7
+ # Contains encoding that's not compatible
8
+ Opal::Processor.stub_file 'builder/xchar'
data/opal/builder.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'builder/xmlmarkup'
2
+ require 'builder/xmlevents'
3
+ require 'opal/builder/xmlbase'
4
+ require 'opal/builder/xmlmarkup'
@@ -0,0 +1,43 @@
1
+ class BuilderMutableString
2
+ def initialize(str)
3
+ @state = str
4
+ end
5
+
6
+ def <<(text)
7
+ @state += text
8
+ self
9
+ end
10
+
11
+ def to_s
12
+ @state
13
+ end
14
+
15
+ def to_str
16
+ @state
17
+ end
18
+
19
+ def nil?
20
+ @state.nil?
21
+ end
22
+
23
+ # Unpack doesn't exist in Opal
24
+ def to_xs
25
+ gsub(/&(?!\w+;)/, '&amp;')
26
+ .gsub(/</, '&lt;')
27
+ .gsub(/>/, '&gt;')
28
+ .gsub(/'/, '&apos;')
29
+ end
30
+
31
+ def gsub(regex, replace)
32
+ @state = @state.gsub regex,replace
33
+ self
34
+ end
35
+
36
+ def ==(other_str)
37
+ @state == other_str
38
+ end
39
+
40
+ def size
41
+ @state.size
42
+ end
43
+ end
@@ -0,0 +1,14 @@
1
+ # In Opal, symbols and strings are the same, builder differentiates
2
+ class BuilderSymbol
3
+ def initialize(str)
4
+ @symbol = str
5
+ end
6
+
7
+ def to_s
8
+ @symbol
9
+ end
10
+
11
+ def to_str
12
+ @symbol
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ require 'builder/version'
2
+
3
+ module Opal
4
+ module OpalBuilder
5
+ # Add a minor version to the end in case there are opal-builder specific issues to fix
6
+ VERSION = "#{::Builder::VERSION}.1"
7
+ end
8
+ end
@@ -0,0 +1,68 @@
1
+ require 'opal/builder/builder_mutable_string'
2
+ require 'opal/builder/builder_symbol'
3
+
4
+ class Builder::XmlBase
5
+ def method_missing(sym, *args, &block)
6
+ # Omitting cache_method_calls because it causes problems
7
+
8
+ # Code in tag cares whether things are actually symbols and method names should be, so "create" them
9
+ tag!(BuilderSymbol.new(sym), *args, &block)
10
+ end
11
+
12
+ def tag!(sym, *args, &block)
13
+ text = nil
14
+ attrs = nil
15
+ sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::BuilderSymbol)
16
+ unless sym.class == ::BuilderSymbol
17
+ riase "not sure how to convert sym, which is class #{sym.class} and value #{sym} to a symbol"
18
+ end
19
+ sym = sym.to_sym unless sym.class == ::BuilderSymbol
20
+ args.each do |arg|
21
+ case arg
22
+ when ::Hash
23
+ attrs ||= {}
24
+ attrs.merge!(arg)
25
+ when nil
26
+ attrs ||= {}
27
+ attrs.merge!({:nil => true}) if explicit_nil_handling?
28
+ else
29
+ # Changed this from text ||= ''
30
+ text ||= BuilderMutableString.new ''
31
+ text << arg.to_s
32
+ end
33
+ end
34
+ if block
35
+ unless text.nil?
36
+ ::Kernel::raise ::ArgumentError,
37
+ "XmlMarkup cannot mix a text argument with a block"
38
+ end
39
+ _indent
40
+ _start_tag(sym, attrs)
41
+ _newline
42
+ begin
43
+ _nested_structures(block)
44
+ ensure
45
+ _indent
46
+ _end_tag(sym)
47
+ _newline
48
+ end
49
+ elsif text.nil?
50
+ _indent
51
+ _start_tag(sym, attrs, true)
52
+ _newline
53
+ else
54
+ _indent
55
+ _start_tag(sym, attrs)
56
+ text! text
57
+ _end_tag(sym)
58
+ _newline
59
+ end
60
+ @target
61
+ end
62
+
63
+ # Not supporting escaping, but do need to ensure we're using mutable strings
64
+ def _escape(text)
65
+ ensure_mutable = text.is_a?(BuilderMutableString) ? text : BuilderMutableString.new(text)
66
+ ensure_mutable.to_xs
67
+ end
68
+ end
@@ -0,0 +1,28 @@
1
+ require 'opal/builder/builder_mutable_string'
2
+ require 'opal/builder/builder_symbol'
3
+
4
+ class Builder::XmlMarkup
5
+ # Try and avoid a bunch of string mutation changes
6
+ def initialize(options={})
7
+ indent = options[:indent] || 0
8
+ margin = options[:margin] || 0
9
+ @quote = (options[:quote] == :single) ? "'" : '"'
10
+ @explicit_nil_handling = options[:explicit_nil_handling]
11
+ super(indent, margin)
12
+ @target = options[:target] || BuilderMutableString.new("")
13
+ end
14
+
15
+ # all strings will be symbols, so we have to change the case statement
16
+ def _attr_value(value)
17
+ case value
18
+ when ::BuilderSymbol
19
+ value.to_s
20
+ else
21
+ _escape_attribute(value.to_s)
22
+ end
23
+ end
24
+
25
+ def declare!(inst, *args, &block)
26
+ ::Kernel.raise 'declare! is not currently supported on Opal because symbols cannot be detected easily.'
27
+ end
28
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $: << File.expand_path('../builder/lib', __FILE__)
3
+ require File.expand_path('../opal/opal/builder/version', __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'opal-builder'
7
+ s.version = Opal::OpalBuilder::VERSION
8
+ s.author = 'Brady Wied'
9
+ s.email = 'brady@bswtechconsulting.com'
10
+ s.summary = 'Builder for Opal'
11
+ s.description = 'Opal compatible builder library'
12
+
13
+ s.files = `git ls-files`.split("\n") + Dir.glob('builder/lib/**/*.rb')
14
+
15
+ s.require_paths = ['lib']
16
+
17
+ s.add_dependency 'opal', ['>= 0.7.0', '< 0.9']
18
+ s.add_development_dependency 'rake'
19
+ end