Skip to content

Instantly share code, notes, and snippets.

@adkron
Forked from anonymous/bob.rb
Last active December 20, 2015 14:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adkron/6148836 to your computer and use it in GitHub Desktop.
Save adkron/6148836 to your computer and use it in GitHub Desktop.
I edited this in the browser so I might not be quite right, but I think I got it.
class << Silent = Object.new
def heard?(other)
other.empty?
end
def respond
"Fine. Be that way."
end
end
class << Question = Object.new
def heard?(other)
other.end_with?("?")
end
def respond
"Sure."
end
end
class << Shout = Object.new
def heard?(other)
other == other.upcase
end
def respond
"Woah, chill out!"
end
end
class << Default = Object.new
def respond
"Whatever."
end
end
class Bob
def self.add_thought(thought)
@thoughts.push thought
end
@thoughts = []
add_thought Silent
add_thought Question
add_thought Shout
def hey(phrase)
think_about(heard(phrase)).respond
end
def heard(phrase)
String(phrase)
end
def think_about(might_have_heard)
thoughts.find(-> { Default }) { |thought| thought.heard?(might_have_heard) }
end
def self.thoughts
@thoughts
end
private
def thoughts
self.class.thoughts
end
end
@markijbema
Copy link

I think it's very dangerous to remove the if construct. When using ifs it is very clear that you only check Shout when Silence is false. Now, the program only works because of the ordering of THOUGHTS. That's a bit too tricky for my taste.

@adkron
Copy link
Author

adkron commented Aug 7, 2013

@markijbema this has nothing to do with the if construct. If I had these as a bunch of if statements and the silent if was not first we would have the same issue. The real problem is that Shout does not check that the string contains a least some letters. With this configuration I can easily write tests to test that piece in isolation. In no way does this have to do with the construct that I used here. This will still only check Shout when Silent is false.

  if phrase.silent?
    # ...
  elsif phrase.shout?
    #...

See what I mean?

The other thing is that I can easily make this expandable and inject different thoughts. Now I am not bound to a set of hard coded circumstances. IMHO that makes this code infinitely more maintainable than a string of if statements. If I change this to inject thoughts then I have truly gotten this class to a good example of the open/closed principle. Bob no longer has reason to change. The if construct becomes larger and more error prone as I continue to add more.

@JEG2
Copy link

JEG2 commented Aug 8, 2013

I agree that this is a more OO version of Bob. I like it.

My thought when reading it was that I might add a trivial one class method DSL for defining new responses. That's just a random idea I had.

@adkron
Copy link
Author

adkron commented Aug 8, 2013

@JEG2, thanks. I think that is a good idea. Something like:

  @responders = []
  def self.add_responder(responder)
    @responders.push responder
  end

  add_responder Silent
  add_responder Question

I think that could be good. I also like the idea of adding multiple responders. Maybe this would be better to do on an instance?

@adkron
Copy link
Author

adkron commented Aug 9, 2013

@JEG2 is this new version what you were thinking?

@adkron
Copy link
Author

adkron commented Aug 9, 2013

Oh, I read that all wrong. You said to define responses.

  respond_with "Fine. Be that way.", when: ->(other) { other.empty? }

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