Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Refactor Like A Boss: A Few Techniques for Ever...
Search
PromptWorks
February 21, 2014
Programming
0
2.3k
Refactor Like A Boss: A Few Techniques for Everyday Ruby Hacking
Presented by Greg Sterndale.
http://promptworks.com
PromptWorks
February 21, 2014
Tweet
Share
More Decks by PromptWorks
See All by PromptWorks
PromptWorks Talk Tuesdays: Yvonne Chen 1/24/17 "Agile-Retros"
promptworks
0
72
PromptWorks Talk Tuesdays: Ray Zane 1/17/17 "Elixir Is Cool"
promptworks
0
93
PromptWorks Talk Tuesdays: Ray Zane 9/13/16 "Elixir Processes"
promptworks
0
3.4k
PromptWorks Talk Tuesdays: Dustin Ingram 8/30/16 "What is an ADR?"
promptworks
1
130
PromptWorks Talk Tuesdays: Dustin Ingram 8/23/16 "Detecting Asteroids with Neural Networks in TensorFlow"
promptworks
1
130
Getting to know Arel: Active Record's nerdy little brother
promptworks
1
100
Writing DSLs with Parslet - NYC.rb
promptworks
0
2.4k
Straight Up Rspec: A Neat Ruby BDD Tool
promptworks
0
31
Double Trouble: Clarity on Test Doubles
promptworks
0
2.4k
Other Decks in Programming
See All in Programming
Practical Tips and Tricks for Working with Compose Multiplatform Previews (mDevCamp 2025)
stewemetal
0
120
Rails産でないDBを Railsに引っ越すHACK - Omotesando.rb #110
lnit
1
160
ASP.NETアプリケーションのモダナイズ インフラ編
tomokusaba
1
220
Javaのルールをねじ曲げろ!禁断の操作とその代償から学ぶメタプログラミング入門 / A Guide to Metaprogramming: Lessons from Forbidden Techniques and Their Price
nrslib
3
2k
生成AIコーディングとの向き合い方、AIと共創するという考え方 / How to deal with generative AI coding and the concept of co-creating with AI
seike460
PRO
1
250
業務自動化をJavaとSeleniumとAWS Lambdaで実現した方法
greenflagproject
1
110
Go1.25からのGOMAXPROCS
kuro_kurorrr
1
500
人には人それぞれのサービス層がある
shimabox
3
670
Enterprise Web App. Development (2): Version Control Tool Training Ver. 5.1
knakagawa
1
110
エラーって何種類あるの?
kajitack
5
140
レガシーシステムの機能調査・開発におけるAI利活用
takuya_ohtonari
0
600
Go Modules: From Basics to Beyond / Go Modulesの基本とその先へ
kuro_kurorrr
0
120
Featured
See All Featured
Optimizing for Happiness
mojombo
379
70k
The Pragmatic Product Professional
lauravandoore
35
6.7k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.4k
Raft: Consensus for Rubyists
vanstee
140
7k
Into the Great Unknown - MozCon
thekraken
39
1.8k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
331
22k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
47
2.8k
Unsuck your backbone
ammeep
671
58k
Docker and Python
trallard
44
3.4k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.2k
Art, The Web, and Tiny UX
lynnandtonic
299
21k
Fireside Chat
paigeccino
37
3.5k
Transcript
Refactor Like A Boss a few techniques for everyday Ruby
hacking
Refactoring The process of changing code without modifying behavior
Ungoals of refactoring • Brevity for the sake of brevity
• To demonstrate mastery of Ruby or design patterns
Goals of refactoring • Improve readability • Improve maintainability •
Improve extensibility • Promote an expressive API • Reduce complexity
Ruby freebies
if 1 > 0 @foo = 'bar' else @foo =
'baz' end ! @foo # => 'bar' DRY Assignment
@foo = if 1 > 0 'bar' else 'baz' end
! @foo # => 'bar' DRY Assignment
@foo = case 1 when 0..1 'bar' else 'baz' end
! @foo # => 'bar' DRY Assignment
@foo = 1 > 0 ? 'bar' : 'qux' !
@foo # => 'bar' Ternary operator
def postive?(number) number > 0 ? 'yes' : 'no' end
! positive?(100) # => 'yes' Ternary operator
def foo? if @foo true else false end end Bang
bang
def foo? @foo ? true : false end Bang bang
def foo? !!@foo end Bang bang
if not @foo @foo = 'bar' end Conditional assignment
unless @foo @foo = 'bar' end Conditional assignment
@foo = 'bar' unless @foo Conditional assignment
@foo ||= 'bar' Conditional assignment
Parallel assignment @foo = 'baz' @bar = 'qux' # =>
"baz" # => "qux"
Parallel assignment @foo, @bar = 'baz', 'qux' # => ["baz",
"qux"] ! @foo # => "baz"
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]
def my_safe_method begin do_something_dangerous() true rescue false end end Implied
begin
def my_safe_method do_something_dangerous() true rescue false end Implied begin
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
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
(1..5).map{|number| number.to_s } # => ["1", "2", "3", "4", "5"]
Symbol to Proc
(1..5).map(&:to_s) # => ["1", "2", "3", "4", "5"] Symbol to
Proc
def fibonacci_sum sum = 0 [1,1,2,3,5,8,13].each{|int| sum += int }
sum end ! fibonacci_sum() # => 33 MapReduce
def fibonacci_sum [1,1,2,3,5,8,13].reduce(0){|sum, int| sum + int } end !
fibonacci_sum() # => 33 MapReduce
{:foo => 'bar'}.inject({}) do |memo, (key, value)| memo[value] = key
memo end ! # => {"bar" => :foo} MapReduce
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
'my lil string'.match(/my (\w+) (\w+)/) $1 # => "lil" $2
# => "string" $3 # => nil Regex captures
'my lil string' =~ /my (\w+) (\w+)/ $1 # =>
"lil" $2 # => "string" $3 # => nil Regex captures
def Resource.create resource = Resource.new resource.save resource end # =>
#<Resource:0xffffff> tap
def Resource.create Resource.new.tap{|resource| resource.save } end # => #<Resource:0xffffff> tap
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
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
def cerealize(val) case val when Numeric, String val when Enumerable
val.to_json else val.to_s end end case equality
if command =~ /sudo/ raise 'Danger!' elsif command =~ /^rm
/ puts 'Are you sure?' else puts 'Run it.' end case equality
case command when /sudo/ raise 'Danger!' when /^rm / puts
'Are you sure?' else puts 'Run it.' end case equality
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"
Splat Array def shopping_list(ingredients) [ingredients].flatten.join(", ") end ! shopping_list("eggs") #
=> "eggs" shopping_list(["eggs", "bacon"]) # => "eggs, bacon" ! !
Splat Array def shopping_list(ingredients) [*ingredients].join(", ") end ! shopping_list("eggs") #
=> "eggs" shopping_list(["eggs", "bacon"]) # => "eggs, bacon" ! !
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"
Rails freebies
if @user.name and
[email protected]
? puts @user.name else puts "no name"
end blank?
if @user.name.blank? puts "no name" else puts @user.name end blank?
if @user.name.present? puts @user.name else puts "no name" end present?
puts @user.name.presence || "no name" presence
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..."
truncate opening = "A long time ago in a galaxy
far, far away" opening.truncate(20) # => "A long time ago i..." !
truncate opening = "A long time ago in a galaxy
far, far away" opening.truncate(20, :separator => ' ') # => "A long time ago..." !
@existing = User.find_by_email(@new.email) @existing.destroy if @existing try
User.find_by_email(@new.email).try(:destroy) try
in? if admin_roles.include? @user.role puts "Hi Admin!" end
in? if @user.role.in? admin_roles puts "Hi Admin!" end
class User ! has_one :account ! def balance self.account.balance end
! def balance=(amount) self.account.balance=(amount) end ! end Delegation
class User ! has_one :account ! delegate :balance, :balance=, :to
=> :account ! end Delegation
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
class Avatar ! extend ActiveSupport::Memoizable ! def file_size result =
some_expensive_calculation result += more_expensive_calculation end memoize :file_size ! end Memoization
! 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
def translate_with_log(*args) result = translate_without_log(*args) Rails.logger.info result result end !
alias_method_chain :translate, :log alias_method_chain
class Resource class < self ! def host=(name) @host =
hame end def host @host end ! end end class_attribute
class Resource class < self ! attr_accessor :host ! end
end class_attribute
class Resource ! class_attribute :host ! end class_attribute
Hash#symbolize_keys my_hash = { 'foo' => 123 }.symbolize_keys my_hash['foo'] #
=> nil my_hash[:foo] # => 123
Hash#stringify_keys my_hash = { :foo => 123 }.stringify_keys my_hash['foo'] #
=> 123 my_hash[:foo] # => nil
HashWithIndifferentAccess my_hash = { :foo => 123 } my_hash['foo'] #
=> nil my_hash[:foo] # => 123
HashWithIndifferentAccess my_hash = { :foo => 123 }.with_indifferent_access my_hash['foo'] #
=> 123 my_hash[:foo] # => 123
forty_two my_array = [] my_array[41] = "the answer" ! my_array[41]
# => "the answer"
forty_two my_array = [] my_array[41] = "the answer" ! my_array.forty_two
# => "the answer"
slideshare github irc gsterndale gsterndale sternicus