Viking's Ruby Snippets

Here's some Ruby snippets I've written or found. Some of these are here to help me remember how to do certain things, and others are here for no good reason at all.

Simple Buffer

Here's a buffer class I whipped up:

class Buffer
  include Enumerable

  attr_reader :length
  def initialize(capacity)
    @buffer = Array.new(capacity)
    @capa   = capacity
    @length = 0
  end

  def <<(value)
    raise "buffer is full"  if full?
    @buffer[@length] = value
    @length += 1
    self
  end

  def each(&block)
    @buffer[0, @length].each(&block)
  end

  def full?
    @length == @capa
  end

  def flush!
    @length = 0
  end
end

Flickr Interesting Photos

Here's a little script I wrote that downloads some of the latest interesting photos from Flickr, crops them, scales them, and sets them as your KDE desktop. It's set up for 6 desktops and 1280x1024 resolution. You can change that by using the variables at the top of the script.

Requirements: imagemagick, xmlsimple (gem)

» Download

A better version of this can be found here: http://github.com/viking/kawalla

Module Class Methods

I forget how to do this a lot, so here's an example:

module Foo
  module ClassMethods
    def junk
      "junk"
    end
  end

  def self.included(klass)
    klass.extend(ClassMethods)
  end
end

class Bar
  include Foo
end

Bar.junk  #=> "junk"

Sudoku Solver

I wrote this sudoku solver during a long road trip because I got frustrated with a sudoku puzzle I was working on.

class Board
  class Space
    attr_accessor :value
    def initialize(value)
      @value = value
    end

    def empty?
      @value == 0
    end

    def to_s
      empty? ? " " : @value.to_s
    end
    alias :inspect :to_s

    def <=>(oth)
      @value <=> oth.value
    end
  end

  ROWS    = (0..8).collect { |i| Array.new(9) { |j| i*9 + j } }
  COLUMNS = (0..8).collect { |i| Array.new(9) { |j| j*9 + i } }
  BOXES   = (0..8).collect do |i|
    j = 27 * (i / 3) + 3 * (i % 3) # first row offset
    k = j + 9   # second row offset
    l = k + 9   # third row offset
    [j, j+1, j+2, k, k+1, k+2, l, l+1, l+2]
  end

  attr_reader :spaces
  def initialize(spaces)
    raise unless spaces.length == 81
    @spaces = spaces.collect { |s| s.is_a?(Space) ? s : Space.new(s) }
  end

  def row(index)
    @spaces.values_at(*ROWS[index])
  end

  def column(index)
    @spaces.values_at(*COLUMNS[index])
  end

  def box(index)
    @spaces.values_at(*BOXES[index])
  end

  def empty_spaces
    empties = []
    @spaces.length.times do |i|
      empties << i  if @spaces[i].empty?
    end
    empties
  end

  def clone
    Board.new(@spaces.collect { |s| s.dup })
  end

  def valid?
    [:row, :column, :box].collect do |method|
      return false unless (0..8).collect { |i|
        set = send(method, i).select { |x| !x.empty? }
        set.collect! { |x| x.value }
        set.uniq == set
      }.all?
    end
    true
  end

  def complete?
    @spaces.collect { |s| !s.empty? }.all? && valid?
  end

  def to_s
    str = ""
    9.times do |i|
      row = row(i)
      str << "+-------" * 3 + "+\n"   if i % 3 == 0
      3.times { |j| str << "| %s %s %s " % row[(j*3)..(j*3+2)] }
      str << "|\n"
    end
    str + "+-------" * 3 + "+"
  end
end

class Solver
  def initialize(board)
    @board = board.clone
  end

  def solve
    empties = @board.empty_spaces
    empties.each_with_index do |space_i, i|
      (1..9).each do |j|
        @board.spaces[space_i].value = j
        next  unless @board.valid?
        return @board  if i == empties.length - 1
        b = Solver.new(@board).solve
        return b  if b
      end
    end
    nil
  end
end

board = Board.new([
  3,0,4,5,0,8,0,0,7,
  9,8,2,7,4,6,1,3,5,
  5,0,7,0,0,9,8,0,4,
  8,4,0,9,0,5,6,7,0,
  1,7,0,0,6,4,0,0,8,
  6,2,0,0,8,7,4,0,0,
  2,9,0,8,5,0,7,4,0,
  7,3,0,4,9,0,5,8,0,
  4,5,8,6,7,0,0,0,0
])
#puts "row 2"
#p board.row(2)
#puts "column 2"
#p board.column(2)
#puts "box 0"
#p board.box(0)
#puts "box 4"
#p board.box(4)
#puts "box 7"
#p board.box(7)
puts "======================"
puts board.to_s
puts "======================"
puts Solver.new(board).solve.to_s

» Download

Bash Progress Meter

class Progress
  RESET = "\r\e[0K"

  def initialize(total, increment = 1, total_steps = 50)
    @total = total.to_f
    @count = 0
    @increment = increment
    @total_steps = total_steps.to_i
  end

  def next
    return  if done?
    @count += @increment
    draw
  end

  def done?
    @count >= @total
  end

  def reset!
    @count = 0
  end

  private
    def draw
      perc  = @count / @total
      steps = (perc * @total_steps).round
      left  = @total_steps - steps

      print "%s[%s>%s] %.2f%" % [RESET, "=" * steps, "_" * left, perc * 100.0]
      $stdout.flush
      puts  if done?
    end
end

x = Progress.new(1000)
while (!x.done?) do
  x.next
  sleep(0.01)
end

Based on ideas from http://snippets.dzone.com/posts/show/3760

Normalizing mp3's

Here's a script to normalize mp3's. sox with mp3 encoding support and the id3lib-ruby rubygem is required.

#!/usr/bin/ruby
require 'rubygems'
require 'id3lib'

targetdir = `mktemp -d`.chomp
puts "Target directory: #{targetdir}"
Dir["*.mp3"].each do |file|
  print "Normalizing #{file}..."
  $stdout.flush

  file2  = file.gsub(/'/, "\\'")
  adjust = %x{sox '#{file2}' -e stat -v 2>&1}.chomp.to_f
  if adjust < 1.01
    puts "not done."
    next
  end
  adjust -= 0.01
  afile   = "#{targetdir}/#{file}"
  afile2  = afile.gsub(/'/, "\\'")
  %x{sox -v #{adjust} '#{file2}' '#{afile2}'}

  # assign id3 tags
  tag  = ID3Lib::Tag.new(file)
  atag = ID3Lib::Tag.new(afile)
  tag.each { |frame| atag << frame.dup }
  atag.update!

  puts "done (#{adjust})."
end

IRB echo

To turn off IRB's echo of return values, do this: conf.return_format = ""

Here's a function in ~/.irbrc to turn it off and on easily:

def echo(bool)
  val = case bool
    when Symbol
      if bool == :on
        true
      else
        false
      end
    else
    bool
  end
  conf.return_format = val ? "=> %s\n" : ""
end

Using Proc's in Case Statements

Someone asked about this in #ruby-lang. I came up with this solution:

class Foo
  def good?
    true
  end
end

class Proc
  alias :orig_eql :===
  def ===(other)
    if other.is_a?(Foo)
      call(other)
    else
      orig_eql(other)
    end
  end
end

f = Foo.new
case f
when proc { |x| x.good? }
  puts "yay"
end

Other Bits of Code

A neat way to calculate number of duplications in an array (rickdangerous from #ruby-lang):

a = [1,1,1,1,2,2,2,3,3,3,4,5,5,6]
res = []; a.uniq.each {|x| res << [x, a.size - [a.delete(x), a.size][1]]}

My version:

a.inject(a.uniq.collect{|x| [x, 0]}) {|arr, x| arr.assoc(x)[1] += 1; arr}

Leet Abbreviation Goodness Stuff

Rails Stuff

Generating fixtures from existing data

Something like this (although this is a specific issue):

template = ERB.new(<<EOF)
two_<%= field %><%= suffix %>:
  patient:    two
  field_name: <%= field %>
  reason:     <%= reason %>
  status:     todo
  created_at: <%%= Time.now.to_s :db %>
  updated_at: <%%= Time.now.to_s :db %>
EOF

hsh = Patient.find(:first, :order => "id desc").problem_hash
hsh.keys.sort.each do |field|
  probs = hsh[field]
  probs.each_with_index do |problem, i|
    reason = problem.reason
    suffix = probs.length > 1 ? "_#{i}": ""
    puts template.result(binding)
  end
end

DRY database.yml

I always forget how to write DRY YAML, so here it is for reference:

login: &login
  adapter: mysql
  encoding: utf8
  username: foo
  password: bar
  socket: /var/run/mysqld/mysqld.sock

development:
  database: foo_dev
  <<: *login

test:
  database: foo_test
  <<: *login

production:
  database: foo
  <<: *login

Development Script

I wrote a script to set up Konsole with several tabs for developing Ruby on Rails applications. It assumes your Rails apps are in ~/rails, but you can change it via the RailsDev::BASEDIR constant. You also need the korundum library (ubuntu package is libkorundum0-ruby1.8). It randomly chooses a port for Webrick to use on a per-application basis. That way each application will run its server on a unique port, so you can set up separate saved passwords in Firefox without conflicting with other app's saved passwords, etc. Ain't Ruby fun? You can tweak the .railsdevrc file in your home area to change tab setup. Here is an example configuration file.

ALERT! If the script segfaults, it's probably the korundum package's fault. Download the korundum source and build it yourself.

» Download

Topic attachments
I Attachment Action Size Date Who Comment
flickr.rbrb flickr.rb manage 2.4 K 11 Apr 2008 - 14:00 JeremyStephens Flickr script
rails_dev.rbrb rails_dev.rb manage 7.5 K 03 Jan 2008 - 09:07 JeremyStephens Rails development script
railsdevrcEXT railsdevrc manage 0.7 K 03 Jan 2008 - 09:08 JeremyStephens Example Rails development configuration
sudoku_solver.rbrb sudoku_solver.rb manage 2.6 K 03 Jan 2008 - 09:23 JeremyStephens Sudoku solver script
Topic revision: r7 - 31 Mar 2010, JeremyStephens
 

This site is powered by FoswikiCopyright © 2013-2017 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Vanderbilt Biostatistics Wiki? Send feedback