wunderbar 0.17.3 → 0.18.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.
- data/README.md +29 -3
- data/lib/wunderbar/builder.rb +95 -139
- data/lib/wunderbar/cgi-methods.rb +7 -7
- data/lib/wunderbar/cssproxy.rb +20 -50
- data/lib/wunderbar/environment.rb +11 -1
- data/lib/wunderbar/html-methods.rb +161 -133
- data/lib/wunderbar/node.rb +208 -0
- data/lib/wunderbar/polymer-v0.0.20131003.min.js +36 -0
- data/lib/wunderbar/polymer.rb +56 -0
- data/lib/wunderbar/rails.rb +1 -1
- data/lib/wunderbar/server.rb +17 -0
- data/lib/wunderbar/sinatra.rb +8 -8
- data/lib/wunderbar/version.rb +2 -2
- data/lib/wunderbar.rb +1 -1
- data/wunderbar.gemspec +5 -8
- metadata +12 -19
- checksums.yaml +0 -15
data/README.md
CHANGED
@@ -8,7 +8,7 @@ that conforms to the
|
|
8
8
|
the emerging results from the [XML Error Recovery Community
|
9
9
|
Group](http://www.w3.org/community/xml-er/wiki/Main_Page).
|
10
10
|
|
11
|
-
Wunderbar
|
11
|
+
Wunderbar was inspired by Jim Weirich's
|
12
12
|
[Builder](https://github.com/jimweirich/builder#readme), and provides
|
13
13
|
the element id and class id syntax and based on the implementation from
|
14
14
|
[Markaby](http://markaby.rubyforge.org/).
|
@@ -130,12 +130,20 @@ Capture exceptions:
|
|
130
130
|
|
131
131
|
Class attribute shortcut (equivalent to class="front"):
|
132
132
|
|
133
|
-
|
133
|
+
_div.front do
|
134
134
|
end
|
135
135
|
|
136
136
|
Id attributes shortcut (equivalent to id="search"):
|
137
137
|
|
138
|
-
|
138
|
+
_div.search! do
|
139
|
+
end
|
140
|
+
|
141
|
+
Complete lists/rows can be defined using arrays:
|
142
|
+
|
143
|
+
_ul %w(apple orange pear)
|
144
|
+
_ol %w(apple orange pear)
|
145
|
+
_table do
|
146
|
+
_tr %w(apple orange pear)
|
139
147
|
end
|
140
148
|
|
141
149
|
Basic interface
|
@@ -208,6 +216,10 @@ Access to all of the builder _defined_ methods (typically these end in an esclam
|
|
208
216
|
* `_.tag! :foo`: insert elements where the name can be dynamic
|
209
217
|
* `_.error 'Log message'`: write a message to the server log
|
210
218
|
|
219
|
+
Underscores in element and attribute names are converted to dashes. To
|
220
|
+
disable this behavior, express attribute names as strings and use the `_.tag!`
|
221
|
+
method for element names.
|
222
|
+
|
211
223
|
XHTML differs from HTML in the escaping of inline style and script elements.
|
212
224
|
XHTML will also fall back to HTML output unless the user agent indicates it
|
213
225
|
supports XHTML via the HTTP Accept header.
|
@@ -227,6 +239,12 @@ If one of the attributes passed on the `_html` declaration is `:_width`, an
|
|
227
239
|
attempt will be made to reflow text in order to not exceed this line width.
|
228
240
|
This won't be done if it will affect what actually is displayed.
|
229
241
|
|
242
|
+
If none of the child elements for the `html` element are either `head` or
|
243
|
+
`body`, then these tags will be created for you, and the relevant children
|
244
|
+
will be moved to the appropriate section. If the body contains a `h1`
|
245
|
+
element, and the `head` doesn't contain a `title`, a title element will be
|
246
|
+
created based on the text supplied to the first `h1` element.
|
247
|
+
|
230
248
|
Methods provided to Wunderbar.json
|
231
249
|
---
|
232
250
|
|
@@ -406,3 +424,11 @@ The following gems, if installed, will produce cleaner and prettier output:
|
|
406
424
|
|
407
425
|
* `nokogiri` cleans up HTML fragments inserted via `<<`
|
408
426
|
* `escape` prettier quoting of `system` commands
|
427
|
+
|
428
|
+
Related efforts:
|
429
|
+
---
|
430
|
+
* [Builder](https://github.com/jimweirich/builder#readme)
|
431
|
+
* [JBuilder](https://github.com/rails/jbuilder)
|
432
|
+
* [Markaby](http://markaby.rubyforge.org/)
|
433
|
+
* [Nokogiri::HTML::Builder](http://nokogiri.org/Nokogiri/HTML/Builder.html)
|
434
|
+
* [Tagz](https://github.com/ahoward/tagz)
|
data/lib/wunderbar/builder.rb
CHANGED
@@ -1,93 +1,4 @@
|
|
1
1
|
module Wunderbar
|
2
|
-
# XmlMarkup handles indentation of elements beautifully, this class extends
|
3
|
-
# that support to text, data, and spacing between elements
|
4
|
-
class SpacedMarkup < Builder::XmlMarkup
|
5
|
-
def indented_text!(text)
|
6
|
-
indented_data!(text) {|data| text! data}
|
7
|
-
end
|
8
|
-
|
9
|
-
def indented_data!(data, pre=nil, post=nil, &block)
|
10
|
-
return if data.strip.length == 0
|
11
|
-
|
12
|
-
self << pre + target!.pop if pre
|
13
|
-
|
14
|
-
if @indent > 0
|
15
|
-
data = data.sub(/\n\s*\Z/, '').sub(/\A\s*\n/, '')
|
16
|
-
|
17
|
-
unindent = data.sub(/s+\Z/,'').scan(/^ *\S/).map(&:length).min || 1
|
18
|
-
|
19
|
-
before = ::Regexp.new('^'.ljust(unindent))
|
20
|
-
after = " " * (@level * @indent)
|
21
|
-
data.gsub! before, after
|
22
|
-
|
23
|
-
_newline if @pending_newline and not @first_tag
|
24
|
-
@pending_newline = @pending_margin
|
25
|
-
@first_tag = @pending_margin = false
|
26
|
-
end
|
27
|
-
|
28
|
-
if block
|
29
|
-
block.call(data)
|
30
|
-
else
|
31
|
-
self << data
|
32
|
-
end
|
33
|
-
|
34
|
-
_newline unless data =~ /\n\Z/
|
35
|
-
|
36
|
-
self << post if post
|
37
|
-
end
|
38
|
-
|
39
|
-
def disable_indentation!(&block)
|
40
|
-
indent, level, pending_newline, pending_margin =
|
41
|
-
indentation_state! [0, 0, @pending_newline, @pending_margin]
|
42
|
-
text! " "*indent*level
|
43
|
-
block.call
|
44
|
-
ensure
|
45
|
-
indentation_state! [indent, level, pending_newline, pending_margin]
|
46
|
-
end
|
47
|
-
|
48
|
-
def indentation_state! new_state=nil
|
49
|
-
result = [@indent, @level, @pending_newline, @pending_margin]
|
50
|
-
if new_state
|
51
|
-
text! "\n" if @indent == 0 and new_state.first > 0
|
52
|
-
@indent, @level, @pending_newline, @pending_margin = new_state
|
53
|
-
end
|
54
|
-
result
|
55
|
-
end
|
56
|
-
|
57
|
-
def margin!
|
58
|
-
_newline unless @first_tag
|
59
|
-
@pending_newline = false
|
60
|
-
@pending_margin = true
|
61
|
-
end
|
62
|
-
|
63
|
-
def _nested_structures(*args)
|
64
|
-
pending_newline = @pending_newline
|
65
|
-
@pending_newline = false
|
66
|
-
@first_tag = true
|
67
|
-
super
|
68
|
-
@first_tag = @pending_margin = false
|
69
|
-
@pending_newline = pending_newline
|
70
|
-
end
|
71
|
-
|
72
|
-
def tag!(sym, *args, &block)
|
73
|
-
_newline if @pending_newline
|
74
|
-
@pending_newline = @pending_margin
|
75
|
-
@first_tag = @pending_margin = false
|
76
|
-
# workaround for https://github.com/jimweirich/builder/commit/7c824996637d2d76455c87ad47d76ba440937e38
|
77
|
-
sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::Symbol)
|
78
|
-
if not block and args.first == ''
|
79
|
-
attrs = {}
|
80
|
-
attrs.merge!(args.last) if ::Hash === args.last
|
81
|
-
_indent
|
82
|
-
_start_tag(sym, attrs)
|
83
|
-
_end_tag(sym)
|
84
|
-
_newline
|
85
|
-
else
|
86
|
-
super
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
2
|
class BuilderBase
|
92
3
|
def set_variables_from_params(locals={})
|
93
4
|
@_scope.params.merge(locals).each do |key,value|
|
@@ -117,18 +28,19 @@ module Wunderbar
|
|
117
28
|
class XmlMarkup < BuilderClass
|
118
29
|
def initialize(args)
|
119
30
|
@_scope = args.delete(:scope)
|
120
|
-
@
|
31
|
+
@_indent = args.delete(:indent) or 2
|
121
32
|
@_pdf = false
|
33
|
+
@doc = Node.new(nil)
|
34
|
+
@node = @doc
|
35
|
+
@indentation_enabled = true
|
36
|
+
@width = nil
|
37
|
+
@spaced = false
|
122
38
|
end
|
123
39
|
|
124
|
-
# forward to Wunderbar
|
40
|
+
# forward to Wunderbar or @_scope
|
125
41
|
def method_missing(method, *args, &block)
|
126
42
|
if Wunderbar.respond_to? method
|
127
43
|
Wunderbar.send method, *args, &block
|
128
|
-
elsif SpacedMarkup.public_instance_methods.include? method
|
129
|
-
@_builder.__send__ method, *args, &block
|
130
|
-
elsif SpacedMarkup.public_instance_methods.include? method.to_s
|
131
|
-
@_builder.__send__ method, *args, &block
|
132
44
|
elsif @_scope and @_scope.respond_to? method
|
133
45
|
@_scope.send method, *args, &block
|
134
46
|
else
|
@@ -151,6 +63,46 @@ module Wunderbar
|
|
151
63
|
super
|
152
64
|
end
|
153
65
|
|
66
|
+
def text! text
|
67
|
+
@node.add_text text
|
68
|
+
end
|
69
|
+
|
70
|
+
def declare! *args
|
71
|
+
@node.children << DocTypeNode.new(*args)
|
72
|
+
end
|
73
|
+
|
74
|
+
def comment! text
|
75
|
+
@node.children << CommentNode.new(text)
|
76
|
+
end
|
77
|
+
|
78
|
+
def indented_text!(text)
|
79
|
+
return if text.strip.length == 0
|
80
|
+
@node.children << IndentedTextNode.new(text)
|
81
|
+
end
|
82
|
+
|
83
|
+
def target!
|
84
|
+
"#{@doc.serialize(indent: ' ' * @_indent).join("\n")}\n"
|
85
|
+
end
|
86
|
+
|
87
|
+
def clear!
|
88
|
+
@doc.children.clear
|
89
|
+
@node = @doc
|
90
|
+
end
|
91
|
+
|
92
|
+
def compact!(width, &block)
|
93
|
+
begin
|
94
|
+
@width = width
|
95
|
+
@indentation_enabled = false
|
96
|
+
block.call
|
97
|
+
ensure
|
98
|
+
@indentation_enabled = true
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def spaced!
|
103
|
+
@spaced = true
|
104
|
+
end
|
105
|
+
|
154
106
|
# avoid method_missing overhead for the most common case
|
155
107
|
def tag!(sym, *args, &block)
|
156
108
|
if sym.respond_to? :children
|
@@ -173,19 +125,32 @@ module Wunderbar
|
|
173
125
|
end
|
174
126
|
end
|
175
127
|
|
176
|
-
if
|
177
|
-
|
128
|
+
if Class === args.first and args.first < Node
|
129
|
+
node = args.shift.new sym, *args
|
178
130
|
else
|
179
|
-
|
131
|
+
node = Node.new sym, *args
|
132
|
+
end
|
133
|
+
|
134
|
+
unless @indentation_enabled
|
135
|
+
node.extend CompactNode
|
136
|
+
node.width = @width
|
137
|
+
end
|
138
|
+
|
139
|
+
if @spaced
|
140
|
+
node.extend SpacedNode
|
141
|
+
@spaced = false
|
180
142
|
end
|
181
|
-
end
|
182
143
|
|
183
|
-
|
144
|
+
node.text = args.first if String === args.first
|
145
|
+
@node.add_child node
|
146
|
+
@node = node
|
184
147
|
if block
|
185
|
-
|
186
|
-
|
187
|
-
CssProxy.new(@_builder, @_builder.target!, sym, args)
|
148
|
+
block.call(self)
|
149
|
+
@node.children << nil if @node.children.empty?
|
188
150
|
end
|
151
|
+
@node = @node.parent
|
152
|
+
|
153
|
+
node
|
189
154
|
end
|
190
155
|
|
191
156
|
def pdf=(value)
|
@@ -230,7 +195,7 @@ module Wunderbar
|
|
230
195
|
stderr = output_class[:stderr] || '_stderr'
|
231
196
|
hilite = output_class[:hilite] || '_stdout _hilite'
|
232
197
|
|
233
|
-
|
198
|
+
tag! tag, echo, :class=>stdin unless opts[:echo] == false
|
234
199
|
|
235
200
|
require 'thread'
|
236
201
|
semaphore = Mutex.new
|
@@ -241,9 +206,9 @@ module Wunderbar
|
|
241
206
|
out_line = pout.readline.chomp
|
242
207
|
semaphore.synchronize do
|
243
208
|
if patterns.any? {|pattern| out_line =~ pattern}
|
244
|
-
|
209
|
+
tag! tag, out_line, :class=>hilite
|
245
210
|
else
|
246
|
-
|
211
|
+
tag! tag, out_line, :class=>stdout
|
247
212
|
end
|
248
213
|
end
|
249
214
|
end
|
@@ -253,7 +218,7 @@ module Wunderbar
|
|
253
218
|
until perr.eof?
|
254
219
|
err_line = perr.readline.chomp
|
255
220
|
semaphore.synchronize do
|
256
|
-
|
221
|
+
tag! tag, err_line, :class=>stderr
|
257
222
|
end
|
258
223
|
end
|
259
224
|
end,
|
@@ -272,44 +237,37 @@ module Wunderbar
|
|
272
237
|
end
|
273
238
|
end
|
274
239
|
|
275
|
-
# declaration (DOCTYPE, etc)
|
276
|
-
def declare(*args)
|
277
|
-
@_builder.declare!(*args)
|
278
|
-
end
|
279
|
-
|
280
|
-
# comment
|
281
|
-
def comment(*args)
|
282
|
-
@_builder.comment! *args
|
283
|
-
end
|
284
|
-
|
285
240
|
# insert verbatim
|
286
241
|
def <<(data)
|
287
242
|
if not String === data or data.include? '<' or data.include? '&'
|
288
243
|
require 'nokogiri'
|
289
244
|
data = Nokogiri::HTML::fragment(data.to_s).to_xml
|
290
|
-
end
|
291
245
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
246
|
+
# fix CDATA in most cases (notably scripts)
|
247
|
+
data.gsub!(/<!\[CDATA\[(.*?)\]\]>/m) do
|
248
|
+
if $1.include? '<' or $1.include? '&'
|
249
|
+
"//<![CDATA[\n#{$1}\n//]]>"
|
250
|
+
else
|
251
|
+
$1
|
252
|
+
end
|
298
253
|
end
|
299
|
-
end
|
300
254
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
255
|
+
# fix CDATA for style elements
|
256
|
+
data.gsub!(/<style([^>])*>\/\/<!\[CDATA\[\n(.*?)\s+\/\/\]\]>/m) do
|
257
|
+
if $2.include? '<' or $2.include? '&'
|
258
|
+
"<style#{$1}>/*<![CDATA[*/\n#{$2.gsub("\n\Z",'')}\n/*]]>*/"
|
259
|
+
else
|
260
|
+
$1
|
261
|
+
end
|
307
262
|
end
|
308
263
|
end
|
309
|
-
|
310
|
-
@_builder << data
|
311
264
|
rescue LoadError
|
312
|
-
|
265
|
+
ensure
|
266
|
+
if String === data
|
267
|
+
@node.children << data
|
268
|
+
else
|
269
|
+
@node.add_child data
|
270
|
+
end
|
313
271
|
end
|
314
272
|
|
315
273
|
def [](*children)
|
@@ -331,10 +289,8 @@ module Wunderbar
|
|
331
289
|
text = child.text
|
332
290
|
if text.strip.empty?
|
333
291
|
text! "\n" if text.count("\n")>1
|
334
|
-
elsif indentation_state!.first == 0
|
335
|
-
indented_text! text
|
336
292
|
else
|
337
|
-
indented_text! text
|
293
|
+
indented_text! text
|
338
294
|
end
|
339
295
|
elsif child.comment?
|
340
296
|
comment! child.text.sub(/\A /,'').sub(/ \Z/, '')
|
@@ -354,7 +310,7 @@ module Wunderbar
|
|
354
310
|
if stop == 0
|
355
311
|
self[children.shift]
|
356
312
|
else
|
357
|
-
|
313
|
+
compact!(nil) do
|
358
314
|
self[*children.shift(stop || children.length)]
|
359
315
|
end
|
360
316
|
end
|
@@ -362,7 +318,7 @@ module Wunderbar
|
|
362
318
|
end
|
363
319
|
else
|
364
320
|
# disable indentation on the entire element
|
365
|
-
|
321
|
+
compact!(nil) do
|
366
322
|
tag!(child) {self[*child.children]}
|
367
323
|
end
|
368
324
|
end
|
@@ -103,13 +103,8 @@ module Wunderbar
|
|
103
103
|
headers['status'] = "500 Internal Server Error"
|
104
104
|
x.clear!
|
105
105
|
output = x.html(*args) do
|
106
|
-
|
107
|
-
|
108
|
-
end
|
109
|
-
_body do
|
110
|
-
_h1 'Internal Server Error'
|
111
|
-
_exception exception
|
112
|
-
end
|
106
|
+
_h1 'Internal Server Error'
|
107
|
+
_exception exception
|
113
108
|
end
|
114
109
|
end
|
115
110
|
|
@@ -192,6 +187,11 @@ module Wunderbar
|
|
192
187
|
self.text(scope, *args, &block)
|
193
188
|
return
|
194
189
|
end
|
190
|
+
when Proc
|
191
|
+
unless xhr_json or text
|
192
|
+
instance_exec scope, args, block, &type
|
193
|
+
return
|
194
|
+
end
|
195
195
|
end
|
196
196
|
end
|
197
197
|
end
|
data/lib/wunderbar/cssproxy.rb
CHANGED
@@ -1,27 +1,12 @@
|
|
1
1
|
module Wunderbar
|
2
|
-
# Class
|
2
|
+
# Class inspired by Markaby to store element options. Methods called
|
3
3
|
# against the CssProxy object are added as element classes or IDs.
|
4
4
|
#
|
5
|
-
# Modified to accept args for empty, non-void elements, and to capture and
|
6
|
-
# restore indentation state.
|
7
|
-
#
|
8
5
|
# See the README for examples.
|
9
|
-
class CssProxy
|
10
|
-
def initialize(builder,
|
6
|
+
class CssProxy < BasicObject
|
7
|
+
def initialize(builder, node)
|
11
8
|
@builder = builder
|
12
|
-
@
|
13
|
-
@stream = stream
|
14
|
-
@sym = sym
|
15
|
-
@args = args
|
16
|
-
@attrs = {}
|
17
|
-
|
18
|
-
@original_stream_length = @stream.length
|
19
|
-
|
20
|
-
@builder.tag! sym, *args
|
21
|
-
end
|
22
|
-
|
23
|
-
def respond_to?(sym, include_private = false)
|
24
|
-
include_private || !private_methods.map { |m| m.to_sym }.include?(sym.to_sym) ? true : false
|
9
|
+
@node = node
|
25
10
|
end
|
26
11
|
|
27
12
|
private
|
@@ -29,44 +14,29 @@ module Wunderbar
|
|
29
14
|
# Adds attributes to an element. Bang methods set the :id attribute.
|
30
15
|
# Other methods add to the :class attribute.
|
31
16
|
def method_missing(id_or_class, *args, &block)
|
17
|
+
empty = args.empty?
|
18
|
+
attrs = @node.attrs
|
19
|
+
|
32
20
|
if id_or_class.to_s =~ /(.*)!$/
|
33
|
-
|
21
|
+
attrs[:id] = $1
|
22
|
+
elsif attrs[:class]
|
23
|
+
attrs[:class] = "#{attrs[:class]} #{id_or_class}"
|
34
24
|
else
|
35
|
-
|
36
|
-
@attrs[:class] = @attrs[:class] ? "#{@attrs[:class]} #{id}".strip : id
|
37
|
-
end
|
38
|
-
|
39
|
-
@attrs.merge! args.pop.to_hash if args.last.respond_to? :to_hash
|
40
|
-
@attrs.merge! @args.pop.to_hash if @args.last.respond_to? :to_hash
|
41
|
-
|
42
|
-
# delete attrs with false/nil values; change true to attribute name
|
43
|
-
@attrs.delete_if {|key, value| !value}
|
44
|
-
@attrs.each {|key, value| @attrs[key]=key if value == true}
|
45
|
-
|
46
|
-
args.push(@attrs)
|
47
|
-
args = @args + args unless block or String === args.first
|
48
|
-
|
49
|
-
if @sym == :pre
|
50
|
-
args.first.chomp! if String === args.first and args.first.end_with? "\n"
|
25
|
+
attrs[:class] = id_or_class
|
51
26
|
end
|
52
27
|
|
53
|
-
|
54
|
-
|
55
|
-
end
|
28
|
+
attrs.merge! args.pop.to_hash if args.last.respond_to? :to_hash
|
29
|
+
args.push(attrs)
|
56
30
|
|
57
|
-
|
58
|
-
indent = @builder.indentation_state! @indent
|
31
|
+
@node.parent.children.delete(@node)
|
59
32
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
@builder.indentation_state! indent
|
33
|
+
if empty and not block
|
34
|
+
@builder.proxiable_tag! @node.name, *args
|
35
|
+
elsif SpacedNode === @node
|
36
|
+
@builder.__send__ "_#{@node.name}_", *args, &block
|
37
|
+
else
|
38
|
+
@builder.__send__ "_#{@node.name}", *args, &block
|
67
39
|
end
|
68
|
-
|
69
|
-
self
|
70
40
|
end
|
71
41
|
end
|
72
42
|
end
|
@@ -23,7 +23,7 @@ module Wunderbar
|
|
23
23
|
# contained within data provided by users of the site.
|
24
24
|
$:.each_with_index do |path, index|
|
25
25
|
if path.tainted?
|
26
|
-
$:[index] = File.expand_path(path.untaint).untaint
|
26
|
+
$:[index] = File.expand_path(path.dup.untaint).untaint
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -37,6 +37,12 @@ module Wunderbar
|
|
37
37
|
@env = env
|
38
38
|
end
|
39
39
|
end
|
40
|
+
|
41
|
+
@@templates = {}
|
42
|
+
|
43
|
+
def self.templates
|
44
|
+
@@templates
|
45
|
+
end
|
40
46
|
end
|
41
47
|
|
42
48
|
require 'socket'
|
@@ -75,6 +81,10 @@ if self.to_s == 'main'
|
|
75
81
|
Wunderbar.websocket(*args, &block)
|
76
82
|
end
|
77
83
|
|
84
|
+
def _template(name, &block)
|
85
|
+
Wunderbar.templates[name.to_s.gsub('_','-')] = block
|
86
|
+
end
|
87
|
+
|
78
88
|
def env
|
79
89
|
ENV
|
80
90
|
end
|