wunderbar 0.10.9 → 0.11.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 +43 -20
- data/lib/wunderbar/builder.rb +6 -2
- data/lib/wunderbar/cgi-methods.rb +2 -1
- data/lib/wunderbar/environment.rb +8 -4
- data/lib/wunderbar/html-methods.rb +27 -0
- data/lib/wunderbar/rack.rb +5 -1
- data/lib/wunderbar/rails.rb +46 -0
- data/lib/wunderbar/server.rb +9 -1
- data/lib/wunderbar/sinatra.rb +21 -6
- data/lib/wunderbar/version.rb +2 -2
- data/wunderbar.gemspec +15 -11
- metadata +13 -12
data/README.md
CHANGED
@@ -136,24 +136,28 @@ Basic interface
|
|
136
136
|
A typical main program produces one or more of HTML, JSON, or plain text
|
137
137
|
output. This is accomplished by providing one or more of the following:
|
138
138
|
|
139
|
-
|
139
|
+
_html do
|
140
140
|
code
|
141
141
|
end
|
142
142
|
|
143
|
-
|
143
|
+
_xhtml do
|
144
144
|
code
|
145
145
|
end
|
146
146
|
|
147
|
-
|
147
|
+
_json do
|
148
148
|
code
|
149
149
|
end
|
150
150
|
|
151
|
-
|
151
|
+
_text do
|
152
152
|
code
|
153
153
|
end
|
154
154
|
|
155
|
-
Arbitrary Ruby code can be placed in each.
|
156
|
-
|
155
|
+
Arbitrary Ruby code can be placed in each. Form parameters are made available
|
156
|
+
as instance variables (e.g., `@name`). Host environment (CGI, Rack, Sinatra)
|
157
|
+
values are accessible as methods of the `_` object: for example `_.headers`
|
158
|
+
(CGI), `_.set_cookie` (Rack), `_.redirect` (Sinatra).
|
159
|
+
|
160
|
+
To append to the output produced, use the `_` methods described below.
|
157
161
|
|
158
162
|
Methods provided to Wunderbar.html
|
159
163
|
---
|
@@ -182,16 +186,33 @@ number of other convenience methods are defined:
|
|
182
186
|
* `_.post?` -- was this invoked via HTTP POST?
|
183
187
|
* `_.system` -- invokes a shell command, captures stdin, stdout, and stderr
|
184
188
|
* `_.submit` -- runs command (or block) as a deamon process
|
189
|
+
* `_.xhtml?` -- output as XHTML?
|
185
190
|
|
186
191
|
Access to all of the builder _defined_ methods (typically these end in an esclamation mark) and all of the Wunderbar module methods can be accessed in this way. Examples:
|
187
192
|
|
188
|
-
* `_.tag! :foo
|
189
|
-
* `_.error 'Log message'
|
193
|
+
* `_.tag! :foo`: insert elements where the name can be dynamic
|
194
|
+
* `_.error 'Log message'`: write a message to the server log
|
195
|
+
* `_import!`: insert markup with indentation matching the current output
|
190
196
|
|
191
197
|
XHTML differs from HTML in the escaping of inline style and script elements.
|
192
198
|
XHTML will also fall back to HTML output unless the user agent indicates it
|
193
199
|
supports XHTML via the HTTP Accept header.
|
194
200
|
|
201
|
+
In addition to the default processing of elements, text, and attributes,
|
202
|
+
Wunderdar defines additional processing for the following:
|
203
|
+
|
204
|
+
* `_head`: insert meta charset utf-8
|
205
|
+
* `_svg`: insert svg namespace
|
206
|
+
* `_math`: insert math namespace
|
207
|
+
* `_coffeescript`: convert [coffeescript](http://coffeescript.org/) to JS and insert script tag
|
208
|
+
|
209
|
+
Note that adding an exclamation mark to the end of the tag name disables this
|
210
|
+
behavior.
|
211
|
+
|
212
|
+
If one of the attributes passed on the `_html` declaration is `:_width`, an
|
213
|
+
attempt will be made to reflow text in order to not exceed this line width.
|
214
|
+
This won't be done if it will affect what actually is displayed.
|
215
|
+
|
195
216
|
Methods provided to Wunderbar.json
|
196
217
|
---
|
197
218
|
|
@@ -258,6 +279,20 @@ output stream, which provides access to other useful methods, for example:
|
|
258
279
|
_.print 'foo'
|
259
280
|
_.printf "Hello %s!\n", 'world'
|
260
281
|
|
282
|
+
Secure by default
|
283
|
+
---
|
284
|
+
|
285
|
+
Wunderbar will properly escape all HTML and JSON output, eliminating problems
|
286
|
+
of HTML or JavaScript injection.
|
287
|
+
|
288
|
+
Unless you call `Wunderbar.unsafe!` at the top of your script, Wunderbar will
|
289
|
+
also set
|
290
|
+
[`$SAFE=1`](http://www.ruby-doc.org/docs/ProgrammingRuby/html/taint.html)
|
291
|
+
before processing requests. This means that you will need to
|
292
|
+
[`untaint`](ruby-doc.org/core/Object.html#method-i-untaint) all inputs
|
293
|
+
received from external sources before you make system calls or access the file
|
294
|
+
system.
|
295
|
+
|
261
296
|
Globals provided
|
262
297
|
---
|
263
298
|
* `$USER` - Host user id
|
@@ -276,18 +311,6 @@ Also, the following environment variables are set if they aren't already:
|
|
276
311
|
Finally, the (Ruby 1.9.x) default external and internal encodings are set to
|
277
312
|
UTF-8. For Ruby 1.8, `$KCODE` is set to `U`
|
278
313
|
|
279
|
-
HTML methods
|
280
|
-
---
|
281
|
-
* `_head`: insert meta charset utf-8
|
282
|
-
* `_svg`: insert svg namespace
|
283
|
-
* `_math`: insert math namespace
|
284
|
-
* `_coffeescript`: convert [coffeescript](http://coffeescript.org/) to JS and insert script tag
|
285
|
-
* `_import!`: insert markup with indentation matching the current output
|
286
|
-
* `xhtml?`: output as XHTML?
|
287
|
-
|
288
|
-
Note that adding an exclamation mark to the end of the tag name disables this
|
289
|
-
behavior.
|
290
|
-
|
291
314
|
Builder extensions
|
292
315
|
---
|
293
316
|
* `indented_text!`: matches text indentation to markup
|
data/lib/wunderbar/builder.rb
CHANGED
@@ -218,7 +218,7 @@ module Wunderbar
|
|
218
218
|
|
219
219
|
@_builder << data
|
220
220
|
rescue LoadError
|
221
|
-
@_builder <<
|
221
|
+
@_builder << data
|
222
222
|
end
|
223
223
|
end
|
224
224
|
|
@@ -230,11 +230,15 @@ module Wunderbar
|
|
230
230
|
instance_variable_set "@#{key}", value if key =~ /^\w+$/
|
231
231
|
end
|
232
232
|
end
|
233
|
+
|
234
|
+
def get_binding
|
235
|
+
binding
|
236
|
+
end
|
233
237
|
end
|
234
238
|
|
239
|
+
require 'stringio'
|
235
240
|
class TextBuilder < BuilderBase
|
236
241
|
def initialize(scope)
|
237
|
-
require 'stringio'
|
238
242
|
@_target = StringIO.new
|
239
243
|
@_scope = scope
|
240
244
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
1
3
|
module Wunderbar
|
2
4
|
module CGI
|
3
5
|
|
@@ -31,7 +33,6 @@ module Wunderbar
|
|
31
33
|
# Conditionally provide output, based on ETAG
|
32
34
|
def self.out?(scope, headers, &block)
|
33
35
|
content = block.call
|
34
|
-
require 'digest/md5'
|
35
36
|
etag = Digest::MD5.hexdigest(content)
|
36
37
|
|
37
38
|
if scope.env['HTTP_IF_NONE_MATCH'] == etag.inspect
|
@@ -5,10 +5,14 @@ module Wunderbar
|
|
5
5
|
TEXT = ARGV.delete('--text')
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
@@unsafe = false
|
9
|
+
|
10
|
+
def self.unsafe!(mode=true)
|
11
|
+
@@unsafe=mode
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.safe?
|
15
|
+
not @@unsafe
|
12
16
|
end
|
13
17
|
|
14
18
|
class Scope
|
@@ -27,6 +27,7 @@ class HtmlMarkup < Wunderbar::BuilderBase
|
|
27
27
|
# default namespace
|
28
28
|
args << {} if args.empty?
|
29
29
|
args.first[:xmlns] ||= 'http://www.w3.org/1999/xhtml' if Hash === args.first
|
30
|
+
@_width = args.first.delete(:_width) if Hash === args.first
|
30
31
|
|
31
32
|
@x.text! "\xEF\xBB\xBF"
|
32
33
|
@x.declare! :DOCTYPE, :html
|
@@ -34,6 +35,32 @@ class HtmlMarkup < Wunderbar::BuilderBase
|
|
34
35
|
set_variables_from_params
|
35
36
|
instance_eval(&block)
|
36
37
|
end
|
38
|
+
|
39
|
+
if @_width
|
40
|
+
# reflow long lines
|
41
|
+
source = @x.target!.slice!(0..-1)
|
42
|
+
indent = col = 0
|
43
|
+
breakable = true
|
44
|
+
while not source.empty?
|
45
|
+
token = source.shift
|
46
|
+
indent = token[/^ */].length if col == 0
|
47
|
+
breakable = false if token.start_with? '<'
|
48
|
+
while token.length + col > @_width and breakable
|
49
|
+
break if token[0...-1].include? "\n"
|
50
|
+
split = token.rindex(' ', [@_width-col,0].max) || token.index(' ')
|
51
|
+
break unless split
|
52
|
+
break if col+split < indent+@_width/2
|
53
|
+
@x.target! << token[0...split] << "\n" << (' '*indent)
|
54
|
+
col = indent
|
55
|
+
token = token[split+1..-1]
|
56
|
+
end
|
57
|
+
breakable = true if token.end_with? '>'
|
58
|
+
@x.target! << token
|
59
|
+
col += token.length
|
60
|
+
col = 0 if token.end_with? "\n"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
37
64
|
@x.target!.join
|
38
65
|
end
|
39
66
|
|
data/lib/wunderbar/rack.rb
CHANGED
@@ -6,7 +6,11 @@ module Wunderbar
|
|
6
6
|
@_request = Rack::Request.new(env)
|
7
7
|
@_response = Rack::Response.new
|
8
8
|
Wunderbar.logger = @_request.logger
|
9
|
-
Wunderbar
|
9
|
+
if Wunderbar.safe? and $SAFE==0
|
10
|
+
Proc.new { $SAFE=1; Wunderbar::CGI.call(self) }.call
|
11
|
+
else
|
12
|
+
Wunderbar::CGI.call(self)
|
13
|
+
end
|
10
14
|
@_response.finish
|
11
15
|
end
|
12
16
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
module Wunderbar
|
4
|
+
module Rails
|
5
|
+
class HtmlHandler
|
6
|
+
cattr_accessor :default_format
|
7
|
+
self.default_format = Mime::HTML
|
8
|
+
|
9
|
+
def self.call(template)
|
10
|
+
pre = %{
|
11
|
+
x = HtmlMarkup.new(self);
|
12
|
+
instance_variables.each do |var|
|
13
|
+
x.instance_variable_set var, instance_variable_get(var)
|
14
|
+
end
|
15
|
+
}.strip.gsub(/\s+/, ' ')
|
16
|
+
|
17
|
+
post ="x._.target!.join"
|
18
|
+
|
19
|
+
# take care to preserve line numbers in original source
|
20
|
+
"#{pre}; x.instance_eval { #{template.source} }; #{post}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class JsonHandler
|
25
|
+
cattr_accessor :default_format
|
26
|
+
self.default_format = Mime::JSON
|
27
|
+
|
28
|
+
def self.call(template)
|
29
|
+
pre = %{
|
30
|
+
x = Wunderbar::JsonBuilder.new(self);
|
31
|
+
instance_variables.each do |var|
|
32
|
+
x.instance_variable_set var, instance_variable_get(var)
|
33
|
+
end
|
34
|
+
}.strip.gsub(/\s+/, ' ')
|
35
|
+
|
36
|
+
post ="x.target!"
|
37
|
+
|
38
|
+
# take care to preserve line numbers in original source
|
39
|
+
"#{pre}; x.instance_eval { #{template.source} }; #{post}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
ActionView::Template.register_template_handler :_html, HtmlHandler
|
44
|
+
ActionView::Template.register_template_handler :_json, JsonHandler
|
45
|
+
end
|
46
|
+
end
|
data/lib/wunderbar/server.rb
CHANGED
@@ -35,6 +35,10 @@ elsif defined? Sinatra
|
|
35
35
|
|
36
36
|
require 'wunderbar/sinatra'
|
37
37
|
|
38
|
+
elsif defined? ActionView::Template
|
39
|
+
|
40
|
+
require 'wunderbar/rails'
|
41
|
+
|
38
42
|
else
|
39
43
|
|
40
44
|
require 'etc'
|
@@ -79,7 +83,11 @@ else
|
|
79
83
|
ENV['REQUEST_METHOD'] ||= 'GET' if ARGV.delete('--get')
|
80
84
|
|
81
85
|
# CGI or command line
|
82
|
-
Wunderbar
|
86
|
+
if Wunderbar.safe? and $SAFE==0
|
87
|
+
Proc.new { $SAFE=1; Wunderbar::CGI.call(cgi) }.call
|
88
|
+
else
|
89
|
+
Wunderbar::CGI.call(cgi)
|
90
|
+
end
|
83
91
|
end
|
84
92
|
end
|
85
93
|
end
|
data/lib/wunderbar/sinatra.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'sinatra'
|
2
2
|
require 'digest/md5'
|
3
|
+
require 'nokogiri'
|
3
4
|
|
4
5
|
module Wunderbar
|
5
6
|
# Tilt template implementation
|
@@ -48,10 +49,24 @@ module Wunderbar
|
|
48
49
|
instance_variable_set "@#{key}", value if key =~ /^[a-z]\w+$/
|
49
50
|
end
|
50
51
|
end
|
51
|
-
|
52
|
+
|
53
|
+
if not block
|
54
|
+
builder.instance_eval(data.untaint, eval_file)
|
55
|
+
elsif not data
|
52
56
|
builder.instance_eval(&block)
|
53
|
-
|
54
|
-
builder.
|
57
|
+
else
|
58
|
+
context = builder.get_binding do
|
59
|
+
builder.instance_eval {_import! block.call}
|
60
|
+
end
|
61
|
+
context.eval(data.untaint, eval_file)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def _evaluate_safely(*args, &block)
|
66
|
+
if Wunderbar.safe? and $SAFE==0
|
67
|
+
Proc.new { $SAFE=1; _evaluate(*args, &block) }.call
|
68
|
+
else
|
69
|
+
_evaluate(*args, &block)
|
55
70
|
end
|
56
71
|
end
|
57
72
|
end
|
@@ -62,7 +77,7 @@ module Wunderbar
|
|
62
77
|
def evaluate(scope, locals, &block)
|
63
78
|
builder = HtmlMarkup.new(scope)
|
64
79
|
begin
|
65
|
-
|
80
|
+
_evaluate_safely(builder, scope, locals, &block)
|
66
81
|
rescue Exception => exception
|
67
82
|
scope.response.status = 500
|
68
83
|
builder.clear!
|
@@ -90,7 +105,7 @@ module Wunderbar
|
|
90
105
|
def evaluate(scope, locals, &block)
|
91
106
|
builder = JsonBuilder.new(scope)
|
92
107
|
begin
|
93
|
-
|
108
|
+
_evaluate_safely(builder, scope, locals, &block)
|
94
109
|
rescue Exception => exception
|
95
110
|
scope.content_type self.class.default_mime_type, :charset => 'utf-8'
|
96
111
|
scope.response.status = 500
|
@@ -106,7 +121,7 @@ module Wunderbar
|
|
106
121
|
def evaluate(scope, locals, &block)
|
107
122
|
builder = TextBuilder.new(scope)
|
108
123
|
begin
|
109
|
-
|
124
|
+
_evaluate_safely(builder, scope, locals, &block)
|
110
125
|
scope.response.status = 404 if builder.target!.empty?
|
111
126
|
rescue Exception => exception
|
112
127
|
scope.headers['Content-Type'] = self.class.default_mime_type
|
data/lib/wunderbar/version.rb
CHANGED
data/wunderbar.gemspec
CHANGED
@@ -1,19 +1,23 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
|
-
s.name =
|
5
|
-
s.version = "0.
|
4
|
+
s.name = %q{wunderbar}
|
5
|
+
s.version = "0.11.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
-
s.authors = [
|
9
|
-
s.date =
|
10
|
-
s.description =
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
s.
|
16
|
-
s.
|
8
|
+
s.authors = [%q{Sam Ruby}]
|
9
|
+
s.date = %q{2012-04-23}
|
10
|
+
s.description = %q{ Wunderbar makes it easy to produce valid HTML5, wellformed XHTML, Unicode
|
11
|
+
(utf-8), consistently indented, readable applications. This includes
|
12
|
+
output that conforms to the Polyglot specification and the emerging
|
13
|
+
results from the XML Error Recovery Community Group.
|
14
|
+
}
|
15
|
+
s.email = %q{rubys@intertwingly.net}
|
16
|
+
s.files = [%q{wunderbar.gemspec}, %q{README.md}, %q{COPYING}, %q{lib/wunderbar.rb}, %q{lib/wunderbar}, %q{lib/wunderbar/version.rb}, %q{lib/wunderbar/installation.rb}, %q{lib/wunderbar/cssproxy.rb}, %q{lib/wunderbar/rack.rb}, %q{lib/wunderbar/logger.rb}, %q{lib/wunderbar/builder.rb}, %q{lib/wunderbar/sinatra.rb}, %q{lib/wunderbar/rails.rb}, %q{lib/wunderbar/server.rb}, %q{lib/wunderbar/html-methods.rb}, %q{lib/wunderbar/job-control.rb}, %q{lib/wunderbar/environment.rb}, %q{lib/wunderbar/cgi-methods.rb}]
|
17
|
+
s.homepage = %q{http://github.com/rubys/wunderbar}
|
18
|
+
s.require_paths = [%q{lib}]
|
19
|
+
s.rubygems_version = %q{1.8.5}
|
20
|
+
s.summary = %q{HTML Generator and CGI application support}
|
17
21
|
|
18
22
|
if s.respond_to? :specification_version then
|
19
23
|
s.specification_version = 3
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wunderbar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 51
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 11
|
9
|
+
- 0
|
10
|
+
version: 0.11.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sam Ruby
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-04-
|
18
|
+
date: 2012-04-23 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: builder
|
@@ -59,18 +59,19 @@ files:
|
|
59
59
|
- README.md
|
60
60
|
- COPYING
|
61
61
|
- lib/wunderbar.rb
|
62
|
+
- lib/wunderbar/version.rb
|
62
63
|
- lib/wunderbar/installation.rb
|
63
|
-
- lib/wunderbar/
|
64
|
-
- lib/wunderbar/job-control.rb
|
65
|
-
- lib/wunderbar/server.rb
|
66
|
-
- lib/wunderbar/logger.rb
|
64
|
+
- lib/wunderbar/cssproxy.rb
|
67
65
|
- lib/wunderbar/rack.rb
|
66
|
+
- lib/wunderbar/logger.rb
|
68
67
|
- lib/wunderbar/builder.rb
|
69
68
|
- lib/wunderbar/sinatra.rb
|
69
|
+
- lib/wunderbar/rails.rb
|
70
|
+
- lib/wunderbar/server.rb
|
71
|
+
- lib/wunderbar/html-methods.rb
|
72
|
+
- lib/wunderbar/job-control.rb
|
70
73
|
- lib/wunderbar/environment.rb
|
71
74
|
- lib/wunderbar/cgi-methods.rb
|
72
|
-
- lib/wunderbar/cssproxy.rb
|
73
|
-
- lib/wunderbar/version.rb
|
74
75
|
homepage: http://github.com/rubys/wunderbar
|
75
76
|
licenses: []
|
76
77
|
|
@@ -100,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
101
|
requirements: []
|
101
102
|
|
102
103
|
rubyforge_project:
|
103
|
-
rubygems_version: 1.8.
|
104
|
+
rubygems_version: 1.8.5
|
104
105
|
signing_key:
|
105
106
|
specification_version: 3
|
106
107
|
summary: HTML Generator and CGI application support
|