stop reinventing
    the wheel
hidden gems in the ruby standard library


      brian hogan - @bphogan
Twitter: @bphogan
Web: http://www.napcs.com/
What about this
                        design?
            describe "the user" do
              it "gets an email when their account is activated" do
                # some stuff
              end
            end




Twitter: @bphogan
Web: http://www.napcs.com/
Sometimes ideas
             evolve for the better.




Twitter: @bphogan
Web: http://www.napcs.com/
Other times not so
                     much.




Twitter: @bphogan
Web: http://www.napcs.com/
In software we
                           reinvent




Twitter: @bphogan
Web: http://www.napcs.com/
How often is
                     “better”
               really just opinion?



Twitter: @bphogan
Web: http://www.napcs.com/
So, we’re not talking
              about always using
                 what exists...


Twitter: @bphogan
Web: http://www.napcs.com/
We’re talking about
            reinventing because
            of ignorance, hubris,
                   or ego.

Twitter: @bphogan
Web: http://www.napcs.com/
Ruby Standard Library

                             http://ruby-doc.org/stdlib/




Twitter: @bphogan
Web: http://www.napcs.com/
•FileUtils
       •Forwardable
       •Pathname
       •open-uri
       •TempFile
       •WEBrick


Twitter: @bphogan
Web: http://www.napcs.com/
Working With The File
               System
     system("mkdir -p tmp/files")
     system("touch tmp/files/lockfile.lock")
     system("rm -rf tmp/files")




Twitter: @bphogan
Web: http://www.napcs.com/
Make it platform-
                   independent!
      require 'fileutils'

      FileUtils.mkdir_p("tmp/files")
      FileUtils.touch("tmp/files/lockfile.lock")
      FileUtils.rm_rf("tmp/files")




Twitter: @bphogan
Web: http://www.napcs.com/
FileUtils
          Namespace for several file utility methods
          for copying, moving, removing, etc.




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used

           •Rake
           •Capistrano stuff
           •Sinatra Reloader gem
           •Compass

Twitter: @bphogan
Web: http://www.napcs.com/
Where does it fall
                     short?



Twitter: @bphogan
Web: http://www.napcs.com/
Delegating Methods
          Calling methods on one class through another.

                             User    Profile




                             name    name




Twitter: @bphogan
Web: http://www.napcs.com/
Here’s how Rails
                        does it
      def delegate(*methods)
        options = methods.pop
        unless options.is_a?(Hash) && to = options[:to]
          raise ArgumentError, "Delegation needs a target.
             Supply an options hash with a :to key as the last argument
              (e.g. delegate :hello, :to => :greeter)."
        end

        methods.each do |method|
          module_eval("def #{method}(*args, &block)
          n#{to}.__send__(#{method.inspect},
           *args, &block)nendn", "(__DELEGATION__)", 1)
        end
      end




Twitter: @bphogan
Web: http://www.napcs.com/
Here’s how Rails
                        does it
                       class User < ActiveRecord::Base
                         has_one :profile
                         delegate :name, :to => :profile
                       end




Twitter: @bphogan
Web: http://www.napcs.com/
Here’s how we could
                   do it.
                     require 'forwardable'

                     class User < ActiveRecord::Base
                       has_one :profile
                       extend Forwardable
                       def_delegator :profile, :bio, :bio
                     end




Twitter: @bphogan
Web: http://www.napcs.com/
Forwardable
                        This library allows you
                        delegate method calls to
                        an object, on a method by
                        method basis.




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used


           •MongoMapper
           •Rack::Client


Twitter: @bphogan
Web: http://www.napcs.com/
Where does it fall
                     short?



Twitter: @bphogan
Web: http://www.napcs.com/
Working with Paths




Twitter: @bphogan
Web: http://www.napcs.com/
Seen in tons of Rails
                    apps...
     file = File.join(RAILS_ROOT, "config", "database.yml")
     config = YAML.load(File.read(file))




Twitter: @bphogan
Web: http://www.napcs.com/
A better way
             file = Rails.root.join("config", "database.yml")
             config = YAML.load(file.read)



                               Rails.root.class
                                => Pathname

                                           http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/




Twitter: @bphogan
Web: http://www.napcs.com/
Pathname
          Library to simplify working
              with files and paths.
        Represents a pathname which locates a file
        in a filesystem. The pathname depends on
                   OS: Unix, Windows, etc.




Twitter: @bphogan
Web: http://www.napcs.com/
Neat stuff
        require 'pathname'
        p = Pathname.new("/usr/bin/ruby")
        size = p.size              # 27662
        isdir = p.directory?       # false
        dir = p.dirname            # Pathname:/usr/bin
        base = p.basename          # Pathname:ruby
        dir, base = p.split        # [Pathname:/usr/bin, Pathname:ruby]




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used

           •Rails
           •DataMapper
           •Warehouse
           •Webistrano
           •many many more
Twitter: @bphogan
Web: http://www.napcs.com/
Grabbing Files




Twitter: @bphogan
Web: http://www.napcs.com/
cURL?
                      puts `curl http://pastie.org/1131498.txt?
                      key=zst64zkddsxafra0jz678g`




Twitter: @bphogan
Web: http://www.napcs.com/
Not available
              everywhere,
          must handle redirects.



Twitter: @bphogan
Web: http://www.napcs.com/
Treat URLs as files!
  require 'open-uri'
  url = "http://pastie.org/1131498.txt?key=zst64zkddsxafra0jz678g"
  puts open(url).read




Twitter: @bphogan
Web: http://www.napcs.com/
open-uri


                 Wraps net/http, net/https, and net/ftp.




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used


           •Everywhere.


Twitter: @bphogan
Web: http://www.napcs.com/
Where does it fall
                     short?



Twitter: @bphogan
Web: http://www.napcs.com/
Temporary files




Twitter: @bphogan
Web: http://www.napcs.com/
The hard way
 path = "http://pastie.org/1131498.txt?key=zst64zkddsxafra0jz678g"
 `curl #{path} > /tmp/template.html`
 s = File.read("/tmp/template.html")
 puts s




Twitter: @bphogan
Web: http://www.napcs.com/
Use TempFile
 require 'open-uri'
 require 'tempfile'
 url = "http://pastie.org/1131498.txt?key=zst64zkddsxafra0jz678g"
 tempfile = Tempfile.new("template.html")
 tempfile.write open(url).read
 puts tempfile.open.read




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used


           •File uploading
           •Caching


Twitter: @bphogan
Web: http://www.napcs.com/
Data structures




Twitter: @bphogan
Web: http://www.napcs.com/
YAML loads to hashes
           require 'YAML'
           config = YAML.load(Pathname.new("config.yml").read)

           puts config["company_name"]
           puts config["banner_image_url"]
           puts config["custom_css_url"]




Twitter: @bphogan
Web: http://www.napcs.com/
Use OpenStruct!
              require 'ostruct'
              require 'YAML'
              config = YAML.load(Pathname.new("config.yml").read)
              config = OpenStruct.new(config)
              puts config.company_name
              puts config.banner_image_url
              puts config.custom_css_url




Twitter: @bphogan
Web: http://www.napcs.com/
Don’t write your own
            “YAML-to-Object”
          thing (like I once did!)




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used

           •Fat Free CMS
           •ActiveMessaging
           •Adhearsion
           •AASM

Twitter: @bphogan
Web: http://www.napcs.com/
Where does it fall
                     short?



Twitter: @bphogan
Web: http://www.napcs.com/
Watching Stuff




Twitter: @bphogan
Web: http://www.napcs.com/
Rails?




Twitter: @bphogan
Web: http://www.napcs.com/
def initialize
                            super
                            observed_descendants.each { |klass| add_observer!(klass) }
                          end


                          def self.method_added(method)
                            method = method.to_sym


                            if ActiveRecord::Callbacks::CALLBACKS.include?(method)
                                self.observed_methods += [method]
                                self.observed_methods.freeze
                            end
                          end


                          protected


                            def observed_descendants
                                observed_classes.sum([]) { |klass| klass.descendants }
                            end


                            def observe_callbacks?
                                self.class.observed_methods.any?
                            end


                            def add_observer!(klass)
                                super
                                define_callbacks klass if observe_callbacks?
                            end


                            def define_callbacks(klass)
                                existing_methods = klass.instance_methods.map { |m| m.to_sym }
                                observer = self
                                observer_name = observer.class.name.underscore.gsub('/', '__')


                                self.class.observed_methods.each do |method|
                                  callback = :"_notify_#{observer_name}_for_#{method}"
                                  unless existing_methods.include? callback
                                      klass.send(:define_method, callback) do   # def _notify_user_observer_for_before_save
                                        observer.update(method, self)           #   observer.update(:before_save, self)
                                      end                                       # end
                                      klass.send(method, callback)              # before_save :_notify_user_observer_for_before_save
                                  end
                                end
                            end
                      end
                    end




Twitter: @bphogan
Web: http://www.napcs.com/
Observer
                                Provides a simple
                                mechanism for one
                                object to inform a set of
                                interested third-party
                                objects when its state
                                changes.




Twitter: @bphogan
Web: http://www.napcs.com/
How we do it
           require 'observer'

           class ConfirmationEmailer
             def update(account)
               puts "Sending confirmation mail to: '#{account.email}'"
               # send the email mechanism
             end
           end




Twitter: @bphogan
Web: http://www.napcs.com/
class Account
                      include Observable
                      attr_accessor :email, :active

                       def initialize(email)
                         self.email = email
                         self.active = false
                         add_observer ConfirmationEmailer.new
                       end

                      def activate_account!
                        self.active = true
                        changed     # <- This is important
                        notify_observers self
                      end
                    end




Twitter: @bphogan
Web: http://www.napcs.com/
Where does it fall
                     short?



Twitter: @bphogan
Web: http://www.napcs.com/
Serving Web Pages




Twitter: @bphogan
Web: http://www.napcs.com/
Sinatra?
                             require 'sinatra'
                             set :public, "~/Sites"




Twitter: @bphogan
Web: http://www.napcs.com/
How about this?
  s = WEBrick::HTTPServer.new(:Port => 3000,
     :DocumentRoot => "~/Sites")
  trap('INT') { s.shutdown };
  s.start




Twitter: @bphogan
Web: http://www.napcs.com/
How about an alias?
 alias serve="ruby -rwebrick -e"s = WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot =>
 Dir.pwd); trap('INT') { s.shutdown }; s.start""



                                     $ cd ~/Sites
                                     $ serve




Twitter: @bphogan
Web: http://www.napcs.com/
Twitter: @bphogan
Web: http://www.napcs.com/
It also serves web
                          apps




Twitter: @bphogan
Web: http://www.napcs.com/
Your dev machine
            really needs Passenger
                    running?




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used


           •Rails
           •Other frameworks


Twitter: @bphogan
Web: http://www.napcs.com/
Where does it fall
                     short?



Twitter: @bphogan
Web: http://www.napcs.com/
Storing Data




Twitter: @bphogan
Web: http://www.napcs.com/
PStore
           Persistent, transactional
           storage. Baked right in to
            Ruby’s standard library.




Twitter: @bphogan
Web: http://www.napcs.com/
We can store stuff...
               require 'pstore'
               store = PStore.new('links')

               links = %W{http://www.github.com
                         http://heroku.com
                         http://ruby-lang.org}

               store.transaction do
                 store[:links] ||= []
                 links.each{|link| store[:links] << link}
                 store[:last_modified] = Time.now
               end




Twitter: @bphogan
Web: http://www.napcs.com/
and we can get it
                       back.
                   store = PStore.new("links")
                   store.transaction do
                     links = store[:links]
                   end

                   puts links.join("n")




Twitter: @bphogan
Web: http://www.napcs.com/
Where it’s used


           •Rails 1.x


Twitter: @bphogan
Web: http://www.napcs.com/
Where does it
                          fall short?


Twitter: @bphogan
Web: http://www.napcs.com/
Better Wheels




Twitter: @bphogan
Web: http://www.napcs.com/
Importing CSV files
     require 'csv'

       CSV.open('data.csv', 'r', ';') do |row|
         p row
       end




Twitter: @bphogan
Web: http://www.napcs.com/
CSV is slow.
                   “Use FasterCSV”


Twitter: @bphogan
Web: http://www.napcs.com/
In Ruby 1.9,
            FasterCSV is the new
                    CSV!

Twitter: @bphogan
Web: http://www.napcs.com/
Working with Dates




Twitter: @bphogan
Web: http://www.napcs.com/
How we do it
           today = DateTime.now
           birthday = Date.new(2010, 10, 5)
           days_to_go = birthday - today
           time_until = birthday - today
           hours,minutes,seconds,frac =
           Date.day_fraction_to_time(time_until)



                             http://www.techotopia.com/index.php/Working_with_Dates_and_Times_in_Ruby


Twitter: @bphogan
Web: http://www.napcs.com/
home_run
            home_run is an implementation of rubyʼs Date/
            DateTime classes in C, with much better
            performance (20-200x) than the version in the
            standard library, while being almost completely
            compatible.

              http://github.com/jeremyevans/home_run




Twitter: @bphogan
Web: http://www.napcs.com/
REXML

            Built-in library for
        parsing and creating XML.




Twitter: @bphogan
Web: http://www.napcs.com/
How about
     HPricot, libxml-
        ruby, or
       Nokogiri.
                             http://www.rubyinside.com/ruby-xml-performance-benchmarks-1641.html




Twitter: @bphogan
Web: http://www.napcs.com/
ERb


      Templating language as part of the Standard Library.




Twitter: @bphogan
Web: http://www.napcs.com/
require 'erb'

                        template = ERB.new <<-EOF
                         <h1><%=@name %></h1>
                        EOF

                        @name = "AwesomeCo"

                        puts template.result




Twitter: @bphogan
Web: http://www.napcs.com/
Templating language
                     !=
              View language!!!



Twitter: @bphogan
Web: http://www.napcs.com/
What can it do?

           •Generate JavaScript
           •Generate YAML
           •Generate ERb
           •Any type of proprietary data export

Twitter: @bphogan
Web: http://www.napcs.com/
Where does it fall
                     short?



Twitter: @bphogan
Web: http://www.napcs.com/
Alternatives?

           •HAML
           •Liquid
           •ERubis
           •Tons of others

Twitter: @bphogan
Web: http://www.napcs.com/
Test::Unit

                 We have an awesome testing library
                   as part of our standard library.




Twitter: @bphogan
Web: http://www.napcs.com/
It’s pretty good.
            Anyone know of any
                 alternatives?



Twitter: @bphogan
Web: http://www.napcs.com/
Only a few.
           •RSpec
           •Bacon
           •Context / Contest / Shoulda / Matchy
           •Testy
           •Micronaut
           •Whatever someone writes next week

Twitter: @bphogan
Web: http://www.napcs.com/
I use RSpec *


                             * And I still use Test::Unit.




Twitter: @bphogan
Web: http://www.napcs.com/
“Minitest is a minitest/unit
             is a small and fast
           replacement for ruby's
          huge and slow test/unit”.



Twitter: @bphogan
Web: http://www.napcs.com/
If X sucks so bad, why
                 do we write
               something else
             instead of fixing it?


Twitter: @bphogan
Web: http://www.napcs.com/
We think we can do it
                 better.



Twitter: @bphogan
Web: http://www.napcs.com/
The original developer
         doesn’t want our help.


Twitter: @bphogan
Web: http://www.napcs.com/
There’s a language
                      barrier.


Twitter: @bphogan
Web: http://www.napcs.com/
Challenge:
              Extend the Standard
                    Library.


Twitter: @bphogan
Web: http://www.napcs.com/
Make the wheels we
                have better.




Twitter: @bphogan
Web: http://www.napcs.com/
That’s it.

           •Twitter: @bphogan
           •email: bphogan@gmail.com
           •web: http://www.napcs.com/
           •blog: http://bphogan.com
           •github: http://github.com/napcs/
Twitter: @bphogan
Web: http://www.napcs.com/

Stop Reinventing The Wheel - The Ruby Standard Library

  • 1.
    stop reinventing the wheel hidden gems in the ruby standard library brian hogan - @bphogan
  • 2.
  • 3.
    What about this design? describe "the user" do it "gets an email when their account is activated" do # some stuff end end Twitter: @bphogan Web: http://www.napcs.com/
  • 4.
    Sometimes ideas evolve for the better. Twitter: @bphogan Web: http://www.napcs.com/
  • 5.
    Other times notso much. Twitter: @bphogan Web: http://www.napcs.com/
  • 6.
    In software we reinvent Twitter: @bphogan Web: http://www.napcs.com/
  • 7.
    How often is “better” really just opinion? Twitter: @bphogan Web: http://www.napcs.com/
  • 8.
    So, we’re nottalking about always using what exists... Twitter: @bphogan Web: http://www.napcs.com/
  • 9.
    We’re talking about reinventing because of ignorance, hubris, or ego. Twitter: @bphogan Web: http://www.napcs.com/
  • 10.
    Ruby Standard Library http://ruby-doc.org/stdlib/ Twitter: @bphogan Web: http://www.napcs.com/
  • 11.
    •FileUtils •Forwardable •Pathname •open-uri •TempFile •WEBrick Twitter: @bphogan Web: http://www.napcs.com/
  • 12.
    Working With TheFile System system("mkdir -p tmp/files") system("touch tmp/files/lockfile.lock") system("rm -rf tmp/files") Twitter: @bphogan Web: http://www.napcs.com/
  • 13.
    Make it platform- independent! require 'fileutils' FileUtils.mkdir_p("tmp/files") FileUtils.touch("tmp/files/lockfile.lock") FileUtils.rm_rf("tmp/files") Twitter: @bphogan Web: http://www.napcs.com/
  • 14.
    FileUtils Namespace for several file utility methods for copying, moving, removing, etc. Twitter: @bphogan Web: http://www.napcs.com/
  • 15.
    Where it’s used •Rake •Capistrano stuff •Sinatra Reloader gem •Compass Twitter: @bphogan Web: http://www.napcs.com/
  • 16.
    Where does itfall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 17.
    Delegating Methods Calling methods on one class through another. User Profile name name Twitter: @bphogan Web: http://www.napcs.com/
  • 18.
    Here’s how Rails does it def delegate(*methods) options = methods.pop unless options.is_a?(Hash) && to = options[:to] raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)." end methods.each do |method| module_eval("def #{method}(*args, &block) n#{to}.__send__(#{method.inspect}, *args, &block)nendn", "(__DELEGATION__)", 1) end end Twitter: @bphogan Web: http://www.napcs.com/
  • 19.
    Here’s how Rails does it class User < ActiveRecord::Base has_one :profile delegate :name, :to => :profile end Twitter: @bphogan Web: http://www.napcs.com/
  • 20.
    Here’s how wecould do it. require 'forwardable' class User < ActiveRecord::Base has_one :profile extend Forwardable def_delegator :profile, :bio, :bio end Twitter: @bphogan Web: http://www.napcs.com/
  • 21.
    Forwardable This library allows you delegate method calls to an object, on a method by method basis. Twitter: @bphogan Web: http://www.napcs.com/
  • 22.
    Where it’s used •MongoMapper •Rack::Client Twitter: @bphogan Web: http://www.napcs.com/
  • 23.
    Where does itfall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 24.
    Working with Paths Twitter:@bphogan Web: http://www.napcs.com/
  • 25.
    Seen in tonsof Rails apps... file = File.join(RAILS_ROOT, "config", "database.yml") config = YAML.load(File.read(file)) Twitter: @bphogan Web: http://www.napcs.com/
  • 26.
    A better way file = Rails.root.join("config", "database.yml") config = YAML.load(file.read) Rails.root.class => Pathname http://litanyagainstfear.com/blog/2010/02/03/the-rails-module/ Twitter: @bphogan Web: http://www.napcs.com/
  • 27.
    Pathname Library to simplify working with files and paths. Represents a pathname which locates a file in a filesystem. The pathname depends on OS: Unix, Windows, etc. Twitter: @bphogan Web: http://www.napcs.com/
  • 28.
    Neat stuff require 'pathname' p = Pathname.new("/usr/bin/ruby") size = p.size # 27662 isdir = p.directory? # false dir = p.dirname # Pathname:/usr/bin base = p.basename # Pathname:ruby dir, base = p.split # [Pathname:/usr/bin, Pathname:ruby] Twitter: @bphogan Web: http://www.napcs.com/
  • 29.
    Where it’s used •Rails •DataMapper •Warehouse •Webistrano •many many more Twitter: @bphogan Web: http://www.napcs.com/
  • 30.
  • 31.
    cURL? puts `curl http://pastie.org/1131498.txt? key=zst64zkddsxafra0jz678g` Twitter: @bphogan Web: http://www.napcs.com/
  • 32.
    Not available everywhere, must handle redirects. Twitter: @bphogan Web: http://www.napcs.com/
  • 33.
    Treat URLs asfiles! require 'open-uri' url = "http://pastie.org/1131498.txt?key=zst64zkddsxafra0jz678g" puts open(url).read Twitter: @bphogan Web: http://www.napcs.com/
  • 34.
    open-uri Wraps net/http, net/https, and net/ftp. Twitter: @bphogan Web: http://www.napcs.com/
  • 35.
    Where it’s used •Everywhere. Twitter: @bphogan Web: http://www.napcs.com/
  • 36.
    Where does itfall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 37.
  • 38.
    The hard way path = "http://pastie.org/1131498.txt?key=zst64zkddsxafra0jz678g" `curl #{path} > /tmp/template.html` s = File.read("/tmp/template.html") puts s Twitter: @bphogan Web: http://www.napcs.com/
  • 39.
    Use TempFile require'open-uri' require 'tempfile' url = "http://pastie.org/1131498.txt?key=zst64zkddsxafra0jz678g" tempfile = Tempfile.new("template.html") tempfile.write open(url).read puts tempfile.open.read Twitter: @bphogan Web: http://www.napcs.com/
  • 40.
    Where it’s used •File uploading •Caching Twitter: @bphogan Web: http://www.napcs.com/
  • 41.
  • 42.
    YAML loads tohashes require 'YAML' config = YAML.load(Pathname.new("config.yml").read) puts config["company_name"] puts config["banner_image_url"] puts config["custom_css_url"] Twitter: @bphogan Web: http://www.napcs.com/
  • 43.
    Use OpenStruct! require 'ostruct' require 'YAML' config = YAML.load(Pathname.new("config.yml").read) config = OpenStruct.new(config) puts config.company_name puts config.banner_image_url puts config.custom_css_url Twitter: @bphogan Web: http://www.napcs.com/
  • 44.
    Don’t write yourown “YAML-to-Object” thing (like I once did!) Twitter: @bphogan Web: http://www.napcs.com/
  • 45.
    Where it’s used •Fat Free CMS •ActiveMessaging •Adhearsion •AASM Twitter: @bphogan Web: http://www.napcs.com/
  • 46.
    Where does itfall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 47.
  • 48.
  • 49.
    def initialize super observed_descendants.each { |klass| add_observer!(klass) } end def self.method_added(method) method = method.to_sym if ActiveRecord::Callbacks::CALLBACKS.include?(method) self.observed_methods += [method] self.observed_methods.freeze end end protected def observed_descendants observed_classes.sum([]) { |klass| klass.descendants } end def observe_callbacks? self.class.observed_methods.any? end def add_observer!(klass) super define_callbacks klass if observe_callbacks? end def define_callbacks(klass) existing_methods = klass.instance_methods.map { |m| m.to_sym } observer = self observer_name = observer.class.name.underscore.gsub('/', '__') self.class.observed_methods.each do |method| callback = :"_notify_#{observer_name}_for_#{method}" unless existing_methods.include? callback klass.send(:define_method, callback) do # def _notify_user_observer_for_before_save observer.update(method, self) # observer.update(:before_save, self) end # end klass.send(method, callback) # before_save :_notify_user_observer_for_before_save end end end end end Twitter: @bphogan Web: http://www.napcs.com/
  • 50.
    Observer Provides a simple mechanism for one object to inform a set of interested third-party objects when its state changes. Twitter: @bphogan Web: http://www.napcs.com/
  • 51.
    How we doit require 'observer' class ConfirmationEmailer def update(account) puts "Sending confirmation mail to: '#{account.email}'" # send the email mechanism end end Twitter: @bphogan Web: http://www.napcs.com/
  • 52.
    class Account include Observable attr_accessor :email, :active def initialize(email) self.email = email self.active = false add_observer ConfirmationEmailer.new end def activate_account! self.active = true changed # <- This is important notify_observers self end end Twitter: @bphogan Web: http://www.napcs.com/
  • 53.
    Where does itfall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 54.
    Serving Web Pages Twitter:@bphogan Web: http://www.napcs.com/
  • 55.
    Sinatra? require 'sinatra' set :public, "~/Sites" Twitter: @bphogan Web: http://www.napcs.com/
  • 56.
    How about this? s = WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => "~/Sites") trap('INT') { s.shutdown }; s.start Twitter: @bphogan Web: http://www.napcs.com/
  • 57.
    How about analias? alias serve="ruby -rwebrick -e"s = WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd); trap('INT') { s.shutdown }; s.start"" $ cd ~/Sites $ serve Twitter: @bphogan Web: http://www.napcs.com/
  • 58.
  • 59.
    It also servesweb apps Twitter: @bphogan Web: http://www.napcs.com/
  • 60.
    Your dev machine really needs Passenger running? Twitter: @bphogan Web: http://www.napcs.com/
  • 61.
    Where it’s used •Rails •Other frameworks Twitter: @bphogan Web: http://www.napcs.com/
  • 62.
    Where does itfall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 63.
  • 64.
    PStore Persistent, transactional storage. Baked right in to Ruby’s standard library. Twitter: @bphogan Web: http://www.napcs.com/
  • 65.
    We can storestuff... require 'pstore' store = PStore.new('links') links = %W{http://www.github.com http://heroku.com http://ruby-lang.org} store.transaction do store[:links] ||= [] links.each{|link| store[:links] << link} store[:last_modified] = Time.now end Twitter: @bphogan Web: http://www.napcs.com/
  • 66.
    and we canget it back. store = PStore.new("links") store.transaction do links = store[:links] end puts links.join("n") Twitter: @bphogan Web: http://www.napcs.com/
  • 67.
    Where it’s used •Rails 1.x Twitter: @bphogan Web: http://www.napcs.com/
  • 68.
    Where does it fall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 69.
  • 70.
    Importing CSV files require 'csv' CSV.open('data.csv', 'r', ';') do |row| p row end Twitter: @bphogan Web: http://www.napcs.com/
  • 71.
    CSV is slow. “Use FasterCSV” Twitter: @bphogan Web: http://www.napcs.com/
  • 72.
    In Ruby 1.9, FasterCSV is the new CSV! Twitter: @bphogan Web: http://www.napcs.com/
  • 73.
    Working with Dates Twitter:@bphogan Web: http://www.napcs.com/
  • 74.
    How we doit today = DateTime.now birthday = Date.new(2010, 10, 5) days_to_go = birthday - today time_until = birthday - today hours,minutes,seconds,frac = Date.day_fraction_to_time(time_until) http://www.techotopia.com/index.php/Working_with_Dates_and_Times_in_Ruby Twitter: @bphogan Web: http://www.napcs.com/
  • 75.
    home_run home_run is an implementation of rubyʼs Date/ DateTime classes in C, with much better performance (20-200x) than the version in the standard library, while being almost completely compatible. http://github.com/jeremyevans/home_run Twitter: @bphogan Web: http://www.napcs.com/
  • 76.
    REXML Built-in library for parsing and creating XML. Twitter: @bphogan Web: http://www.napcs.com/
  • 77.
    How about HPricot, libxml- ruby, or Nokogiri. http://www.rubyinside.com/ruby-xml-performance-benchmarks-1641.html Twitter: @bphogan Web: http://www.napcs.com/
  • 78.
    ERb Templating language as part of the Standard Library. Twitter: @bphogan Web: http://www.napcs.com/
  • 79.
    require 'erb' template = ERB.new <<-EOF <h1><%=@name %></h1> EOF @name = "AwesomeCo" puts template.result Twitter: @bphogan Web: http://www.napcs.com/
  • 80.
    Templating language != View language!!! Twitter: @bphogan Web: http://www.napcs.com/
  • 81.
    What can itdo? •Generate JavaScript •Generate YAML •Generate ERb •Any type of proprietary data export Twitter: @bphogan Web: http://www.napcs.com/
  • 82.
    Where does itfall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 83.
    Alternatives? •HAML •Liquid •ERubis •Tons of others Twitter: @bphogan Web: http://www.napcs.com/
  • 84.
    Test::Unit We have an awesome testing library as part of our standard library. Twitter: @bphogan Web: http://www.napcs.com/
  • 85.
    It’s pretty good. Anyone know of any alternatives? Twitter: @bphogan Web: http://www.napcs.com/
  • 86.
    Only a few. •RSpec •Bacon •Context / Contest / Shoulda / Matchy •Testy •Micronaut •Whatever someone writes next week Twitter: @bphogan Web: http://www.napcs.com/
  • 87.
    I use RSpec* * And I still use Test::Unit. Twitter: @bphogan Web: http://www.napcs.com/
  • 88.
    “Minitest is aminitest/unit is a small and fast replacement for ruby's huge and slow test/unit”. Twitter: @bphogan Web: http://www.napcs.com/
  • 89.
    If X sucksso bad, why do we write something else instead of fixing it? Twitter: @bphogan Web: http://www.napcs.com/
  • 90.
    We think wecan do it better. Twitter: @bphogan Web: http://www.napcs.com/
  • 91.
    The original developer doesn’t want our help. Twitter: @bphogan Web: http://www.napcs.com/
  • 92.
    There’s a language barrier. Twitter: @bphogan Web: http://www.napcs.com/
  • 93.
    Challenge: Extend the Standard Library. Twitter: @bphogan Web: http://www.napcs.com/
  • 94.
    Make the wheelswe have better. Twitter: @bphogan Web: http://www.napcs.com/
  • 95.
    That’s it. •Twitter: @bphogan •email: bphogan@gmail.com •web: http://www.napcs.com/ •blog: http://bphogan.com •github: http://github.com/napcs/ Twitter: @bphogan Web: http://www.napcs.com/