# This is a simple refactoring exercise. # # What to do? # # 1. Look at the code of the class CorrectAnswerBehavior # 2. Try to see what it does by running `ruby refactoring_example.rb` # 3. Record characterisation tests by running `ruby refactoring_example.rb --record` # 4. Make the code beautiful;) # 5. You are allowed to modify only the code between markers (REFACTORING START/REFACTORING END). # 6. Test must pass! You can run them with command `ruby refactoring_example.rb --test` # 7. For suggestions of other exercises based on this code... # a) Follow http://twitter.com/programmingwod or # b) like https://www.facebook.com/ProgrammingWorkout or # c) signup to http://programmingworkout.com # # Usage: # ruby refactoring_example.rb [-h|--help|help] - shows help screen. # ruby refactoring_example.rb [-c|--clean|clean] - clean recorded results of simulation. # ruby refactoring_example.rb [-r|--record|record] - records 5000 results of simulation. # ruby refactoring_example.rb [-t|--test|test] - tests against 5000 recorded results of simulation. # ruby refactoring_example.rb - shows result of simulation initialized with . # ruby refactoring_example.rb - shows result of random simulation. # # License: MIT (see at the end of the file) # This code is based on Trivia Game example used in Legacy Code Retreats # You can find it at https://github.com/jbrains/trivia # ------------------------------ REFACTORING START ------------------------------ class CorrectAnswerBehavior attr_reader :is_getting_out_of_penalty_box, :players def was_correctly_answered return correct_answer if not current_player.penalty return player_gets_out_penalty_box if is_getting_out_of_penalty_box return player_stays_in_penalty_box end def player_gets_out_penalty_box puts "#{player_name} got out of penalty box" puts 'Answer was correct!!!!' increment_purse puts "#{player_name} now has #{purse} Gold Coins." next_player! puts "Player is now #{player_name}" end def player_stays_in_penalty_box puts "#{player_name} stays in penalty box" next_player! puts "Player is now #{player_name}" end def correct_answer puts "Answer was corrent!!!!" increment_purse puts "#{player_name} now has #{purse} Gold Coins." next_player! puts "Player is now #{player_name}" end def player_name current_player.name end def purse current_player.purse end def increment_purse current_player.increment_purse end def next_player! players.next end def current_player players.peek end # ------------------------------ REFACTORING END ------------------------------ public def initialize seed = nil srand(seed) if seed purses = (1..3).map { rand(3) + 2 } in_penalty_box = (1..3).map { rand(2) == 0 } player_index = rand(3) @is_getting_out_of_penalty_box = in_penalty_box[player_index] && rand(2) == 0 names = %w[Alice Bob Cecil] @players = names.zip(purses, in_penalty_box).map do |(name, purse, penalty)| Player.new(name, purse, penalty) end @players = @players.rotate(player_index).cycle end end class Player attr_reader :name, :purse, :penalty def initialize(name, purse, penalty) @name = name @purse = purse @penalty = penalty end def increment_purse @purse += 1 end end require 'fileutils' module FixtureHandler def self.clear_fixtures FileUtils.rm_rf(fixtures_dir) end def self.create_fixture_dir FileUtils.mkdir(fixtures_dir) end def self.write_fixture index, text File.open(fixture_path(index), "w") do |file| file.write(text) end end def self.fixture_exists? index File.exists?(fixture_path(index)) end def self.read_fixture index File.read(fixture_path(index)) end def self.fixture_path index "#{fixtures_dir}/#{index}.txt" end def self.fixtures_dir "#{File.expand_path(File.dirname(__FILE__))}/fixtures" end end module StdOutToStringRedirector require 'stringio' def self.redirect_stdout_to_string sio = StringIO.new old_stdout, $stdout = $stdout, sio yield $stdout = old_stdout sio.string end end SIMULATIONS_COUNT = 5000 def run_simulation index = nil CorrectAnswerBehavior.new(index).was_correctly_answered end def capture_simulation_output index StdOutToStringRedirector.redirect_stdout_to_string do run_simulation(index) end end def clean_fixtures FixtureHandler.clear_fixtures end def record_fixtures SIMULATIONS_COUNT.times do |index| raise "You need to clean recorded simulation results first!" if FixtureHandler.fixture_exists?(index) end FixtureHandler.create_fixture_dir SIMULATIONS_COUNT.times do |index| FixtureHandler.write_fixture(index, capture_simulation_output(index)) end rescue RuntimeError => e puts "ERROR!!!" puts e.message end require 'test/unit/assertions' include Test::Unit::Assertions def test_output SIMULATIONS_COUNT.times do |index| raise "You need to record simulation results first!" unless FixtureHandler.fixture_exists?(index) assert_equal(FixtureHandler.read_fixture(index), capture_simulation_output(index)) end puts "OK." rescue RuntimeError => e puts "ERROR!!!" puts e.message end case ARGV[0].to_s.downcase when "-h", "--help", "help" puts "Usage:" puts " ruby #{__FILE__} [-h|--help|help] - shows help screen." puts " ruby #{__FILE__} [-c|--clean|clean] - clean recorded results of simulation." puts " ruby #{__FILE__} [-r|--record|record] - records #{SIMULATIONS_COUNT} results of simulation." puts " ruby #{__FILE__} [-t|--test|test] - tests against #{SIMULATIONS_COUNT} recorded results of simulation." puts " ruby #{__FILE__} - shows result of simulation initialized with ." puts " ruby #{__FILE__} - shows result of random simulation." when "-c", "--clean", "clean" clean_fixtures when "-r", "--record", "record" record_fixtures when "-t", "--test", "test" test_output when /\d(.\d+)?/ run_simulation ARGV[0].to_f else run_simulation end # Copyright © 2012 Michal Taszycki # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.