Module: Wunderbar

Defined in:
lib/wunderbar/server.rb,
lib/wunderbar/rack.rb,
lib/wunderbar/rails.rb,
lib/wunderbar/logger.rb,
lib/wunderbar/builder.rb,
lib/wunderbar/sinatra.rb,
lib/wunderbar/version.rb,
lib/wunderbar/cssproxy.rb,
lib/wunderbar/websocket.rb,
lib/wunderbar/cgi-methods.rb,
lib/wunderbar/environment.rb,
lib/wunderbar/job-control.rb,
lib/wunderbar/html-methods.rb,
lib/wunderbar/installation.rb

Overview

Wrapper class that understands HTML

Defined Under Namespace

Modules: Options, Rails, SinatraHelpers, Template, VERSION Classes: BuilderBase, BuilderClass, CGI, Channel, CssProxy, HtmlMarkup, JsonBuilder, RackApp, Scope, SpacedMarkup, TextBuilder, XmlMarkup

Constant Summary collapse

CALLERS_TO_IGNORE =
[
  %r{/(wunderbar|webrick)/},
  %r{<internal:},
  %r{/gems/.*/lib/(builder|rack|sinatra|tilt)/}
]
@@unsafe =
false

Class Method Summary collapse

Class Method Details

.dataObject

Extract data from the script (after __END__)



3
4
5
6
7
8
9
10
11
12
13
# File 'lib/wunderbar/installation.rb', line 3

def self.data
  data = DATA.read 

  # process argument overrides
  data.scan(/^\s*([A-Z]\w*)\s*=\s*(['"]).*\2$/).each do |name, q|
    override = ARGV.find {|arg| arg =~ /--#{name}=(.*)/i}
    data[/^\s*#{name}\s*=\s*(.*)/,1] = $1.inspect if override
  end

  data
end

.debug(*args, &block) ⇒ Object

convenience methods



41
42
43
# File 'lib/wunderbar/logger.rb', line 41

def self.debug(*args, &block)
  logger.debug *args, &block
end

.error(*args, &block) ⇒ Object



53
54
55
# File 'lib/wunderbar/logger.rb', line 53

def self.error(*args, &block)
  logger.error *args, &block
end

.fatal(*args, &block) ⇒ Object



57
58
59
# File 'lib/wunderbar/logger.rb', line 57

def self.fatal(*args, &block)
  logger.fatal *args, &block
end

.html(*args, &block) ⇒ Object

canonical interface



195
196
197
# File 'lib/wunderbar/cgi-methods.rb', line 195

def self.html(*args, &block)
  @queue << [:html, args, block]
end

.info(*args, &block) ⇒ Object



45
46
47
# File 'lib/wunderbar/logger.rb', line 45

def self.info(*args, &block)
  logger.info *args, &block
end

.json(*args, &block) ⇒ Object



203
204
205
# File 'lib/wunderbar/cgi-methods.rb', line 203

def self.json(*args, &block)
  @queue << [:json, args, block]
end

.log_levelObject



32
33
34
35
36
37
38
# File 'lib/wunderbar/logger.rb', line 32

def self.log_level
  return 'debug' if logger.level == Logger::DEBUG
  return 'info'  if logger.level == Logger::INFO
  return 'warn'  if logger.level == Logger::WARN
  return 'error' if logger.level == Logger::ERROR
  return 'fatal' if logger.level == Logger::FATAL
end

.log_level=(level) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/wunderbar/logger.rb', line 18

def self.log_level=(level)
  return unless level

  case level.to_s.downcase
  when 'debug'; logger.level = Logger::DEBUG
  when 'info';  logger.level = Logger::INFO
  when 'warn';  logger.level = Logger::WARN
  when 'error'; logger.level = Logger::ERROR
  when 'fatal'; logger.level = Logger::FATAL
  else
    warn "Invalid log_level specified: #{level}"
  end
end

.loggerObject



4
5
6
7
8
9
10
11
12
# File 'lib/wunderbar/logger.rb', line 4

def self.logger
  return @logger if @logger
  @logger = Logger.new($stderr)
  @logger.level = Logger::WARN
  @logger.formatter = proc { |severity, datetime, progname, msg|
    "_#{severity} #{msg}\n"
  }
  @logger
end

.logger=(new_logger) ⇒ Object



14
15
16
# File 'lib/wunderbar/logger.rb', line 14

def self.logger= new_logger
  @logger = new_logger
end

.queueObject



211
212
213
# File 'lib/wunderbar/cgi-methods.rb', line 211

def self.queue
  @queue
end

.safe?Boolean

Returns:

  • (Boolean)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/wunderbar/environment.rb', line 14

def self.safe?
  if $SAFE == 0 and not @@unsafe
    # some gems (e.g. em-websocket-0.3.6) insert unsafe entries into the
    # path, and that prevents requires from succeeding.  If it looks like
    # we are about to make a transition to $SAFE=1, clean up that mess
    # before proceeding.
    #
    # the goal of $SAFE is not to protect us against software which was
    # installed by the owner of the site, but from injection attacks
    # contained within data provided by users of the site.
    $:.each_with_index do |path, index|
      if path.tainted?
        $:[index] = File.expand_path(path.untaint).untaint
      end
    end
  end

  not @@unsafe
end

.submit(cmd = nil) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/wunderbar/job-control.rb', line 3

def self.submit(cmd=nil)
  fork do
    # detach from tty
    Process.setsid
    fork and exit

    # clear working directory and mask
    Dir.chdir '/'
    File.umask 0000

    # close open files
    STDIN.reopen '/dev/null'
    STDOUT.reopen '/dev/null', 'a'
    STDERR.reopen STDOUT

    # clear environment of cgi cruft
    require 'cgi'
    ENV.keys.select {|key| key =~ /^HTTP_/}.each do |key|
      ENV.delete key.dup.untaint
    end
    ::CGI::QueryExtension.public_instance_methods.each do |method|
      ENV.delete method.to_s.upcase
    end

    # setup environment
    ENV['USER'] ||= $USER
    ENV['HOME'] ||= $HOME

    # run cmd and/or block
    system cmd if cmd
    yield if block_given?
  end
end

.text(*args, &block) ⇒ Object



207
208
209
# File 'lib/wunderbar/cgi-methods.rb', line 207

def self.text(*args, &block)
  @queue << [:text, args, block]
end

.unsafe!(mode = true) ⇒ Object



10
11
12
# File 'lib/wunderbar/environment.rb', line 10

def self.unsafe!(mode=true)
  @@unsafe=mode
end

.warn(*args, &block) ⇒ Object



49
50
51
# File 'lib/wunderbar/logger.rb', line 49

def self.warn(*args, &block)
  logger.warn *args, &block
end

.websocket(opts = {}, &block) ⇒ Object



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/wunderbar/websocket.rb', line 175

def self.websocket(opts={}, &block)
  opts = {:port => opts} if Fixnum === opts
  port = opts[:port]
  buffer = opts.fetch(:buffer,1)

  if not port
    socket = TCPServer.new(0)
    port = Socket.unpack_sockaddr_in(socket.getsockname).first
    socket.close
  end

  sock1 = nil

  proc = Proc.new do
    begin
      channel = Wunderbar::Channel.new(port, buffer, opts[:locals])
      if sock1
        sock1.send('x',0)
        sock1.close
      end
      channel.instance_eval &block
    rescue Exception => exception
      channel._ :type=>:stderr, :line=>exception.inspect
      exception.backtrace.each do |frame| 
        next if Wunderbar::CALLERS_TO_IGNORE.any? {|re| frame =~ re}
        channel._ :type=>:stderr, :line=>"  #{frame}"
      end
    ensure
      if channel
        channel.complete = true
        sleep 5
        sleep 60 unless channel.connected or opts[:sync]
        channel.close
      end
    end
  end

  if opts[:sync]
    instance_eval &proc
  else
    sock1, sock2 = UNIXSocket.pair
    submit &proc
    sleep 0.3 while sock2.recv(1) != 'x'
    sock2.close
  end

  port
end

.xhtml(*args, &block) ⇒ Object



199
200
201
# File 'lib/wunderbar/cgi-methods.rb', line 199

def self.xhtml(*args, &block)
  @queue << [:xhtml, args, block]
end