Archive for the ‘Ruby’ Category

Merb exception email notifier

Tuesday, May 13th, 2008

1. Handle internal_server_error in your exceptions controller. Deliver email before render.

In app/controllers/exceptions.rb:

class Exceptions < Merb::Controller
 
  ...
 
  cattr_accessor :email_addresses
 
  def internal_server_error
    @exception = self.params[:exception]
    @exception_name = @exception.name.split("_").map {|x| x.capitalize}.join(" ")
    notify_emails if Merb.env?(:production)
    render
  end
 
private
 
  def notify_emails
    begin      
      return if self.class.email_addresses.blank?
 
      subject = "[#{@exception.class::STATUS}] #{@exception_name}: #{@exception.message}"
      mail_body = render(:template => "exceptions/error_email.txt")
 
      email = Merb::Mailer.new({ 
        :to => self.class.email_addresses.join(", "), 
        :from => "MyApp", 
        :subject => subject, 
        :text => mail_body })
 
      email.deliver!
 
    rescue Error => e
      Merb.logger.error("Error sending error email: #{e}")
    end
  end
 
 
end

2. Define your email template.

In app/views/exceptions/error_email.txt.rb:

<%= @exception_name %> (<%= @exception.class::STATUS %>): <%= @exception.message %>
 
URL: <%= "#{request.protocol}#{request.env["HTTP_HOST"]}#{request.uri}" %>
Parameters: <%= params[:original_params].inspect %>
 
<% @exception.backtrace.each_with_index do |line, index| %>
  <%= (line.match(/^([^:]+)/)[1] rescue 'unknown').sub(/\/((opt|usr)\/local\/lib\/(ruby\/)?(gems\/)?(1.8\/)?(gems\/)?|.+\/app\/)/, '') %>:<%=line%>
<% end %>

3. Configure the mailer. This example uses sendmail.

In config/init.rb:

dependency "merb-mailer"
 
Merb::BootLoader.after_app_loads do
 
  ...
 
  # Mailer configuration
  Merb::Mailer.config = {:sendmail_path => "/usr/sbin/sendmail"}
  Merb::Mailer.delivery_method = :sendmail
  Exceptions.email_addresses = ["my@email.com"]
end

If you need something more complex, there is a merb_exceptions plugin from newbamboo.

Freezing gems with Gem.use_path

Wednesday, April 9th, 2008

Edge rails now has gem dependency support built in, with tasks to freeze in vendor/gems.

I have tried a bunch of different methods, and things like setting $GEM_HOME or using gemsonrails work well. But lately I have been using the Gem.use_paths method.

If you put this in the config/environments rb:

Gem.use_paths(nil, [ "#{RAILS_ROOT}/vendor/rubygems" ])
# Gem.path is now:
# ["/Users/ghandford/Projects/my_rails_proj/vendor/rubygems", "/Library/Ruby/Gems/1.8"]

The vendor/rubygems directory is the same structure as system gems folder:

  vendor/rubygems/cache
  vendor/rubygems/doc
  vendor/rubygems/gems
  vendor/rubygems/specifications

The convention I use is any non-native gems get frozen with the project, and then all the native gems go in the system gem path, which gets you pretty close to clone/checkout and rake setup.

As far as unpacking and install gems, you just use gem install with GEM_HOME of your local project:

GEM_HOME=`pwd`/vendor/rubygems gem install capitate

A benefit of the use_paths method is that you can create scripts in your Rails project that use gems frozen in your project (and not necessarily have to require rails or environment.rb to get at them).

./script/my_non_rails_script
  require 'rubygems'
  Gem.use_paths(nil, [ File.dirname(__FILE__) + "/../vendor/rubygems" ])

Has anyone else tried this before?

require

Monday, January 14th, 2008

Here are some different ways to require stuff in ruby. The funny ones courtesy of why the lucky stiff.

require "rubygems"
require "open-uri"
require "yaml"
[ "rubygems", "open-uri", "yaml" ].each { |s| require s }
%w[rubygems open-uri yaml].map(&method(:require))

File.dirname(__FILE__)

What got me looking at require was how annoying it is to use the File.dirname(__FILE__) syntax all the time in init.rb’s, like:

require File.dirname(__FILE__) + "/parser/black_cat"
require File.dirname(__FILE__) + "/parser/dar"
require File.dirname(__FILE__) + "/parser/dc_nine"
require File.dirname(__FILE__) + "/parser/iota"
require File.dirname(__FILE__) + "/parser/jammin_java"

I am always just verbose with requires, I don’t know why. It gets even less readable if you start using File.join(...). I was poking around in the rails source to see how they do requires and they use $::

$:.unshift(File.dirname(__FILE__)) unless
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
 
require 'action_controller/base'
require 'action_controller/request'
require 'action_controller/rescue'
...

$:

What is $:?

irb(main):001:0> $:
=> ["/usr/local/lib/ruby/site_ruby/1.8", "/usr/local/lib/ruby/site_ruby/universal-darwin8.0", 
"/usr/local/lib/ruby/site_ruby/1.8/universal-darwin8.0", "/usr/local/lib/ruby/site_ruby", 
"/usr/local/lib/ruby/1.8", "/usr/local/lib/ruby/1.8/universal-darwin8.0", 
"/usr/local/lib/ruby/1.8/universal-darwin8.0", "."]

Its the load path. It turns out $LOAD_PATH is a synonym. So that would take me:

$LOAD_PATH.unshift(File.dirname(__FILE__))
 
require "parser/black_cat"
require "parser/dar"
require "parser/dc_nine"
require "parser/iota"
require "parser/jammin_java"

But is this a bad idea? What if the load path gets large? Do we care?

Closures

Friday, December 28th, 2007

There is alot of debate going on between the CICE and BGGA proposals for Java closure support.

I thought I would try to experiment with the different proposals and compare to languages I am using right now. I picked something simple to try out, like summing an array of integers:

Also check out good closures, bad closures.

Actionscript 3

Assume you have a reduce function, for example:

public function reduce(array:Array, f:Function, index:int = 0):* {
  if (index == array.length - 1) return array[index];
  return f(array[index], reduce(array, f, index + 1));
}

Then the syntax is:

var array:Array = [ 1, 2, 3 ];
reduce(array, function(x1:Number, x2:Number):Number { return x1 + x2; });

Ruby

Sorry I have to.

array = [ 1, 2, 3 ];
array.inject { |sum, n| sum + n }

or with Symbol#to_proc:

array = [ 1, 2, 3 ];
array.inject(&:+)

Java (CICE)

Assume you have a “Reducer” interface (and Collections#reduce):

interface Reducer<T> {
  T reduce(T t1, T t2);
}
List<Integer> = Arrays.asList([ 1, 2, 3 ]);
Integer sum = Collections.reduce(list, Reducer<Integer>(Integer x1, Integer x2) {
  return x1 + x2;
});

I think this is right, help? So you might have to declare new interfaces if the API doesn’t have them. It would probably have common ones though.

Java (BGGA)

Assume you have Collections#reduce:

List<Integer> = Arrays.asList([ 1, 2, 3 ]);
Integer sum = Collections.reduce(list, { Integer x, Integer y => x+y });

The other powerful thing with the BGGA proposal is the control invocations, like:

Lock lock = new Lock();
 
Lock.withLock(lock) {
  doSomething();
}
 
// Automatically close stream when done
with(FileInputStream f : exp) {
  doSomething();
}

Like in Ruby:

mutex = Mutex.new
mutex.synchronize do
  doSomething
end
 
File.open("foo.txt", "w") do |file|
  doSomething
end

Since I’ve been doing Ruby lately, I know which Java proposal I prefer. The CICE doesn’t address the problem that within an anonymous inner instance return, and this and any anonymous instance methods are scoped to that anonymous instance and not the enclosing method.

I guess CICE is more about reducing the verbosity of the anonymous instance declaration and allowing mutability on public variables, and its not a real closure in the strict definition. I know people refer to anonymous inner classes as the poor man’s closure, but I don’t really think of it as a closure, I think of it as, you know, an anonymous inner class.

twittertale.com

Monday, December 17th, 2007

Some friends and I did a twitter thing where we catch tweets with curse words and put them on twittertale.com. Its kind of funny. The backend twitter side is xmpp4r and xmpp4r-simple straight up ruby. And the web side is fresh rails 2.0 happiness.

On a side note, if you are doing ruby sans rails with mysql gem, you need to take care of the character encoding on the connection, which you can do by sending SET NAMES UTF8; after connect or I guess by setting the default on connection settings in my.cnf

Contracts

Tuesday, December 4th, 2007

There is no reason you couldn’t define a Ruby DSL or library (or even test harness) to assert or enforce “contracts”, method signatures, responds, whatever. All I could find so far, are these:

  • handshake: Handshake is an informal design-by-contract system written in pure Ruby. It‘s intended to allow Ruby developers to apply simple, clear constraints to their methods and classes.
  • ruby-contract: Represents a contract between Objects as a collection of test cases. Objects are said to fulfill a contract if all test cases suceed.

I don’t think I have an opinion yet. When would you really need something like this?

Protocol

Sunday, December 2nd, 2007

The similarity of this approach to protocols was clear to users of OOP languages long ago. Smalltalk and ObjectiveC, both dynamic OOP languages, have long used the term Protocol to refer to this concept.

The Protocol concept is certainly useful, if only to give a name to a particular set of messages.

Duck Typing and Protocols vs. Inheritance

It would be nice to know ahead of time what methods a Ruby object accepts. It would be nice to talk about a bunch of classes as all defining read, write and size methods as IO classes. Even if you could use some kind of marker interface (or marker module) that says, “Hey, you probably don’t care but my object might respond to these methods..”, ruby doesn’t itself protect or enforce it anyway.

popen’ing part 2

Friday, November 9th, 2007

I guess I should rtfm before blogging about something. This is my new IO.popen block which allows you to run a process which wants input, like the adt (Adobe Debug Tool) package task (which asks for your certificate password):

IO.popen(@cmd) do |f|                        
  while s = f.read(1)
    printf s
    STDOUT.flush
  end
end
@process = $?

View the airake/runner.rb. The IO.read call if not given args will block until EOF. This means we can’t output anything until the process ends which makes it appear hung if its asking for input. The waitpid call in the previous version just picks up the Process::Status since the read was the blocking call, but you can get that from $? after the popen block returns. I needed to add the STDOUT flush since printf isn’t guaranteed to (and wasn’t) outputing on the adt password input since I think it waits for a newline. Also this totally works on windows, although the whole read char + printf + flush makes it feel like a typewriter. This might be solved by using the IO.read_nonblock method. I’ll need to look into that.

Also, I updated the blog css, which I was told was depressing. Now its a total ripoff of coudal.com instead of danwebb.net

Parsing bash.org quotes for eggdrop bottalk.tcl

Wednesday, October 10th, 2007

Here is a script to scrape quotes from bash.org, and create a bottalker data file (source’d tcl script) for our eggdrop. If you want to chat with it, come to #oaktoncc on freenode.

require 'rubygems'
require 'open-uri'
require 'hpricot'
require 'cgi'
 
count = 10
last_page = 407
 
lines = []
 
count.times do |i|
  page = last_page - i
  uri = "http://bash.org/?browse&p=#{page}"
  puts "#{uri}"
  doc = Hpricot(open(uri))
 
  doc.search("//p[@class='qt']").each do |element|
 
    quote = element.inner_html
 
    quote.split(/\n/).each do |line|
      line = CGI::unescapeHTML(line)
      line.gsub!(/<br\s*\/>/, "")
      line.gsub!("&nbsp;", " ")
 
      # Different formats (otherwise ignore):
      # <name> blah
      # (@name:#channel) blah
      # name: blah
      # [name] blah
 
      if line =~ /^\s*<.*?>(.*)/ or line =~ /^\s*\(.*?\)(.*)/ or line =~ /^\s*.+?\:(.*)/ or line =~ /^\s*\[.+?\](.*)/ 
        lines << $1.strip
      end
 
    end
 
  end
end
 
File.open("BotTalker_data_bash_org.tcl", "w") do |f|
  f.puts("# Bot Talker Data file.")
  f.puts("set TalkzStrArray {")    
  lines.each do |line| 
    next if line =~ /[\{\}\\]/ # Ignore lines with {}\ chars since it screws up the tcl source
    line.gsub!(/\[/, "(")
    line.gsub!(/\]/, ")")
    f.puts(" {#{line}}") 
  end
  f.puts("}")
end

set_trace_func and filter on regex

Wednesday, August 29th, 2007

I needed to use the trace_func to figure out a bug, and I came up with:

1
2
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
  class Tracer
    
    class << self
      
      def on(io = STDERR, regex = nil)
        set_trace_func proc { |event, file, line, id, binding, classname|
          if !regex.blank?
            s = format("%8s %s:%-2d %10s %8s\n", event, file, line, id, classname)
            io.printf(s) if s =~ regex            
          else
            io.printf("%8s %s:%-2d %10s %8s\n", event, file, line, id, classname)
          end
        }
      end
    
      def off
        set_trace_func nil
      end
    
      def trace(io = STDERR, regex = nil, &block)
        on(io, regex)
        retval = yield if block_given?
        off      
        retval
      end
      
    end
  end
  
end

Then Tracer.trace { 1 + 1 } or specify a regex filter:

1
2
3
4
5
>> Tracer.trace(STDERR, /Fixnum/) { 1 + 1 }
  c-call (irb):2           +   Fixnum
c-return (irb):2           +   Fixnum
=> 2
>>