2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

RubyAdvent Calendar 2022

Day 17

「たのしいRuby」クラス

Last updated at Posted at 2022-12-16

Rubyの本、買ってきた。「たのしいRuby」勉強しながらtwitterに投稿した文を加筆訂正してQiitaに投稿する。今回は、いよいよラスボス、クラス。
Twitter、Green_helmet@bethlehem4099
Qiita、@dosaidon

参考文献

この記事は以下の情報を参考にして執筆しました。
-たのしいRuby、高橋征義、後藤裕蔵著、 まつもとゆきひろ監修、SBクリエイティブ株式会社、第6版2019年
-『たのしいRuby 第6版』サポートページ、ソースコード

クラス

用語の定義:
まずクラスから(意訳)
✅クラスはオブジェクトの種類を表すもの
✅クラスはRubyでは型
✅何らかのクラスに全てのRubyのオブジェクトは属している
例1:Arrayクラスのオブジェクトが配列、例a=[1,2,3]
例2:Stringクラスのオブジェクトが文字列、例s= "Ruby"
✅クラスのオブジェクトをインスタンスと言う
例1:配列はArrayクラスのインスタンス
例2:文字列はStringクラスのインスタンス
はい
✅クラスは雛形あるいは設計図
✅インスタンスは雛形あるいは設計図をもとに作ったもの

たい焼きの型とたい焼きの絵
宇宙猫…
クラスの説明がよくわからない
かなり意訳した

ああ、
たい焼きは粒餡かな、それともこし餡か
東京三大たい焼きは人形町柳屋、麻布十番浪速屋総本店、四谷たいやきわかば
白いたい焼きもあったな
乱獲がたたって今や絶滅危惧種
はっ、Rubyと関係無い
Green_helmet@bethlehem4099·7月24日

クラスを作る

receipt.rb
# receipt.rb参照しコメントを独自に追加
class Receipt # クラス宣言開始
    def initialize(name) # initializeメソッド、コンストラクタ
        @name=name  #@name:インスタンス変数の定義
        @lines=[]   #@lines:インスタンス変数の定義、空
    end
    def lines=(line)    #lines=:「英字=」の変数名が許される!
        @lines=line #@lines:インスタンス変数のセッター
    end
    def calc            # 計算メソッド、価格と数量の積和を求める
        total=0
        @lines.each do | line |
            total += line[:price] * line[:num]
        end
        total
    end
    def output  # 出力メソッド
        puts "レシート #{@name}"
        @lines.each do  | line |
            puts "#{line[:name]} #{line[:price]}  x #{line[:num]}"
        end
        puts "合計金額: #{calc}円"
    end
end#クラス宣言終わり

r = Receipt.new("ストアA") # レシートクラスのインスタンス/オブジェクトを作る
r.lines= [{ name:"卵", price:139, num:1 },
        { name:"きゅうり", price:42, num:3 }] # レシートの名称と金額、数量をセット
r.output#出力メソッド
command_line
➜  ruby receipt.rb
レシート ストアA
卵 139  x 1
きゅうり 42  x 3
合計金額: 265円

この例題は複雑だがコメントのように理解するとわかる。うん、Rubyのクラス定義を完全に理解した

Green_helmet@bethlehem4099·7月24日

もっと単純なクラスを自分で作って見る

ruby
# mini_class.rb
class MiniClass
    def initialize(var)
        @x = var
    end

    def meth1
        puts @x
    end

    def meth2
        puts @x * 2
    end
end

obj=MiniClass.new(2020)
obj.meth1
obj.meth2
command_line
➜  ruby mini_class.rb
2020
4040

Rubyのクラスのキモ

ごく雑に要約すると上の例のように関数(メソッド)をclass クラス名endで囲ったものがクラスで、使うときはオブジェクト名=クラス名.newと書くと新しくオブジェクトが作られる(new)、さらにオブジェクト名.関数名(メソッド名)と書くとクラス内のメソッドが実行される。他に色々マイナーチェンジがあるがクラスのキモはこれ。

RubyとPythonの比較

Rubyは意外なことにPythonよりタイプ量が少ない
まず (self): が無いのと、self. が@に入れ替わる、あと()も無い。
Pythonでクラスを書いているとやたらとself.がでてくる。
自己中なヘビ。
Green_helmet@bethlehem4099·7月25日

つぎ、アクセッサ

attr_accessor.rb
class MyClass
attr_accessor:name
    def initialize(name);@name=name end
    def meth; puts @name; end
end

obj=MyClass.new("初期")
puts obj.name
obj.meth
obj.name="変更"
obj.meth
puts obj.name
command_line
初期
初期
変更
変更

アクセッサ:インスタンス変数(@が付いてる変数)を楽に読み書き出来るようにする。
あと、Rubyはプログラムを改行せずにコンパクトに書くこともでき自由度が高い

つぎ、特別な変数self

エッ、Rubyにもself.があるの?
@はself.の代わりじゃないのか
@がつくのは変数だけか

Green_helmet@bethlehem4099·7月29日

つぎ、クラスメソッド

class_method5.rb
class << HelloWorld
   def hello(name)
       puts "#{name} said hello."
   end
end

HelloWorld.hello("John")

楽しいRuby、クラスメソッドの例題が動かない。
親クラスHelloWorldが抜けているとのアドバイスを頂いたので追加。
Green_helmet@bethlehem4099·7月29日

class_method5.rb
class HelloWorld
end

class << HelloWorld
   def hello(name)
       puts "#{name} said hello."
   end
end

HelloWorld.hello("John")
command_line
~ % ruby hello_world_inheritance.rb
John said hello.

動いた、ありがとうございます。
Green_helmet@bethlehem4099·7月30日

HelloWorld6.rb
class HelloWorld6
    class << self
        def  hello(name)
            puts "#{name} said hello."
    end
    end
end

HelloWorld6.hello("John")
➜  ruby class_method6.rb
John said hello.

ああ、これは動く

Rubyクラスメソッドのサンプル

Green_helmet@bethlehem4099·7月30日

class_method7.rb
class HelloWorld7
    def  self.hello(name)
        puts "#{name} said hello."
    end
end

HelloWorld7.hello("Tommy")
command_line
➜  ruby class_method7.rb
Tommy said hello.

これも大丈夫

Rubyクラスメソッドのサンプル

Green_helmet@bethlehem4099·7月30日

class_method8.rb
class HelloWorld8
    def  HelloWorld8.hello(name)
        puts "#{name} said hello."
    end
end

HelloWorld8.hello("Roger")
➜  ruby class_method8.rb
Roger said hello.

これも動く

Rubyのクラスメソッドのサンプル

Green_helmet@bethlehem4099·7月30日

class_method9.rb
class HelloWorld9
    def self.hello(name)
        puts "#{name} said hello."
    end
end

HelloWorld9.hello("Mark")
➜  ruby class_method9.rb
Mark said hello.

ちゃんと動く

Rubyのクラスメソッドのサンプル

Green_helmet@bethlehem4099·7月30日

見た目の感じはself.関数名の書き方が好きかな。
Pythonでは@staticmethodに相当すると思うけどRubyの方がスマート。
クラスメソッドはこれでおしまい。

Rubyの勉強からは少し外れるが、変数の型宣言のある言語の方がないRubyのような言語より良いというTwitterがたくさん流れてくる。
でも、変数の型宣言のある言語にはとても小さな欠点があって、それはプログラムを期限内に開発できない事なんだよね。

Green_helmet@bethlehem4099·7月31日

つぎ、クラスの中の定数

const.rb
class Constant
    Version = 1.0
    def self.hello
        puts "Version is #{Version}"
    end
end

Constant.hello
print "Version is ", Constant::Version, "\n"
➜  ruby const.rb
Version is 1.0
Version is 1.0

クラスの中の定数
はい

Green_helmet@bethlehem4099·7月31日

つぎ、クラス変数

例題が複雑すぎて理解できないので独自に作成

cvar.rb
class ClVar
   @@cnt=0
   def initialize
        @cnt=0
   end
   def cnter
       @@cnt+=1
       @cnt+=1
       puts "@@cnt=#{@@cnt}"
       puts "@cnt=#{@cnt}","\n"
   end
end

r1=ClVar.new
r2=ClVar.new
r1.cnter
r2.cnter
r2.cnter
r1.cnter
command_line
➜  ruby cvar.rb
@@cnt=1
@cnt=1

@@cnt=2
@cnt=1

@@cnt=3
@cnt=2

@@cnt=4
@cnt=2

@@変数はインスタンスをまたいで値を変更・参照できる
@変数はそれぞれのインスタンスで独立に値を変更・参照できる
よくできている

Green_helmet@bethlehem4099·8月12日

つぎ、メソッドの呼び出しを制御する

access_test.rb
class AccessTest
    def pub
       puts "pub is a public method."
    end

    public:pub

    def priv
       puts "priv is a private method."
    end

    private :priv
end

access = AccessTest.new
access.pub
access.priv
➜  ruby Access_test.rb
pub is a public method.
Access_test.rb:18:in `<`: private method `priv` called for #<AccessTest:0x000000014b938450> (NoMethodError)

プライベートなメソッドは自分のインスタンスでも呼べない
ふむ

Green_helmet@bethlehem4099·8月12日

ちなみに半角スペースが意味を持つ

    public:pub #OK
    public :pub #OK
    public: pub #ERROR
    public : pub #ERROR

Green_helmet@bethlehem4099·8月12日

つぎ

access_test2.rb
class AccessTest

    public
    def pub
       puts "pub is a public method."
    end

    private
    def priv
       puts "priv is a private method."
    end

end

access = AccessTest.new
access.pub
access.priv

Green_helmet@bethlehem4099·8月12日

➜  ruby Access_test2.rb
pub is a public method.
Access_test2.rb:14:in `<main>`: private method `priv` called for #<AccessTest:0x000000014b883a50> (NoMethodError)

コッチの書き方の方が馴染み深いが
C++はprivate:だったような…

Green_helmet@bethlehem4099·8月13日

point.rb
def swap(other)
       tmp_x, tmp_y = @x, @y
       @x,@y= other.x, other.y
       other.x, other.y=tmp_x, tmp_y
       return self
    end
end

p0 = Point.new
p1 = Point.new(1.0, 2.0)

p [p0.x, p0.y]
p [p1.x, p1.y]
p0.swap(p1)
p [p0.x, p0.y]
p [p1.x, p1.y]
p.x=10.0
➜  ruby point.rb
[0.0, 0.0]
[1.0, 2.0]
[1.0, 2.0]
[0.0, 0.0]
point.rb:23:in `<main>`: undefined method `x=` for nil:NilClass (NoMethodError)

Green_helmet@bethlehem4099·8月13日

よく分からんが次

RubyのProtectedはC++と大体同じで、PythonにはProtectedが無いと言うことかな。
あと、Rubyには友達(Friend)がいないと。
まあ、今日はこれぐらいにしといたるわ。

Green_helmet@bethlehem4099·8月14日

いよいよ大物、クラスの継承

ext_string.rb
class String
    def count_word
        ary = self.split(" ")
        return ary.size
    end
end

str = "An example of inheritance in Ruby."
p str.count_word
➜  ruby ext_string.rb
6

Green_helmet@bethlehem4099·8月14日

組み込みクラスのStringを継承して自前のcount_wordメソッドを追加する
ふむ、なかなかキレイ

Green_helmet@bethlehem4099·8月14日

つぎ、オーバーライド

ring_array.rb
class RingArray < Array
    def [](i)
        inx=i % size
        super(inx)
    end
end

wday=RingArray["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]

print wday[-1],","
print wday[0],","
print wday[1],","
print wday[2],","
print wday[3],","
print wday[4],","
print wday[5],","
print wday[6],","
puts wday[7]
→ ruby ring_array.rb
Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday,Monday

Arrayクラスの[]メソッドをオーバーライドしたということか
了解しました

Green_helmet@bethlehem4099·8月17日

つぎ、ベーシックオブジェクト

basic_objects.rb
puts Object.instance_methods,"\n\n"
puts BasicObject.instance_methods

〜略〜

!
==
!=
__id__
equal?
instance_eval
instance_exec
__send__

あまりにBasicすぎてpすら無かった
終わり

つぎ、Alias

Green_helmet@bethlehem4099·8月17日

alias_sample.rb
class C1

    def hello
        "hello"
    end

end

class C2<C1

    alias old_hello hello # old←new
    def hello
        "#{old_hello}, again"
    end

end

obj1 = C1.new
p obj1.hello
obj2 = C2.new
p obj2.old_hello
p obj2.hello
➜  ruby alias_sample.rb
"hello"
"hello"
"hello, again"

クラスのメソッド名を後から書き換える、う〜ん
大混乱の種まきのような気がするが、まあいっか

Green_helmet@bethlehem4099·8月17日

つぎ、undef

undef.rb
undef method_name
undef: method_name

はい

これでクラスは終わり。どっとはらい。

Green_helmet@bethlehem4099·8月17日

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?