ruby snippets

Capistrano 2 task for backing up your MySQL production database before each deployment

Tagged ruby, rails, backup, mysql, capistrano  Languages ruby

This Capistrano task connects to your production database and dumps the contents to a file. The file is compressed and put in a directory specified with set :backup_dir, "#{deploy_to}/backups". This is a slight modification of http://pastie.caboo.se/42574. All credit to court3nay.

task :backup, :roles => :db, :only => { :primary => true } do
  filename = "#{backup_dir}/#{application}.dump.#{Time.now.to_f}.sql.bz2"
  text = capture "cat #{deploy_to}/current/config/database.yml"
  yaml = YAML::load(text)

  on_rollback { run "rm #{filename}" }
  run "mysqldump -u #{yaml['production']['username']} -p #{yaml['production']['database']} | bzip2 -c > #{filename}" do |ch, stream, out|
    ch.send_data "#{yaml['production']['password']}\n" if out =~ /^Enter password:/
  end
end

To automatically backup your data before you deploy a new version add this to config/deploy.rb:

task :before_deploy do
    backup
  end

To restore the backup run the following command:

mysql database_name -uroot < filename.sql

Find the installation directory of a RubyGem package programmatically

Tagged gem, ruby, rubygems, path, package  Languages ruby

This snippet prints the full path to the Rails installation directory--the path is retrieved using the RubyGems API:

require 'rubygems'
puts Gem.cache.search('rails').first.full_gem_path
# Specify version number
puts Gem.cache.search('rails', '=1.0.0').first.full_gem_path

Example output:

/usr/lib/ruby/gems/1.8/gems/rails-1.0.0

To find the directory where your gems are hiding, use:

gem env

There's also the gem which command:

$ gem which activesupport
(checking gem activesupport-2.3.2 for activesupport)
/opt/ruby-enterprise-1.8.6-20090201/lib/ruby/gems/1.8/gems/activesupport-2.3.2/lib/activesupport.rb

How to use Rails helpers from controllers, models, anywhere

Tagged url_for, helpers, ruby, rails, template, link_to  Languages ruby

How to use e.g. url_for where you need it, not where you’ve been told to use it:

Rails 4

ActionController::Base.helpers.escape_javascript(text)
ActionController::Base.helpers.image_path(path)

Rails 3

class URLHelper
  include Singleton
  include ActionDispatch::Routing::UrlFor
  include Rails.application.routes.url_helpers
end

Rails 1-2.x

Use this snippet if you need to use one of the many Rails helpers in controllers or elsewhere:

class Helpers
    include Singleton
    include ActionView::Helpers::TextHelper
    include ActionView::Helpers::UrlHelper
    include ActionView::Helpers::DateHelper
    include ActionView::Helpers::TagHelper
    include ActionView::Helpers::ActiveRecordHelper
end

Console

You can test named routes in the console through the app object:

app.get '/'
# Named route
app.image_path Image.first

Usage

For example, to obfuscate email use the mail_to helper and set the encoding to JavaScript:

Helpers.instance.mail_to "me@domain.com", "My email", :encode => "javascript"

In Rails controllers there's no need to do anything, simply use the template instance to call helpers:

def index
   @template.link_to x, x.title
end

Troubleshooting

If you get this error:

Missing host to link to! Please provide :host parameter or set default_url_options[:host]

Fix it by specifying the host:

URLHelper.default_url_options[:host] = 'xxx.com'

Generate a TOC for a textile file

Tagged ruby, toc generation, textile, redcloth  Languages ruby

Takes a textile document as input (reads from a file) and generates a TOC (Table Of Contents) for it. The resulting output is a complete HTML document with the TOC and your document integrated. Requires Redcloth. Usage:

ruby ./textile_to_html_with_toc.rb my_textile_document.tex > my_textile_document.html

NOTE: Does not work with direct copy & paste because of a problem of correctly displaying the escaping quotes of the here document.

#!/usr/bin/env ruby
# author: marko dot haapala at aktagon dot com
# idea taken from here: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/134005
require "rubygems"
require "redcloth"

def generate_toc (file_name, headreg)
    document = IO.read(file_name)
    toc = "" 
    document.gsub(headreg) do |match|
        number = $1
        name = $2
        header = name.gsub(/\s/,"+")
        toc << '#' * number.to_i + ' "' + name + '":#' + header + "\n"
    end
    RedCloth.new(toc).to_html
end

def manipulate_body(file_name, headreg)
    document = IO.read(file_name)
    document.gsub!(headreg) do |match|
        number = $1
        name = $2
        header = name.gsub(/\s/,"+")
        "\nh" + number + '. <a name="' + header + '">' + name + '</a>'
    end
    RedCloth.new(document).to_html
end

if ARGV[0] == nil 
    puts "Oh no! You didn't give me a filename :(" 
    exit 1
end

file_name = ARGV[0]
headreg = /^\s*h([1-6])\.\s+(.*)/
toc = generate_toc(file_name, headreg)
body = manipulate_body(file_name, headreg)
template = <<-'EOF'
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">
<html xml:lang=\"en\" lang=\"en\" xmlns=\"http://www.w3.org/1999/xhtml\">
    <head>
        <title>#{file_name}</title>
        <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=ISO-8859-1\">
        <link rel=stylesheet href=\"style.css\" type=\"text/css\">
    </head>
    <body>
        #{toc}
        #{body}
    </body>
</html>
EOF
puts eval("\"" + template + "\"")

Solution to "require': no such file to load -- readline (LoadError)" problem

Tagged ruby, readline, console, compile  Languages bash

If you've compiled Ruby from source, you might get this error when executing script/console:

/usr/local/lib/ruby/1.8/irb/completion.rb:10:in require': no such file to load -- readline (LoadError)

One way of fixing this is to compile readline, which is distributed along with the Ruby source:

cd /opt/src/ruby-1.8.5-p2/ext/readline
ruby extconf.rb
make
sudo make install

This works even after compiling Ruby, so no need to recompile... If you're wondering what readline is then this quote from the project homepage sums it up in one sentence: "The GNU Readline library provides a set of functions for use by applications that allow users to edit command lines as they are typed in."

Syntax highlighting code with Ruby and Ultraviolet

Tagged ultraviolet, ruby, themes  Languages ruby

This site uses Ultraviolet for syntax highlighting. Ultraviolet supports 50 languages and 20 themes, so it's sometimes difficult to pick the best theme, which is why I created the following code snippet that renders the code in all available themes and creates an HTML page displaying them all:

require 'uv'

language      = ARGV[1]
input_file    = ARGV[0]
line_numbers  = true
output_format = "xhtml"

input = File.read(input_file)

# Render input using all available themes
syntax_highlighted_code = ""
Uv.themes.each do |theme|
  syntax_highlighted_code << "<h2>#{theme}</h2>"
  syntax_highlighted_code << Uv.parse( input, output_format, language, line_numbers, theme)
end

# Template for output file
page_template = <<HTML_DOC
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>
        <head>
        <title>test</title>
    #{Uv.themes.map{|theme| %Q(<link rel="stylesheet" type="text/css" href="css/#{theme}.css" />\n)}}
                <script type="text/javascript" src=""></script>
                <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
        </head>
        <body>
  #{syntax_highlighted_code}
        </body>
</html>
HTML_DOC

# Write highlighted text to output
File.open("output.html", "w") do |file|
  file << page_template
end

Yes, using ERB templates would be better but interpolated strings work just fine... Save the code in highlight.rb and run it as follows:

highlight.rb ruby input_file.rb

Installing Ultraviolet and Oniguruma

Tagged onigurama, ultraviolet, ruby, ubuntu, install, oniguruma  Languages bash

First install Oniguruma

Oniguruma is a regular expression engine that Ultraviolet uses to parse text; Ruby also uses Oniguruma by the way. If you don't have Oniguruma on your system you'll get this error while installing Ultraviolet (at least on Ubuntu Linux):

oregexp.c:2:23: error: oniguruma.h: No such file or directory

This tells you that you should download and install Oniguruma. For me version 5.8.0 was the only version that worked, so execute this command to get the right version of Oniguruma:

$ wget http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.8.0.tar.gz

You now have the source package on your computer, so decompress it with the following command:

$ tar zxvf onig-5.8.0.tar.gz

If everything went fine, change current directory:

$ cd onig-5.8.0/

Next, run configure:

$ ./configure

Watch the output closely and fix any errors reported, then run make:

$ make

To build and install Onigurama run:

$ sudo make install

I managed to get the following errors from Ultraviolet with other versions of Oniguruma, but these went away after installing 5.8.0 and re-installing Oniguruma:

Parsing error in // ==UserScript==: wrong number of arguments (2 for 0) #<Textpow::SyntaxNode:0xb7c91780>

Installing Ultraviolet and dependencies

Next install Ultraviolet with RubyGems:

$ sudo gem install -r ultraviolet --include-dependencies

Select which gem to install for your platform (i486-linux)
 1. oniguruma 1.1.0 (mswin32)
 2. oniguruma 1.1.0 (ruby)
 3. Skip this gem
 4. Cancel installation
> 2
Building native extensions.  This could take a while...
Successfully installed ultraviolet-0.10.0
Successfully installed textpow-0.9.0
Successfully installed oniguruma-1.1.0
Successfully installed plist-3.0.0

Test that Ultraviolet works by running the following code with irb:

$ irb

require 'rubygems'
require 'uv'
puts Uv.syntaxes.join( "\n" )
puts Uv.themes.join( "\n" )
input = <<HTML
<html>
  <body>
  </body>
</html>
HTML

puts Uv.parse( input, "xhtml", "html", true, "slush_poppies")

Problems

You might get this error:

require 'uv'
LoadError: libonig.so.2: cannot open shared object file: No such file or directory - /usr/lib/ruby/gems/1.8/gems/oniguruma-1.1.0/lib/oregexp.so

This message is a bit confusing. It means Ruby can't find libonig.so.2, not oregexp.so as you could believe.

To fix this, check if the library has been linked:

$ ldconfig -p|grep libonig

If the library is not linked, add the path to the directory where the file is located to /etc/ld.so.conf:

/usr/local/lib

include /etc/ld.so.conf.d/*.conf

Then run:

$ ldconfig

Another way of fixing this problem would be to tell the build script to install it to /usr/lib.

How to install the exception_logger Rails plugin and protect the logs with basic authentication

Tagged ruby, exception_logger, install, routes, rails, basic, authentication  Languages ruby

This snippet explains how to install and use the Rails exception_logger plugin. I'll also show you how to protect your logs by extending the plugin with basic authentication.

script/plugin source http://svn.techno-weenie.net/projects/plugins
script/plugin install exception_logger

I'm using Rails Edge on this project, so I had to install classic pagination also:

script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination

Next create and execute the migration file:

./script/generate exception_migration
rake db:migrate

Before starting the server we need to setup the routes:

map.exceptions '/logged_exceptions/:action/:id', :controller => 'logged_exceptions', :action => 'index', :id => nil

You also need to include the ExceptionLoggable in your ApplicationController:

class ApplicationController < ActionController::Base
  include ExceptionLoggable
...

Start your server and access the exception log at /logged_exceptions.

Exceptions can contain email addresses, passwords, credit card numbers, so you'll want to protect /logged_exceptions from the public. This can be done by adding the following code to the end of environment.rb:

config.after_initialize do
  require 'application' unless Object.const_defined?(:ApplicationController)
  LoggedExceptionsController.class_eval do
    before_filter :authenticate

    protected

    def authenticate
      authenticate_or_request_with_http_basic do |username, password|
        username == "foo" && password == "bar"
      end
    end
  end
end

With this code we add a before filter that shows a login dialog to anyone trying to access /logged_exception/. Note that this requires Rails 2.0 basic authentication to work, so make sure you have the proper version installed.

How to install Hyper Estraier and the Ruby bindings on Mac OS X, including a mini example on how to use the P2P capabilities

Tagged hyper estraier, search, ruby, install  Languages bash

This is a slightly modified version of some Japanese fellow's documention on how to install Hyper Estraier on Mac OS X

First we need libiconv:

$ cd /usr/local/src
$ wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.11.tar.gz
$ tar zxvf libiconv-1.11.tar.gz
$ cd libiconv-1.11
$ ./configure
$ make
$ sudo make install

zlib:

$ cd /usr/local/src
$ wget http://www.zlib.net/zlib-1.2.3.tar.gz
$ tar zxvf zlib-1.2.3.tar.gz
$ ./configure
$ make
$ sudo make install

QDBM:

$ cd /usr/local/src
$ wget http://qdbm.sourceforge.net/qdbm-1.8.74.tar.gz
$ tar zxvf qdbm-1.8.74.tar.gz
$ cd qdbm-1.8.74
$ ./configure --enable-zlib
$ make mac
$ make check-mac
$ sudo make install-mac

Hyper Estraier

$ cd /usr/local/src
$ wget http://hyperestraier.sourceforge.net/hyperestraier-1.4.9.tar.gz
$ tar zxvf hyperestraier-1.4.9.tar.gz
$ cd hyperestraier-1.4.9
$ ./configure
$ make mac
$ make check-mac
$ sudo make install-mac

Finally we'll install the pure ruby bindings:

$ cd rubypure
$ ./configure
$ make
$ sudo make install

To verify that Hyper Estraier is installed and working, try one of the examples in the examples folder, or follow these instructions:

First create and start a P2P node:

estmaster init casket
estmaster start casket

Open http://localhost:1978/master\_ui in your browser and create a node called dictionary.

Then run this code which adds a record to the index:

require "estraierpure"
include EstraierPure

node = Node::new
node.set_url("http://localhost:1978/node/dictionary")
node.set_auth("admin", "admin")

doc = Document::new
# @uri : the location of a document which any document should have.
doc.add_attr("@uri", "This is the URL, required?")
# @title : the title used as a headline in the search result.
doc.add_attr("@title", "This is the title, required?")
doc.add_text("Text goes here")

result = node.put_doc(doc)
unless result
  printf("error: %s\n", node.status)
end

Next we'll perform a query which returns the object we just added:

require "estraierpure"
include EstraierPure

# create and configure the node connecton object
node = Node::new
node.set_url("http://localhost:1978/node/dictionary")

# create a search condition object
cond = Condition::new

# set the search phrase to the search condition object
cond.set_phrase("Text goes here")

# get the result of search
nres = node.search(cond, 0);
if nres
  # for each document in the result
  for i in 0...nres.doc_num
    # get a result document object
    rdoc = nres.get_doc(i)
    # display attributes
    value = rdoc.attr("@uri")
    printf("URI: %s\n", value) if value
    value = rdoc.attr("@title")
    printf("Title: %s\n", value) if value
    # display the snippet text */
    printf("%s", rdoc.snippet)
  end
else
  STDERR.printf("error: %d\n", node.status)
end

The query language is documented here.

If you're indexing ActiveRecord objects use acts_as_searchable:

gem install acts_as_searchable