Ruby expect alternative, responding to commandline interfaces

A small snippet to interact with commandline applications that ask questions on stdin, particularly useful for testing.

Usage

interact "rails new foo -m template.rb", /RSpec/ => 'y', /MySql/ => 'n'

Code

 # https://gist.github.com/2166521
 # capture commandline output and send responses if nothing was read
  def interact(command, answers)
    puts command
    line = ""
    write = false

    PTY.spawn(command) do |output, input, pid|
      loop do
        rs, ws, = IO.select([output], [input])

        # read into the buffer
        if r = rs[0]
          write = false
          ret = r.read(1)
          print ret

          return unless ret

          line << ret
          line = "" if ret == "\n"
        end

        # time to write ?
        if w = ws[0]
          if write and line != ""
            text = line.gsub(/\e\[\d+m/,'').strip
            answer = answers.detect do |question, answer|
              text =~ question
            end || raise("Question #{text.inspect} has no answer!")
            w.write(answer.last + "\n")
            line = ""
          else
            write = true
          end
        end
      end
    end
    $?.success?
  end

Moving config mess from environment files to config.yml

If your environments/*.rb look like a repetitive mess, its time to get a config.yml!

  • overview of your configuration
  • dry code
  • (optional) not check in all the passwords/keys of your app (only check in config.example.yml), great for open-source apps
  • Can be loaded without loading the environment (e.g. small rake tasks)
# lib/cfg.rb
CFG = YAML.load(ERB.new(
  File.read("config/config.yml")
).result)[Rails.env].with_indifferent_access

# config/application.rb
require "cfg"

# config/config.yml
common: &common
  api:
    airbrake_key: xxx
    google_analytics_key: yyy
  admin_email: admin@example.com

test:
  <<: *common
  host: 'localhost'

development:
  <<: *common
  host: 'localhost'

production:
  <<: *common
  host: 'fuu.bar'

# config/application.rb
config.action_mailer.default_url_options = {:host => CFG[:host]}

vpn-fuse aka kill this app when vpn fails

Lets say you are running something over VPN,
and VPN suddenly fails, then this will kill the app you dont want to connect via the normal interface.

Its just a small ruby script you can put into e.g. /usr/bin/

vpn-fuse VpnName 'killall secret-app'
vpn-fuse BankNetwork 'killall bank-client'
vpn-fuse iPredator 'killall transmission-gtk'
...

so far only tested on Ubuntu…

vpn-fuse