wunderbar 0.8.14 → 0.9.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 +108 -4
- data/lib/wunderbar/builder.rb +126 -0
- data/lib/wunderbar/cgi-methods.rb +28 -25
- data/lib/wunderbar/logger.rb +5 -1
- data/lib/wunderbar/version.rb +2 -2
- data/wunderbar.gemspec +2 -2
- metadata +5 -5
data/README.md
CHANGED
@@ -12,9 +12,42 @@ Wunderbar is both inspired by, and builds upon 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/).
|
15
|
-
.
|
16
15
|
|
17
|
-
|
16
|
+
Wunderbar's JSON support is inspired by David Heinemeier Hansson's
|
17
|
+
[jbuilder](https://github.com/rails/jbuilder).
|
18
|
+
|
19
|
+
Overview
|
20
|
+
---
|
21
|
+
|
22
|
+
The premise of Wunderbar is that output of various types are typically formed
|
23
|
+
by appending either a series of key/value pairs or simple values, and those
|
24
|
+
operations should be optimized for. Appending a key/value pair is done via:
|
25
|
+
|
26
|
+
_key value
|
27
|
+
|
28
|
+
... and appending a simple value is done thus:
|
29
|
+
|
30
|
+
_ value
|
31
|
+
|
32
|
+
For HTML, key/value is used for element nodes, and simple values are used for
|
33
|
+
text nodes. For JSON, key/value is used for Hashes and simple values are used
|
34
|
+
for arrays. For text, simple values are output via puts, and key/value pairs
|
35
|
+
are not used.
|
36
|
+
|
37
|
+
Nesting is performed using blocks.
|
38
|
+
|
39
|
+
The underscore method, when passed no arguments, returns an object that can be
|
40
|
+
used to perform a number of special functions. Some of those functions are
|
41
|
+
unique to the output method. Others like logging methods are common.
|
42
|
+
|
43
|
+
The underscore method when passed multiple arguments or a combination of
|
44
|
+
arguments and a block may do other common functions, depending on the types of
|
45
|
+
the arguments passed.
|
46
|
+
|
47
|
+
Question mark, exclamation mark, and underscore suffixes to the method name
|
48
|
+
may modify the results.
|
49
|
+
|
50
|
+
Quick Start (HTML)
|
18
51
|
---
|
19
52
|
|
20
53
|
Simple element:
|
@@ -112,14 +145,15 @@ output. This is accomplished by providing one or more of the following:
|
|
112
145
|
end
|
113
146
|
|
114
147
|
Wunderbar.json do
|
115
|
-
|
148
|
+
code
|
116
149
|
end
|
117
150
|
|
118
151
|
Wunderbar.text do
|
119
152
|
code
|
120
153
|
end
|
121
154
|
|
122
|
-
Arbitrary Ruby code can be placed in each.
|
155
|
+
Arbitrary Ruby code can be placed in each. To append to the output produced,
|
156
|
+
use the `_` methods described here.
|
123
157
|
|
124
158
|
Methods provided to Wunderbar.html
|
125
159
|
---
|
@@ -154,6 +188,76 @@ Access to all of the builder _defined_ methods (typically these end in an esclam
|
|
154
188
|
* `_.tag! :foo`
|
155
189
|
* `_.error 'Log message'`
|
156
190
|
|
191
|
+
XHTML differs from HTML in the escaping of inline style and script elements.
|
192
|
+
XHTML will also fall back to HTML output unless the user agent indicates it
|
193
|
+
supports XHTML via the HTTP Accept header.
|
194
|
+
|
195
|
+
Methods provided to Wunderbar.json
|
196
|
+
---
|
197
|
+
|
198
|
+
Common operations are to return a Hash or an Array of values. Hashes are
|
199
|
+
a series of name/value pairs, and Arrays are a series of values.
|
200
|
+
|
201
|
+
``` ruby
|
202
|
+
Wunderbar.json do
|
203
|
+
_content format_content(@message.content)
|
204
|
+
_ @message, :created_at, :updated_at
|
205
|
+
|
206
|
+
_author do
|
207
|
+
_name @message.creator.name.familiar
|
208
|
+
_email_address @message.creator.email_address_with_name
|
209
|
+
_url url_for(@message.creator, format: :json)
|
210
|
+
end
|
211
|
+
|
212
|
+
if current_user.admin?
|
213
|
+
_visitors calculate_visitors(@message)
|
214
|
+
end
|
215
|
+
|
216
|
+
_comments @message.comments, :content, :created_at
|
217
|
+
|
218
|
+
_attachments @message.attachments do |attachment|
|
219
|
+
_filename attachment.filename
|
220
|
+
_url url_for(attachment)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
```
|
224
|
+
|
225
|
+
Invoking methods that start with a Unicode
|
226
|
+
[low line](http://www.fileformat.info/info/unicode/char/5f/index.htm)
|
227
|
+
character ("_") will add a key/value pair to that hash. Hashes can
|
228
|
+
also be nested. Logic can be freely intermixed.
|
229
|
+
|
230
|
+
The "`_`" method serves a number of purposes.
|
231
|
+
|
232
|
+
* calling it with multiple arguments will cause the first argument to be
|
233
|
+
treated as the object, and the remainder as the attributes to be extracted
|
234
|
+
* Example: `_ File.stat('foo'), :mtime, :size, :mode`
|
235
|
+
|
236
|
+
* calling it with a single Enumerable object and a block will cause an array
|
237
|
+
to be returned based on mapping each objection from the enumeration against
|
238
|
+
the block
|
239
|
+
* Example: `_([1,2,3]) {|n| n*n}`
|
240
|
+
|
241
|
+
* arrays can be also be built using the `_` method:
|
242
|
+
_ 1
|
243
|
+
_ 2
|
244
|
+
|
245
|
+
The `_` method returns a proxy to the object being constructed. This is often
|
246
|
+
handy when called with no arguments. Examples:
|
247
|
+
|
248
|
+
_.sort!
|
249
|
+
_['foo'] = 'bar'
|
250
|
+
|
251
|
+
Methods provided to Wunderbar.text
|
252
|
+
---
|
253
|
+
|
254
|
+
Appending to the output stream is done using the `_` method, which is
|
255
|
+
equivalent to `puts`. The `_` method returns an object which proxies the
|
256
|
+
output stream, which provides access to other useful methods, for example:
|
257
|
+
|
258
|
+
_.print 'foo'
|
259
|
+
_.printf "Hello %s!\n", 'world'
|
260
|
+
|
157
261
|
Globals provided
|
158
262
|
---
|
159
263
|
* `$cgi` - Common Gateway Interface
|
data/lib/wunderbar/builder.rb
CHANGED
@@ -170,4 +170,130 @@ module Wunderbar
|
|
170
170
|
$HTTP_POST
|
171
171
|
end
|
172
172
|
end
|
173
|
+
|
174
|
+
class TextBuilder
|
175
|
+
def initialize
|
176
|
+
require 'stringio'
|
177
|
+
@_target = StringIO.new
|
178
|
+
end
|
179
|
+
|
180
|
+
def encode(params = {}, &block)
|
181
|
+
params.each do |key,value|
|
182
|
+
instance_variable_set "@#{key}", value.first if key =~ /^\w+$/
|
183
|
+
end
|
184
|
+
|
185
|
+
self.instance_eval(&block)
|
186
|
+
@_target.string
|
187
|
+
end
|
188
|
+
|
189
|
+
def _(*args)
|
190
|
+
@_target.puts *args if args.length > 0
|
191
|
+
self
|
192
|
+
end
|
193
|
+
|
194
|
+
# forward to either Wunderbar or @_target
|
195
|
+
def method_missing(method, *args, &block)
|
196
|
+
if Wunderbar.respond_to? method
|
197
|
+
return Wunderbar.send method, *args, &block
|
198
|
+
elsif @_target.respond_to? method
|
199
|
+
return @_target.send method, *args, &block
|
200
|
+
else
|
201
|
+
super
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def target!
|
206
|
+
@_target.string
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
class JsonBuilder
|
211
|
+
def initialize
|
212
|
+
@_target = {}
|
213
|
+
end
|
214
|
+
|
215
|
+
def encode(params = {}, &block)
|
216
|
+
params.each do |key,value|
|
217
|
+
instance_variable_set "@#{key}", value.first if key =~ /^\w+$/
|
218
|
+
end
|
219
|
+
|
220
|
+
self.instance_eval(&block)
|
221
|
+
@_target
|
222
|
+
end
|
223
|
+
|
224
|
+
# forward to either Wunderbar or @_target
|
225
|
+
def method_missing(method, *args, &block)
|
226
|
+
|
227
|
+
if method.to_s =~ /^_(\w*)$/
|
228
|
+
name = $1
|
229
|
+
elsif Wunderbar.respond_to? method
|
230
|
+
return Wunderbar.send method, *args, &block
|
231
|
+
elsif @_target.respond_to? method
|
232
|
+
return @_target.send method, *args, &block
|
233
|
+
else
|
234
|
+
super
|
235
|
+
end
|
236
|
+
|
237
|
+
if args.length == 0
|
238
|
+
return self unless block
|
239
|
+
result = JsonBuilder.new.encode(&block)
|
240
|
+
elsif args.length == 1
|
241
|
+
result = args.first
|
242
|
+
|
243
|
+
if block
|
244
|
+
if Symbol === result or String === result
|
245
|
+
result = {result.to_s => JsonBuilder.new.encode(&block)}
|
246
|
+
else
|
247
|
+
result = result.map {|n| @_target = {}; block.call(n); @_target}
|
248
|
+
end
|
249
|
+
end
|
250
|
+
elsif block
|
251
|
+
::Kernel::raise ::ArgumentError,
|
252
|
+
"can't mix multiple arguments with a block"
|
253
|
+
else
|
254
|
+
object = args.shift
|
255
|
+
|
256
|
+
if not Enumerable === object or String === object or Struct === object
|
257
|
+
result = {}
|
258
|
+
args.each {|arg| result[arg.to_s] = object.send arg}
|
259
|
+
else
|
260
|
+
result = object.map do |item|
|
261
|
+
args.inject({}) {|hash, arg| hash[arg.to_s] = item.send arg; hash}
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
if name != ''
|
267
|
+
unless Hash === @_target or @_target.empty?
|
268
|
+
::Kernel::raise ::ArgumentError, "mixed array and hash calls"
|
269
|
+
end
|
270
|
+
|
271
|
+
@_target[name.to_s] = result
|
272
|
+
elsif args.length == 0 or (args.length == 1 and not block)
|
273
|
+
@_target = [] if @_target == {}
|
274
|
+
|
275
|
+
if Hash === @_target
|
276
|
+
::Kernel::raise ::ArgumentError, "mixed hash and array calls"
|
277
|
+
end
|
278
|
+
|
279
|
+
@_target << result
|
280
|
+
else
|
281
|
+
@_target = result
|
282
|
+
end
|
283
|
+
|
284
|
+
self
|
285
|
+
end
|
286
|
+
|
287
|
+
def _!(object)
|
288
|
+
@_target = object
|
289
|
+
end
|
290
|
+
|
291
|
+
def target!
|
292
|
+
begin
|
293
|
+
JSON.pretty_generate(@_target)+ "\n"
|
294
|
+
rescue
|
295
|
+
@_target.to_json + "\n"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
173
299
|
end
|
@@ -4,44 +4,47 @@ module Wunderbar
|
|
4
4
|
|
5
5
|
# produce json
|
6
6
|
def self.json(&block)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
output = instance_eval(&block)
|
7
|
+
builder = JsonBuilder.new
|
8
|
+
output = builder.encode($param, &block)
|
9
|
+
Kernel.print "Status: 404 Not Found\r\n" if output == {}
|
11
10
|
rescue Exception => exception
|
12
11
|
Kernel.print "Status: 500 Internal Error\r\n"
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
Wunderbar.error exception.inspect
|
13
|
+
backtrace = []
|
14
|
+
exception.backtrace.each do |frame|
|
15
|
+
next if frame =~ %r{/wunderbar/}
|
16
|
+
next if frame =~ %r{/gems/.*/builder/}
|
17
|
+
Wunderbar.warn " #{frame}"
|
18
|
+
backtrace << frame
|
19
|
+
end
|
20
|
+
builder = JsonBuilder.new
|
21
|
+
builder._exception exception.inspect
|
22
|
+
builder._backtrace backtrace
|
17
23
|
ensure
|
18
|
-
Kernel.print "Status: 404 Not Found\r\n" unless output
|
19
24
|
out? 'type' => 'application/json', 'Cache-Control' => 'no-cache' do
|
20
|
-
|
21
|
-
JSON.pretty_generate(output)+ "\n"
|
22
|
-
rescue
|
23
|
-
output.to_json + "\n"
|
24
|
-
end
|
25
|
+
builder.target!
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
# produce text
|
29
30
|
def self.text &block
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
instance_variable_set "@#{key}", value.first if key =~ /^\w+$/
|
34
|
-
end
|
35
|
-
buffer.instance_eval &block
|
31
|
+
builder = TextBuilder.new
|
32
|
+
output = builder.encode($param, &block)
|
33
|
+
Kernel.print "Status: 404 Not Found\r\n" if output == ''
|
36
34
|
rescue Exception => exception
|
35
|
+
Wunderbar.error exception.inspect
|
37
36
|
Kernel.print "Status: 500 Internal Error\r\n"
|
38
|
-
|
39
|
-
|
40
|
-
exception.backtrace.each
|
37
|
+
builder.puts unless builder.size == 0
|
38
|
+
builder.puts exception.inspect
|
39
|
+
exception.backtrace.each do |frame|
|
40
|
+
next if frame =~ %r{/wunderbar/}
|
41
|
+
next if frame =~ %r{/gems/.*/builder/}
|
42
|
+
Wunderbar.warn " #{frame}"
|
43
|
+
builder.puts " #{frame}"
|
44
|
+
end
|
41
45
|
ensure
|
42
|
-
Kernel.print "Status: 404 Not Found\r\n" if buffer.size == 0
|
43
46
|
out? 'type' => 'text/plain', 'Cache-Control' => 'no-cache' do
|
44
|
-
|
47
|
+
builder.target!
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
data/lib/wunderbar/logger.rb
CHANGED
@@ -3,7 +3,7 @@ require 'logger'
|
|
3
3
|
module Wunderbar
|
4
4
|
def self.logger
|
5
5
|
return @logger if @logger
|
6
|
-
@logger = Logger.new(
|
6
|
+
@logger = Logger.new($stderr)
|
7
7
|
@logger.level = Logger::WARN
|
8
8
|
@logger.formatter = proc { |severity, datetime, progname, msg|
|
9
9
|
"_#{severity} #{msg}\n"
|
@@ -11,6 +11,10 @@ module Wunderbar
|
|
11
11
|
@logger
|
12
12
|
end
|
13
13
|
|
14
|
+
def self.logger= new_logger
|
15
|
+
@logger = new_logger
|
16
|
+
end
|
17
|
+
|
14
18
|
def self.log_level=(level)
|
15
19
|
return unless level
|
16
20
|
|
data/lib/wunderbar/version.rb
CHANGED
data/wunderbar.gemspec
CHANGED
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "wunderbar"
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.9.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Sam Ruby"]
|
9
|
-
s.date = "2012-
|
9
|
+
s.date = "2012-04-01"
|
10
10
|
s.description = " Wunderbar makes it easy to produce valid HTML5, wellformed XHTML, Unicode\n (utf-8), consistently indented, readable applications. This includes\n output that conforms to the Polyglot specification and the emerging\n results from the XML Error Recovery Community Group.\n"
|
11
11
|
s.email = "rubys@intertwingly.net"
|
12
12
|
s.files = ["wunderbar.gemspec", "README.md", "COPYING", "lib/wunderbar.rb", "lib/wunderbar", "lib/wunderbar/installation.rb", "lib/wunderbar/html-methods.rb", "lib/wunderbar/job-control.rb", "lib/wunderbar/logger.rb", "lib/wunderbar/builder.rb", "lib/wunderbar/environment.rb", "lib/wunderbar/cgi-methods.rb", "lib/wunderbar/cssproxy.rb", "lib/wunderbar/version.rb"]
|
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: 59
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 9
|
9
|
+
- 0
|
10
|
+
version: 0.9.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-
|
18
|
+
date: 2012-04-01 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: builder
|