I've written a Twitter bot, @answering_yelp, which responds to another Twitter bot, @hard_to_yelp. They scrape yelp reviews for sentences which start "How hard is it to..." and my bot answer with some version of how hard it is.
I recently refactored the code to handle changes to the source text as a list of command classes, instead of one ever-expanding method, or collection of methods, in my Generator class.
You can see the code in context on GitHub.
I'm wondering if I should have implemented these classes as singletons, or if there's some reason to leave the singleton declaration out.
Here's some snippets:
generator.rb (much smaller since this refactor)
class Generator
TRANSFORMS = [
Transforms::Substitutions,
Transforms::Answer,
Transforms::Question,
Transforms::Recipient
]
def initialize(source, options, recipient='hard_to_yelp')
@source = source
@transform_arguments = {
options: options,
recipient: recipient
}
end
def run
result = @source.dup
TRANSFORMS.each { |transform| result = transform.run(result, @transform_arguments) }
result = run until result.length <= 140
result
end
end
Just one of my transforms, Question, which adds a question mark if there's a questioning word present (or removes one if there isn't).
module Transforms
class Question
include Singleton
QUESTION_WORDS = %w{why where which who}
def self.run(source, arguments={})
if is_question?(source)
has_punctuation?(source) ? source.gsub('.', '?') : source + '?'
else
source.gsub('?', '.')
end
end
def self.is_question?(source)
src = source.downcase
QUESTION_WORDS.any? { |q| src.index(q) }
end
private_class_method :is_question?
def self.has_punctuation?(source)
source.index('.') || source.index('?')
end
private_class_method :has_punctuation?
end
end
Singleton pros:
- The only public interface is the
run
method. Some other interface (such as thenew
method) is removed. - If I choose to keep the environment open (say, with spring), there'll be fewer objects initialised, marginally more performant.
Singleton cons:
- It's probably not needed, if I remove the include, it still works.
- People don't like singletons.
To singleton, or not to singleton. That is the question.