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
83
PromptWorks Talk Tuesdays: Ray Zane 1/17/17 "Elixir Is Cool"
promptworks
0
98
PromptWorks Talk Tuesdays: Ray Zane 9/13/16 "Elixir Processes"
promptworks
0
3.5k
PromptWorks Talk Tuesdays: Dustin Ingram 8/30/16 "What is an ADR?"
promptworks
1
150
PromptWorks Talk Tuesdays: Dustin Ingram 8/23/16 "Detecting Asteroids with Neural Networks in TensorFlow"
promptworks
1
140
Getting to know Arel: Active Record's nerdy little brother
promptworks
1
110
Writing DSLs with Parslet - NYC.rb
promptworks
0
2.5k
Straight Up Rspec: A Neat Ruby BDD Tool
promptworks
0
43
Double Trouble: Clarity on Test Doubles
promptworks
0
2.4k
Other Decks in Programming
See All in Programming
Bakuraku E2E Scenario Test System Architecture #bakuraku_qa_study
teyamagu
PRO
0
780
flutter_kaigi_2025.pdf
kyoheig3
1
350
AI 時代だからこそ抑えたい「価値のある」PHP ユニットテストを書く技術 #phpconfuk / phpcon-fukuoka-2025
shogogg
1
560
Nitro v3
kazupon
2
310
All(?) About Point Sets
hole
0
190
TVerのWeb内製化 - 開発スピードと品質を両立させるまでの道のり
techtver
PRO
3
1.1k
MCPサーバー「モディフィウス」で変更容易性の向上をスケールする / modifius
minodriven
8
1.6k
Phronetic Team with AI - Agile Japan 2025 closing
hiranabe
2
640
モビリティSaaSにおけるデータ利活用の発展
nealle
0
530
JJUG CCC 2025 Fall: Virtual Thread Deep Dive
ternbusty
3
460
Private APIの呼び出し方
kishikawakatsumi
3
890
SUZURIの規約違反チェックにおけるクリエイタフィードバックの試⾏錯誤/Trial and Error in Creator Feedback for SUZURI's Terms of Service Violation Checks
ae14watanabe
1
160
Featured
See All Featured
Why You Should Never Use an ORM
jnunemaker
PRO
60
9.6k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.5k
Rails Girls Zürich Keynote
gr2m
95
14k
How to Think Like a Performance Engineer
csswizardry
28
2.3k
GitHub's CSS Performance
jonrohan
1032
470k
Music & Morning Musume
bryan
46
7k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
51k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
34
2.3k
Embracing the Ebb and Flow
colly
88
4.9k
Designing Experiences People Love
moore
142
24k
Art, The Web, and Tiny UX
lynnandtonic
303
21k
Build your cross-platform service in a week with App Engine
jlugia
234
18k
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