Top Level Namespace

Defined Under Namespace

Modules: Book, Gorp Classes: HTMLRunner, String

Instance Method Summary collapse

Instance Method Details

#cmd(args, hilight = []) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/gorp.rb', line 84

def cmd args, hilight=[]
  log :cmd, args
  $x.pre args, :class=>'stdin'
  if args == 'rake db:migrate'
    Dir.chdir 'db/migrate' do
      date = '20080601000000'
      Dir['[0-9]*'].sort_by {|file| file=~/2008/?file:'x'+file}.each do |file|
        file =~ /^([0-9]*)_(.*)$/
        FileUtils.mv file, "#{date}_#{$2}" unless $1 == date.next!
        $x.pre "mv #{file} #{date}_#{$2}"  unless $1 == date
      end
    end
  end
  popen3 args, hilight
end

#console(script) ⇒ Object



80
81
82
# File 'lib/gorp.rb', line 80

def console script
  cmd "echo #{script.inspect} | ruby script/console '--irb=irb -f'"
end

#db(statement, hilight = []) ⇒ Object



69
70
71
72
73
74
# File 'lib/gorp.rb', line 69

def db statement, hilight=[]
  log :db, statement
  $x.pre "sqlite3> #{statement}", :class=>'stdin'
  cmd = "sqlite3 --line db/development.sqlite3 #{statement.inspect}"
  popen3 cmd, hilight
end

#desc(message) ⇒ Object



52
53
54
# File 'lib/gorp.rb', line 52

def desc message
  $x.p message, :class=>'desc'
end

#edit(filename, tag = nil) ⇒ Object



164
165
166
167
168
169
170
171
172
173
174
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
# File 'lib/gorp.rb', line 164

def edit filename, tag=nil
  log :edit, filename
  $x.pre "edit #{filename}", :class=>'stdin'

  stale = File.mtime(filename) rescue Time.now-2
  data = open(filename) {|file| file.read} rescue ''
  before = data.split("\n")

  begin
    yield data
    open(filename,'w') {|file| file.write data}
    File.utime(stale+2, stale+2, filename) if File.mtime(filename) <= stale

  rescue Exception => e
    $x.pre :class => 'traceback' do
      STDERR.puts e.inspect
      $x.text! "#{e.inspect}\n"
      e.backtrace.each {|line| $x.text! "  #{line}\n"}
    end
    tag = nil

  ensure
    include = tag.nil?
    hilight = false
    data.split("\n").each do |line|
      if line =~ /START:(\w+)/
        include = true if $1 == tag
      elsif line =~ /END:(\w+)/
        include = false if $1 == tag
      elsif line =~ /START_HIGHLIGHT/
        hilight = true
      elsif line =~ /END_HIGHLIGHT/
        hilight = false
      elsif include
        if hilight or ! before.include?(line)
          outclass='hilight'
        else
          outclass='stdout'
        end

        if line.empty?
          $x.pre ' ', :class=>outclass
        else
          $x.pre line, :class=>outclass
        end
      end
    end
  end
end

#get(path) ⇒ Object



374
375
376
# File 'lib/gorp.rb', line 374

def get path
  post path, {}
end

#head(number, title) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/gorp.rb', line 61

def head number, title
  text = "#{number} #{title}"
  log '====>', text

  $x.a(:class => 'toc', :name => "section-#{number}") {$x.h2 text}
  $toc.li {$toc.a text, :href => "#section-#{number}"}
end

#irb(file) ⇒ Object



127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/gorp.rb', line 127

def irb file
  $x.pre "irb #{file}", :class=>'stdin'
  log :irb, file
  cmd = "irb -f -rubygems -r ./config/boot --prompt-mode simple #{$CODE}/#{file}"
  Open3.popen3(cmd) do |pin, pout, perr|
    terr = Thread.new do
      $x.pre perr.readline.chomp, :class=>'stderr' until perr.eof?
    end
    pin.close
    prompt = nil
    until pout.eof?
      line = pout.readline
      if line =~ /^([?>]>)\s*#\s*(START|END):/
        prompt = $1
      elsif line =~ /^([?>]>)\s+$/
        $x.pre ' ', :class=>'irb'
        prompt ||= $1
      elsif line =~ /^([?>]>)(.*)\n/
        prompt ||= $1
        $x.pre prompt + $2, :class=>'irb'
	prompt = nil
      elsif line =~ /^\w+(::\w+)*: /
        $x.pre line.chomp, :class=>'stderr'
      elsif line =~ /^\s+from [\/.:].*:\d+:in `\w.*'\s*$/
        $x.pre line.chomp, :class=>'stderr'
      elsif line =~ /\x1b\[\d/
        line.gsub! /\x1b\[4(;\d+)*m(.*?)\x1b\[0m/, '\2'
        line.gsub! /\x1b\[0(;\d+)*m(.*?)\x1b\[0m/, '\2'
        $x.pre line.chomp, :class=>'logger'
      else
        $x.pre line.chomp, :class=>'stdout'
      end
    end
    terr.join
  end
end

#log(type, message) ⇒ Object



56
57
58
59
# File 'lib/gorp.rb', line 56

def log type, message
  type = type.to_s.ljust(5).upcase
  STDOUT.puts Time.now.strftime("[%Y-%m-%d %H:%M:%S] #{type} #{message}")
end

#overview(message) ⇒ Object



48
49
50
# File 'lib/gorp.rb', line 48

def overview message
  $x.p message.gsub(/(^|\n)\s+/, ' ').strip, :class=>'overview'
end

#popen3(args, hilight = []) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/gorp.rb', line 100

def popen3 args, hilight=[]
  Open3.popen3(args) do |pin, pout, perr|
    terr = Thread.new do
      $x.pre perr.readline.chomp, :class=>'stderr' until perr.eof?
    end
    pin.close
    until pout.eof?
      line = pout.readline
      if hilight.any? {|pattern| line.include? pattern}
        outclass='hilight'
      elsif line =~ /\x1b\[\d/
        line.gsub! /\x1b\[1m\x1b\[3\dm(.*?)\x1b\[0m/, '\1'
        outclass = 'logger'
      else
        outclass='stdout'
      end

      if line.strip.size == 0
        $x.pre ' ', :class=>outclass
      else
        $x.pre line.chomp, :class=>outclass
      end
    end
    terr.join
  end
end

#post(path, form) ⇒ Object



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/gorp.rb', line 378

def post path, form
  $x.pre "get #{path}", :class=>'stdin'

  if path.include? ':'
    host, port, path = URI.parse(path).select(:host, :port, :path)
  else
    host, port = '127.0.0.1', 3000
  end

  Net::HTTP.start(host, port) do |http|
    get = Net::HTTP::Get.new(path)
    get['Cookie'] = $COOKIE if $COOKIE
    response = http.request(get)
    snap response, form
    $COOKIE = response.response['set-cookie'] if response.response['set-cookie']

    if ! form.empty?
      body = xhtmlparse(response.body).at('//body')
      body = xhtmlparse(response.body).root unless body
      xform = body.at('//form[.//input[@name="commit"]]')
      return unless xform
      path = xform.attribute('action').to_s unless
        xform.attribute('action').to_s.empty?
      $x.pre "post #{path}", :class=>'stdin'

      $x.ul do
        form.each do |name, value|
          $x.li "#{name} => #{value}"
        end
      end

      body.search('//input[@type="hidden"]').each do |element|
        form[element['name']] ||= element['value']
      end

      post = Net::HTTP::Post.new(path)
      post.form_data = form
      post['Cookie'] = $COOKIE
      response=http.request(post)
      snap response
    end

    if response.code == '302'
      path = response['Location']
      $x.pre "get #{path}", :class=>'stdin'
      get = Net::HTTP::Get.new(path)
      get['Cookie'] = $COOKIE if $COOKIE
      response = http.request(get)
      snap response
    end
  end
end

#rails(name, app = nil) ⇒ Object



453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
# File 'lib/gorp.rb', line 453

def rails name, app=nil
  Dir.chdir($WORK)
  FileUtils.rm_rf name
  log :rails, name

  # determine how to invoke rails
  rails = which_rails $rails

  $x.pre "#{rails} #{name}", :class=>'stdin'
  popen3 "#{rails} #{name}"

  # make paths seem Mac OSX'ish
  Dir["#{name}/public/dispatch.*"].each do |dispatch|
    code = open(dispatch) {|file| file.read}
    code.sub! /^#!.*/, '#!/opt/local/bin/ruby'
    open(dispatch,'w') {|file| file.write code}
  end

  Dir.chdir(name)
  FileUtils.rm_rf 'public/.htaccess'

  cmd 'rake rails:freeze:edge' if ARGV.include? 'edge'

  if $rails != 'rails' and File.directory?($rails)
    cmd "ln -s #{$rails} vendor/rails"
  end
end

#read(name) ⇒ Object



44
45
46
# File 'lib/gorp.rb', line 44

def read name
  open(File.join($DATA, name)) {|file| file.read}
end

#restart_serverObject



481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
# File 'lib/gorp.rb', line 481

def restart_server
  log :server, 'restart'
  if $server
    $x.h3 'Restart the server.'
    Process.kill "INT", $server
    Process.wait($server)
  else
    $x.h3 'Start the server.'
  end

  $server = fork
  if $server
    # wait for server to start
    60.times do
      sleep 0.5
      begin
        status = Net::HTTP.get_response('localhost','/',3000).code
        break if %(200 404).include? status
      rescue Errno::ECONNREFUSED
      end
    end
  else
    begin
      if File.exist?('config.ru')
        require 'rack'
        server = Rack::Builder.new {eval open('config.ru').read}
        Rack::Handler::WEBrick.run(server, :Port => 3000)
      else
        # start server, redirecting stdout to a string
        $stdout = StringIO.open('','w')
        require './config/boot'
        if Rails::VERSION::MAJOR == 2
          require 'commands/server'
        else
          require 'rails/commands/server'
        end
      end
    rescue 
      STDERR.puts $!
      $!.backtrace.each {|method| STDERR.puts "\tfrom " + method}
    ensure
      Process.exit!
    end
  end
end

#ruby(args) ⇒ Object



76
77
78
# File 'lib/gorp.rb', line 76

def ruby args
  cmd "ruby #{args}"
end

#secsplit(section) ⇒ Object



527
528
529
# File 'lib/gorp.rb', line 527

def secsplit section
  section.to_s.split('.').map {|n| n.to_i}
end

#section(number, title, &steps) ⇒ Object



17
18
19
20
# File 'lib/gorp.rb', line 17

def section number, title, &steps
  number = (sprintf "%f", number).sub(/0+$/,'') if number.kind_of? Float
  $sections << [number, title, steps]
end

#snap(response, form = {}) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
# File 'lib/gorp.rb', line 304

def snap response, form={}
  if response.content_type == 'text/plain' or response.content_type =~ /xml/
    $x.div :class => 'body' do
      response.body.split("\n").each do |line| 
        $x.pre line.chomp, :class=>'stdout'
      end
    end
    return
  end

  if response.body =~ /<body/
    body = response.body
  else
    body = "<body>#{response.body}</body>"
  end

  begin
    doc = xhtmlparse(body)
  rescue
    body.split("\n").each {|line| $x.pre line.chomp, :class=>'hilight'}
    raise
  end

  title = doc.at('html/head/title').text rescue ''
  body = doc.at('//body')
  doc.search('//link[@rel="stylesheet"]').each do |sheet|
    body.children.first.add_previous_sibling(sheet)
  end

  if ! form.empty?
    body.search('//input[@name]').each do |input|
      input['value'] ||= form[input['name']].to_s
    end
    body.search('//textarea[@name]').each do |textarea|
      textarea.text ||= form[textarea['name']].to_s
    end
  end

  %w{ a[@href] form[@action] }.each do |xpath|
    name = xpath[/@(\w+)/,1]
    body.search("//#{xpath}").each do |element|
      next if element[name] =~ /^http:\/\//
      element[name] = URI.join('http://localhost:3000/', element[name]).to_s
    end
  end

  %w{ img[@src] }.each do |xpath|
    name = xpath[/@(\w+)/,1]
    body.search("//#{xpath}").each do |element|
      if element[name][0] == ?/
        element[name] = 'data' + element[name]
      end
    end
  end

  body.search('//textarea').each do |element|
    element.content=''
  end

  attrs = {:class => 'body', :title => title}
  attrs[:class] = 'traceback' if response.code == '500'
  attrs[:id] = body['id'] if body['id']
  $x.div(attrs) do
    body.children.each do |child|
      $x << child.serialize unless child.instance_of?(Comment)
    end
  end
  $x.div :style => "clear: both"
end

#which_rails(rails) ⇒ Object



443
444
445
446
447
448
449
450
451
# File 'lib/gorp.rb', line 443

def which_rails rails
  railties = File.join(rails, 'railties', 'bin', 'rails')
  rails = railties if File.exists?(railties)
  if File.exists?(rails)
    firstline = open(rails) {|file| file.readlines.first}
    rails = 'ruby ' + rails unless firstline =~ /^#!/
  end
  rails
end