wunderbar 0.9.0 → 0.10.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 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