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

99e2a6afab542ba98a9f1d1cae6c9670?s=47 PromptWorks
February 21, 2014

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

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

99e2a6afab542ba98a9f1d1cae6c9670?s=128

PromptWorks

February 21, 2014
Tweet

Transcript

  1. Refactor Like A Boss a few techniques for everyday Ruby

    hacking
  2. Refactoring The process of changing code without modifying behavior

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

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

    Improve extensibility • Promote an expressive API • Reduce complexity
  5. Ruby freebies

  6. if 1 > 0 @foo = 'bar' else @foo =

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

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

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

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

    ! positive?(100) # => 'yes' Ternary operator
  11. def foo? if @foo true else false end end Bang

    bang
  12. def foo? @foo ? true : false end Bang bang

  13. def foo? !!@foo end Bang bang

  14. if not @foo @foo = 'bar' end Conditional assignment

  15. unless @foo @foo = 'bar' end Conditional assignment

  16. @foo = 'bar' unless @foo Conditional assignment

  17. @foo ||= 'bar' Conditional assignment

  18. Parallel assignment @foo = 'baz' @bar = 'qux' # =>

    "baz" # => "qux"
  19. Parallel assignment @foo, @bar = 'baz', 'qux' # => ["baz",

    "qux"] ! @foo # => "baz"
  20. 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]
  21. def my_safe_method begin do_something_dangerous() true rescue false end end Implied

    begin
  22. def my_safe_method do_something_dangerous() true rescue false end Implied begin

  23. 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
  24. 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
  25. (1..5).map{|number| number.to_s } # => ["1", "2", "3", "4", "5"]

    Symbol to Proc
  26. (1..5).map(&:to_s) # => ["1", "2", "3", "4", "5"] Symbol to

    Proc
  27. def fibonacci_sum sum = 0 [1,1,2,3,5,8,13].each{|int| sum += int }

    sum end ! fibonacci_sum() # => 33 MapReduce
  28. def fibonacci_sum [1,1,2,3,5,8,13].reduce(0){|sum, int| sum + int } end !

    fibonacci_sum() # => 33 MapReduce
  29. {:foo => 'bar'}.inject({}) do |memo, (key, value)| memo[value] = key

    memo end ! # => {"bar" => :foo} MapReduce
  30. 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
  31. 'my lil string'.match(/my (\w+) (\w+)/) $1 # => "lil" $2

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

    "lil" $2 # => "string" $3 # => nil Regex captures
  33. def Resource.create resource = Resource.new resource.save resource end # =>

    #<Resource:0xffffff> tap
  34. def Resource.create Resource.new.tap{|resource| resource.save } end # => #<Resource:0xffffff> tap

  35. 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
  36. def cerealize(val) if val.is_a?(Numeric) || val.is_a?(String) val elsif val.is_a?(Enumerable) val.to_json

    else val.to_s end end case equality
  37. def cerealize(val) case val when Numeric, String val when Enumerable

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

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

    'Are you sure?' else puts 'Run it.' end case equality
  40. 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"
  41. Splat Array def shopping_list(ingredients) [ingredients].flatten.join(", ") end ! shopping_list("eggs") #

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

    => "eggs" shopping_list(["eggs", "bacon"]) # => "eggs, bacon" ! !
  43. 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"
  44. Rails freebies

  45. if @user.name and !@user.name.empty? puts @user.name else puts "no name"

    end blank?
  46. if @user.name.blank? puts "no name" else puts @user.name end blank?

  47. if @user.name.present? puts @user.name else puts "no name" end present?

  48. puts @user.name.presence || "no name" presence

  49. 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..."
  50. truncate opening = "A long time ago in a galaxy

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

    far, far away" opening.truncate(20, :separator => ' ') # => "A long time ago..." !
  52. @existing = User.find_by_email(@new.email) @existing.destroy if @existing try

  53. User.find_by_email(@new.email).try(:destroy) try

  54. in? if admin_roles.include? @user.role puts "Hi Admin!" end

  55. in? if @user.role.in? admin_roles puts "Hi Admin!" end

  56. class User ! has_one :account ! def balance self.account.balance end

    ! def balance=(amount) self.account.balance=(amount) end ! end Delegation
  57. class User ! has_one :account ! delegate :balance, :balance=, :to

    => :account ! end Delegation
  58. 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
  59. class Avatar ! extend ActiveSupport::Memoizable ! def file_size result =

    some_expensive_calculation result += more_expensive_calculation end memoize :file_size ! end Memoization
  60. ! 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
  61. def translate_with_log(*args) result = translate_without_log(*args) Rails.logger.info result result end !

    alias_method_chain :translate, :log alias_method_chain
  62. class Resource class < self ! def host=(name) @host =

    hame end def host @host end ! end end class_attribute
  63. class Resource class < self ! attr_accessor :host ! end

    end class_attribute
  64. class Resource ! class_attribute :host ! end class_attribute

  65. Hash#symbolize_keys my_hash = { 'foo' => 123 }.symbolize_keys my_hash['foo'] #

    => nil my_hash[:foo] # => 123
  66. Hash#stringify_keys my_hash = { :foo => 123 }.stringify_keys my_hash['foo'] #

    => 123 my_hash[:foo] # => nil
  67. HashWithIndifferentAccess my_hash = { :foo => 123 } my_hash['foo'] #

    => nil my_hash[:foo] # => 123
  68. HashWithIndifferentAccess my_hash = { :foo => 123 }.with_indifferent_access my_hash['foo'] #

    => 123 my_hash[:foo] # => 123
  69. forty_two my_array = [] my_array[41] = "the answer" ! my_array[41]

    # => "the answer"
  70. forty_two my_array = [] my_array[41] = "the answer" ! my_array.forty_two

    # => "the answer"
  71. slideshare github irc
 gsterndale gsterndale sternicus