質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

2633閲覧

Moduleにincludeする場合とClassにincludeする場合で、結果が違うのだが、どうしてかな?

momijiMac

総合スコア39

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2017/02/19 00:38

###前提・実現したいこと
module Kazをmodule Test2にincludeして
名前を小文字で出力したい。

###発生している問題・エラーメッセージ
現状では、Classにincludeすれば予想通りに小文字(”car”)が出力されるが、
moduleにincludeすると大文字(”Car”)で標示される。

###該当のソースコード

module Kaz listA = ["Car", "Train"] # method generate listA.each do |c| define_method "#{c}" do eval "#{c}.new" end end # class generate listA.each do |vahi| Object.const_set vahi, Class.new(){ attr_accessor :name def initialize @name = self.class.name.downcase end } end end class Test include Kaz end a = Test.new p a.Car.name => "car" module Test2 include Kaz p Car.name=> "Car" end

###補足情報(言語/FW/ツール等のバージョンなど)
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16]

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

a.Car.nameでは、a.Carというメソッド呼び出しであり、Test2モジュールの中のCar.nameCarという定数呼び出しです。KazモジュールにはCarという定数※とCarというインスタンスメソッドの同じ名前で違うものが同時に存在し、定数のCarはCarというクラスで、メソッド呼び出しはCarをnewしたインスタンスです。クラスにはデフォルトでnameメソッドがあり、自分の名前(クラス名)を返すので、どちらもエラーになりません。nameの代わりにclassとすると何のクラスのオブジェクトなのかがよくわかると思います。

※ Car定数が定義されているのはObjectですが、定数参照により辿り着くことができるため、全ての場所にCar定数が存在することになります。

より単純化した、下記のコードで説明します。

Ruby

1module M 2 def X 3 1 4 end 5 X = 0 6end 7 8class A 9 include M 10end 11a = A.new 12p a.X 13 14module B 15 include M 16 p X 17end

Mモジュールには二つのXが存在します。

  • Xメソッド … 1を返す
  • X定数 ... 0

AクラスもBモジュールもMモジュールをincludeしていますので、上と同じようにXメソッドとX定数が定義されます。(Xメソッドはインスタンスメソッドであることに注意してください)

a.Xとしたとき、.があるため、Xはaのメソッド呼び出しとして解釈されます。aはAクラスのインスタンスなので、Aクラスのメソッドを探します。ちょうどincludeしたMモジュールにXメソッドありましたので、それを使って1を返します。

Xとしたとき、.とかがなく大文字から始まるため、Xは定数呼び出しとして解釈されます。定数参照の優先順位に従って探し、includeしたMモジュールにX定数がありましたので、それを使って0を返します。

通常※、メソッド名を大文字から始めることは推奨されていませんので、このような混乱を起こすことはほとんどありません。

String(1)のようなクラス名関数という考え方があるため、大文字から始まるメソッド名が絶対に悪いわけではありません。

投稿2017/02/19 02:28

編集2017/02/20 12:14
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otn

2017/02/20 05:23

> Carという定数※とCarというメソッドの同じ名前で違うものが同時に存在し 後半のほうでは、Carというメソッドは定義されないようですよ。
raccy

2017/02/20 12:19

モジュールの特異メソッドだと勘違いされそうなので、インスタンスメソッドとしました。これであってますかね?
guest

0

1つ目の方では、クラスTestのインスタンスメソッドCarとTrain、およびクラスTest::Carが定義されます。
aは、クラスTestのインスタンスで、メソッドCarが呼び出されます。その戻り値は、Test::Car.new つまりクラスTest::Carのインスタンスが生成されてそれが戻ります。このとき@nameは"car"がセットされています。そのクラスTest::Carの新規インスタンスに対して、クラスTest::Carのインスタンスメソッドnameが呼び出されるので、"car"が返ります。

2つ目の方では、モジュールのメソッドTest2::CarとTest2::Trainは定義されず(※)、クラスTest2::Carが定義されます。ここで、Carと出てくるとクラスTest2::Carを表します。Car.name で、クラス名が返ります。ここのnameはModuleクラスのインスタンスメソッドです。

※定義されない理由はうまく説明できません。Module#inlcudeは、C言語の#includeとは違って、ソースを埋め込むわけでは無い。仮に定義されていても同名の場合、メソッド名よりクラス名が優先されるようです。

投稿2017/02/19 01:53

otn

総合スコア84557

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問