Stop Reinventing The Wheel - The Ruby Standard Library
Sep. 5, 2010•0 likes•9,817 views
Download to read offline
Report
Technology
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.
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/
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/
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/
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/
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/
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/
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/
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/