Advanced Ruby - Day 2
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>
...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.9require 'benchmark' puts Benchmark.measure {(1..1000000).map{|num| ""+num.to_s}} 0.940000 0.050000 0.990000 ( 1.001714)
puts Benchmark.measure {(1..1000000).map{|num| ""+num.to_s}} 1.800000 0.050000 1.850000 ( 1.850319)
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
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 definitionclass << 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 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
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…
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.
- Keynote – Dave Thomas
- Questions & Answers – Yukihiro ‘Matz’ Matsumoto
- Introducing Red Sun – Ruby to Flash – Jonathan Branam
- MacRuby: Ruby for your Mac – Laurent Sansonetti
- OS X Application Development with HotCocoa – Rich Kilmer
- Hacking with ruby2ruby – Marc Chung
- Using Git in Ruby Applications – Scott Chacon
- Adrenaline-Driven Development – Bruce Williams
- Fear of Programming – Nahaniel Talbott
- Recovering from Enterprise – Jamis Buck
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
Moving "private" and non-Rails related entries to http:blog.wanja.com
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:
- 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:
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
endBloated 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)
endDownload 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
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
RubyKagi2007 (日本 Ruby 会議 2007)

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)