見出し画像

【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
if1 === _tmp or2 === _tmp
 stmt1
elsif3 === _tmp or4 === _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日営業日!!(まだ寝てない、ちょっと寝##峠を超え目が覚めた!)

よろしければ、スキボタン及びサポートお願いします。勉強の励みになります。


この記事が気に入ったらサポートをしてみませんか?