Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Refactor Like A Boss: A Few Techniques for Everyday Ruby Hacking

PromptWorks
February 21, 2014

Refactor Like A Boss: A Few Techniques for Everyday Ruby Hacking

Presented by Greg Sterndale. http://promptworks.com

PromptWorks

February 21, 2014
Tweet

More Decks by PromptWorks

Other Decks in Programming

Transcript

  1. Ungoals of refactoring • Brevity for the sake of brevity

    • To demonstrate mastery of Ruby or design patterns
  2. Goals of refactoring • Improve readability • Improve maintainability •

    Improve extensibility • Promote an expressive API • Reduce complexity
  3. if 1 > 0 @foo = 'bar' else @foo =

    'baz' end ! @foo # => 'bar' DRY Assignment
  4. @foo = if 1 > 0 'bar' else 'baz' end

    ! @foo # => 'bar' DRY Assignment
  5. @foo = case 1 when 0..1 'bar' else 'baz' end

    ! @foo # => 'bar' DRY Assignment
  6. @foo = 1 > 0 ? 'bar' : 'qux' !

    @foo # => 'bar' Ternary operator
  7. def postive?(number) number > 0 ? 'yes' : 'no' end

    ! positive?(100) # => 'yes' Ternary operator
  8. Multiple return def get_with_benchmark(uri) res = nil bench = Benchmark.measure

    do res = Net::HTTP.get_response(uri) end return res, bench.real end ! @response, @benchmark = get_with_benchmark(@uri) # => [#<Net::HTTPOK 200 OK>, 0.123]
  9. def self.likelihood_of_rain Hpricot::XML(weather_xml)/'probability-of-rain' rescue Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError return false end

    ! def self.likelihood_of_snow Hpricot::XML(weather_xml)/'probability-of-snow' rescue Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError return false end Exception lists
  10. NET_EXCEPTIONS = [ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError ] ! def self.likelihood_of_rain

    Hpricot::XML(weather_xml)/'probability-of-rain' rescue NET_EXCEPTIONS return false end ! def self.likelihood_of_snow Hpricot::XML(weather_xml)/'probability-of-snow' rescue NET_EXCEPTIONS return false end Exception lists
  11. def fibonacci_sum sum = 0 [1,1,2,3,5,8,13].each{|int| sum += int }

    sum end ! fibonacci_sum() # => 33 MapReduce
  12. match_data = 'my lil string'.match(/my (\w+) (\w+)/) match_data.captures[0] # =>

    "lil" match_data.captures[1] # => "string" match_data.captures[2] # => nil Regex captures
  13. 'my lil string'.match(/my (\w+) (\w+)/) $1 # => "lil" $2

    # => "string" $3 # => nil Regex captures
  14. 'my lil string' =~ /my (\w+) (\w+)/ $1 # =>

    "lil" $2 # => "string" $3 # => nil Regex captures
  15. sprintf("%d as hexadecimal: %04x", 123, 123) # => "123 as

    hexadecimal: 007b" ! "%d as hexadecimal: %04x" % [123, 123] # => "123 as hexadecimal: 007b" ! "%s string" % ['my'] # => "my string" sprintf
  16. def cerealize(val) case val when Numeric, String val when Enumerable

    val.to_json else val.to_s end end case equality
  17. if command =~ /sudo/ raise 'Danger!' elsif command =~ /^rm

    / puts 'Are you sure?' else puts 'Run it.' end case equality
  18. case command when /sudo/ raise 'Danger!' when /^rm / puts

    'Are you sure?' else puts 'Run it.' end case equality
  19. Splat Array def shopping_list(ingredients) unless ingredients.is_a?(Array) ingredients = [ingredients] end

    ingredients.join(", ") end ! shopping_list("eggs") # => "eggs" shopping_list(["eggs", "bacon"]) # => "eggs, bacon"
  20. Splat Array def shopping_list(ingredients) [*ingredients].join(", ") end ! shopping_list("eggs") #

    => "eggs" shopping_list(["eggs", "bacon"]) # => "eggs, bacon" ! !
  21. Splat args def shopping_list(*ingredients) ingredients.join(", ") end ! shopping_list("eggs") #

    => "eggs" shopping_list(["eggs", "bacon"]) # => "eggs, bacon" ! shopping_list("eggs", "bacon") # => "eggs, bacon"
  22. truncate opening = "A long time ago in a galaxy

    far, far away" if opening.size > 20 opening[0..16] + "..." end # => "A long time ago i..."
  23. truncate opening = "A long time ago in a galaxy

    far, far away" opening.truncate(20) # => "A long time ago i..." !
  24. truncate opening = "A long time ago in a galaxy

    far, far away" opening.truncate(20, :separator => ' ') # => "A long time ago..." !
  25. class User ! has_one :account ! def balance self.account.balance end

    ! def balance=(amount) self.account.balance=(amount) end ! end Delegation
  26. class Avatar ! def file_size if @file_size return @file_size else

    result = some_expensive_calculation result += more_expensive_calculation @file_size = result end end ! end Memoization
  27. class Avatar ! extend ActiveSupport::Memoizable ! def file_size result =

    some_expensive_calculation result += more_expensive_calculation end memoize :file_size ! end Memoization
  28. ! alias_method :translate_without_log, :translate ! def translate_with_log(*args) result = translate_without_log(*args)

    Rails.logger.info result result end ! alias_method :translate, :translate_with_log alias_method_chain
  29. class Resource class < self ! def host=(name) @host =

    hame end def host @host end ! end end class_attribute