Advanced Ruby - Day 2

I just missed the first half hour of the training due to a long commute due to a little snow in Denver. Chad completed the design discussion on Inheritance .vs. Composition, using mixins and modules.
 
1.class.ancestors
=> [Fixnum, Integer, Numeric, Comparable, Object, Kernel, BasicObject]

1.class.instance_methods(false)
=> [:to_s, :-@, :+, :-, :*, :/, :div, :%, :modulo, :divmod, :fdiv, :**, :abs, :magnitude, :==, :<=>, :>, :>=, :<, :<=, :~, :&, :|, :^, :[], :<<, :>>, :to_f, :size, :zero?, :odd?, :even?, :succ]

m = 1.method(:inspect)
=> #<Method: Fixnum(Kernel)#inspect>
We are moving on to performance.

...make it fast.

Rails doesn't scale and Ruby is slow. This said Ruby is arguably the slowest of the scripting languages with a naive implementation. But for 99% of the work we do, it's fast enough...Now let's talk about that last 1%. Premature optimization is the root of all evil - Donald Knuth.

Benchmarking

In 1.9
require 'benchmark'
puts Benchmark.measure {(1..1000000).map{|num| ""+num.to_s}}
  0.940000   0.050000   0.990000 (  1.001714)
In 1.8
puts Benchmark.measure {(1..1000000).map{|num| ""+num.to_s}}
  1.800000   0.050000   1.850000 (  1.850319)
Yea, 1.9 is twice as fast. Now to compare approaches, here using map or inject...which one is the fastest:
require 'benchmark'
Benchmark.bm do |b|
  b.report("map") {(1..1000000).map{|num| ""+num.to_s}}
  b.report("inject") {(1..1000000).inject(""){|accum, num| ""+num.to_s}}
end
      user     system      total        real
map  1.970000   0.070000   2.040000 (  2.077786)
inject  1.910000   0.010000   1.920000 (  1.978541)

Don't Use Ruby

* C (or OCAML?) extensions * Sockets * DL * Don't use Ruby at all DL is "Pure Ruby" way of calling native code form shared libraries.
require 'dl/import'
require 'dl/struct'

memoization

def fib(n)
 @k||={}
 n<=2 ? 1 : (@k[n-1]||=fib(n-1))+(@k[n-2]||=fib(n-2))
end

puts fib(200)
280571172992510140037611932413038677189525

Program exited with code #0 after 0.02 seconds
Now the same code as above without the cluttering
def fib(n)
  if n <= 2 
      1
  else
     fib(n-1) + fib(n-2)
  end
end

alias :pre_memoized_fib :fib

def fib(n)
  @cache ||= {}
  @cache[n] ||= pre_memoized_fib(n)
end

The Ruby Object Model

Now we move onto the essence of an Object in Ruby. * self is the "current object" * self always as a value * two things change self: 1) method calls 2) class or module definition
class << str   # << opens up the singleton class. Arrows seem to go wrong way.
  p self  # ghost class: <Class:#<String:0x1d0ec>> - class of the class String
  def speak
    puts "miaow"
  end
end

puts str.speak

class Dave
  class << self   # puts the methods into the singleton class and becomes class methods
    def do_something      
    end
  end
end

class Person < Struct.new(:name, :age)
  def greet
      puts "Hello #{self.name}"
  end
end

f = Person.new("Chad", 28)
module Logger
  def log(msg)
    puts msg
  end
end

class Album
  include Logger
end


Album.ancestors # => [Album, Logger, Object, Kernel]
# Note that Logger becomes ancestor of Album...It's insert a generated class named after the module that shares the method table.
Module can extend an object:
module Speak
  def hello
     puts "hello"
  end
end

str = "cat"
str.extend Speak

puts str.hello

Metaprogramming

After the break we will be diving into metaprogramming. I saw his talk at the Advanced Rails Studio a while back and took some notes then. I will therefore sit back, relax, and code along his examples.

Library Organization

Posted by Daniel Wanja Tue, 10 Mar 2009 00:40:00 GMT


Advanced Ruby - Day 1

Let’s get started. I’m at the Advanced Ruby training. Here are the topics we gonna cover

  • Blocks, Procs, and Closures
  • Ruby 1.9
  • Your Own, Private Ruby
  • Design in a Dynamic Language
  • Messin’ with Types
  • …make it fast.
  • The Ruby Object Model
  • Metaprogramming
  • Making Domains-Specific Languages
  • Concurrency
  • Exotic Control Flow
  • Library Organization
  • Debugging and Profiling
  • JRuby
  • Ruby Extras
  • Distributed Programming
  • Onward and Upward!

In fact when I saw the topics that will be covered by Dave Thomas and Chad Fowler, and the fact that some of my collogues from Pinnacol where attending I had to join…Oh yea, it’s a 25 minute drive from home too.

So this morning I woke up and installed Ruby 1.9. I didn’t use multiruby as many do I just downloaded Ruby 1.9.1-p0 from http://www.ruby-lang.org/en/downloads. These are the steps to install:


cd ruby-1.9.1-p0
autoconf
./configure —prefix=/usr/local/ruby1.9
make
sudo make install

Then you can check the version by

 
$/usr/local/ruby1.9/bin/ruby -v 
ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-darwin9.6.0]
$/usr/local/ruby1.9/bin/irb 
RUBY_VERSION 
=> "1.9.1"

I didn’t add /usr/local/ruby1.9/bin to my path, so the default ruby is still my mack default, 1.8.6 of my mac (ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]).

Keep on reading to see some of the code we are walking through. This said it’s hard to convey how much value Chad and Dave are passing along with all their deep explanations of each of the examples…

Posted by Daniel Wanja Mon, 09 Mar 2009 22:30:27 GMT


RubyConf 2008 videos available at confreaks.com - Thank you!

I couldn’t make it this year to RubyConf so I am really thankful to see that most of the presentations are online at confreaks. It’s just awesome that these videos are made available online and so quickly after the conference and for free. It’s a real tribute to the Ruby community and it’s open and sharing spirit. Thanks guys! My understanding is that the rubyconf pays Confreaks to take, processes and distribute these videos. Let me know if the arrangement is different, to give credit where credit is due. Thanks RubyConf and the presenters, and good job Confreaks.

Here are the videos I selected for my commute this week.

View the full list of videos available here.

You may wonder why I would watch videos during my commute. Effectively I drive 40 minutes each way to my customers (happen to be both near enough for me to drive and not tele-commute) and this gives me a chance to catch up on many of the excellent screencast and podcast out there. Now when one screencast really sticks out, I watch it again at night…without driving ;-).

This said I converted the confreaks small videos format (640 × 240) to the iPhone format using Quicktime pro, but I only get the sound…which is fine for my commute. Any hint on how I can convert them to also get the video going would be appreciated?

Enjoy!
Daniel

Posted by Daniel Wanja Mon, 01 Dec 2008 14:57:21 GMT


Moving "private" and non-Rails related entries to http:blog.wanja.com

I received a couple of comments and emails about my non-Rails related entries, more specifically about the iPhone related entries. So from now on I will move these type of entries to my new "private" blog http://blog.wanja.com. As I am starting the development of a new iPhone app and will report about it over there. I am still doing quite some Rails related work and will keep posting about it here (http://onrails.org). I am also experimenting with MacRuby, which is so cool, and will report about it here unless it's specific to iPhone development. I short if you are only interested in Rails or Ruby keep ready this blog, if you are interested in the other "stuff" I play with, such a iPhone, games, Wii, PS3, programming the Wii Remote, and any other geek stuff, check out http://blog.wanja.com

Posted by Daniel Wanja Mon, 17 Nov 2008 04:59:00 GMT


gemedit version 0.0.1 has been released!

Check out my first published gem: gemedit

A utility to view a gem’s source in your favorite editor

Changes:

  1. 0.0.1 2008-02-27
  • 1 major enhancement:
    • Initial release

Specials thanks go to the following gems for making it easy to put this out there:

Posted by Lee Marlow Fri, 29 Feb 2008 19:00:00 GMT


Upgraded Syntax Highlighting for Scribbish Theme

We were bored of the plain green on black syntax highlighting for our code blocks, not to mention sick of the weird borders around code comments, so I hunted around for a little to find something a little better. The theme we’re using, Scribbish, didn’t have any CSS defined for Typo’s code blocks, so I stole them from James Wilford’s post. Thanks, James.

Maybe we’ll tweak the colors some more later, but these will do for now.

class Scribbish < TypoTheme
  include JamesWilfordCSS
end

Posted by Lee Marlow Tue, 22 May 2007 16:02:00 GMT


Bloated RailsConf Presentation Downloader

I’ve updated my downloader from earlier to include all sorts of fancy options. It no longer requires wget, it just uses open-uri. It can give the files a fancy name. It can be told where to download the files to. It will skip files that won’t download for some reason. It will even butter your toast if you can find the correct command line switch.

It’s about 3 times bigger than the previous one. But maybe you can learn a little more about optparse, hpricot, file handling, and error handling along the way.

Here it is:

#!/usr/bin/env ruby

require 'optparse'

OPTIONS = { :Verbose => false,
            :Force => false,
            :DownloadDir => '.',
            :DescriptiveFilenames => true
          }
OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} [options]"

  opts.on("-v", "--[no-]verbose", "Run verbosely, default #{OPTIONS[:Verbose]}") do |verbose|
    OPTIONS[:Verbose] = verbose
  end
  opts.on("-f", "--[no-]force", "Force downloads, default #{OPTIONS[:Force]}") do |force|
    OPTIONS[:Force] = force
  end
  opts.on("-d", "--[no-]descriptive", "Use long descriptive filenames, default #{OPTIONS[:DescriptiveFilenames]}") do |long|
    OPTIONS[:DescriptiveFilenames] = long
  end
  opts.on("-p", "--path PATH", "Path to download to, default #{OPTIONS[:DownloadDir]}") do |path|
    OPTIONS[:DownloadDir] = path
  end
  opts.on_tail("-h", "--help", "Print help message") do |help|
    puts opts
    exit
  end
end.parse!

require 'rubygems'
require 'hpricot'
require 'open-uri'
require 'fileutils'

BASE_URL = 'http://www.web2expo.com'

def log(str)
  puts str if OPTIONS[:Verbose]
end

def download(href, filename)
  url = "#{BASE_URL}#{URI.escape(href)}"
  download_file = File.join(OPTIONS[:DownloadDir], filename)
  if OPTIONS[:Force] || !File.exists?(download_file)
    log "downloading #{File.basename(href)}..."
    begin
      File.open(download_file, 'w') { |f| f.write(open(url).read)}
      log "\tsaved as #{download_file}"
    rescue Object => e
      FileUtils.rm(download_file)
      $stderr.puts "ERROR downloading #{url}: #{e.message}"
    end
  else
    log "skipping #{File.basename(href)}... already downloaded as #{download_file}"
  end
end

FileUtils.mkdir_p(OPTIONS[:DownloadDir])
h = Hpricot(open("#{BASE_URL}/pub/w/51/presentations.html"))
h.search('div.presentation').each do |presentation_node|
  href = presentation_node.at('a[@href^="/presentations/rails2007/"]')[:href]
  if OPTIONS[:DescriptiveFilenames]
    name = presentation_node.at('b a').inner_text.strip
    text = presentation_node.inner_text
    speaker = text[/Speaker\(s\):\s+(.*)\s*$/, 1]
    date = Date.parse(text[/Presentation Date:\s+(.*)\s*$/, 1])
    filename = [speaker, date, name, File.basename(href)].compact.map { |s| s.to_s.strip.gsub(/[^\w\.]/, '_').squeeze('_') }.join('-')
  else
    File.basename(href)
  end
  download(href, filename)
end

Posted by Lee Marlow Mon, 21 May 2007 22:49:00 GMT


Download RailsConf 2007 Presentations

Updated: Now more bloated!

Run this to get the RailsConf 2007 presentations:
#!/usr/bin/env ruby

require 'rubygems'
require 'hpricot'
require 'open-uri'

base = 'http://www.web2expo.com'
h = Hpricot(open("#{base}/pub/w/51/presentations.html"))

h.search('div .presentation > a[@href^="/presentations/rails2007/"]').each do |a|
  url = "#{base}#{a[:href]}"
  if File.exists?(File.basename(url))
    puts "skipping #{url}... already downloaded"
  else
    puts "downloading #{url}..."
    `wget --quiet #{url}`
  end
end
I might clean it up more later to name the files better and not use wget, but this was quick and easy... not to mention a way to use everyone's favorite parsing tool: Hpricot.

Posted by Lee Marlow Mon, 21 May 2007 18:27:00 GMT


Will Marcel Molina Steal Matz's Ruby Super Powers

I didn’t start watching Heroes until after I heard Rich Kilmer and Marcel Molina talking about it while putting the badges together for RubyConf 2006 in Denver.  Had I watched it before maybe I would have been a little scared of Marcel (Sylar), but he was very nice and didn’t seem like a threat to the Ruby world at all.

So, why be scared of Mr. Molina? You be the judge.

class MarcelMolina
  include Heroes
  
  def <=>(other_hero)
    other_hero.name == 'Sylar' ? 0 : 1
  end
end

== # => true

Posted by Lee Marlow Fri, 18 May 2007 18:02:00 GMT


RubyKagi2007 (日本 Ruby 会議 2007)

20070515_rubykaigilogo.gif

I would love to go once to Japan to attend the (now) RubyKaigi conference. This year won’t work for me…hey Lee, what about next year?

Find more info here (in Japanese) and here (in Google translated English)

Posted by Daniel Wanja Tue, 15 May 2007 20:16:08 GMT