Skip to content

Instantly share code, notes, and snippets.

@IanWhitney
Last active January 9, 2024 12:21
Show Gist options
  • Save IanWhitney/5e2f3ff7099768f3cf40 to your computer and use it in GitHub Desktop.
Save IanWhitney/5e2f3ff7099768f3cf40 to your computer and use it in GitHub Desktop.
class Bob
def reply_to(statement)
public_send("reply_to_#{statement.class}".downcase.to_sym)
rescue NoMethodError
default_reply
end
def reply_to_silence
"Fine. Be that way!"
end
def reply_to_yelling
"Woah, chill out!"
end
def reply_to_question
"Sure."
end
def default_reply
"Whatever."
end
end
class Statements
def self.all
[Question, Yelling, Silence, NullStatement]
end
end
Statement = Struct.new(:statement)
class Question < Statement
def self.match?(statement)
statement.end_with?("?")
end
end
class Yelling < Statement
def self.match?(statement)
statement.upcase == statement && statement.downcase != statement
end
end
class Silence < Statement
def self.match?(statement)
statement.strip.empty?
end
end
class NullStatement < Statement
def self.match?(statement)
true
end
end
class StatementFactory
def self.build(statement)
Statements.all.detect { |s| s.match?(statement) }.new(statement)
end
end
@disbelief
Copy link

@amcaplan I agree with you regarding #2 — I don't love the use of exceptions for flow control. However I think this is a contrived example with the stated goal of zero conditionals, so maybe we shouldn't judge too harshly.

However regarding your gripe in #1:

We've basically now forced Bob to know the names of lots of other classes.

I don't see how Bob having a REPLIES hash with keys matching the names of Statement classes is any different from Bob having methods matching those names.

In addition, I don't love the Factory, nor the need to maintain an array of Statements in a separate class. Now if a programmer creates a new kind of Statement, she also needs to know about putting it into an array in a separate class. @mereghost's solution leaving instantiation to the superclass and using inherited? to keep track of all descendants seems the ideal solution to me.

@rmcsharry
Copy link

@mereghost's answer is pretty interesting but I think it has a typo?

I think it should be like this:

self.inherited(klass)

No question mark in the name.

Ref: https://apidock.com/ruby/Class/inherited

@mereghost
Copy link

@rmcsharry Yep. >.<

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment