पाठ 13 / 25
Duck Typing, Open Classes and Refinements
Use duck typing and understand monkey patching and refinements.
Behaviour over types
Ruby relies on duck typing: what matters is whether an object responds to the methods you call, not its class. A method that calls io.write(text) works with a file, a StringIO or a network socket. Check capabilities with respond_to?(:write) when needed, rather than is_a?. Ruby classes are open: you can reopen any class, even core ones like String or Integer, and add or change methods. This monkey patching is powerful, and Rails' ActiveSupport adds conveniences such as 3.days.ago this way, but global patches to core classes can conflict between libraries and surprise other developers. Refinements (refine String do ... end inside a module, activated with using) scope such changes to a file or module, making them much safer. Prefer adding methods to your own classes, wrapping objects in your own types, or helper modules; reach for refinements only when extending a core or third-party class really makes the calling code clearer.
Duck typing
Any object that responds to the needed method works, whatever its class.
Duck typing and a scoped refinement
Any writable object works; the String extension is visible only where refined.
require "stringio"
def export_csv(rows, io)
rows.each { |r| io.write(r.join(",") + "\n") } # anything with #write works
io
end
buffer = export_csv([["o1", 1200], ["o2", 300]], StringIO.new)
puts buffer.string
File.open("orders.csv", "w") { |f| export_csv([["o1", 1200]], f) }
module RupeeFormatting
refine Integer do
def to_rupees = format("Rs %.2f", self / 100.0)
end
end
module Receipts
using RupeeFormatting # refinement active only inside this module
def self.line(item, paise) = "#{item}: #{paise.to_rupees}"
end
puts Receipts.line("Notebook", 12_000) # Notebook: Rs 120.00
# 12_000.to_rupees # NoMethodError here: refinement not activePatch core classes only with care
A global patch to String or Hash affects every gem in the process. If two libraries patch the same method differently, the result depends on load order. Refinements or your own wrapper classes avoid this.
त्वरित जाँच: What does duck typing mean in Ruby?
- Code depends on what methods an object responds to, not on its class
- Objects must inherit from Duck
- All variables must declare types
- Only classes can be passed to methods
Answer
Code depends on what methods an object responds to, not on its class — If it responds to the right methods, it can be used.