![見出し画像](https://assets.st-note.com/production/uploads/images/63911791/rectangle_large_type_2_32659fee78ca69b1076023f315dc125e.png?width=800)
【88】【Rails】【Ruby】==と===の違い、case文の置き換え
この記事を読むとcase文、==と===の違いについて理解を深めることができます。
テストが通らない
まずこのコードを見て下さい。
class Trip
attr_reader :bicycles,:customers,:vehicle
def initialize(args)
@bicycles = args[:bicycles]
@customers = args[:customers]
@vehicle = args[:vehicle]
end
def prepare(prepares)
prepares.each do |prepare|
case prepare
when Mechanic
prepare.prepare_bicycles(bicycles)
when TripCoordinator
prepare.buy_foods(customers)
when Driver
prepare.gas_up(vehicle)
prepare.fill_water_tank(vehicle)
end
end
end
end
class Mechanic
def prepare_bicycles(bicycles)
puts "#{bicycles}の準備が出来ました"
end
end
class TripCoordinator
def buy_foods(customers)
puts "#{customers}様の食事を用意しました"
end
end
class Driver
def gas_up(vehicle)
puts "#{vehicle}の補給をしました。"
end
def fill_water_tank(vehicle)
puts "#{vehicle}内の飲料水を準備しました"
end
end
オブジェクト指向設計実践ガイド
~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
に掲載されているコードです。
この本では動くけど、変更しにくいコードを問題のあるコードとして紹介し、リファクタリングしていく形で進めていきます。
このコードは、この本の主旨で解説すると、動くコードではあるが、放置しておくと後々大変危険な、負債となるコードという意味合いです。
当然、動くことが前提です。
ところが、動かなかった。
正確に言うと、期待した動作をしなくて、テストが通らなかったのだ。
テスト
require_relative '3_1_1_before_refactoring'
RSpec.describe do
prepares = [Mechanic,TripCoordinator,Driver]
args = {
:bicycles => "ママチャリ",
:customers => "稲葉浩志",
:vehicle => "Crazy Rendezvous"
}
text = <<TEXT
ママチャリの準備が出来ました
稲葉浩志様の食事を用意しました
Crazy Rendezvousの補給をしました。
Crazy Rendezvous内の飲料水を準備しました
TEXT
it '#prapare' do
trip = Trip.new(args)
expect {trip.prepare(prepares)} .to output(text).to_stdout
end
end
結果
expected block to output "ママチャリの準備が出来ました\n稲葉浩志様の食事を用意しました\nCrazy Rendezvousの補給をしました。\nCrazy Rendezvous内の飲料水を準備しました\n" to stdout, but output nothing
なぜ通らないのか?
原因:case 文がnilを返したから。
原因はcase 文の処理にあります。case文でnilを返し、case文内の期待した処理が動作しなかったからです。
なぜ、nilを返した?(CASE文を置き換える)
なぜnilを返したのか?そもそもcase文とは?
case文を置き換えてみる
公式ドキュメントより
_tmp = 式0
if 式1 === _tmp or 式2 === _tmp
stmt1
elsif 式3 === _tmp or 式4 === _tmp
stmt2
else
stmt3
end
==と===の違い
ポイントは==ではなく、===である点だ。
ではこの違いは何か?
このサイトによると、
左辺が単独のStringやIntegerオブジェクトの場合
==と同じ動作
左辺がClassオブジェクトの場合:
右辺がそのクラスのインスタンスであるかどうかを比較する
左辺がRegexpオブジェクトの場合:
右辺とマッチするかどうかを取れる
つまり、左辺がClassオブジェクトだったので、==とは違う挙動になったのだ。
irb(main):030:0> Mechanic == Mechanic
=> true
irb(main):031:0> Mechanic === Mechanic
=> false
irb(main):032:0> Mechanic.new === Mechanic
=> false
irb(main):033:0> Mechanic === Mechanic.new
=> true
リファクタリングしてとりあえず動くようにした。
class Trip
attr_reader :bicycles,:customers,:vehicle
def initialize(args)
@bicycles = args[:bicycles]
@customers = args[:customers]
@vehicle = args[:vehicle]
end
def prepare(prepares)
prepares.each do |prepare|
prepare.prepare_bicycles(bicycles) if prepare == Mechanic
prepare.buy_foods(customers) if prepare == TripCoordinator
prepare.gas_up(vehicle) if prepare == Driver
prepare.fill_water_tank(vehicle) if prepare == Driver
end
end
end
class Mechanic
def self.prepare_bicycles(bicycles)
puts "#{bicycles}の準備が出来ました"
end
end
class TripCoordinator
def self.buy_foods(customers)
puts "#{customers}様の食事を用意しました"
end
end
class Driver
def self.gas_up(vehicle)
puts "#{vehicle}の補給をしました。"
end
def self.fill_water_tank(vehicle)
puts "#{vehicle}内の飲料水を準備しました"
end
end
テストも通るようになった
require_relative '3_1_2_refactoring'
RSpec.describe do
prepares = [Mechanic,TripCoordinator,Driver]
args = {
:bicycles => "ママチャリ",
:customers => "稲葉浩志",
:vehicle => "Crazy Rendezvous"
}
text = <<TEXT
ママチャリの準備が出来ました
稲葉浩志様の食事を用意しました
Crazy Rendezvousの補給をしました。
Crazy Rendezvous内の飲料水を準備しました
TEXT
it '#prapare' do
trip = Trip.new(args)
expect {trip.prepare(prepares)}.to output(text).to_stdout
end
end
これで動くようになった。
だか、このコードは良いコードではない。
実は本題はここからだったりする。
続きはこの記事から。
関連する記事
参考文献
オブジェクト指向設計実践ガイド
~Rubyでわかる 進化しつづける柔軟なアプリケーションの育て方
最後に
私がブログを書く目的は、素晴らしい本や、素晴らしい方々の技術記事を知って頂きたいからです。ぜひ、上記の参考文献を見て下さい。(noteなので広告とかは一切ありません。)
現在、株式会社grabssに行くために最後の悪あがきをしています!!
現在の進行状況
この記事は88件目の投稿。目標達成!!!!
目標再設定
20日までに100件目指す!!(88件目)
20日超えたが、寝るまでは20日営業日!!(まだ寝てない、ちょっと寝##峠を超え目が覚めた!)
よろしければ、スキボタン及びサポートお願いします。勉強の励みになります。
この記事が気に入ったらサポートをしてみませんか?