「たのしいRuby」クラス

Rubyの本、買ってきた。「たのしいRuby」勉強しながらtwitterに投稿した文を加筆訂正してQiitaに投稿する。今回は、いよいよラスボス、クラス。
Twitter、Green_helmet@bethlehem4099
Qiita、@dosaidon
## 参考文献
この記事は以下の情報を参考にして執筆しました。
-[たのしいRuby、高橋征義、後藤裕蔵著、 まつもとゆきひろ監修、SBクリエイティブ株式会社、第6版2019年](https://www.amazon.co.jp/%E3%81%9F%E3%81%AE%E3%81%97%E3%81%84Ruby-%E7%AC%AC6%E7%89%88-%E9%AB%98%E6%A9%8B-%E5%BE%81%E7%BE%A9-ebook/dp/B07PNN3TYF/ref=tmm_kin_swatch_0?_encoding=UTF8&qid=1671278506&sr=8-1)
-[『たのしいRuby 第6版』サポートページ、ソースコード](https://tanoshiiruby.github.io/6/index.html)
## クラス
用語の定義:
まずクラスから(意訳)
✅クラスはオブジェクトの種類を表すもの
✅クラスはRubyでは型
✅何らかのクラスに全てのRubyのオブジェクトは属している
例1:Arrayクラスのオブジェクトが配列、例a=[1,2,3]
例2:Stringクラスのオブジェクトが文字列、例s= "Ruby"
✅クラスのオブジェクトをインスタンスと言う
例1:配列はArrayクラスのインスタンス
例2:文字列はStringクラスのインスタンス
はい
✅クラスは雛形あるいは設計図
✅インスタンスは雛形あるいは設計図をもとに作ったもの

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

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

## クラスを作る
~~~Ruby: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:command_line
➜  ruby receipt.rb
レシート ストアA
卵 139  x 1
きゅうり 42  x 3
合計金額: 265円
~~~
この例題は複雑だがコメントのように理解するとわかる。うん、Rubyのクラス定義を完全に理解した

***Green_helmet@bethlehem4099·7月24日***

### もっと単純なクラスを自分で作って見る
~~~Ruby: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: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日***

## つぎ、アクセッサ

~~~Ruby: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:command_line
初期
初期
変更
変更
~~~

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

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

***Green_helmet@bethlehem4099·7月29日***

## つぎ、クラスメソッド
~~~Ruby:class_method5.rb
class << HelloWorld
   def hello(name)
       puts "#{name} said hello."
   end
end

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

~~~Ruby:class_method5.rb
class HelloWorld
end

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

HelloWorld.hello("John")
~~~
~~~command_line:command_line
~ % ruby hello_world_inheritance.rb
John said hello.
~~~
動いた、ありがとうございます。
Green_helmet@bethlehem4099·7月30日
~~~Ruby: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日***

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

HelloWorld7.hello("Tommy")
~~~
~~~command_line:command_line
➜  ruby class_method7.rb
Tommy said hello.
~~~
これも大丈夫
## Rubyクラスメソッドのサンプル

Green_helmet@bethlehem4099·7月30日

~~~Ruby: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日***
~~~Ruby: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日***

### つぎ、クラスの中の定数
~~~Ruby: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日***

## つぎ、クラス変数
例題が複雑すぎて理解できないので独自に作成
~~~Ruby: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: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日***

## つぎ、メソッドの呼び出しを制御する
~~~Ruby: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日***

ちなみに半角スペースが意味を持つ
~~~Ruby:
    public:pub　#OK
    public :pub　#OK
    public: pub　#ERROR
    public : pub　#ERROR
~~~
***Green_helmet@bethlehem4099·8月12日***

## つぎ

~~~Ruby: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日
~~~Ruby: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日***

## いよいよ大物、クラスの継承
~~~Ruby: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日***

## つぎ、オーバーライド
~~~Ruby: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日***

## つぎ、ベーシックオブジェクト
~~~Ruby: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日
~~~Ruby: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
~~~Ruby:undef.rb
undef method_name
undef: method_name
~~~
はい

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


***Green_helmet@bethlehem4099·8月17日***