SlideShare a Scribd company logo
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/

More Related Content

KEY
Intro To Advanced Ruby
KEY
Building A Gem From Scratch
PDF
Introduction To Django (Strange Loop 2011)
PDF
Python beautiful soup - bs4
KEY
Web Development with CoffeeScript and Sass
PDF
Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...
PDF
SEO Cheat Sheets for WordPress
PPT
How we build Vox
Intro To Advanced Ruby
Building A Gem From Scratch
Introduction To Django (Strange Loop 2011)
Python beautiful soup - bs4
Web Development with CoffeeScript and Sass
Shiny, Let’s Be Bad Guys: Exploiting and Mitigating the Top 10 Web App Vulner...
SEO Cheat Sheets for WordPress
How we build Vox

What's hot (10)

ODP
Getting started with Django 1.8
PPT
Rush, a shell that will yield to you
PDF
Big data beyond the JVM - DDTX 2018
PDF
Rails 4.0
PDF
Yahoo is open to developers
PDF
Layouts and Rendering in Rails, Season 2
KEY
Supa fast Ruby + Rails
PDF
Selenium&amp;scrapy
PDF
Opening up the Social Web - Standards that are bridging the Islands
KEY
Socket applications
Getting started with Django 1.8
Rush, a shell that will yield to you
Big data beyond the JVM - DDTX 2018
Rails 4.0
Yahoo is open to developers
Layouts and Rendering in Rails, Season 2
Supa fast Ruby + Rails
Selenium&amp;scrapy
Opening up the Social Web - Standards that are bridging the Islands
Socket applications
Ad

Viewers also liked (20)

PDF
Diễn họa ( Sketch with water colour)
PPS
Proyec Aeroblade Bahia De Cadiz
PDF
Global Ceramic Tiles Industry
PDF
Topled Introduction
PDF
Ylb planta móvil mezcladora de asfalto
DOC
VYS Devon Youth News Local June 2010
PDF
Caracterizacion parcial de peliculas preparadas con almidon oxidado de platano
PPT
dmr's Moments Of Truth Conclave Webinar
PPT
Dc08 Joe Suh
PDF
Pinterest. La guía definitiva
PDF
Explicació teoria de l'evolució
PPTX
Todo sobre la Web 2.0
PDF
01 PIAS y PAIS Carmen Echevarría
PDF
How To Engineer A Christmas Tree
PPT
ELV companies in UAE
PDF
PPTX
Saleme roseliane danzas
PDF
Guion de blade runner
PDF
Introduction_to_FRACAS - Course_Outline
Diễn họa ( Sketch with water colour)
Proyec Aeroblade Bahia De Cadiz
Global Ceramic Tiles Industry
Topled Introduction
Ylb planta móvil mezcladora de asfalto
VYS Devon Youth News Local June 2010
Caracterizacion parcial de peliculas preparadas con almidon oxidado de platano
dmr's Moments Of Truth Conclave Webinar
Dc08 Joe Suh
Pinterest. La guía definitiva
Explicació teoria de l'evolució
Todo sobre la Web 2.0
01 PIAS y PAIS Carmen Echevarría
How To Engineer A Christmas Tree
ELV companies in UAE
Saleme roseliane danzas
Guion de blade runner
Introduction_to_FRACAS - Course_Outline
Ad

Similar to Stop Reinventing The Wheel - The Ruby Standard Library (20)

KEY
Using and scaling Rack and Rack-based middleware
KEY
PDF
Digital Library Federation, Fall 07, Connotea Presentation
PDF
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...
KEY
REST teori og praksis; REST in theory and practice
PDF
Puppet getting started by Dirk Götz
PDF
Extreme APIs for a better tomorrow
PPTX
Exploiter le Web Semantic, le comprendre et y contribuer
PDF
Node.js 기반 정적 페이지 블로그 엔진, 하루프레스
PPTX
How to connect social media with open standards
PPTX
How I built the demo's
PDF
Building Google-in-a-box: using Apache SolrCloud and Bigtop to index your big...
PPTX
Web backends development using Python
PDF
REST Introduction (PHP London)
KEY
Motion Django Meetup
PDF
Python & Django TTT
PDF
WordCamp Bournemouth 2014 - Designing with data in WordPress
PPTX
Everything you wanted to know about writing async, concurrent http apps in java
PPT
How to? Drupal developer toolkit. Dennis Povshedny.
PDF
Puppet at Pinterest
Using and scaling Rack and Rack-based middleware
Digital Library Federation, Fall 07, Connotea Presentation
Fulfilling the Hypermedia Constraint via HTTP OPTIONS, The HTTP Vocabulary In...
REST teori og praksis; REST in theory and practice
Puppet getting started by Dirk Götz
Extreme APIs for a better tomorrow
Exploiter le Web Semantic, le comprendre et y contribuer
Node.js 기반 정적 페이지 블로그 엔진, 하루프레스
How to connect social media with open standards
How I built the demo's
Building Google-in-a-box: using Apache SolrCloud and Bigtop to index your big...
Web backends development using Python
REST Introduction (PHP London)
Motion Django Meetup
Python & Django TTT
WordCamp Bournemouth 2014 - Designing with data in WordPress
Everything you wanted to know about writing async, concurrent http apps in java
How to? Drupal developer toolkit. Dennis Povshedny.
Puppet at Pinterest

More from Brian Hogan (19)

PDF
Creating and Deploying Static Sites with Hugo
PDF
Automating the Cloud with Terraform, and Ansible
PDF
Create Development and Production Environments with Vagrant
PDF
Docker
PDF
Getting Started Contributing To Open Source
PDF
Rethink Frontend Development With Elm
KEY
Testing Client-side Code with Jasmine and CoffeeScript
KEY
FUD-Free Accessibility for Web Developers - Also, Cake.
KEY
Responsive Web Design
KEY
Turning Passion Into Words
PDF
HTML5 and CSS3 Today
PDF
Web Development With Ruby - From Simple To Complex
KEY
Intro to Ruby
KEY
Intro to Ruby - Twin Cities Code Camp 7
KEY
Make GUI Apps with Shoes
KEY
The Why Of Ruby
KEY
Story-driven Testing
KEY
Learning To Walk In Shoes
KEY
Rails and Legacy Databases - RailsConf 2009
Creating and Deploying Static Sites with Hugo
Automating the Cloud with Terraform, and Ansible
Create Development and Production Environments with Vagrant
Docker
Getting Started Contributing To Open Source
Rethink Frontend Development With Elm
Testing Client-side Code with Jasmine and CoffeeScript
FUD-Free Accessibility for Web Developers - Also, Cake.
Responsive Web Design
Turning Passion Into Words
HTML5 and CSS3 Today
Web Development With Ruby - From Simple To Complex
Intro to Ruby
Intro to Ruby - Twin Cities Code Camp 7
Make GUI Apps with Shoes
The Why Of Ruby
Story-driven Testing
Learning To Walk In Shoes
Rails and Legacy Databases - RailsConf 2009

Recently uploaded (20)

PPTX
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
PPTX
A Presentation on Artificial Intelligence
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Spectral efficient network and resource selection model in 5G networks
PPT
Teaching material agriculture food technology
PDF
NewMind AI Weekly Chronicles - August'25 Week I
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
Encapsulation_ Review paper, used for researhc scholars
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
CIFDAQ's Market Insight: SEC Turns Pro Crypto
PDF
Encapsulation theory and applications.pdf
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PDF
Machine learning based COVID-19 study performance prediction
PDF
Modernizing your data center with Dell and AMD
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Empathic Computing: Creating Shared Understanding
Detection-First SIEM: Rule Types, Dashboards, and Threat-Informed Strategy
A Presentation on Artificial Intelligence
Chapter 3 Spatial Domain Image Processing.pdf
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Spectral efficient network and resource selection model in 5G networks
Teaching material agriculture food technology
NewMind AI Weekly Chronicles - August'25 Week I
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Unlocking AI with Model Context Protocol (MCP)
Encapsulation_ Review paper, used for researhc scholars
The AUB Centre for AI in Media Proposal.docx
Reach Out and Touch Someone: Haptics and Empathic Computing
CIFDAQ's Market Insight: SEC Turns Pro Crypto
Encapsulation theory and applications.pdf
Diabetes mellitus diagnosis method based random forest with bat algorithm
Machine learning based COVID-19 study performance prediction
Modernizing your data center with Dell and AMD
20250228 LYD VKU AI Blended-Learning.pptx
Empathic Computing: Creating Shared Understanding

Stop Reinventing The Wheel - The Ruby Standard Library

  • 1. stop reinventing the wheel hidden gems in the ruby standard library brian hogan - @bphogan
  • 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 not so 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 not talking 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 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/
  • 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 it fall 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 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/
  • 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 it fall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 24. Working with Paths Twitter: @bphogan Web: http://www.napcs.com/
  • 25. 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/
  • 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. Grabbing Files Twitter: @bphogan Web: http://www.napcs.com/
  • 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 as files! 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 it fall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 37. Temporary files Twitter: @bphogan Web: http://www.napcs.com/
  • 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. Data structures Twitter: @bphogan Web: http://www.napcs.com/
  • 42. 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/
  • 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 your own “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 it fall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 47. Watching Stuff Twitter: @bphogan Web: http://www.napcs.com/
  • 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 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/
  • 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 it fall 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 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/
  • 59. It also serves web 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 it fall short? Twitter: @bphogan Web: http://www.napcs.com/
  • 63. Storing Data Twitter: @bphogan Web: http://www.napcs.com/
  • 64. PStore Persistent, transactional storage. Baked right in to Ruby’s standard library. Twitter: @bphogan Web: http://www.napcs.com/
  • 65. 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/
  • 66. 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/
  • 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. Better Wheels Twitter: @bphogan Web: http://www.napcs.com/
  • 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 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/
  • 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 it do? •Generate JavaScript •Generate YAML •Generate ERb •Any type of proprietary data export Twitter: @bphogan Web: http://www.napcs.com/
  • 82. Where does it fall 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 a minitest/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 sucks so bad, why do we write something else instead of fixing it? Twitter: @bphogan Web: http://www.napcs.com/
  • 90. We think we can 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 wheels we 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/