receiver = Receiver.new
receiver.message
# or, implicit receiver
message
# => NameError: undefined local variable or method `message' for main:Object
# this metaphor also applies to core types
[1, 2, 3].first
class Cat
def meow
"meow"
end
def louder
upcase + " said the cat"
end
end
c = Cat.new
c.meow.louder
# => NoMethodError: undefined method `louder' for "meow":String
class Cat
def meow
"meow"
end
def louder(meow)
meow.upcase + " said the cat"
end
end
c = Cat.new
c.louder(c.meow)
# => "MEOW said the cat"
class Cat
attr_reader :meow
def meow
@meow = "meow"
self
end
def louder
@meow.upcase + " said the cat"
end
end
c = Cat.new
c.meow.louder
# => "MEOW said the cat"
class String
def louder
upcase + " said the cat"
end
end
class Cat
def meow
"meow"
end
end
c = Cat.new
c.meow.louder
# => "MEOW said the cat"
class Array
def first
if rand(1..10) == 1
'wat'
else
super
end
end
end
module Loud
refine String do
def louder
upcase + " said the cat"
end
end
end
class Cat
def meow
"meow"
end
end
using Loud
c = Cat.new
c.meow.louder
# => "MEOW said the cat"
# not activated here
class Foo
# not activated here
def foo
# not activated here
end
using M
# activated here
def bar
# activated here
end
# activated here
end
# not activated here
module HashFmap
refine Hash do
def fmap &block
self.reduce({}) { |memo, (k,v)| memo.merge!({ k => block.call(v) }) }
end
end
end
h = {:foo=>"bar", :biz=>"baz"}
h.map {|k, v| v.upcase }
# => ["BAR", "BAZ"]
using HashFmap
h.fmap(&:upcase)
# => {:foo=>"BAR", :biz=>"BAZ"}
module ThirdPartyAPIParams
refine ModelOne do
def params
{ ParamOne: 21 }
end
end
refine ModelTwo do
def params
{ ParamTwo: 22 }
end
end
end
class Worker
using ThirdPartyAPIParams
def perform(id, model)
m = model.find(id)
APIClient.post(m.params)
end
end
module MyWeirdFormatting
refine Thing do
def as_weird_format
to_s.chars.map(&:ord).map {|c| c.to_s(2) }.join
end
end
end
class ThingService
using MyWeirdFormatting
attr_accessor :thing
def initialize(thing)
@thing = thing
end
def store
$db.store(thing.id, thing.as_weird_format)
end
end
Do you really need every method on your class everywhere your class appears?
Really really??
My opinion: when an object has a smaller "surface area" of methods at base, and I extend its behavior explicitly in select contexts, I find it easier to reason about.
pry(main)> my_refined_object.methods
# => [ :to_s, :as_json, :inherited ]
pry(main)> my_object_bloated_with_mixins.methods
# => [ :to_s, :as_json, :random_method, :irrelevant, :wont_work, :inherited , :idc, :definitely_wrong, :mysterious ]
Literally, pry into some code and call .methods on it. What's truly useful for your receiver to accept as a message in that calling context?