Your SlideShare is downloading. ×
Stop Reinventing The Wheel - The Ruby Standard Library
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Introducing the official SlideShare app

Stunning, full-screen experience for iPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Stop Reinventing The Wheel - The Ruby Standard Library

3,337
views

Published on

My talk from Ruby Hoedown MMX. We talked about the Ruby standard library and how sometimes we reinvent things when we have perfectly good tools waiting for us to use them.

My talk from Ruby Hoedown MMX. We talked about the Ruby standard library and how sometimes we reinvent things when we have perfectly good tools waiting for us to use them.

Published in: Technology

0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,337
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
37
Comments
0
Likes
6
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. stop reinventing the wheel hidden gems in the ruby standard library brian hogan - @bphogan
  • 2. Twitter: @bphogan Web: http://www.napcs.com/
  • 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/
  • 48. Rails? 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/
  • 58. 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/