wunderbar 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
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
-