How to refactor long if/return statements in Ruby? -


i encounter complex pile of if statements, ruby way clean up?

(in service object example, foo has many bars. transferring bar different foo.)

class barmanager   include fancyerrorlogger    def self.transfer(bar, new_foo)      # move needed? line superfluous , premature optimisation?     return true if bar.foo_id == new_foo.id      # checks bar can moved new_foo. many more elsifs in practice, needs refactoring. these examples demonstrate potential complexity of each step, preventing use of overly simplistic solutions such seen here http://codereview.stackexchange.com/questions/14080/avoiding-a-lot-of-ifs-in-ruby     if bar.dependency == :do_not_move_me or bar.some_condition == false       bar.errors.add( :transfer, "this bar can't moved, on street corners moping , singing")       return false     elsif new_foo.want_more_bars == false       bar.errors.add( :transfer, "\"we don't take kindly type, bar\" - #{new_foo.name}")       return false     elsif ((bar.baz.optional_external_nightmare_status != :unused) || (new_foo.bars.inject(false){|result, element| result = result || element.baz.optional_external_nightmare_status != :unused}))       bar.errors.add( :transfer, "i have baz news you...")       return false     elsif bar.yet_another_failure_reason_there_are_many       bar.errors.add( :transfer, "there many ways fail, if statement short")       return false     elsif bar.stubborn?       bar.lure_with_carrot!       if bar.munching?         bar.errors.add ( :transfer, "eh, what's doc" )         return false       elsif !bar.following?         bar.errors.add ( :transfer, "your carrot small , inadequate. no jokes please" )         return false       end     end      # made through gauntlet, transfer     cache_old_foo_id = bar.foo_id # might need     bar.foo_id = new_foo.id     bar.save!      # if using rails counter caching:     foo.increment_counter(:bars_count, new_foo.id)     foo.decrement_counter(:bars_count, cache_old_foo_id) # did need      return true    rescue exception => e     fancy_error_log e     false   end  end 

step 1 remove duplication long if statement. if returns value (and returns nil if no if/elsif matches), can do

error =   if bar.dependency == :do_not_move_me or bar.some_condition == false     "this bar can't moved, on street corners moping , singing"   elsif new_foo.want_more_bars == false     "\"we don't take kindly type, bar\" - #{new_foo.name}")   elsif ((bar.baz.optional_external_nightmare_status != :unused) || (new_foo.bars.inject(false){|result, element| result = result || element.baz.optional_external_nightmare_status != :unused})     "i have baz news you..."   elsif bar.yet_another_failure_reason_there_are_many     "there many ways fail, if statement short"   elsif bar.stubborn?     bar.lure_with_carrot!     if bar.munching?       "eh, what's doc"     elsif !bar.following?       "your carrot small , inadequate. no jokes please"     end   end if error   bar.errors.add :transfer, error   return false end 

step 2 extract conditions methods understandable names, idea in case. move in each condition method, ! operators, , give every method same parameter list. we'll see why in moment.

error =   if bar.unmovable? new_foo     "this bar can't moved, on street corners moping , singing"   elsif bar.unwanted? new_foo     "\"we don't take kindly type, bar\" - #{new_foo.name}")   elsif bar.has_bad_news? new_foo     "i have baz news you..."   elsif bar.will_fail_for_yet_another_reason? new_foo     "there many ways fail, if statement short"   elsif bar.lure_with_carrot? new_foo # if don't side effects, lure before if     "eh, what's doc"   elsif bar.uninterested_in_carrot? new_foo     "your carrot small , inadequate. no jokes please"   end # use error above 

step 3 remove duplication again:

checks = {   unmovable?: "this bar can't moved, on street corners moping , singing",   unwanted?: "\"we don't take kindly type, bar\" - #{new_foo.name}"),   has_bad_news?: "i have baz news you...",   will_fail_for_yet_another_reason?: "there many ways fail, if statement short",   lure_with_carrot?: "eh, what's doc",   uninterested_in_carrot?: "your carrot small , inadequate. no jokes please" } method_name, error = checks.find { |method_name, _| bar.send :method_name, new_foo } # use error above 

Comments

Popular posts from this blog

javascript - RequestAnimationFrame not working when exiting fullscreen switching space on Safari -

Python ctypes access violation with const pointer arguments -