Rubyのチートシート 変数 / クラス / モジュール

Shunsuke Sawada

Rubyをさわり始めた時に戸惑ったインスタンス変数やクラスインスタンス変数なんかのためのチートシート。変数、クラス、モジュールの使い方についてざっとまとめてみた。RailsでGemばっかり使ってると忘れるんだよなー。
 

登場人物はこんな感じです。

Screen Shot 2014-02-04 at 12.56.39 PM

ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# モジュールはいろんなクラスで共有できる部品のようなもの
# クラスに組み込むには'include'で指定する
# モジュールはincludeの前に記述されている必要がある
module Keyboard

    # モジュールをincludeしたクラスのインスタンス変数を表示するメソッド
    def type(key)
        puts "You typed [#{key}] with #{self.name}.\n\n"
    end

end




class Phone

    # モジュールを読み込む
    include Keyboard

    # 定数
    TYPE = "mobile"

    # クラス変数
    # Phoneクラス、もしくはPhoneを継承しているクラスの
    # インスタンスからアクセスできる
    # アクセサメソッドではアクセスできないので、
    # 参照したい場合は別にメソッドを用意する必要がある
    @@count = 0

    # クラスインスタンス変数
    # 継承先のクラスからは参照できない / 継承先で同じ名前で定義しても互いに影響しない
    # インスタンスからも参照できない
    @camera = "NO"

    # インスタンスが作られる時に自動的に実行されるメソッド
    # JAVAでいうコンストラクタ
    def initialize(name, version, color)
        # インスタンス変数
        # 名前は同じでもインスタンスごとに実態は異なる
        @name = name
        @version = version
        @color = color
        # 新しくインスタンスが作られた時に、クラス変数を更新してみる
        @@count += 1
    end

    # アクセサメソッド
    # phone.nameみたいにインスタンス変数を参照することができるようにする
    # 3種類あり、できることがそれぞれ違う
    attr_reader     :name       # read
    attr_writer     :version    # write
    attr_accessor :color        # read/write

    def start
        puts "Welcome to #{self.color} #{self.name}! (instance method)\n\n"
    end

    def sleep(wake_up_time)
        puts "See you at #{wake_up_time}, zzz.... (instance method)\n\n"
    end

    def exit
        puts "Good bye! from #{self.name} (instance method)\n\n"
    end

    def change_color(color)
        # インスタンス変数の値を変えてみる
        self.color = color
        puts "You changed color to #{color} (instance method)\n\n"
    end

    # クラスメソッドは.selfをつける
    # Phone.show_device_countとしてクラス変数を表示している
    # インスタンスの状況に左右されない処理をおこなう
    def self.show_device_count
        puts "@@count : #{@@count} ('Class' method with class variable)\n\n"
    end

    # クラスメソッドを定義してクラスインスタンス変数を表示してみる
    def self.camera?
        puts "Camera : #{@camera}\n\n"
    end

end




# クラスの継承
# SmartPhoneクラスはPhoneクラスを継承している
class SmartPhone < Phone

    # Phoneクラスで読み込んでいるで再度モジュールを読み込む必要はない
    # include Keyboard

    # このメソッドはSmartPhoneクラスのインスタンスだけが使える
    def take_photo
        puts "You can take photo with smartphone!\n\n"
        # プライベートメソッド / 下記private参照
        store_photo(self)
    end

    # メソッドのオーバーライド(上書き)
    # Phoneクラスでもchange_colorが定義されているが、同じ名前で上書きできる
    def change_color(color, surface)
        # スーパークラス(親クラス)のメソッドを実行する場合はsuperを使う
        super(color)
        puts "Now your phone's surface is polished! (Override instance method)\n\n"
    end

    # @cameraはnilを返す
    # @camearaはPhoneのクラスインスタンス変数でありSmartPhoneクラスからは参照できない
    def self.camera?
        puts "Camera : #{@camera} (of course dosn't work)\n\n"
    end


    # privateから下に書かれたメソッドはプライベートメソッドとなる
    # 同じクラス内のメソッドからのみ実行できる
    private

        def store_photo(device)
            puts " -> Photo is saved in #{device.name}. (Private method)\n\n"
        end

end






# Phoneクラスのインスタンスを作成してphoneに代入
# 3つの引数はinitializeメソッドに使われる
phone = Phone.new('Traditional Phone', 1.0, 'black')

# 定数を表示してみる :: で参照可能
puts "\n\nTYPE : #{Phone::TYPE}"

# クラスメソッド(self.がついたメソッド)を実行
puts Phone.camera?

# インスタンスメソッド
phone.start

# 引数ありのインスタンスメソッド
phone.change_color('white')

# @versionはattr_writerが設定されているので、
# アクセサメソッドで@versionの値を'変更'できるが'表示'はできない
phone.version = 1.1

now = Time.now()
wake_up_time = now + 2*60*60
phone.sleep(wake_up_time)

# 読み込んだモジュールのメソッドを使ってみる
phone.type('t')

# クラスメソッド
# クラス変数@@countを表示する
Phone.show_device_count

# SmartPhoneクラスからインスタンスを作成
# SmartPhoneクラスではinitializeを定義していないが、
# Phoneクラスを継承しているので引数を3つとる
iphone = SmartPhone.new('iPhone', 5.2, 'black')
# Phoneクラスのメソッドが使える
iphone.start

# クラス変数@@countを表示
# クラス変数は継承先のクラスとも共有されるので2を返すはず
# これがクラスインスタンス変数と異なる特徴
Phone.show_device_count

# PhoneクラスにはないメソッドがSmartPhoneクラスでは使える
iphone.take_photo

# オーバーライドされたメソッドを使ってみる
iphone.change_color('gold', 'polished')

# 上で書いたようにこのメソッドは意図した通り動かない
# SmartPhoneクラスでは@cameraというクラスインスタンス変数が定義されていない
SmartPhone.camera?

# 継承先のクラスでも継承元で読み込んだモジュールのメソッドが使える
iphone.type('i')

phone.exit
iphone.exit

 

拡張子.rbで保存して、実行すると下記のようになるはずです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
TYPE : mobile
Camera : NO


Welcome to black Traditional Phone! (instance method)

You changed color to white (instance method)

See you at 2014-02-04 14:00:16 +0100, zzz.... (instance method)

You typed [t] with Traditional Phone.

@@count : 1 ('Class' method with class variable)

Welcome to black iPhone! (instance method)

@@count : 2 ('Class' method with class variable)

You can take photo with smartphone!

 -> Photo is saved in iPhone. (Private method)

You changed color to gold (instance method)

Now your phone's surface is polished! (Override instance method)

Camera :  (of course dosn't work)

You typed [i] with iPhone.

Good bye! from Traditional Phone (instance method)

Good bye! from iPhone (instance method)
700
Shunsuke Sawada

おすすめの記事

acts-as-taggable-on タグを表示させる順番を決めたい
Railsを4.2にバージョンアップしたら、Vagrantのローカル開発環境にアクセスできなくなった問題
Railsのバリデーションエラー後にレイアウトが崩れるとき