気軽に楽しくプログラムと遊ぶ

自分が興味があってためになるかもって思う情報を提供しています。

Ruby Goldで問われる押さえておきたい仕様2

protectedとprivateメソッドの可視性

基本的なルールは以下

  • protected

    • レシーバーなしで参照可能
    • レシーバー(自分またはサブクラス)から参照可能
    • 自クラス、サブクラスから参照可能
    • クラス外部からは参照できない
  • private

    • レシーバーなしで参照可能
    • レシーバーから参照できない
    • 自クラス、サブクラスから参照可能
    • クラス外部からは参照できない
class C
  def internal_use_private_and_protected
    protected_method # 呼び出し可
    private_method # 呼び出し可
  end

  def internal_use_private_and_protected_with_reciever
    self.protected_method # 呼び出し可。自クラスから呼び出し可。
    self.private_method # 呼び出し不可。レシーバーから呼び出せない。
  end
  
  def use_protected(other)
    other.protected_method # 自クラス、サブクラスなら呼び出し可。
  end

  protected
  def protected_method
    puts "protected_method"
  end
  
  private
  def private_method
    puts "private_method"
  end
end

class D < C
end

c = C.new
# 外部から直接呼び出し不可
c.protected_method #=> NoMethodError: protected method `protected_method' called for 

# 外部から直接呼び出し不可
c.private_method #=> NoMethodError: private method `private_method' called for

# レシーバーなしでは両方呼び出し可
c.internal_use_private_and_protected
#=> protected_method
#=> private_method

# レシーバーあり(自クラス)ではprotectedのみ呼び出せる
c.internal_use_private_and_protected_with_reciever
#=> protected_method
#=> NoMethodError: private method `private_method' called for

d = D.new
# サブクラスから呼び出し可
d.use_protected(d) #=>protected_method

メソッドの可視性変更

子クラスで再定義した場合、子クラスのメソッドが優先される。可視性の変更も可能

class C
  protected
  def protected_method
    puts "protected_method"
  end
  
  private
  def private_method
    puts "private_method"
  end
end

class D < C
  #表示内容の変更と可視性をpublicへ変更
  def protected_method
    puts "edit protected_method"
  end
  
  #表示内容の変更と可視性をpublicへ変更
  def private_method
    puts "edit private_method"
  end
end

d = D.new
d.protected_method # =>edit protected_method
d.private_method # =>edit private_method

open-uriとopen

http/ftpに簡単にアクセスするためのクラス

require 'open-uri'
open("http://www.ruby-lang.org/") { |f|
  # 開いたファイルオブジェクトはStringIOまたはTempfile
  f.each_line { |line| p line }
  # OpenURI::Metaモジュールで拡張されているため、メタ情報取得メソッドが使用可能
  p f.base_uri         # <URI::HTTP:0x40e6ef2 URL:http://www.ruby-lang.org/en/>
  p f.content_type     # "text/html"
  p f.charset          # "iso-8859-1"
  p f.content_encoding # []
  p f.last_modified    # Thu Dec 05 02:45:02 UTC 2002
}

環境変数のEnv

keyと値には文字列しか使えない。

ENV[1] = "A"
Exception TypeError at (irb):16 - no implicit conversion of Fixnum into String

ENV['A'] = 1
Exception TypeError at (irb):17 - no implicit conversion of Fixnum into String

ENV['A'] = "TEST"
=> "TEST"

hashと同様のインターフェースをもつが、hashではない。

ENV.class
=> Object

pとprintの裏で使われているメソッド

p は inspectメソッド
print は to_sメソッド

で表示している。

Object#to_s と Object#to_strの違い

to_sは明示的な変換。printや文字列展開で使われている。
to_strは暗黙的な変換。文字列の+演算子利用時に呼び出される。

class Person
  attr_reader :name
  
  def initialize(name)
    @name = name
  end

  def to_str
    @name
  end
end

class NotStringPerson
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def to_s
    @name
  end
end

tanaka = Person.new("tanaka")
suzuki = NotStringPerson.new("suzuki")

# + 演算子利用時に暗黙的に to_str を利用した変換が行われる
puts "■ + 演算子利用時の to_str  呼び出し確認"
puts "tanaka name = " + tanaka
begin
  puts "suzuki name = " + suzuki
rescue => e
  puts e.message
end

# 変数展開時にも暗黙的に to_s を利用した変換が行われる
puts "■ 変数展開"
puts "tanaka name = #{tanaka}"
puts "suzuki name = #{suzuki}"

出力結果

■ + 演算子利用時の to_str  呼び出し確認
tanaka name = tanaka
no implicit conversion of NotStringPerson into String #to_strなし
■ 変数展開
tanaka name = #<Person:0x2bcd370> #to_sなし
suzuki name = suzuki

ensure 節あるときの評価値

下記の評価値はどうなるか?

def m
  begin
    1
  rescue
    2
  else
    3
  ensure
    4
  end
end

p m

答えは「3」まじか。。

下記のような仕様らしい。
本体、rescure節、else節のうち最後に評価された文の値がbegin式全体の評価値。
ensure節は実行されるが、評価値としては無視される。

メソッド内で定数を更新

下記でエラーになる二つは??

X = 'abc'
def m
  X #  (1)
  X = 'def' # (2)
  X += 'def' #(3)
  X << 'def' # (4)
end

答えは(2),(3)らしい。
メソッド内で定数を更新(定義 =で代入)するとSyntaxError発生。
<<は破壊的でないので、OKらしい。へーー。

参考URL

徒然なるままに|Rubyにおけるメソッドの可視性(public, private, protected)について
library open-uri (Ruby 1.8.7)
武田哲也さんのRuby技術者認定試験受験記 - Togetterまとめ
Ruby | 文字列への明示的変換と暗黙的変換。Object#to_s , Object#to_str の使い分け - Qiita
制御構造 (Ruby 2.1.0)