4. JAMES EDWARD
GRAY II
Created the Ruby Quiz and wrote that book
Built FasterCSV (now CSV), HighLine (with Greg), Elif, and
some other scarier experiments
5. JAMES EDWARD
GRAY II
Created the Ruby Quiz and wrote that book
Built FasterCSV (now CSV), HighLine (with Greg), Elif, and
some other scarier experiments
Documented some of Ruby
6. JAMES EDWARD
GRAY II
Created the Ruby Quiz and wrote that book
Built FasterCSV (now CSV), HighLine (with Greg), Elif, and
some other scarier experiments
Documented some of Ruby
http://blog.grayproductions.net/
7. JAMES EDWARD
GRAY II
Created the Ruby Quiz and wrote that book
Built FasterCSV (now CSV), HighLine (with Greg), Elif, and
some other scarier experiments
Documented some of Ruby
http://blog.grayproductions.net/
http://twitter.com/JEG2
14. RUBYKAIGI2009
See how the Japanese do
conferences
The translation time
allows you to think more
Meet nice Rubyists from
Japan and other places
15. RUBYKAIGI2009
See how the Japanese do
conferences
The translation time
allows you to think more
Meet nice Rubyists from
Japan and other places
See Japan!
31. module Mixin
def shared_method
puts "Called!"
end
end
class Whatever
include Mixin
end
Whatever.new.shared_method
A TRIVIAL MIXIN
I’m sure most of us know this
32. module Mixin
def shared_method
puts "Called!"
end
end
class Whatever
Called!
include Mixin
end
Whatever.new.shared_method
A TRIVIAL MIXIN
I’m sure most of us know this
33.
34.
35.
36.
37.
38. class A
def call
puts "A"
end
end
%w[B C D].each do |name|
eval <<-END_RUBY
module #{name}
def call
puts "#{name}"
super
end
end
END_RUBY
end
class E < A
include B
include C
include D
def call
puts "E"
super
end
end
E.new.call
39. E
class A
def call
puts "A"
end
end
D
%w[B C D].each do |name|
eval <<-END_RUBY
module #{name}
def call
puts "#{name}"
super
C
end
end
END_RUBY
end
B
class E < A
include B
include C
include D
def call
puts "E"
A
super
end
end
E.new.call
41. [E, D, C, B, A, Object, Kernel, BasicObject]
INHERITANCE
p E.ancestors
42.
43.
44.
45.
46.
47. class A
def call
puts "A"
end
end
%w[B C D].each do |name|
eval <<-END_RUBY
module #{name}
def call
puts "#{name}"
super
end
end
END_RUBY
end
a = A.new
a.extend(B)
a.extend(C)
a.extend(D)
a.call
48. D
class A
def call
puts "A"
end
end
C
%w[B C D].each do |name|
eval <<-END_RUBY
module #{name}
def call
puts "#{name}"
super
B
end
end
END_RUBY
end
A
a = A.new
a.extend(B)
a.extend(C)
a.extend(D)
a.call
50. [D, C, B, A, Object, Kernel, BasicObject]
INVISIBLE CLASS
class << a; p ancestors end
51. The (invisible) “singleton class” is here
[D, C, B, A, Object, Kernel, BasicObject]
INVISIBLE CLASS
class << a; p ancestors end
52.
53. class A
def call
puts "A"
end
end
%w[B C D].each do |name|
eval <<-END_RUBY
module #{name}
def call
puts "#{name}"
super
end
end
END_RUBY
end
a = A.new
a.extend(B)
a.extend(C)
a.extend(D)
class << a
def call
puts "Invisible"
super
end
end
a.call
54. class A
def call
puts "A"
end
Invisible
end
%w[B C D].each do |name|
eval <<-END_RUBY
D
module #{name}
def call
puts "#{name}"
super
C
end
end
END_RUBY
end
B
a = A.new
a.extend(B)
a.extend(C)
a.extend(D)
A
class << a
def call
puts "Invisible"
super
end
end
a.call
61. class Logger
# ...
# Logging severity.
module Severity
DEBUG = 0
INFO = 1
WARN = 2
ERROR = 3
FATAL = 4
UNKNOWN = 5
end
include Severity
# ...
end
GROUP CONSTANTS
Group constants/classes and even mix them in
62. class Logger module JSON
# ...
# Logging severity. class Array
module Severity
DEBUG = 0
# ...
INFO = 1 end
WARN = 2
ERROR = 3 class Object
FATAL = 4
UNKNOWN = 5
# ...
end end
include Severity
# ... # ...
end end
GROUP CONSTANTS
Group constants/classes and even mix them in
68. module MoreMath
def self.dist(x1, y1, x2, y2)
Math.sqrt( (x2 - x1) ** 2 +
(y2 - y1) ** 2 )
end
end
DUAL INTERFACE
Some modules are both a namespace and a mixin
69. module MoreMath module MoreMath
def self.dist(x1, y1, x2, y2) extend Math
def self.dist( x1, y1,
Math.sqrt( (x2 - x1) ** 2 + x2, y2 )
(y2 - y1) ** 2 ) sqrt( (x2 - x1) ** 2 +
(y2 - y1) ** 2 )
end end
end
end
DUAL INTERFACE
Some modules are both a namespace and a mixin
71. module MiniLogger
extend self
def logger
$stdout
end
def log(message)
logger.puts "%s: %s" %
[ Time.now.strftime("%D %H:%M:%S"),
message ]
end
end
if __FILE__ == $PROGRAM_NAME
MiniLogger.log "Called as a module method and " +
"written to $stdout."
end
MIXIN YOURSELF
Better than Ruby’s module_function()
72. module MiniLogger require "mini_logger"
extend self
def logger class Whatever
$stdout include MiniLogger
end def logger
def log(message) @logger ||=
open("whatever.log", "w")
logger.puts "%s: %s" %
end
[ Time.now.strftime("%D %H:%M:%S"),
def initialize
message ]
log "Called as an " +
end "instance method " +
end "and written to " +
"a file."
if __FILE__ == $PROGRAM_NAME end
MiniLogger.log "Called as a module method and " + end
"written to $stdout."
end Whatever.new
MIXIN YOURSELF
Better than Ruby’s module_function()
78. module Errors
class BaseError < RuntimeError; end
def self.const_missing(error_name)
if error_name.to_s =~ /wErrorz/
const_set(error_name, Class.new(BaseError))
else
super
end
end
end
p Errors::SaveError
LIMITED MAGIC
Summon new error types as needed
85. require "ostruct"
# These extra methods are mixed into the OpenStruct stored in Config.
module Configured
# This method loads configuration settings from a plain Ruby file.
def update_from_config_file(path = config_file)
eval <<-END_UPDATE
config = self
#{File.read(path)}
config
END_UPDATE
end
# ...
end
# This constant holds all global configuration, see Configured for details.
Config = OpenStruct.new.extend(Configured)
LESS MAGIC
RDoc and I can both read it now
91. module DoubleMixin
module ClassMethods
# ...
end
module InstanceMethods
# ...
end
def self.included(receiver)
receiver.extend(ClassMethods)
receiver.send(:include, InstanceMethods)
end
end
WITH CLASS METHODS
A classic pattern made popular by Rails
97. module DRb
# ...
module DRbUndumped
def _dump(dummy) # :nodoc:
raise TypeError, 'can't dump'
end
end
# ...
class DRbMessage
# ...
def dump(obj, error=false) # :nodoc:
obj = make_proxy(obj, error) if obj.kind_of? DRbUndumped
# ...
end
# ...
end
# ...
end
LABELING OBJECTS
You can use a do-nothing module as a type
99. p "ruby".strip!.
capitalize!
# NoMethodError:
# undefined method
# `capitalize!' for
# nil:NilClass
OBJECT EDITING
Using hooks to edit objects
100. module SafelyChainable
def self.extended(singleton)
singleton.methods.grep(/w!z/).
each do |bang|
p "ruby".strip!. singleton.instance_eval <<-END_RUBY
def #{bang}
capitalize!
super
self
# NoMethodError:
end
# undefined method END_RUBY
# `capitalize!' for end
# nil:NilClass end
end
p "ruby".extend(SafelyChainable).
strip!.capitalize!
OBJECT EDITING
Using hooks to edit objects
105. SUMMARY
Master Ruby’s method
lookup; it’s worth the effort
Modules are a terrific at
limiting the scope of magic
Remember, modules can
modify individual objects
106. SUMMARY
Master Ruby’s method
lookup; it’s worth the effort
Modules are a terrific at
limiting the scope of magic
Remember, modules can
modify individual objects
Try replacing some
inheritance with extend()