wunderbar 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -181,7 +181,9 @@ number of other convenience methods are defined:
181
181
 
182
182
  * `_.post?` -- was this invoked via HTTP POST?
183
183
  * `_.system` -- invokes a shell command, captures stdin, stdout, and stderr
184
- * `_.submit`: runs command (or block) as a deamon process
184
+ * `_.submit` -- runs command (or block) as a deamon process
185
+ * `_.SELF` -- Request URI
186
+ * `_.SELF?` -- Request URI with '?' appended (avoids spoiling the cache)
185
187
 
186
188
  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
189
 
@@ -260,21 +262,14 @@ output stream, which provides access to other useful methods, for example:
260
262
 
261
263
  Globals provided
262
264
  ---
263
- * `$cgi` - Common Gateway Interface
264
- * `$param` - Access to parameters (read-only OpenStruct like interface)
265
- * `$env` - Access to environment variables (read-only OpenStruct like interface)
266
- * `$USER` - Host user id
267
- * `$HOME` - Home directory
268
- * `$SERVER`- Server name
269
- * `SELF` - Request URI
270
- * `SELF?` - Request URI with '?' appended (avoids spoiling the cache)
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
+ * `$USER` - Host user id
269
+ * `$HOME` - Home directory
270
+ * `$SERVER` - Server name
271
271
  * `$HOME` - user's home directory
272
272
  * `$HOST` - server host
273
- * `$HTTP_GET` - request is an HTTP GET
274
- * `$HTTP_POST` - request is an HTTP POST
275
- * `$XHR_JSON` - request is XmlHttpRequest for JSON
276
- * `$XHTML` - user agent accepts XHTML responses
277
- * `$TEXT` - user agent accepts plain text responses
278
273
 
279
274
  Also, the following environment variables are set if they aren't already:
280
275
 
@@ -292,6 +287,7 @@ HTML methods
292
287
  * `_svg`: insert svg namespace
293
288
  * `_math`: insert math namespace
294
289
  * `_coffeescript`: convert [coffeescript](http://coffeescript.org/) to JS and insert script tag
290
+ * `xhtml?`: output as XHTML?
295
291
 
296
292
  Note that adding an exclamation mark to the end of the tag name disables this
297
293
  behavior.
@@ -75,29 +75,47 @@ module Wunderbar
75
75
  end
76
76
 
77
77
  class XmlMarkup
78
- def initialize(*args)
79
- @x = SpacedMarkup.new(*args)
78
+ def initialize(args)
79
+ @_scope = args.delete(:scope)
80
+ @_builder = SpacedMarkup.new(args)
80
81
  end
81
82
 
82
- # forward to either Wunderbar or XmlMarkup
83
+ # forward to Wunderbar, XmlMarkup, or @_scope
83
84
  def method_missing(method, *args, &block)
84
85
  if Wunderbar.respond_to? method
85
86
  Wunderbar.send method, *args, &block
86
87
  elsif SpacedMarkup.public_instance_methods.include? method
87
- @x.__send__ method, *args, &block
88
+ @_builder.__send__ method, *args, &block
88
89
  elsif SpacedMarkup.public_instance_methods.include? method.to_s
89
- @x.__send__ method, *args, &block
90
+ @_builder.__send__ method, *args, &block
91
+ elsif @_scope and @_scope.respond_to? method
92
+ @_scope.send method, *args, &block
90
93
  else
91
94
  super
92
95
  end
93
96
  end
94
97
 
98
+ def methods
99
+ result = super + Wunderbar.methods
100
+ result += SpacedMarkup.public_instance_methods
101
+ result += @_scope.methods if @_scope
102
+ result.uniq
103
+ end
104
+
105
+ def respond_to?(method)
106
+ respond true if Wunderbar.respond_to? method
107
+ respond true if SpacedMarkup.public_instance_methods.include? method
108
+ respond true if SpacedMarkup.public_instance_methods.include? method.to_s
109
+ respond true if @_scope and @_scope.respond_to? method?
110
+ super
111
+ end
112
+
95
113
  # avoid method_missing overhead for the most common case
96
114
  def tag!(sym, *args, &block)
97
115
  if !block and (args.empty? or args == [''])
98
- CssProxy.new(@x, @x.target!, sym, args)
116
+ CssProxy.new(@_builder, @_builder.target!, sym, args)
99
117
  else
100
- @x.tag! sym, *args, &block
118
+ @_builder.tag! sym, *args, &block
101
119
  end
102
120
  end
103
121
 
@@ -122,7 +140,7 @@ module Wunderbar
122
140
  stdout = output_class[:stdout] || '_stdout'
123
141
  stderr = output_class[:stderr] || '_stderr'
124
142
 
125
- @x.tag! tag, command, :class=>stdin unless opts[:echo] == false
143
+ @_builder.tag! tag, command, :class=>stdin unless opts[:echo] == false
126
144
 
127
145
  require 'thread'
128
146
  semaphore = Mutex.new
@@ -131,14 +149,18 @@ module Wunderbar
131
149
  Thread.new do
132
150
  until pout.eof?
133
151
  out_line = pout.readline.chomp
134
- semaphore.synchronize { @x.tag! tag, out_line, :class=>stdout }
152
+ semaphore.synchronize do
153
+ @_builder.tag! tag, out_line, :class=>stdout
154
+ end
135
155
  end
136
156
  end,
137
157
 
138
158
  Thread.new do
139
159
  until perr.eof?
140
160
  err_line = perr.readline.chomp
141
- semaphore.synchronize { @x.tag! tag, err_line, :class=>stderr }
161
+ semaphore.synchronize do
162
+ @_builder.tag! tag, err_line, :class=>stderr
163
+ end
142
164
  end
143
165
  end,
144
166
 
@@ -157,17 +179,12 @@ module Wunderbar
157
179
 
158
180
  # declaration (DOCTYPE, etc)
159
181
  def declare(*args)
160
- @x.declare!(*args)
182
+ @_builder.declare!(*args)
161
183
  end
162
184
 
163
185
  # comment
164
186
  def comment(*args)
165
- @x.comment! *args
166
- end
167
-
168
- # was this invoked via HTTP POST?
169
- def post?
170
- $HTTP_POST
187
+ @_builder.comment! *args
171
188
  end
172
189
  end
173
190
 
@@ -191,12 +208,14 @@ module Wunderbar
191
208
  self
192
209
  end
193
210
 
194
- # forward to either Wunderbar or @_target
211
+ # forward to Wunderbar, @_target, or @_scope
195
212
  def method_missing(method, *args, &block)
196
213
  if Wunderbar.respond_to? method
197
214
  return Wunderbar.send method, *args, &block
198
215
  elsif @_target.respond_to? method
199
216
  return @_target.send method, *args, &block
217
+ elsif @_scope and @_scope.respond_to? method
218
+ return @_scope.send method, *args, &block
200
219
  else
201
220
  super
202
221
  end
@@ -208,7 +227,8 @@ module Wunderbar
208
227
  end
209
228
 
210
229
  class JsonBuilder
211
- def initialize
230
+ def initialize(scope=nil)
231
+ @_scope = scope
212
232
  @_target = {}
213
233
  end
214
234
 
@@ -221,7 +241,7 @@ module Wunderbar
221
241
  @_target
222
242
  end
223
243
 
224
- # forward to either Wunderbar or @_target
244
+ # forward to Wunderbar, @_target, or @_scope
225
245
  def method_missing(method, *args, &block)
226
246
 
227
247
  if method.to_s =~ /^_(\w*)$/
@@ -230,6 +250,8 @@ module Wunderbar
230
250
  return Wunderbar.send method, *args, &block
231
251
  elsif @_target.respond_to? method
232
252
  return @_target.send method, *args, &block
253
+ elsif @_scope and @_scope.respond_to? method
254
+ return @_scope.send method, *args, &block
233
255
  else
234
256
  super
235
257
  end
@@ -2,18 +2,21 @@ module Wunderbar
2
2
 
3
3
  module CGI
4
4
 
5
+ HIDE_FRAME = [ %r{/(wunderbar|webrick)/},
6
+ %r{/gems/.*/(builder|rack|sinatra)/} ]
7
+
5
8
  # produce json
6
9
  def self.json(&block)
10
+ headers = { 'type' => 'application/json', 'Cache-Control' => 'no-cache' }
7
11
  builder = JsonBuilder.new
8
- output = builder.encode($param, &block)
9
- Kernel.print "Status: 404 Not Found\r\n" if output == {}
12
+ output = builder.encode($params, &block)
13
+ headers['status'] = "404 Not Found" if output == {}
10
14
  rescue Exception => exception
11
- Kernel.print "Status: 500 Internal Error\r\n"
12
15
  Wunderbar.error exception.inspect
16
+ headers['status'] = "500 Internal Server Error"
13
17
  backtrace = []
14
18
  exception.backtrace.each do |frame|
15
- next if frame =~ %r{/wunderbar/}
16
- next if frame =~ %r{/gems/.*/builder/}
19
+ next if HIDE_FRAME.any? {|re| frame =~ re}
17
20
  Wunderbar.warn " #{frame}"
18
21
  backtrace << frame
19
22
  end
@@ -21,31 +24,27 @@ module Wunderbar
21
24
  builder._exception exception.inspect
22
25
  builder._backtrace backtrace
23
26
  ensure
24
- out? 'type' => 'application/json', 'Cache-Control' => 'no-cache' do
25
- builder.target!
26
- end
27
+ out?(headers) { builder.target! }
27
28
  end
28
29
 
29
30
  # produce text
30
31
  def self.text &block
32
+ headers = {'type' => 'text/plain', 'charset' => 'UTF-8'}
31
33
  builder = TextBuilder.new
32
- output = builder.encode($param, &block)
33
- Kernel.print "Status: 404 Not Found\r\n" if output == ''
34
+ output = builder.encode($params, &block)
35
+ headers['status'] = "404 Not Found" if output == ''
34
36
  rescue Exception => exception
35
37
  Wunderbar.error exception.inspect
36
- Kernel.print "Status: 500 Internal Error\r\n"
38
+ headers['status'] = "500 Internal Server Error"
37
39
  builder.puts unless builder.size == 0
38
40
  builder.puts exception.inspect
39
41
  exception.backtrace.each do |frame|
40
- next if frame =~ %r{/wunderbar/}
41
- next if frame =~ %r{/gems/.*/builder/}
42
+ next if HIDE_FRAME.any? {|re| frame =~ re}
42
43
  Wunderbar.warn " #{frame}"
43
44
  builder.puts " #{frame}"
44
45
  end
45
46
  ensure
46
- out? 'type' => 'text/plain', 'Cache-Control' => 'no-cache' do
47
- builder.target!
48
- end
47
+ out?(headers) { builder.target! }
49
48
  end
50
49
 
51
50
  # Conditionally provide output, based on ETAG
@@ -54,8 +53,11 @@ module Wunderbar
54
53
  require 'digest/md5'
55
54
  etag = Digest::MD5.hexdigest(content)
56
55
 
57
- if ENV['HTTP_IF_NONE_MATCH'] == etag.inspect
58
- Kernel.print "Status: 304 Not Modified\r\n\r\n"
56
+ if $env.HTTP_IF_NONE_MATCH == etag.inspect
57
+ headers['Date'] = ::CGI.rfc1123_date(Time.now)
58
+ $cgi.out headers.merge('status' => '304 Not Modified') do
59
+ ''
60
+ end
59
61
  else
60
62
  $cgi.out headers.merge('Etag' => etag.inspect) do
61
63
  content
@@ -66,33 +68,30 @@ module Wunderbar
66
68
 
67
69
  # produce html/xhtml
68
70
  def self.html(*args, &block)
69
- args << {} if args.empty?
70
- if Hash === args.first
71
- args.first[:xmlns] ||= 'http://www.w3.org/1999/xhtml'
72
- end
73
- mimetype = ($XHTML ? 'application/xhtml+xml' : 'text/html')
71
+ headers = { 'type' => 'text/html', 'charset' => 'UTF-8' }
72
+ headers['type'] = 'application/xhtml+xml' if @xhtml
73
+
74
74
  x = HtmlMarkup.new
75
- x._! "\xEF\xBB\xBF"
76
- x._.declare :DOCTYPE, :html
77
75
 
78
76
  begin
79
- output = x.html *args, &block
77
+ if @xhtml
78
+ output = x.xhtml *args, &block
79
+ else
80
+ output = x.html *args, &block
81
+ end
80
82
  rescue ::Exception => exception
81
- Kernel.print "Status: 500 Internal Error\r\n"
83
+ headers['status'] = "500 Internal Server Error"
82
84
  x.clear!
83
- x._! "\xEF\xBB\xBF"
84
- x._.declare :DOCTYPE, :html
85
85
  output = x.html(*args) do
86
86
  _head do
87
- _title 'Internal Error'
87
+ _title 'Internal Server Error'
88
88
  end
89
89
  _body do
90
- _h1 'Internal Error'
90
+ _h1 'Internal Server Error'
91
91
  text = exception.inspect
92
92
  Wunderbar.error text
93
93
  exception.backtrace.each do |frame|
94
- next if frame =~ %r{/wunderbar/}
95
- next if frame =~ %r{/gems/.*/builder/}
94
+ next if HIDE_FRAME.any? {|re| frame =~ re}
96
95
  Wunderbar.warn " #{frame}"
97
96
  text += "\n #{frame}"
98
97
  end
@@ -102,10 +101,73 @@ module Wunderbar
102
101
  end
103
102
  end
104
103
 
105
- out? 'type' => mimetype, 'charset' => 'UTF-8' do
106
- output
104
+ out?(headers) { output }
105
+ end
106
+
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
113
+
114
+ # implied request types
115
+ xhr_json = Wunderbar::Options::XHR_JSON || (accept =~ /json/)
116
+ text = Wunderbar::Options::TEXT ||
117
+ (accept =~ /plain/ and accept !~ /html/)
118
+ @xhtml = (accept =~ /xhtml/ or accept == '')
119
+
120
+ # overrides via the uri query parameter
121
+ xhr_json ||= (request_uri =~ /\?json$/)
122
+ text ||= (request_uri =~ /\?text$/)
123
+
124
+ # overrides via the command line
125
+ xhtml_override = ARGV.include?('--xhtml')
126
+ html_override = ARGV.include?('--html')
127
+
128
+ # disable conneg if only one handler is provided
129
+ if Wunderbar.queue.length == 1
130
+ type = Wunderbar.queue.first.first
131
+ xhr_json = (type == :json)
132
+ text = (type == :text)
133
+ end
134
+
135
+ Wunderbar.queue.each do |type, args, block|
136
+ case type
137
+ when :html, :xhtml
138
+ unless xhr_json or text
139
+ if type == :html
140
+ @xhtml = false unless xhtml_override
141
+ else
142
+ @xhtml = false if html_override
143
+ end
144
+
145
+ self.html(*args, &block)
146
+ return
147
+ end
148
+ when :json
149
+ if xhr_json
150
+ self.json(*args, &block)
151
+ return
152
+ end
153
+ when :text
154
+ if text
155
+ self.text(*args, &block)
156
+ return
157
+ end
158
+ end
107
159
  end
108
160
  end
161
+
162
+ # map Ruby CGI headers to Rack headers
163
+ def self.headers(headers)
164
+ result = headers.dup
165
+ type = result.delete('type') || 'text/html'
166
+ charset = result.delete('charset')
167
+ type = "#{type}; charset=#{charset}" if charset
168
+ result['Content-Type'] ||= type
169
+ result
170
+ end
109
171
  end
110
172
 
111
173
  @queue = []
@@ -127,40 +189,7 @@ module Wunderbar
127
189
  @queue << [:text, args, block]
128
190
  end
129
191
 
130
- def self.evaluate
131
- queue, @queue = @queue, []
132
- xhtml = ARGV.delete('--xhtml')
133
- html = ARGV.delete('--html')
134
-
135
- queue.each do |type, args, block|
136
- case type
137
- when :html
138
- unless $XHR_JSON or $TEXT
139
- $XHTML = false unless xhtml
140
- CGI.html(*args, &block)
141
- break
142
- end
143
- when :xhtml
144
- unless $XHR_JSON or $TEXT
145
- $XHTML = false if html
146
- CGI.html(*args, &block)
147
- break
148
- end
149
- when :json
150
- if $XHR_JSON
151
- CGI.json(*args, &block)
152
- break
153
- end
154
- when :text
155
- if $TEXT
156
- CGI.text(*args, &block)
157
- break
158
- end
159
- end
160
- end
192
+ def self.queue
193
+ @queue
161
194
  end
162
195
  end
163
-
164
- at_exit do
165
- Wunderbar.evaluate
166
- end
@@ -1,46 +1,36 @@
1
1
  # explicit request types
2
- $HTTP_GET = ARGV.delete('--get')
3
- $HTTP_POST = ARGV.delete('--post')
4
- $XHR_JSON = ARGV.delete('--json')
5
- $TEXT = ARGV.delete('--text')
6
-
7
- # Only prompt if explicitly asked for
8
- ARGV.push '' if ARGV.empty?
9
- ARGV.delete('--prompt') or ARGV.delete('--offline')
10
-
11
- # standard objects
12
- $cgi = CGI.new
13
- $param = $cgi.params
14
-
15
- # implied request types
16
- $HTTP_GET ||= ($cgi.request_method == 'GET')
17
- $HTTP_POST ||= ($cgi.request_method == 'POST')
18
- $XHR_JSON ||= ($cgi.accept.to_s =~ /json/)
19
- $TEXT ||= ($cgi.accept.to_s =~ /plain/ and $cgi.accept.to_s !~ /html/)
20
- $XHTML = ($cgi.accept.to_s =~ /xhtml/ or $cgi.accept == nil)
21
-
22
- # get arguments if CGI couldn't find any...
23
- $param.merge!(CGI.parse(ARGV.join('&'))) if $param.empty?
24
-
25
2
  module Wunderbar
3
+ module Options
4
+ XHR_JSON = ARGV.delete('--json')
5
+ TEXT = ARGV.delete('--text')
6
+ end
7
+
26
8
  module Untaint
27
9
  def untaint_if_match regexp
28
10
  self.untaint if regexp.match(self)
29
11
  end
30
12
  end
31
- end
32
13
 
33
- # fast path for accessing CGI parameters
34
- def $param.method_missing(name)
35
- if has_key? name.to_s
36
- if self[name.to_s].length == 1
37
- self[name.to_s].first.extend(Wunderbar::Untaint)
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
38
22
  else
39
- self[name.to_s].join
23
+ SELF + "?" # avoids spoiling the cache
40
24
  end
41
25
  end
26
+
27
+ # was this invoked via HTTP POST?
28
+ def self.post?
29
+ $env.REQUEST_METHOD.to_s.upcase == 'POST'
30
+ end
42
31
  end
43
32
 
33
+ # environment objects
44
34
  $env = {}
45
35
  def $env.method_missing(name)
46
36
  delete name.to_s if ENV[name.to_s] != self[name.to_s]
@@ -50,32 +40,9 @@ def $env.method_missing(name)
50
40
  self[name.to_s]
51
41
  end
52
42
 
53
- # quick access to request_uri
54
- SELF = ENV['REQUEST_URI'].to_s
55
- def SELF?
56
- if SELF.include? '?'
57
- SELF
58
- else
59
- SELF + "?" # avoids spoiling the cache
60
- end
61
- end
62
-
63
- # environment objects
64
- $USER = ENV['REMOTE_USER'] || ENV['USER'] ||
65
- if RUBY_PLATFORM =~ /darwin/
66
- `dscl . -search /Users UniqueID #{Process.uid}`.split.first
67
- else
68
- `getent passwd #{Process.uid}`.split(':').first
69
- end
70
-
71
- ENV['REMOTE_USER'] ||= $USER
72
-
73
- $HOME = ENV['HOME'] ||= File.expand_path('~' + $USER)
74
- $SERVER = ENV['HTTP_HOST'] || `hostname`.chomp
75
-
76
- # more implied request types
77
- $XHR_JSON ||= ($env.REQUEST_URI.to_s =~ /\?json$/)
78
- $TEXT ||= ($env.REQUEST_URI.to_s =~ /\?text$/)
43
+ require 'socket'
44
+ $SERVER = ENV['HTTP_HOST'] || Socket::gethostname
45
+ $HOME = ENV['HOME'] ||= Dir.home() rescue nil
79
46
 
80
47
  # set encoding to UTF-8
81
48
  ENV['LANG'] ||= "en_US.UTF-8"
@@ -5,23 +5,54 @@ class HtmlMarkup
5
5
  link meta param source track wbr
6
6
  )
7
7
 
8
- def initialize(*args, &block)
9
- @x = Wunderbar::XmlMarkup.new :indent => 2, :target => []
8
+ def initialize(scope = nil)
9
+ @_scope = scope
10
+ @x = Wunderbar::XmlMarkup.new :scope => scope, :indent => 2, :target => []
11
+ @xthml = false
12
+ end
13
+
14
+ def xhtml(*args, &block)
15
+ @xhtml = true
16
+ html(*args, &block)
10
17
  end
11
18
 
12
19
  def html(*args, &block)
20
+ # default namespace
21
+ args << {} if args.empty?
22
+ args.first[:xmlns] ||= 'http://www.w3.org/1999/xhtml' if Hash === args.first
23
+
24
+ @x.text! "\xEF\xBB\xBF"
25
+ @x.declare! :DOCTYPE, :html
13
26
  @x.tag! :html, *args do
14
- $param.each do |key,value|
15
- instance_variable_set "@#{key}", value.first if key =~ /^\w+$/
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
16
32
  end
17
33
  instance_exec(@x, &block)
18
34
  end
19
35
  @x.target!.join
20
36
  end
21
37
 
38
+ def _html(*args, &block)
39
+ html(*args, &block)
40
+ end
41
+
42
+ def _xhtml(*args, &block)
43
+ @xhtml = true
44
+ html(*args, &block)
45
+ end
46
+
47
+ def xhtml?
48
+ @xhtml
49
+ end
50
+
22
51
  def method_missing(name, *args, &block)
23
52
  if name.to_s =~ /^_(\w+)(!|\?|)$/
24
53
  name, flag = $1, $2
54
+ elsif @_scope and @_scope.respond_to? name
55
+ return @_scope.__send__ name, *args, &block
25
56
  else
26
57
  error = NameError.new "undefined local variable or method `#{name}'", name
27
58
  error.set_backtrace caller
@@ -36,7 +67,7 @@ class HtmlMarkup
36
67
  if %w(script style).include?(name)
37
68
  if String === args.first and not block
38
69
  text = args.shift
39
- if $XHTML
70
+ if @xhtml
40
71
  block = Proc.new {@x.indented_text! text}
41
72
  else
42
73
  block = Proc.new {@x.indented_data! text}
@@ -82,8 +113,7 @@ class HtmlMarkup
82
113
  text = exception.inspect
83
114
  Wunderbar.warn text
84
115
  exception.backtrace.each do |frame|
85
- next if frame =~ %r{/wunderbar/}
86
- next if frame =~ %r{/gems/.*/builder/}
116
+ next if Wunderbar::CGI::HIDE_FRAME.any? {|re| frame =~ re}
87
117
  Wunderbar.warn " #{frame}"
88
118
  text += "\n #{frame}"
89
119
  end
@@ -1,3 +1,18 @@
1
+ module Wunderbar
2
+ # Extract data from the script (after __END__)
3
+ def self.data
4
+ data = DATA.read
5
+
6
+ # process argument overrides
7
+ data.scan(/^\s*([A-Z]\w*)\s*=\s*(['"]).*\2$/).each do |name, q|
8
+ override = ARGV.find {|arg| arg =~ /--#{name}=(.*)/i}
9
+ data[/^\s*#{name}\s*=\s*(.*)/,1] = $1.inspect if override
10
+ end
11
+
12
+ data
13
+ end
14
+ end
15
+
1
16
  # option to create an suexec callable wrapper
2
17
  install = ARGV.find {|arg| arg =~ /--install=(.*)/}
3
18
  if install and ARGV.delete(install)
@@ -40,17 +55,7 @@ if install and ARGV.delete(install)
40
55
  file.puts "Dir.chdir #{File.dirname(main).inspect}"
41
56
 
42
57
  # Optional data from the script (after __END__)
43
- if Object.const_defined? :DATA
44
- data = DATA.read
45
-
46
- # process argument overrides
47
- data.scan(/^\s*([A-Z]\w*)\s*=\s*(['"]).*\2$/).each do |name, q|
48
- override = ARGV.find {|arg| arg =~ /--#{name}=(.*)/}
49
- data[/^\s*#{name}\s*=\s*(.*)/,1] = $1.inspect if override
50
- end
51
-
52
- file.puts "\n#{data}\n"
53
- end
58
+ file.puts "\n#{Wunderbar.data}\n" if Object.const_defined? :DATA
54
59
 
55
60
  # Load script
56
61
  require = "require #{"./#{File.basename(main).sub(/\.rb$/,'')}".inspect}"
@@ -0,0 +1,112 @@
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')
5
+
6
+ $cgi = CGI.new
7
+
8
+ port = ARGV.find {|arg| arg =~ /--port=(.*)/}
9
+ if port and ARGV.delete(port)
10
+ port = $1.to_i
11
+
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
+ # Evaluate optional data from the script (after __END__)
35
+ eval Wunderbar.data if Object.const_defined? :DATA
36
+
37
+ # start the server
38
+ require 'rack'
39
+ require 'rack/showexceptions'
40
+ app = Rack::ShowExceptions.new(Rack::Lint.new($cgi))
41
+ Rack::Server.start :app => app, :Port => port
42
+
43
+ elsif defined? Sinatra
44
+
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
62
+
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
87
+
88
+ # allow the REQUEST_METHOD to be set for command line invocations
89
+ ENV['REQUEST_METHOD'] ||= 'POST' if ARGV.delete('--post')
90
+ ENV['REQUEST_METHOD'] ||= 'GET' if ARGV.delete('--get')
91
+
92
+ # standard objects
93
+ $params = $cgi.params
94
+
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
105
+ end
106
+ end
107
+ end
108
+
109
+ # CGI or command line
110
+ Wunderbar::CGI.call(ENV)
111
+ end
112
+ end
@@ -0,0 +1,91 @@
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
+
@@ -1,7 +1,7 @@
1
1
  module Wunderbar
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 9
4
+ MINOR = 10
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
data/lib/wunderbar.rb CHANGED
@@ -3,12 +3,13 @@ require 'builder'
3
3
  require 'json'
4
4
 
5
5
  require 'wunderbar/environment'
6
+ require 'wunderbar/builder'
6
7
  require 'wunderbar/cgi-methods'
7
8
  require 'wunderbar/cssproxy'
8
9
  require 'wunderbar/html-methods'
9
- require 'wunderbar/job-control'
10
10
  require 'wunderbar/installation'
11
- require 'wunderbar/builder'
11
+ require 'wunderbar/job-control'
12
12
  require 'wunderbar/logger'
13
+ require 'wunderbar/server'
13
14
 
14
15
  W_ = Wunderbar
data/wunderbar.gemspec CHANGED
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "wunderbar"
5
- s.version = "0.9.0"
5
+ s.version = "0.10.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-04-01"
9
+ s.date = "2012-04-07"
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/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/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"]
13
13
  s.homepage = "http://github.com/rubys/wunderbar"
14
14
  s.require_paths = ["lib"]
15
- s.rubygems_version = "1.8.15"
15
+ s.rubygems_version = "1.8.21"
16
16
  s.summary = "HTML Generator and CGI application support"
17
17
 
18
18
  if s.respond_to? :specification_version then
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: 59
4
+ hash: 55
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 9
8
+ - 10
9
9
  - 0
10
- version: 0.9.0
10
+ version: 0.10.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-01 00:00:00 Z
18
+ date: 2012-04-07 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: builder
@@ -62,6 +62,8 @@ 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
+ - lib/wunderbar/server.rb
65
67
  - lib/wunderbar/logger.rb
66
68
  - lib/wunderbar/builder.rb
67
69
  - lib/wunderbar/environment.rb
@@ -97,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
99
  requirements: []
98
100
 
99
101
  rubyforge_project:
100
- rubygems_version: 1.8.15
102
+ rubygems_version: 1.8.21
101
103
  signing_key:
102
104
  specification_version: 3
103
105
  summary: HTML Generator and CGI application support