Skip to content

Instantly share code, notes, and snippets.

@kevingriffin
Created August 2, 2012 19:44
Show Gist options
  • Save kevingriffin/3240036 to your computer and use it in GitHub Desktop.
Save kevingriffin/3240036 to your computer and use it in GitHub Desktop.
Dependency Injection
# We have a FunnySentences class. Objects of this class generate five **wacky** phrases with random upper and lower case.
# Because the logic of returning the sentences in some modified form is seperate
# from the process of generating the sentences, we use a different object to do the generation (single responsiblity princible).
# Instead of just using this generation object directly, we assign it to a variable when we create a new FunnySentences object.
# Interally, the FunnySentencs object calls methods on this object we pass in, asking it to generate sentences for us.
# As long as the generator we pass in returns strings when we call generate on it,
# the logic in our FunnySentences class will work no matter what we use for the generator.
class FunnySentences
# We use an attr_accessor so we can set up an object of a different class to take over the sentence generation
attr_accessor :sentence_generator
# When we initialize a FunnySentences object, we can pass in a custom generator. By default, it uses the lame one.
def initialize(sentence_generator = LameSentenceGenerator.new)
self.sentence_generator = sentence_generator
end
# The rest of our code doesn't need to know about the generator, so we can focus on its logic
def wacky_time!
get_sentences.map do |sentence|
"WHOA! #{sentence}"
end
end
def random_case(sentence)
sentence.each_char.map {|c| [c, c.upcase].sample }.join
end
# We don't have to change any of this logic to use a different generator, provided they both have the same method (generate)
def get_sentences
sentences = sentence_generator.generate(5)
sentences.map do |sentence|
random_case(sentence)
end
end
end
class LameSentenceGenerator
def generate(number)
number.times.map { "This one is lame and only makes one sentence" }
end
end
class BetterSentenceGenerator
def generate(number)
number.times.map do
["Two sentences this time!", "Double your pleasure."].sample
end
end
end
a = FunnySentences.new
a.wacky_time! # => ["WHOA! THIs oNE Is LamE aNd oNlY MaKEs ONe SEntEncE", "WHOA! ThIs OnE is LAme and ONLY MaKes one seNTEnCe", "WHOA! THiS one Is LaME AND onLY MaKEs oNE sEnTeNcE", "WHOA! This One iS Lame anD ONlY makeS oNE SENtence", "WHOA! ThIS onE Is lAmE anD ONly MAkES oNe SeNteNCe"]
b = FunnySentences.new(BetterSentenceGenerator.new)
b.wacky_time! # => ["WHOA! TWo senTENcEs this time!", "WHOA! Two seNTEnces this time!", "WHOA! DOuBLe Your plEASURE.", "WHOA! DoublE YouR PLeasUrE.", "WHOA! TWO sentENceS ThiS tiMe!"]
# We can take this a step further and abstract out the casing of the sentences (since that really isn't the job of our wacky class).
class FunnySentencesV2
# This time we can set both a generator and a caser (a word Josh would use in Boggle no doubt)
attr_accessor :sentence_generator, :caser
# When we initialize a FunnySentences object, we can pass in a custom generator. By default, it uses the lame one.
def initialize(sentence_generator = LameSentenceGenerator.new, caser = RandomCaser.new)
self.sentence_generator = sentence_generator
self.caser = caser
end
def wacky_time!
get_sentences.map do |sentence|
"WHOA! #{sentence}"
end
end
def get_sentences
sentences = sentence_generator.generate(5)
sentences.map do |sentence|
# Now we use our caser object instead of the class's own random method
caser.case sentence
end
end
end
class RandomCaser
def case(sentence)
sentence.each_char.map {|c| [c, c.upcase].sample }.join
end
end
class UpCaser
def case(sentence)
sentence.upcase
end
end
class DownCaser
def case(sentence)
sentence.downcase
end
end
c = FunnySentencesV2.new
c.wacky_time! # => ["WHOA! ThIs One iS lAmE anD ONLY mAkes One SENTENCE", "WHOA! ThiS oNe iS LaMe AnD ONlY makes OnE SenTencE", "WHOA! ThIS ONE Is lame aNd ONLY makes one sENTence", "WHOA! THiS One Is lAMe AnD onLY makes ONE SentenCe", "WHOA! THiS one is LAme anD oNLY MAKeS ONe SEnTENCE"]
d = FunnySentencesV2.new(BetterSentenceGenerator.new, UpCaser.new)
d.wacky_time! # => ["WHOA! DOUBLE YOUR PLEASURE.", "WHOA! TWO SENTENCES THIS TIME!", "WHOA! DOUBLE YOUR PLEASURE.", "WHOA! DOUBLE YOUR PLEASURE.", "WHOA! DOUBLE YOUR PLEASURE."]
e = FunnySentencesV2.new(LameSentenceGenerator.new, DownCaser.new)
e.wacky_time! # => ["WHOA! this one is lame and only makes one sentence", "WHOA! this one is lame and only makes one sentence", "WHOA! this one is lame and only makes one sentence", "WHOA! this one is lame and only makes one sentence", "WHOA! this one is lame and only makes one sentence"]
f = FunnySentencesV2.new(BetterSentenceGenerator.new, RandomCaser.new)
f.wacky_time! # => ["WHOA! Two seNTences ThIs tIME!", "WHOA! TWO seNTeNCEs ThIS tIMe!", "WHOA! TWo seNteNCeS THIs TimE!", "WHOA! TWo sentENceS ThIS TIMe!", "WHOA! DoUbLE YouR PLEASURE."]
# Now let's test our logic by mocking our generator to return a string we can test against
class GeneratorMock
def generate(number)
number.times.map { "This is a test sentence" }
end
end
test = FunnySentencesV2.new(GeneratorMock.new, UpCaser.new)
test.wacky_time! == ["WHOA! THIS IS A TEST SENTENCE", "WHOA! THIS IS A TEST SENTENCE", "WHOA! THIS IS A TEST SENTENCE", "WHOA! THIS IS A TEST SENTENCE", "WHOA! THIS IS A TEST SENTENCE", ] # => true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment