すずかのプログラミング勉強記

元教員からエンジニアを目指す、プログラミング勉強記録です。

「追いかけるメソッド」は定義できるが「猫クラス」はエラーになる【Ruby】

はじめに

輪読会で「現場で使える Ruby on Rails 5速習実践ガイド」を読んでいると、Rubyの文法説明の例で「猫クラス」・「追いかけるメソッド」が出てきました。

実際に irbで「猫クラス」を作ったところ、class/module name must be CONSTANT (SyntaxError)というエラーが出て、定義できませんでした。

irb(main):* class 猫
irb(main):> end
/Users/suzuka/.rbenv/versions/3.3.0/lib/ruby/gems/3.3.0/gems/irb-1.11.2/lib/irb/workspace.rb:117:in `eval': (irb):1: class/module name must be CONSTANT (SyntaxError)

同じ日本語でも、「追いかけるメソッド」は定義できたため、「猫クラス」を定義できないのを不思議に思いました。

irb(main):* def 追いかける
irb(main):> end
=> :追いかける

この記事では、「猫クラス」が定義できない理由について、調べたことをまとめます。

初心者が書いた記事のため、間違いなどあれば指摘していただけると嬉しいです。


実行環境


結論

クラス名はアルファベット大文字始まりでなくてはいけないようです。

「猫クラス」はエラーになりますが、「A猫クラス」は定義できました。

irb(main):* class A猫
irb(main):> end
=> nil

メソッド名には「アルファベット大文字始まり」の決まりがないため、日本語はもちろん、絵文字や記号でも定義できました。

irb(main):* def 猫
irb(main):> end
=> :猫
irb(main):* def 🐈
irb(main):> end
=> :🐈
irb(main):* def -
irb(main):> end
=> :-


クラス名が大文字始まりの理由

では、なぜクラス名は大文字始まりでなくてはいけないのでしょうか?

「猫クラス」を定義した時の、エラー文を見てみましょう。

class/module name must be CONSTANT (SyntaxError)
訳:クラス/モジュール名は定数である必要があります (構文エラー)

一見クラス定義には関係なさそうな、「定数」という言葉が出てきました。

定数は大文字で始める

Ruby の変数・定数は、最初の一文字によってローカル変数・インスタンス変数・クラス変数・グローバル変数・定数のどれかに区別されます。

その中で、アルファベット大文字 (A-Z) で始まるものが定数です。

クラス定義では定数への代入が行われる

では、定数とクラスの定義はどんな関係があるのでしょうか?
公式ドキュメントに説明がありました。

クラス定義式はクラスオブジェクトの生成を行うと同時に、名前がクラス名である定数にクラスオブジェクトを代入する動作をします。クラス名を参照することは文法上は定数を参照していることになります。 変数と定数 (Ruby 3.3 リファレンスマニュアル)

少し説明が難しいので、「Catクラス」が定義された場合を例に説明します。

class Cat
end

このコードが実行された時、以下の 2 つの処理がされています。

  • 新しくクラスオブジェクトを作る。
    クラスもオブジェクトの一つで、Classクラスのインスタンスです。
  • クラスオブジェクトを定数「Cat」に代入する。

下のようなコードを思い浮かべると、オブジェクトの作成と代入のイメージしやすいかもしれません。(この書き方でもクラスを定義できます)

Cat = Class.new

つまり、クラス定義ではクラス名と同名の定数への代入が行われており、定数はアルファベット大文字で始まる必要があります。

まとめ

  • 「猫クラス」を定義するとエラーになる理由は、Rubyクラス名はアルファベット大文字始まりである必要があるから。
  • クラス名がアルファベット大文字始まりでないといけない理由は、クラス定義の際に内部で定数への代入が行われているから。


おまけ:「猫クラス」を作るには?

どうしても「猫クラス」を作りたかったので、方法を調べました。

1. gemを検討する

ruby-japanizeという、Rubyを日本語で書けるようにする素敵なgemがありました。

github.com

私の環境では Rubyのバージョンを切り替えてもエラーが出てしまい、動きませんでした。 下のようなコードが書けるみたいなので使ってみたかったです 🥲

  組(数値) {
  定義(:足す) {|他の数|
    自分.+(他の数)
    }
  }

  ある数 = 5.足す 6


2. 一度変数に代入する

「猫」という変数にクラスオブジェクトを代入するようにしたところ、猫.newができるようになりました。

猫 = Class.new do
  def 鳴く
    puts 'にゃー'
  end
end

タマ = 猫.new
タマ.鳴く
# => にゃー

ただし、名前なしのクラスオブジェクトを「猫」という変数に代入しているだけなので、クラス名を調べると「nil」になっています。

"文字列".class.name
# => "String"

タマ.class.name
# => nil

真の猫クラスを定義できたわけではなく、見た目上猫.newができているだけです😅

できる限り日本語にした

偽物とはいえ、せっかく猫.newができるようになったので、できる限り日本語のコードを書いてみました。

  • 準備:エイリアスの設定と、猫クラスの中に属性・メソッドを追加
alias 表示する puts

猫 = Class.new do
  attr_reader :名前

  def initialize(名前)
    @名前 = 名前
  end

  class << self
    alias 作る new
  end

  def 鳴く
    表示する 'にゃー'
  end
end
  • コードを日本語で動かす
ある猫 = 猫.作る('タマ')
ある猫.鳴く
表示する ある猫.名前
# => にゃー
# => タマ

日本語化はとても難しくて、初心者には短いコードで限界でした。

どうしても日本語でコードを書きたい時は、日本語プログラミング言語の「なでしこ」を使うのがいいと思いました。 nadesi.com

参考文献