wunderbar 0.10.0 → 0.10.1

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 CHANGED
@@ -182,8 +182,6 @@ number of other convenience methods are defined:
182
182
  * `_.post?` -- was this invoked via HTTP POST?
183
183
  * `_.system` -- invokes a shell command, captures stdin, stdout, and stderr
184
184
  * `_.submit` -- runs command (or block) as a deamon process
185
- * `_.SELF` -- Request URI
186
- * `_.SELF?` -- Request URI with '?' appended (avoids spoiling the cache)
187
185
 
188
186
  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:
189
187
 
@@ -262,9 +260,6 @@ output stream, which provides access to other useful methods, for example:
262
260
 
263
261
  Globals provided
264
262
  ---
265
- * `$cgi` - Common Gateway Interface
266
- * `$params` - Access to parameters (read-only OpenStruct like interface)
267
- * `$env` - Access to environment variables (read-only OpenStruct like interface)
268
263
  * `$USER` - Host user id
269
264
  * `$HOME` - Home directory
270
265
  * `$SERVER` - Server name
@@ -292,10 +287,6 @@ HTML methods
292
287
  Note that adding an exclamation mark to the end of the tag name disables this
293
288
  behavior.
294
289
 
295
- OpenStruct methods (for $params and $env)
296
- ---
297
- * `untaint_if_match`: untaints value if it matches a regular expression
298
-
299
290
  Builder extensions
300
291
  ---
301
292
  * `indented_text!`: matches text indentation to markup
@@ -188,17 +188,25 @@ module Wunderbar
188
188
  end
189
189
  end
190
190
 
191
- class TextBuilder
192
- def initialize
191
+ class BuilderBase
192
+ def set_variables_from_params
193
+ @_scope.params.each do |key,value|
194
+ value = value.first if Array === value
195
+ value.gsub! "\r\n", "\n" if String === value
196
+ instance_variable_set "@#{key}", value if key =~ /^\w+$/
197
+ end
198
+ end
199
+ end
200
+
201
+ class TextBuilder < BuilderBase
202
+ def initialize(scope)
193
203
  require 'stringio'
194
204
  @_target = StringIO.new
205
+ @_scope = scope
195
206
  end
196
207
 
197
- def encode(params = {}, &block)
198
- params.each do |key,value|
199
- instance_variable_set "@#{key}", value.first if key =~ /^\w+$/
200
- end
201
-
208
+ def encode(&block)
209
+ set_variables_from_params
202
210
  self.instance_eval(&block)
203
211
  @_target.string
204
212
  end
@@ -221,22 +229,35 @@ module Wunderbar
221
229
  end
222
230
  end
223
231
 
232
+ def _exception(*args)
233
+ exception = args.first
234
+ if exception.respond_to? :backtrace
235
+ Wunderbar.error exception.inspect
236
+ @_target.puts unless size == 0
237
+ @_target.puts exception.inspect
238
+ exception.backtrace.each do |frame|
239
+ next if CALLERS_TO_IGNORE.any? {|re| frame =~ re}
240
+ Wunderbar.warn " #{frame}"
241
+ @_target.puts " #{frame}"
242
+ end
243
+ else
244
+ super
245
+ end
246
+ end
247
+
224
248
  def target!
225
249
  @_target.string
226
250
  end
227
251
  end
228
252
 
229
- class JsonBuilder
230
- def initialize(scope=nil)
253
+ class JsonBuilder < BuilderBase
254
+ def initialize(scope)
231
255
  @_scope = scope
232
256
  @_target = {}
233
257
  end
234
258
 
235
- def encode(params = {}, &block)
236
- params.each do |key,value|
237
- instance_variable_set "@#{key}", value.first if key =~ /^\w+$/
238
- end
239
-
259
+ def encode(&block)
260
+ set_variables_from_params
240
261
  self.instance_eval(&block)
241
262
  @_target
242
263
  end
@@ -258,13 +279,13 @@ module Wunderbar
258
279
 
259
280
  if args.length == 0
260
281
  return self unless block
261
- result = JsonBuilder.new.encode(&block)
282
+ result = JsonBuilder.new(@_scope).encode(&block)
262
283
  elsif args.length == 1
263
284
  result = args.first
264
285
 
265
286
  if block
266
287
  if Symbol === result or String === result
267
- result = {result.to_s => JsonBuilder.new.encode(&block)}
288
+ result = {result.to_s => JsonBuilder.new(@_scope).encode(&block)}
268
289
  else
269
290
  result = result.map {|n| @_target = {}; block.call(n); @_target}
270
291
  end
@@ -310,6 +331,22 @@ module Wunderbar
310
331
  @_target = object
311
332
  end
312
333
 
334
+ def _exception(*args)
335
+ exception = args.first
336
+ if exception.respond_to? :backtrace
337
+ Wunderbar.error exception.inspect
338
+ super(exception.inspect)
339
+ @_target['backtrace'] = []
340
+ exception.backtrace.each do |frame|
341
+ next if CALLERS_TO_IGNORE.any? {|re| frame =~ re}
342
+ Wunderbar.warn " #{frame}"
343
+ @_target['backtrace'] << frame
344
+ end
345
+ else
346
+ super
347
+ end
348
+ end
349
+
313
350
  def target!
314
351
  begin
315
352
  JSON.pretty_generate(@_target)+ "\n"
@@ -1,77 +1,59 @@
1
1
  module Wunderbar
2
-
3
2
  module CGI
4
3
 
5
- HIDE_FRAME = [ %r{/(wunderbar|webrick)/},
6
- %r{/gems/.*/(builder|rack|sinatra)/} ]
7
-
8
4
  # produce json
9
- def self.json(&block)
5
+ def self.json(scope, &block)
10
6
  headers = { 'type' => 'application/json', 'Cache-Control' => 'no-cache' }
11
- builder = JsonBuilder.new
12
- output = builder.encode($params, &block)
7
+ builder = JsonBuilder.new(scope)
8
+ output = builder.encode(&block)
13
9
  headers['status'] = "404 Not Found" if output == {}
14
10
  rescue Exception => exception
15
- Wunderbar.error exception.inspect
16
11
  headers['status'] = "500 Internal Server Error"
17
- backtrace = []
18
- exception.backtrace.each do |frame|
19
- next if HIDE_FRAME.any? {|re| frame =~ re}
20
- Wunderbar.warn " #{frame}"
21
- backtrace << frame
22
- end
23
- builder = JsonBuilder.new
24
- builder._exception exception.inspect
25
- builder._backtrace backtrace
12
+ builder._! Hash.new
13
+ builder._exception exception
26
14
  ensure
27
- out?(headers) { builder.target! }
15
+ out?(scope, headers) { builder.target! }
28
16
  end
29
17
 
30
18
  # produce text
31
- def self.text &block
19
+ def self.text(scope, &block)
32
20
  headers = {'type' => 'text/plain', 'charset' => 'UTF-8'}
33
- builder = TextBuilder.new
34
- output = builder.encode($params, &block)
21
+ builder = TextBuilder.new(scope)
22
+ output = builder.encode(&block)
35
23
  headers['status'] = "404 Not Found" if output == ''
36
24
  rescue Exception => exception
37
- Wunderbar.error exception.inspect
38
25
  headers['status'] = "500 Internal Server Error"
39
- builder.puts unless builder.size == 0
40
- builder.puts exception.inspect
41
- exception.backtrace.each do |frame|
42
- next if HIDE_FRAME.any? {|re| frame =~ re}
43
- Wunderbar.warn " #{frame}"
44
- builder.puts " #{frame}"
45
- end
26
+ builder._exception exception
46
27
  ensure
47
- out?(headers) { builder.target! }
28
+ out?(scope, headers) { builder.target! }
48
29
  end
49
30
 
50
31
  # Conditionally provide output, based on ETAG
51
- def self.out?(headers, &block)
32
+ def self.out?(scope, headers, &block)
52
33
  content = block.call
53
34
  require 'digest/md5'
54
35
  etag = Digest::MD5.hexdigest(content)
55
36
 
56
- if $env.HTTP_IF_NONE_MATCH == etag.inspect
37
+ if scope.env['HTTP_IF_NONE_MATCH'] == etag.inspect
57
38
  headers['Date'] = ::CGI.rfc1123_date(Time.now)
58
- $cgi.out headers.merge('status' => '304 Not Modified') do
39
+ scope.out headers.merge('status' => '304 Not Modified') do
59
40
  ''
60
41
  end
61
42
  else
62
- $cgi.out headers.merge('Etag' => etag.inspect) do
43
+ scope.out headers.merge('Etag' => etag.inspect) do
63
44
  content
64
45
  end
65
46
  end
66
- rescue
47
+ rescue Exception => exception
48
+ Wunderbar.fatal exception.inspect
67
49
  end
68
50
 
69
51
  # produce html/xhtml
70
- def self.html(*args, &block)
52
+ def self.html(scope, *args, &block)
71
53
  headers = { 'type' => 'text/html', 'charset' => 'UTF-8' }
72
54
  headers['type'] = 'application/xhtml+xml' if @xhtml
73
55
 
74
- x = HtmlMarkup.new
56
+ x = HtmlMarkup.new(scope)
75
57
 
76
58
  begin
77
59
  if @xhtml
@@ -88,28 +70,18 @@ module Wunderbar
88
70
  end
89
71
  _body do
90
72
  _h1 'Internal Server Error'
91
- text = exception.inspect
92
- Wunderbar.error text
93
- exception.backtrace.each do |frame|
94
- next if HIDE_FRAME.any? {|re| frame =~ re}
95
- Wunderbar.warn " #{frame}"
96
- text += "\n #{frame}"
97
- end
98
-
99
- _pre text
73
+ _exception exception
100
74
  end
101
75
  end
102
76
  end
103
77
 
104
- out?(headers) { output }
78
+ out?(scope, headers) { output }
105
79
  end
106
80
 
107
- def self.call(env)
108
- require 'etc'
109
- $USER = ENV['REMOTE_USER'] ||= ENV['USER'] || Etc.getlogin
110
-
111
- accept = $env.HTTP_ACCEPT.to_s
112
- request_uri = $env.REQUEST_URI.to_s
81
+ def self.call(scope)
82
+ env = scope.env
83
+ accept = env['HTTP_ACCEPT'].to_s
84
+ request_uri = env['REQUEST_URI'].to_s
113
85
 
114
86
  # implied request types
115
87
  xhr_json = Wunderbar::Options::XHR_JSON || (accept =~ /json/)
@@ -118,8 +90,8 @@ module Wunderbar
118
90
  @xhtml = (accept =~ /xhtml/ or accept == '')
119
91
 
120
92
  # overrides via the uri query parameter
121
- xhr_json ||= (request_uri =~ /\?json$/)
122
- text ||= (request_uri =~ /\?text$/)
93
+ xhr_json ||= (request_uri =~ /\?json$/)
94
+ text ||= (request_uri =~ /\?text$/)
123
95
 
124
96
  # overrides via the command line
125
97
  xhtml_override = ARGV.include?('--xhtml')
@@ -142,17 +114,17 @@ module Wunderbar
142
114
  @xhtml = false if html_override
143
115
  end
144
116
 
145
- self.html(*args, &block)
117
+ self.html(scope, *args, &block)
146
118
  return
147
119
  end
148
120
  when :json
149
121
  if xhr_json
150
- self.json(*args, &block)
122
+ self.json(scope, *args, &block)
151
123
  return
152
124
  end
153
125
  when :text
154
126
  if text
155
- self.text(*args, &block)
127
+ self.text(scope, *args, &block)
156
128
  return
157
129
  end
158
130
  end
@@ -11,38 +11,16 @@ module Wunderbar
11
11
  end
12
12
  end
13
13
 
14
- # quick access to request_uri
15
- def self.SELF
16
- $env.REQUEST_URI
17
- end
18
-
19
- def self.SELF?
20
- if SELF '?'
21
- self.self
22
- else
23
- SELF + "?" # avoids spoiling the cache
14
+ class Scope
15
+ attr_accessor :env
16
+ def initialize(env)
17
+ @env = env
24
18
  end
25
19
  end
26
-
27
- # was this invoked via HTTP POST?
28
- def self.post?
29
- $env.REQUEST_METHOD.to_s.upcase == 'POST'
30
- end
31
- end
32
-
33
- # environment objects
34
- $env = {}
35
- def $env.method_missing(name)
36
- delete name.to_s if ENV[name.to_s] != self[name.to_s]
37
- if ENV[name.to_s] and not has_key?(name.to_s)
38
- self[name.to_s]=ENV[name.to_s].dup.extend(Wunderbar::Untaint)
39
- end
40
- self[name.to_s]
41
20
  end
42
21
 
43
22
  require 'socket'
44
23
  $SERVER = ENV['HTTP_HOST'] || Socket::gethostname
45
- $HOME = ENV['HOME'] ||= Dir.home() rescue nil
46
24
 
47
25
  # set encoding to UTF-8
48
26
  ENV['LANG'] ||= "en_US.UTF-8"
@@ -52,3 +30,24 @@ if defined? Encoding
52
30
  else
53
31
  $KCODE = 'U'
54
32
  end
33
+
34
+ # Add methods to the 'main' object
35
+ if self.to_s == 'main'
36
+ class << self
37
+ def _html(*args, &block)
38
+ Wunderbar.html(*args, &block)
39
+ end
40
+
41
+ def _xhtml(*args, &block)
42
+ Wunderbar.xhtml(*args, &block)
43
+ end
44
+
45
+ def _json(*args, &block)
46
+ Wunderbar.json(*args, &block)
47
+ end
48
+
49
+ def _text(*args, &block)
50
+ Wunderbar.text(*args, &block)
51
+ end
52
+ end
53
+ end
@@ -1,11 +1,11 @@
1
1
  # Wrapper class that understands HTML
2
- class HtmlMarkup
2
+ class HtmlMarkup < Wunderbar::BuilderBase
3
3
  VOID = %w(
4
4
  area base br col command embed hr img input keygen
5
5
  link meta param source track wbr
6
6
  )
7
7
 
8
- def initialize(scope = nil)
8
+ def initialize(scope)
9
9
  @_scope = scope
10
10
  @x = Wunderbar::XmlMarkup.new :scope => scope, :indent => 2, :target => []
11
11
  @xthml = false
@@ -24,13 +24,8 @@ class HtmlMarkup
24
24
  @x.text! "\xEF\xBB\xBF"
25
25
  @x.declare! :DOCTYPE, :html
26
26
  @x.tag! :html, *args do
27
- if $params
28
- $params.each do |key,value|
29
- value = value.first if Array === value
30
- instance_variable_set "@#{key}", value if key =~ /^\w+$/
31
- end
32
- end
33
- instance_exec(@x, &block)
27
+ set_variables_from_params
28
+ instance_eval(&block)
34
29
  end
35
30
  @x.target!.join
36
31
  end
@@ -101,28 +96,13 @@ class HtmlMarkup
101
96
  end
102
97
  elsif flag == '?'
103
98
  # capture exceptions, produce filtered tracebacks
104
- options = (Hash === args.last)? args.last : {}
105
- traceback_class = options.delete(:traceback_class)
106
- traceback_style = options.delete(:traceback_style)
107
- traceback_style ||= 'background-color:#ff0; margin: 1em 0; ' +
108
- 'padding: 1em; border: 4px solid red; border-radius: 1em'
109
99
  @x.tag!(name, *args) do
110
100
  begin
111
101
  block.call
112
102
  rescue ::Exception => exception
113
- text = exception.inspect
114
- Wunderbar.warn text
115
- exception.backtrace.each do |frame|
116
- next if Wunderbar::CGI::HIDE_FRAME.any? {|re| frame =~ re}
117
- Wunderbar.warn " #{frame}"
118
- text += "\n #{frame}"
119
- end
120
-
121
- if traceback_class
122
- @x.tag! :pre, text, :class=>traceback_class
123
- else
124
- @x.tag! :pre, text, :style=>traceback_style
125
- end
103
+ options = (Hash === args.last)? args.last : {}
104
+ options[:log_level] = 'warn'
105
+ _exception exception, options
126
106
  end
127
107
  end
128
108
  else
@@ -130,6 +110,34 @@ class HtmlMarkup
130
110
  end
131
111
  end
132
112
 
113
+ def _exception(*args)
114
+ exception = args.first
115
+ if exception.respond_to? :backtrace
116
+ options = (Hash === args.last)? args.last : {}
117
+ traceback_class = options.delete(:traceback_class)
118
+ traceback_style = options.delete(:traceback_style)
119
+ traceback_style ||= 'background-color:#ff0; margin: 1em 0; ' +
120
+ 'padding: 1em; border: 4px solid red; border-radius: 1em'
121
+
122
+ text = exception.inspect
123
+ log_level = options.delete(:log_level) || :error
124
+ Wunderbar.send log_level, text
125
+ exception.backtrace.each do |frame|
126
+ next if Wunderbar::CALLERS_TO_IGNORE.any? {|re| frame =~ re}
127
+ Wunderbar.send log_level, " #{frame}"
128
+ text += "\n #{frame}"
129
+ end
130
+
131
+ if traceback_class
132
+ @x.tag! :pre, text, :class=>traceback_class
133
+ else
134
+ @x.tag! :pre, text, :style=>traceback_style
135
+ end
136
+ else
137
+ super
138
+ end
139
+ end
140
+
133
141
  def _head(*args, &block)
134
142
  @x.tag!('head', *args) do
135
143
  @x.tag! :meta, :charset => 'utf-8'
@@ -16,8 +16,10 @@ module Wunderbar
16
16
  STDERR.reopen STDOUT
17
17
 
18
18
  # clear environment of cgi cruft
19
- ENV.keys.to_a.each do |key|
20
- ENV.delete(key) if key =~ /HTTP/ or $cgi.respond_to? key.downcase
19
+ require 'cgi'
20
+ ENV.delete_if {|key,value| key =~ /^HTTP_/}
21
+ CGI::QueryExtension.public_instance_methods.each do |method|
22
+ ENV.delete method.to_s.upcase
21
23
  end
22
24
 
23
25
  # setup environment
@@ -0,0 +1,40 @@
1
+ module Wunderbar
2
+ class RackApp
3
+ # entry point for Rack
4
+ def call(env)
5
+ @_env = env
6
+ @_request = Rack::Request.new(env)
7
+ @_response = Rack::Response.new
8
+ Wunderbar.logger = @_request.logger
9
+ Wunderbar::CGI.call(self)
10
+ @_response.finish
11
+ end
12
+
13
+ # redirect the output produced
14
+ def out(headers,&block)
15
+ status = headers.delete('status')
16
+ @_response.status = status if status
17
+
18
+ headers = Wunderbar::CGI.headers(headers)
19
+ headers.each {|key, value| @_response[key] = value}
20
+
21
+ @_response.write block.call unless @_request.head?
22
+ end
23
+
24
+ def env
25
+ @_env
26
+ end
27
+
28
+ def params
29
+ @_request.params
30
+ end
31
+
32
+ def request
33
+ @_request
34
+ end
35
+
36
+ def response
37
+ @_response
38
+ end
39
+ end
40
+ end
@@ -1,112 +1,81 @@
1
- at_exit do
2
- # Only prompt if explicitly asked for
3
- ARGV.push '' if ARGV.empty?
4
- ARGV.delete('--prompt') or ARGV.delete('--offline')
1
+ # http://rack.rubyforge.org/doc/classes/Rack/Request.html
2
+ # http://rubydoc.info/gems/sinatra/Sinatra/Application
3
+ # http://www.ruby-doc.org/stdlib-1.9.3/libdoc/cgi/rdoc/CGI.html#public-class-method-details
4
+
5
+ module Wunderbar
5
6
 
6
- $cgi = CGI.new
7
+ CALLERS_TO_IGNORE = [
8
+ %r{/(wunderbar|webrick)/},
9
+ %r{<internal:},
10
+ %r{/gems/.*/lib/(builder|rack|sinatra|tilt)/}
11
+ ]
7
12
 
13
+ end
14
+
15
+ at_exit do
8
16
  port = ARGV.find {|arg| arg =~ /--port=(.*)/}
9
17
  if port and ARGV.delete(port)
10
18
  port = $1.to_i
11
19
 
12
- # entry point for Rack
13
- def $cgi.call(env)
14
- @request = Rack::Request.new(env)
15
- @response = Rack::Response.new
16
- $env = OpenStruct.new(env)
17
- $params = @request.params
18
-
19
- Wunderbar::CGI.call(env)
20
- @response.finish
21
- end
22
-
23
- # redirect the output produced
24
- def $cgi.out(headers,&block)
25
- status = headers.delete('status')
26
- @response.status = status if status
27
-
28
- headers = Wunderbar::CGI.headers(headers)
29
- headers.each { |key, value| @response[key] = value }
30
-
31
- @response.write block.call unless @request.head?
32
- end
33
-
34
20
  # Evaluate optional data from the script (after __END__)
35
21
  eval Wunderbar.data if Object.const_defined? :DATA
36
22
 
23
+ # Allow optional environment override
24
+ environment = ARGV.find {|arg| arg =~ /--environment=(.*)/}
25
+ ENV['RACK_ENV'] = environment if environment and ARGV.delete(environment)
26
+
37
27
  # start the server
38
28
  require 'rack'
39
- require 'rack/showexceptions'
40
- app = Rack::ShowExceptions.new(Rack::Lint.new($cgi))
41
- Rack::Server.start :app => app, :Port => port
29
+ require 'wunderbar/rack'
30
+ Rack::Server.start :app => Wunderbar::RackApp.new, :Port => port,
31
+ :environment => (ENV['RACK_ENV'] || 'development')
42
32
 
43
33
  elsif defined? Sinatra
44
34
 
45
- require 'wunderbar/template'
46
- Tilt.register '_html', Wunderbar::Template::Html
47
- Tilt.register '_xhtml', Wunderbar::Template::Xhtml
48
- Tilt.register '_json', Wunderbar::Template::Json
49
- Tilt.register '_text', Wunderbar::Template::Text
50
-
51
- # define helpers
52
- helpers do
53
- def _html(*args, &block)
54
- if block
55
- Wunderbar::Template::Html.evaluate('_html', self) do
56
- _html(*args) { instance_eval &block }
57
- end
58
- else
59
- Wunderbar::Template::Html.evaluate('_html', self, *args)
60
- end
61
- end
35
+ require 'wunderbar/sinatra'
62
36
 
63
- def _xhtml(*args, &block)
64
- if env['HTTP_ACCEPT'] and not env['HTTP_ACCEPT'].include? 'xhtml'
65
- return _html(*args, &block)
66
- end
67
-
68
- if block
69
- Wunderbar::Template::Xhtml.evaluate('_xhtml', self) do
70
- _xhtml(*args) { instance_eval &block }
71
- end
72
- else
73
- Wunderbar::Template::Xhtml.evaluate('_xhtml', self, *args)
74
- end
75
- end
76
-
77
- def _json(*args, &block)
78
- Wunderbar::Template::Json.evaluate('_json', self, *args, &block)
79
- end
80
-
81
- def _text(*args, &block)
82
- Wunderbar::Template::Text.evaluate('_text', self, *args, &block)
83
- end
84
- end
85
-
86
- else
37
+ elsif Wunderbar.queue.length > 0
87
38
 
88
39
  # allow the REQUEST_METHOD to be set for command line invocations
89
40
  ENV['REQUEST_METHOD'] ||= 'POST' if ARGV.delete('--post')
90
41
  ENV['REQUEST_METHOD'] ||= 'GET' if ARGV.delete('--get')
91
42
 
92
- # standard objects
93
- $params = $cgi.params
43
+ # Only prompt if explicitly asked for
44
+ ARGV.push '' if ARGV.empty?
45
+ ARGV.delete('--prompt') or ARGV.delete('--offline')
94
46
 
95
- # get arguments if CGI couldn't find any...
96
- $params.merge!(CGI.parse(ARGV.join('&'))) if $params.empty?
97
-
98
- # fast path for accessing CGI parameters
99
- def $params.method_missing(name)
100
- if has_key? name.to_s
101
- if self[name.to_s].length == 1
102
- self[name.to_s].first.extend(Wunderbar::Untaint)
103
- else
104
- self[name.to_s].join
47
+ cgi = CGI.new
48
+ cgi.instance_variable_set '@env', ENV
49
+ class << cgi
50
+ attr_accessor :env
51
+
52
+ # was this invoked via HTTP POST?
53
+ %w(delete get head options post put trace).each do |http_method|
54
+ define_method "#{http_method}?" do
55
+ env['REQUEST_METHOD'].to_s.downcase == http_method
105
56
  end
106
57
  end
107
58
  end
108
59
 
60
+ # get arguments if CGI couldn't find any...
61
+ cgi.params.merge!(CGI.parse(ARGV.join('&'))) if cgi.params.empty?
62
+
63
+ require 'etc'
64
+ $USER = ENV['REMOTE_USER'] ||= ENV['USER'] || Etc.getlogin
65
+ if $USER.nil?
66
+ if RUBY_PLATFORM =~ /darwin/i
67
+ $USER = `dscl . -search /Users UniqueID #{Process.uid}`.split.first
68
+ elsif RUBY_PLATFORM =~ /linux/i
69
+ $USER = `getent passwd #{Process.uid}`.split(':').first
70
+ end
71
+
72
+ ENV['USER'] ||= $USER
73
+ end
74
+
75
+ ENV['HOME'] ||= Dir.home($USER) rescue nil
76
+ ENV['HOME'] = ENV['DOCUMENT_ROOT'] if not File.exist? ENV['HOME'].to_s
77
+
109
78
  # CGI or command line
110
- Wunderbar::CGI.call(ENV)
79
+ Wunderbar::CGI.call(cgi)
111
80
  end
112
81
  end
@@ -0,0 +1,161 @@
1
+ require 'sinatra'
2
+ require 'digest/md5'
3
+
4
+ module Wunderbar
5
+ # Tilt template implementation
6
+ module Template
7
+ class Base < Tilt::Template
8
+ def self.engine_initialized?
9
+ defined? ::Wunderbar
10
+ end
11
+
12
+ def initialize_engine
13
+ require_template_library 'wunderbar'
14
+ end
15
+
16
+ def prepare
17
+ end
18
+
19
+ def precompiled_template(locals)
20
+ raise NotImplementedError.new("dynamic only")
21
+ end
22
+
23
+ def precompiled_preamble(locals)
24
+ raise NotImplementedError.new("dynamic only")
25
+ end
26
+
27
+ def precompiled_postamble(locals)
28
+ raise NotImplementedError.new("dynamic only")
29
+ end
30
+
31
+ def self.evaluate(template, scope, *args, &block)
32
+ scope.content_type default_mime_type
33
+ if block
34
+ output = new(&Proc.new {}).evaluate(scope, {}, &block)
35
+ else
36
+ output = scope.send :render, template, *args
37
+ end
38
+ scope.etag Digest::MD5.hexdigest(output)
39
+ output
40
+ end
41
+
42
+ private
43
+
44
+ def _evaluate(builder, scope, locals, &block)
45
+ builder.instance_eval do
46
+ scope.params.merge(locals).each do |key,value|
47
+ value = value.first if ::Array === value
48
+ instance_variable_set "@#{key}", value if key =~ /^[a-z]\w+$/
49
+ end
50
+ end
51
+ if block
52
+ builder.instance_eval(&block)
53
+ elsif data
54
+ builder.instance_eval(data, eval_file)
55
+ end
56
+ end
57
+ end
58
+
59
+ class Html < Base
60
+ self.default_mime_type = 'text/html'
61
+
62
+ def evaluate(scope, locals, &block)
63
+ builder = HtmlMarkup.new(scope)
64
+ begin
65
+ _evaluate(builder, scope, locals, &block)
66
+ rescue Exception => exception
67
+ scope.response.status = 500
68
+ builder.clear!
69
+ builder.html do
70
+ _head do
71
+ _title 'Internal Server Error'
72
+ end
73
+ _body do
74
+ _h1 'Internal Server Error'
75
+ _exception exception
76
+ end
77
+ end
78
+ end
79
+ builder._.target!.join
80
+ end
81
+ end
82
+
83
+ class Xhtml < Html
84
+ self.default_mime_type = 'application/xhtml+xml'
85
+ end
86
+
87
+ class Json < Base
88
+ self.default_mime_type = 'application/json'
89
+
90
+ def evaluate(scope, locals, &block)
91
+ builder = JsonBuilder.new(scope)
92
+ begin
93
+ _evaluate(builder, scope, locals, &block)
94
+ rescue Exception => exception
95
+ scope.content_type self.class.default_mime_type, :charset => 'utf-8'
96
+ scope.response.status = 500
97
+ builder._exception exception
98
+ end
99
+ builder.target!
100
+ end
101
+ end
102
+
103
+ class Text < Base
104
+ self.default_mime_type = 'text/plain'
105
+
106
+ def evaluate(scope, locals, &block)
107
+ builder = TextBuilder.new(scope)
108
+ begin
109
+ _evaluate(builder, scope, locals, &block)
110
+ scope.response.status = 404 if builder.target!.empty?
111
+ rescue Exception => exception
112
+ scope.headers['Content-Type'] = self.class.default_mime_type
113
+ scope.response.status = 500
114
+ builder._exception exception
115
+ end
116
+ builder.target!
117
+ end
118
+ end
119
+ end
120
+
121
+ module SinatraHelpers
122
+ def _html(*args, &block)
123
+ if block
124
+ Wunderbar::Template::Html.evaluate('_html', self) do
125
+ _html(*args) { instance_eval &block }
126
+ end
127
+ else
128
+ Wunderbar::Template::Html.evaluate('_html', self, *args)
129
+ end
130
+ end
131
+
132
+ def _xhtml(*args, &block)
133
+ if env['HTTP_ACCEPT'] and not env['HTTP_ACCEPT'].include? 'xhtml'
134
+ return _html(*args, &block)
135
+ end
136
+
137
+ if block
138
+ Wunderbar::Template::Xhtml.evaluate('_xhtml', self) do
139
+ _xhtml(*args) { instance_eval &block }
140
+ end
141
+ else
142
+ Wunderbar::Template::Xhtml.evaluate('_xhtml', self, *args)
143
+ end
144
+ end
145
+
146
+ def _json(*args, &block)
147
+ Wunderbar::Template::Json.evaluate('_json', self, *args, &block)
148
+ end
149
+
150
+ def _text(*args, &block)
151
+ Wunderbar::Template::Text.evaluate('_text', self, *args, &block)
152
+ end
153
+ end
154
+ end
155
+
156
+ Tilt.register '_html', Wunderbar::Template::Html
157
+ Tilt.register '_xhtml', Wunderbar::Template::Xhtml
158
+ Tilt.register '_json', Wunderbar::Template::Json
159
+ Tilt.register '_text', Wunderbar::Template::Text
160
+
161
+ helpers Wunderbar::SinatraHelpers
@@ -2,7 +2,7 @@ module Wunderbar
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 10
5
- TINY = 0
5
+ TINY = 1
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/wunderbar.gemspec CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "wunderbar"
5
- s.version = "0.10.0"
5
+ s.version = "0.10.1"
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-04-07"
9
+ s.date = "2012-04-12"
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
- 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/template.rb", "lib/wunderbar/server.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"]
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/server.rb", "lib/wunderbar/logger.rb", "lib/wunderbar/rack.rb", "lib/wunderbar/builder.rb", "lib/wunderbar/sinatra.rb", "lib/wunderbar/environment.rb", "lib/wunderbar/cgi-methods.rb", "lib/wunderbar/cssproxy.rb", "lib/wunderbar/version.rb"]
13
13
  s.homepage = "http://github.com/rubys/wunderbar"
14
14
  s.require_paths = ["lib"]
15
15
  s.rubygems_version = "1.8.21"
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: 55
4
+ hash: 53
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 10
9
- - 0
10
- version: 0.10.0
9
+ - 1
10
+ version: 0.10.1
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-07 00:00:00 Z
18
+ date: 2012-04-12 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: builder
@@ -62,10 +62,11 @@ files:
62
62
  - lib/wunderbar/installation.rb
63
63
  - lib/wunderbar/html-methods.rb
64
64
  - lib/wunderbar/job-control.rb
65
- - lib/wunderbar/template.rb
66
65
  - lib/wunderbar/server.rb
67
66
  - lib/wunderbar/logger.rb
67
+ - lib/wunderbar/rack.rb
68
68
  - lib/wunderbar/builder.rb
69
+ - lib/wunderbar/sinatra.rb
69
70
  - lib/wunderbar/environment.rb
70
71
  - lib/wunderbar/cgi-methods.rb
71
72
  - lib/wunderbar/cssproxy.rb
@@ -1,91 +0,0 @@
1
- require 'tilt/template'
2
-
3
- module Wunderbar
4
- # Tilt template implementation
5
- module Template
6
- class Base < Tilt::Template
7
- def self.engine_initialized?
8
- defined? ::Wunderbar
9
- end
10
-
11
- def initialize_engine
12
- require_template_library 'wunderbar'
13
- end
14
-
15
- def prepare
16
- end
17
-
18
- def precompiled_template(locals)
19
- raise NotImplementedError.new("dynamic only")
20
- end
21
-
22
- def precompiled_preamble(locals)
23
- raise NotImplementedError.new("dynamic only")
24
- end
25
-
26
- def precompiled_postamble(locals)
27
- raise NotImplementedError.new("dynamic only")
28
- end
29
-
30
- def self.evaluate(template, scope, *args, &block)
31
- scope.content_type default_mime_type
32
- if block
33
- new(&Proc.new {}).evaluate(scope, {}, &block)
34
- else
35
- scope.send :render, template, *args
36
- end
37
- end
38
-
39
- private
40
-
41
- def _evaluate(builder, scope, locals, &block)
42
- builder.instance_eval do
43
- scope.params.merge(locals).each do |key,value|
44
- value = value.first if ::Array === value
45
- instance_variable_set "@#{key}", value if key =~ /^[a-z]\w+$/
46
- end
47
- end
48
- if block
49
- builder.instance_eval(&block)
50
- else
51
- builder.instance_eval(data, eval_file)
52
- end
53
- end
54
- end
55
-
56
- class Html < Base
57
- self.default_mime_type = 'text/html'
58
-
59
- def evaluate(scope, locals, &block)
60
- builder = HtmlMarkup.new(scope)
61
- _evaluate(builder, scope, locals, &block)
62
- builder._.target!.join
63
- end
64
- end
65
-
66
- class Xhtml < Html
67
- self.default_mime_type = 'application/xhtml+xml'
68
- end
69
-
70
- class Json < Base
71
- self.default_mime_type = 'application/json'
72
-
73
- def evaluate(scope, locals, &block)
74
- builder = JsonBuilder.new(scope)
75
- _evaluate(builder, scope, locals)
76
- builder.target!
77
- end
78
- end
79
-
80
- class Text < Base
81
- self.default_mime_type = 'text/plain'
82
-
83
- def evaluate(scope, locals, &block)
84
- builder = JsonBuilder.new(scope)
85
- _evaluate(builder, scope, locals)
86
- builder.target!
87
- end
88
- end
89
- end
90
- end
91
-