メタプログラミング Ruby Rubyについてのノート sinatra/org-ruby

目次

メタプログラミングRuby / 毎回 の講義 / OO へ至る道 / ruby 入門 / 講義ドキュメント / meta-ruby まとめ / note / ruby-note / poker

test-unit

ruby/test

test-unit

新らしい単体テスト・フレームワークを使いましょう:

install

gem install test-unit

テストの書き方

基本
  • classで書く.
  • TestCase毎に呼ばれる startup/shutdown
  • Test毎に呼ばれる setup/teardown/cleanup
  • テストは test で始まるメソッドで書く
require
require "rubygems"
gem "test-unit"
require 'test/unit'
テスト・クラス定義
class TestSample < Test::Unit::TestCase
テスト全体の前後処理メソッド:
class << self
  # テスト群の実行前に呼ばれる.変な初期化トリックがいらなくなる
  def startup
    p :_startup
  end

  # テスト群の実行後に呼ばれる
  def shutdown
    p :_shutdown
  end
end
テストの前後の処理:
# 毎回テスト実行前に呼ばれる
def setup
  p :setup
end

# テストがpassedになっている場合に,テスト実行後に呼ばれる.テスト後の状態確認とかに使える
def cleanup
  p :cleanup
end

# 毎回テスト実行後に呼ばれる
def teardown
  p :treadown
end
テストを test_で始まるメソッドとして定義する:
  def test_foo
    p 'test_foo'
    assert_true(1 == 1)
  end

  def test_bar
    p 'test_bar'
    assert_equal(1, 1)
  end
end
テスト準備

(defvar org-babel-ruby-command "users/home/masayuki.rbenv/shims/ruby" "Name of command to use for executing ruby code.")

p require "rubygems"
p gem "test-unit"
p RUBY_VERSION
'end'
テスト実行

デフォルトだとアルファベット順にテストが実行される.

which ruby
gem install test-unit
ruby test_sample.rb
echo 'end'
/usr/bin/ruby
Run options: 

# Running tests:

:setup
"test_bar"
:treadown
.:setup
"test_foo"
:treadown
E

Finished tests in 0.003415s, 585.6515 tests/s, 292.8258 assertions/s.

  1) Error:
test_foo(TestSample):
NoMethodError: undefined method `assert_true' for #<TestSample:0x007fb08a8164c8>
    test_sample.rb:36:in `test_foo'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:1301:in `run'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit/testcase.rb:17:in `run'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:919:in `block in _run_suite'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:912:in `map'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:912:in `_run_suite'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:657:in `block in _run_suites'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:655:in `each'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:655:in `_run_suites'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:867:in `_run_anything'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:1060:in `run_tests'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:1047:in `block in _run'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:1046:in `each'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:1046:in `_run'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:1035:in `run'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:21:in `run'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:774:in `run'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:366:in `block (2 levels) in autorun'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:27:in `run_once'
    /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/test/unit.rb:365:in `block in autorun'

2 tests, 1 assertions, 0 failures, 1 errors, 0 skips

ruby -v: ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin14]
end
アサーション

https://test-unit.github.io/test-unit/ja/Test/Unit/Assertions.html

のページの"Instance Method Summary"にあるassertで始まるメソッド群 が該当.各メソッドに飛べば実際のコード例が出てくるので,参照しつつ 適宜使い分ける.

便利な機能
sub_test_case

RSpecだとdescribeとかでネスト出来るが,それをTest::Unitで出来る.実際 はTest::Unitでも継承すれば出来るけど,こっちの方が簡潔で好き.

class TestSample < Test::Unit::TestCase sub_test_case "Foo context" do

end

sub_test_case "Bar context" do

end end

test

メソッド名ベースだと使えない文字とかもあり,少し表現がしにくかっ た.けど,testを使えば解決!

class TestSample < Test::Unit::TestCase
  test "We can write good information" do
    # assert_nil(nil)
  end
end

Test::Unitのgemにはdescriptionという機能があって,それとメソッド 定義のシンタックスシュガーらしい.以下のコードは上とほぼ同じ.

class TestSample < Test::Unit::TestCase description "We can write good information" def test_foo_bar

end end

setup/teardown ブロック

sub_test_caseを使っていると,RSpecのbeforeのように各ケース毎に追 加でセットアップ処理を書きたくなる.TestCaseにはsetupメソッドがあ るけど,これはオーバーライドしてしまうので使えない.このような場 合にはsetupブロックを使う.setupメソッドとは違い,beforeのように 何個でも書ける.

class TestSample < Test::Unit::TestCase setup do puts "parent" end

sub_test_case "Sub!" do setup do puts "sub1" end

setup do puts "sub2" end

def test_sub assert_true(true) end end end

上の例を走らせると以下のようになる.もちろん,teardownも同様に出来る.

Loaded suite test_nest Started parent sub1 sub2 .

Finished in 0.000896 seconds.

注意点として,setupメソッドとsetupブロックでは優先順位が決まっている.気になるなら,setupブロックで統一した方が良いかもしれない.

test_order

テストの実行順序を指定出来る.どうしても定義順に実行したいのであれば,:definedを指定すれば上から順に実行される.

class TestSample < Test::Unit::TestCase self.test_order = :defined end

データ駆動テスト

テストとデータを分けて書ける機能です.成功するテストや失敗するテ ストをまとめたりするのに便利.テストの中でeach回すのはイケてない し,かといってコピペで重複したテスト書くのもつらい.この機能使え ば,ちゃんとデータセット毎にテストがわかれます.

class TestSample < Test::Unit::TestCase
  # 'test1'がラベルで,[1, 1]がtest_equalの引数に渡される
  data(
    'test1' => [1, 1],
    'test2' => [2, 2])
  def test_equal(data)
    expected, actual = data
    assert_equal(expected, actual)
  end

  data(
    'test1' => [1, 2],
    'test2' => [2, 3])
  def test_not_equal(data)
    expected, actual = data
    assert_not_equal(expected, actual)
  end
end
その他
assertの作り方

Test::Unit::Assertions以下に定義して,そのファイルをrequireで読み 込むだけ.assert_blockとかbuild_messageとかのヘルパーが利用可能. assert_blockの中に条件を書く.

require 'test/unit/assertions'

module Test::Unit::Assertions
  def assert_oreore(expected, actual)
    assert_block("failure message") do
      expected == (actual + 'oreore')
    end
  end
end
Rakeのタスク定義

コピペで使い回す

desc 'Run test_unit based test'
Rake::TestTask.new do |t|
  # To run test for only one file (or file path pattern)
  #  $ bundle exec rake test TEST=test/test_specified_path.rb
  t.libs << "test"
  t.test_files = Dir["test/**/test_*.rb"]
  t.verbose = true
end
まとめ

RSpecほど機能がリッチじゃないので,足りないなら自分で書く必要があ るけど,Fluentdレベルだとそんなに困ってない. 個人的には, Parameterized Testが入ってくれれば嬉しいという所かな.

情報元

オブジェクト指向スクリプト言語 Ruby リファレンスマニュアル (Ruby 2.0.0) http://docs.ruby-lang.org/ja/2.0.0/doc/index.html

Ruby入門 http://www.rubylife.jp/ini/

Ruby紹介

Ruby

はじめに

  • Rubyは手軽なオブジェクト指向プログラミングのためのインタプリタ言語
  • Rubyはテキスト処理やシステム管理のための豊富な機能を持っています。
  • Rubyは単純で、分かりやすく、簡単に拡張できます。
Rubyの特長
  • インタプリタ

    Rubyはインタプリタ言語です。プログラムを実行するためにコンパイル する必要はありません。

  • 変数に型が無い (動的型付け)

    Rubyの変数はどのような型のデータも格納する事ができますので、 変 数の型について心配する必要はありません。 半面、コンパイル時のチェッ クは弱くなります。

  • 変数宣言が不要

    Rubyでは変数を宣言無しで使う事ができます。 変数の種類(ローカル変 数、グローバル変数、インスタンス変数など)は 変数名から知る事がで きます。

  • 単純な文法

    Rubyの文法はEiffelからわずかに影響を受けた単純なものです。

  • ユーザによるメモリ管理が不要

    Rubyはメモリ管理を自動的に行います。 どこからもアクセスされなく なったオブジェクトは インタプリタに組み込みのガーベージコレクタ によって回収されます。

  • 全てがオブジェクト

    Rubyははじめから純粋なオブジェクト指向言語として設計されています。 整数のような基本的なデータ型をはじめとして、 全てのデータをオブ ジェクトとして統一的に取り扱えます。

  • クラス、継承、メソッド

    Rubyは クラス、継承、メソッドのようなオブジェクト指向言語として 基本的な機能は 当然持っています。

  • 特異メソッド

    ある特定のオブジェクトにメソッドを付加することができます。 たと えば、GUIのあるボタンを押された時の動作を メソッドとして記述する ような使い方ができますし、 これを応用してプロトタイプベースの オ ブジェクト指向プログラミングも可能です(やりたければね)。

  • モジュールによるMix-in

    Rubyは多重継承は複雑さの源であるという見地から、 意図的に多重継 承を持っていませんが、 モジュールを使ってクラス階層を横断して実 装を共有できます。 この機能を"Mix-in"と呼びます。

  • ブロック付きメソッド呼び出し(イテレータ)

    制御構造の抽象化を援助するブロック付きメソッド呼び出しという機能があります。

  • クロージャ

    手続きをオブジェクトとして扱う機能があります。 このオブジェクト 化された手続きのことをクロージャと呼びます。

  • 強力な文字列操作/正規表現

    Perlをお手本とした強力な文字列操作や正規表現検索の機能があります。

  • 多倍長整数

    組み込みの多倍長整数機能がありますので、 メモリが許す限り、非常 に大きな整数の演算もできます。 たとえば、400の階乗なども簡単に計 算できます。

  • 例外処理機能

    例外処理機能は例外的な状況への対処が簡単に書けます。

  • OSへの直接アクセス

    Rubyは(UNIXの)ほとんどのシステムコールの呼び出し機能を持っていま す。 Rubyだけでシステムプログラミングも可能です。

  • ダイナミックローディング

    OSが許せば、オブジェクトファイルを実行時に読み込む機能が提供され ます。

Rubyの原理

Rubyの原理

Todo オブジェクト

ここに,ruby の基本原理, が書かれていると,s-:は思う。

オブジェクトとは
  • Ruby で扱える全ての値はオブジェクトです。
  • Rubyのオブジェクトに対して可能な操作はメソッド呼び出しのみです。
  • あるオブジェクトが反応できるメソッドは、 そのオブジェクトが所属するクラスによって一意に決定します。
  • 所属するクラスはオブジェクト生成時に決まり、その後は特異クラスの導入 以外、所属クラスが変わることはありません。
  • またオブジェクトは、特定のクラスに対比して、その「インスタンス」とも呼ばれます。
  • オブジェクトの生成は、一般には、別のオブジェクトのメソッドを呼び出すことによって行われます。
クラス
  • クラスは自身に所属するオブジェクトが反応できるメソッドを決定します。
  • 所属するオブジェクトに対してあるメソッドを呼び出すことができるなら、 そのメソッドが「クラスに定義されている」と言います。
  • またメソッドはクラスとメソッド名によって一意に決定します。
  • クラスは必ずただひとつの「スーパークラス」を持ち、
  • スーパークラスであるメソッドが定義されていれば自クラスでもそのメソッ ドが同じ内容で定義されていることになります。 これを「継承」と呼びます。
  • 継承は推移するので、スーパークラスのスーパークラスが持つメソッドもま た自クラスにおいて定義されていることになります。
モジュール
  • ちょっと特殊でクラスではない。しかし機能は同じ。
メソッド
  • メソッドは実行することができます。その実行を開始することを通常「呼び 出す」と言います。
  • また呼び出すときにはオブジェクトを渡すことができ、そのオブジェクトを 「引数」と呼びます。
  • いくつの引数を受け取ることができるかはメソッドの定義時に決定し、変更 することはできません。

Todo クラス

クラスとオブジェクト
  • Ruby プログラムからはクラスもまたオブジェクトとして扱うことができる。
  • 以下の基本操作が可能:
    • メソッドの存在を問い合わせる
    • メソッドを定義する
    • メソッドの定義を取り消す
モジュール
  • Ruby プログラムからはクラスもまたオブジェクトとして扱うことができる。
  • 以下の基本操作が可能:
    • メソッドの存在を問い合わせる
    • メソッドを定義する
    • メソッドの定義を取り消す

クラスと同じだが,インスタンスを作ること,はできない。

特異クラス

あるオブジェクトだけに定義されたクラス (by s-:)

言語上のこと

変数 http://www.rubylife.jp/ini/var/ 変数 - Ruby入門

変数への代入

変数への代入

変数 = 値

多重代入 : 変数1, 変数2, 変数3 = 値1, 値2, 値3

x1 = 10

x1, x2, x3 = 1, 2, 3

x1, x2, x3 = [1, 2, 3]

'end'

変数の種類

http://docs.ruby-lang.org/ja/2.0.0/doc/s 変数と定数 (Ruby 2.0.0)

  • グローバル変数
  • ローカル変数
  • インスタンス変数
  • クラス変数
  • 定数

Ruby予約語

: BEGIN class ensure nil self when : END def false not super while : alias defined? for or then yield : and do if redo true : begin else in rescue undef : break elsif module retry unless : case end next return until

変数名としては使用できません。

自己代入

多重代入

スコープ

講義後半で説明します。

Block/Module

  • ローカル変数
  • グローバル変数

Object

  • インスタンス変数

Class

  • クラス変数

Module/Class (?) - ((自信なし))

http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fcall.html

http://docs.ruby-lang.org/ja/2.0.0/doc/spec=2fdef.html

メソッド - Ruby入門

Rubyにおけるトップレベル
トップレベル
print("Hello¥n")
'end'

クラス定義の外側の部分はトップレベルと呼ばれています。

ruby が実行されると, トップレベルに記述されたプログラムが順に実行 されて行きます。

selfとmain
self
'end'

では「main」と言うオブジェクトの元になっているクラスは何かを確認し てみます。オブジェクトに対して「class」メソッドを実行するとそのオ ブジェクトをのクラスを返します。

self
self.class
'end'

「main」オブジェクトの元になっているクラスは「Object」クラスと表示 されます。

トップレベルに定義されたメソッド

ップレベルの中にもメソッドを定義することが出来ます。

トップレベルに定義されたメソッドは*「Kernel」モジュール*の中に追加 されることになっています。

「Kernel」モジュールは全てのクラスの元になっている「Object」クラス に読み込まれています。

その為、トップレベルに定義されたモジュールは、「Kernel」モジュール の中で既に定義されている「print」メソッドなどと同じようにどのクラス 内からでも呼び出すことができます。

またメソッドを呼び出す際に、呼び出し元のオブジェクト(レシーバーと呼 ばれています)を省略できるので、あたかも関数のように使用することが可 能です。

よって特定のクラス内ではなくトップレベルの位置にメソッドを定義すれ ば、関数のように使用できるメソッドを定義することが可能となります。

メソッドの定義と呼び出し
def メソッド名(引数1, 引数2, ...)
 実行する処理
 実行する処理
end
public
(def printHello
  print("Hello\n")
end).class

printHello
self.printHello

'end'
メソッドの呼び出し

定義されたメソッドを呼び出すと、処理がメソッド内に移りメソッド内に 記述された処理が実行されます。そしてメソッドの最後まで処理が終わる と、メソッドを呼び出した次の行へ処理が戻ります。

メソッドを呼び出す時の書式は次の通りです。

オブジェクト.メソッド名(引数1, 引数2, ...)

メソッドはクラス内で定義され、そのクラスから作成されるオブジェクト (レシーバーと呼ばれます)に対して行わせたい処理を記述するものです。 その為、メソッドを呼び出す時には対象となるオブジェクトと実行させる メソッド名を指定して呼び出します。

メソッド名(引数1, 引数2, ...)

では定義されたメソッドを呼び出してみます。

メソッド定義の位置

メソッドは実際に呼び出されるよりも前に定義されていなければなりませ ん。例えば次のようなプログラムはエラーとなります。

上記のようにメソッド呼び出しがメソッドの定義よりも前に実行されると 「undefined local variable or method」と言うエラーが表示されます。

x
'end'
引数を付けたメソッド呼び出し
引数のデフォルト値

通常引数は呼び出し側とメソッド定義側で数が一致している必要がありますが、メソッ ド定義側では引数にデフォルト値を設定することが可能です。書式は次の通りです。

def メソッド名(変数1=デフォルト値1, 変数2=デフォルト値2, ...)
  実行する処理
  実行する処理
end
def printHello(msg="No msg", name="No name")
  print(msg + "," + name + "¥n")
end

printHello("Hello", "Yamada")
printHello("Hello")
printHello()

def printHello(msg, name="No name")
  print(msg + "," + name + "¥n")
end

printHello("Hello", "Yamada")
printHello("Hello")

'end'
引数を配列として受け取る
メソッドの戻り値
多重代入を使って複数の戻り値を取得
クラスとは
クラスとオブジェクト
  • クラス*は *オブジェクト の設計図です。
  • オブジェクトはクラスから生まれる
    • 具体化 (instantiate)
    • オブジェクトはクラスの インスタンス (instance)
  • オブジェクトの処理を記述するのが*メソッド*
    • クラス定義の中に記述する.
  • オブジェクト の状態を保持するのが インスタンス変数
  • (instance) メソッドの実行
  • 自分の状態 (instance)
class Car … end

class は Carクラスから生まれるオブジェクトの振舞を記述する。

class Car
  def initialize(carname)
    @name = carname
  end

  def dispName
    print(@name)
  end
end

car = Car.new("crown")
car.dispName
'end'
  • 「車」の設計図であるクラスを定義し、

    : class Car … end

  • クラスからオブジェクトを作成した後で、
    car = Car.new
    
  • オブジェクトに対して名前を画面に出力させる
    car.dispName
    
インスタンスメソッド

クラス内に記述されたメソッドはクラスから作成されたオブジェクトしか 呼び出すことが出来ません。このようなメソッドを インスタンスメソッ ド と呼びます。

class クラス名

  def メソッド名(引数1, 引数2, ...)
    処理
  end

end
'end'

例えばクラス名について表示するだけの簡単なインスタンスメソッドは次のようになり ます。

class Car
  def dispString(str)
    print(str, "¥n")
  end
end
'end'

なお、引数が無いメソッドの場合は括弧を省略しても構いません。

class Car
  def dispClassname
    print("Car class¥n")
  end

  def dispString(str, "¥n")
    print(str)
  end
end
'end'

インスタンスメソッドの呼び出し

定義されたインスタンスメソッドはクラスのオブジェクトから呼び出すことができます。

class Car def dispClassname print("Car class¥n") end

def dispString(str, "¥n") print(str) end end

car = Car.new car.dispClassname car.dispString("crown")

オブジェクトからメソッドを呼び出すにはオブジェクトの後にドット「.」を付けてメ ソッドを名を記述します。引数がある場合は括弧の後に引数をカンマで列挙して記述し て下さい。引数が無い場合はメソッド名だけで結構です。

オブジェクト名.メソッド名(引数1, 引数2, …) オブジェクト名.メソッド名

またドット「.」の代わりにコロン(:)を2つ続けて次のように記述することも出来ます。

オブジェクト名::メソッド名(引数1, 引数2, …) オブジェクト名::メソッド名

どちらの形式も違いはありませんので、どちらかに統一して利用すればいいと思います。

オブジェクトを作成する為に使用した「new」メソッドはクラスに対して実行しました。 例えば「Car.new()」のようにです。このようなメソッドはクラスに対して実行するク ラスメソッドと呼ばされます。今回のようにクラス内に定義したインスタンスメソッド はクラスから作成したオブジェクトに対して実行する点が異なっていることに注意して 下さい。

サンプルプログラム

では実際に試してみます。

ClassTest3.rb

class Car def dispClassname print("Car class¥n") end

def dispString(str) print(str, "¥n") end end

car = Car.new() car.dispClassname car.dispString("crown")

上記を実行すると次のように表示されます。

インスタンスメソッド

今回は2つのインスタンスメソッドを定義し、クラスから作成したオブジェクトに対し てメソッドを実行してみました。

class Reji
  SHOUHIZEI = 0.05

  def initialize(init=0)
    @sum = init
  end

  def kounyuu(kingaku)
    @sum += kingaku
  end

  def goukei()
    return @sum * (1 + SHOUHIZEI)
  end
end
'end'
reji = Reji.new(0)
reji.kounyuu(100)
reji.kounyuu(80)
print(reji.goukei())

'end'
SHOUHIZEI
class \Reji
print SHOUHIZEI
end
Reji::SHOUHIZEI
'end'
継承
class Car
  def accele
    print("アクセルを踏みました")
  end

  def brake
    print("ブレーキを踏みました")
  end
end
'end'
a = Car.new("abc")
a.brake
'end'
class Soarer < Car
  def initialize(name,type)
     @type = type
     super(name)
  end
  def openroof
    print("open roof\n");
  end
end

class Crown < Car
  def reclining
    print("reclining")
  end
end

'end'
so = Soarer.new("soarer")
cr = Crown.new("crwon")

so.class
(so.class).superclass

so.dispName
'end'

\

#<Soarer:0x007fb02b61d888 @name="soarer">
#<Crown:0x007fb02b616ec0 @name="crwon">
Soarer
Car
soarernil

クラスライブラリ

Rubyリファレンス

原典

method名やkeywordからクラスを探せるようにこの org文書を作成しました。

BasicObject

http://ref.xaio.jp/ruby/classes/basic_object

*=BasicObject=*クラスは、Ruby 1.9で新しく用意されたクラスで、=Object= クラスの親クラスです。通常は、=BasicObject=オブジェクトを直接使うこと はありません。

=BasicObject=は=Object=や=Kernel=のメソッドを持たないので、「メソッド がほぼゼロの白紙のクラスを作りたい」というときは、=BasicObject=を継承 したサブクラスで実現できます。

メソッド一覧

クラスメソッド
  • new : インスタンスの作成。
インスタンスメソッド
  • ! : 否定。
  • != : 別のものか調べる。
  • == : オブジェクトの内容が同じか調べる。
  • __send__ : メソッドを呼び出す。
  • equal? : 同じオブジェクトか調べる。
  • instance_eval : インスタンスの元でコードを実行。
  • instance_exec : インスタンスの元でコードを実行。
特別な役割のメソッド
  • initialize : オブジェクトを作成(=new=)するとき呼ばれる。
  • initialize_copy : オブジェクトをコピー(=clone=、=dup=)するとき呼ばれる。
  • method_missing : メソッドが見つからないとき呼ばれる。
  • singleton_method_added : 特異メソッドを定義するとき呼ばれる。
  • singleton_method_removed : 特異メソッドを削除するとき呼ばれる。
  • singleton_method_undefined : 特異メソッドを未定義にするとき呼ばれる。

このサイトについて 記事の読み方 参考文献

Sponsored by Oiax Inc. / Powered by Ruby on Rails and AmiWiki

Object

*=Object=*クラスは、すべてのクラスの親クラスです。

親クラスとモジュール

=Object=クラスは=Kernel=モジュールをインクルードしています。

=BasicObject=クラスが=Object=クラスの親クラスになりました。

Object < Kernel (< BasicObject)

メソッド一覧

クラスメソッド
  • new : インスタンスの作成。
インスタンスメソッド

これらのメソッドは、実際には=Kernel=モジュールの=public=なメソッドとして実装されていますが、一般的に=Object=クラスのメソッドとして扱われます。また、この一覧には=BasicObject=のメソッドも混ぜてあります。

  • ! : 否定。Ruby 1.9
  • != : 別のものか調べる。Ruby 1.9
  • !~ : パターンマッチの否定。Ruby 1.9
  • == : オブジェクトの内容が同じか調べる。
  • === : =case=式でオブジェクトをテストする。
  • =~ : パターンマッチ。
  • __id__ : オブジェクトIDを返す。
  • __send__ : メソッドを呼び出す。
  • class : オブジェクトのクラスを返す。
  • clone : オブジェクトのコピーを作成する。
  • define_singleton_method : 特異メソッドを定義する。Ruby 1.9
  • display : オブジェクトを文字列として出力する。
  • dup : オブジェクトのコピーを作成する。
  • eql? : ハッシュのキーとして同じか調べる。
  • equal? : 同じオブジェクトか調べる。
  • enum_for : =Enumerator=オブジェクトの作成。Ruby 1.8.7
  • extend : モジュールのメソッドを取り込む。
  • freeze : オブジェクトを凍結する。
  • frozen? : オブジェクトの凍結状態を調べる。
  • hash : ハッシュ値を返す。
  • id : オブジェクトIDを返す。+Ruby 1.9+
  • inspect : 読みやすい文字列に変換。
  • instance_eval : インスタンスの元でコードを実行。
  • instance_exec : インスタンスの元でコードを実行。Ruby 1.8.7
  • instance_of? : クラスに属しているか調べる。
  • instance_variable_defined? : インスタンス変数があるか調べる。
  • instance_variable_get : インスタンス変数の値を得る。
  • instance_variable_set : インスタンス変数の値を変える。
  • instance_variables : インスタンス変数の名前を配列で返す。
  • is_a? : クラスに属しているか調べる。
  • kind_of? : クラスに属しているか調べる。
  • method : メソッドから=Method=オブジェクトを作成。
  • methods : メソッドの名前を配列で返す。
  • nil? : =nil=かどうか調べる。
  • object_id : オブジェクトIDを返す。
  • private_methods : =private=なメソッドの名前を配列で返す。
  • protected_methods : =protected=なメソッドの名前を配列で返す。
  • public_method : =public=なメソッドから=Method=オブジェクトを作成。Ruby 1.9
  • public_methods : =public=なメソッドの名前を配列で返す。
  • public_send : =public=なメソッドを呼び出す。Ruby 1.9
  • respond_to? : メソッドを呼び出せるか調べる。
  • send : メソッドを呼び出す。
  • singleton_class : 特異クラスを返す。Ruby 1.9.2
  • singleton_methods : 特異メソッドの名前を配列で返す。
  • taint : オブジェクトを汚染する。
  • tainted? : 汚染状態を調べる。
  • tap : ブロックに自身を渡し、自身を返す。Ruby 1.8.7
  • to_a : 配列に変換。+Ruby 1.9+
  • to_enum : =Enumerator=オブジェクトの作成。Ruby 1.8.7
  • to_s : 文字列に変換。
  • trust : 信頼される状態に戻す。Ruby 1.9
  • type : オブジェクトのクラスを返す。+Ruby 1.9+
  • untaint : オブジェクトの汚染を除く。
  • untrust : オブジェクトを信頼されない状態にする。Ruby 1.9
  • untrusted? : 信頼状態を調べる。Ruby 1.9
privateメソッド
  • remove_instance_variable : インスタンス変数の削除。
Rubyから呼び出されるメソッド
  • initialize : オブジェクトを作成(=new=)するとき呼ばれる。
  • initialize_copy : オブジェクトをコピー(=clone=、=dup=)するとき呼ばれる。
  • method_missing : メソッドが見つからないとき呼ばれる。
  • respond_to_missing? : =respond_to?=が=false=のとき呼ばれる。Ruby 1.9.2
  • singleton_method_added : 特異メソッドを定義するとき呼ばれる。
  • singleton_method_removed : 特異メソッドを削除するとき呼ばれる。
  • singleton_method_undefined : 特異メソッドを未定義にするとき呼ばれる。

Module

=Module=クラスは、クラスとモジュールを表すクラスです。=Class=クラスは =Module=のサブクラスで、クラスだけを表します。

クラス・モジュールを定義すると、クラス名・モジュール名は =Class=/=Module=オブジェクトを指す変数(定数)になります。 =Class=/=Module=オブジェクトをレシーバにすれば、=Class=/=Module=クラス の=public=メソッドを呼び出せます。

クラス・モジュール定義の中のように、=self=が=Class=/=Module=オブジェク トである場所では、=Class=/=Module=クラスの=private=メソッドを呼び出せ ます。=attr_accessor=や=include=は=Module=クラスの=private=メソッドで す。

親クラスとモジュール

=Module=クラスの親クラスは=Object=クラスです。

Module < Object < Kernel (< BasicObject)

メソッド一覧

クラスメソッド
  • constants : 現在使える定数名の一覧を返す。
  • nesting : 現在のクラス・モジュールのネスト状態を調べる。
  • new : モジュール定義を使わずにモジュールを作成。
publicなインスタンスメソッド
  • <, <, >, >== : 2つのクラスやモジュールの関係を調べる。
  • <=> : 2つのクラスやモジュールの関係を調べる。
  • == : 同じものか調べる。
  • === : クラスに属しているか調べる。
  • ancestors : 祖先クラスとモジュールの一覧を返す。
  • autoload : 定数に対応するファイルを自動ロードする。
  • autoload? : 定数が自動ロードされるか調べる。
  • class_eval : クラスやモジュールの元でコードを実行。
  • class_exec : クラスやモジュールの元でコードを実行。Ruby 1.8.7
  • class_variable_defined? : クラス変数があるか調べる。
  • class_variables : クラス変数名の一覧を返す。
  • const_defined? : 定数があるか調べる。
  • const_get : 定数の値を得る。
  • const_set : 定数を設定する。
  • constants : 定数名の一覧を返す。
  • freeze : クラスやモジュールを凍結する。
  • include? : モジュールをインクルードしているか調べる。
  • included_modules : インクルードしているモジュールの一覧を返す。
  • instance_method : メソッドから=UnboundMethod=オブジェクトを作成。
  • instance_methods : メソッドの名前を配列で返す。
  • method_defined? : メソッドがあるか調べる。
  • module_eval : クラスやモジュールの元でコードを実行。
  • module_exec : クラスやモジュールの元でコードを実行。Ruby 1.8.7
  • name : クラスやモジュールの名前を返す。
  • private_class_method : クラスメソッドを=private=にする。
  • private_instance_methods : =private=メソッドの名前を配列で返す。
  • private_method_defined? : =private=メソッドがあるか調べる。
  • protected_instance_methods : =protected=メソッドの名前を配列で返す。
  • protected_method_defined? : =protected=メソッドがあるか調べる。
  • public_class_method : クラスメソッドを=public=にする。
  • public_instance_method : =public=メソッドから=UnboundMethod=オブジェクトを作成。Ruby 1.9
  • public_instance_methods : =public=メソッドの名前を配列で返す。
  • public_method_defined? : =public=メソッドがあるか調べる。
  • to_s : クラスやモジュールを表す文字列を返す。

以下のメソッドは、Ruby 1.8では=private=でしたが、Ruby 1.9では=public=になりました。

  • class_variable_get : クラス変数の値を得る。
  • class_variable_set : クラス変数を設定する。
  • remove_class_variable : クラス変数の削除。
privateなインスタンスメソッド
  • alias_method : メソッドに別名を付ける。
  • attr : インスタンス変数のアクセサを定義する。
  • attr_accessor : インスタンス変数のアクセサを定義する。
  • attr_reader : インスタンス変数の読み出し専用アクセサを定義する。
  • attr_writer : インスタンス変数の書き込み専用アクセサを定義する。
  • define_method : メソッドを定義する。
  • include : モジュールをインクルードする。
  • module_function : モジュールのメソッドをモジュール関数にする。
  • private : メソッドを=private=にする。
  • protected : メソッドを=protected=にする。
  • public : メソッドを=public=にする。
  • remove_const : 定数の削除。
  • remove_method : メソッドの削除。
  • undef_method : メソッドを未定義にする。
Rubyから呼び出されるメソッド
  • append_features : インクルードされる前に呼ばれる。
  • const_missing : 存在しない定数を参照したときに呼ばれる。
  • included : インクルードされたあとで呼ばれる。
  • extended : オブジェクトに取り込まれたあとで呼ばれる。
  • extend_object : オブジェクトに取り込まれる前に呼ばれる。
  • method_added : メソッドを定義したときに呼ばれる。
  • method_removed : メソッドを削除したときに呼ばれる。
  • method_undefined : メソッドを未定義にしたときに呼ばれる。

Class

=Class=クラスは、クラスを表すクラスで、=Module=クラスのサブクラスです。

クラスに関する機能のほとんどは、=Module=クラスに実装されていますので、=Module=クラスのほうを先に調べるといいでしょう。=Class=クラスの機能は、「=Module=の機能+インスタンスの作成とクラスの継承」です。

親クラスとモジュール

=Class=クラスの親クラスは=Module=クラスです。

Class < Module < Object < Kernel (< BasicObject)

メソッド一覧

クラスメソッド
  • new : クラス定義を使わずにクラスを作成。

    Class.new で無名クラスを作る

インスタンスメソッド
  • allocate : インスタンスの作成。
  • new : インスタンスの作成と初期化。
  • superclass : 親クラスを返す。
Rubyから呼び出されるメソッド
  • inherited : クラスが継承されたときに呼ばれる。

次のメソッドは=Module=クラスで定義されていますが、=Class=クラスでは未定義にされています:
append_features=、=extend_object

このサイトについて 記事の読み方 参考文献

Sponsored by Oiax Inc. / Powered by Ruby on Rails and AmiWiki

ruby入門

文字列 - Ruby入門
文字列オブジェクト
String.new("こんにちは\n")
"こんにちは\n"
"こんにちは\n".class
String.class
'end'
バックスラッシュ記法によるエスケープ
%Q、%qによる文字列の作成
require 'kconv'
print Kconv.toutf8(%Q[こんにちは"佐藤"さん\nお元気ですか]), "\n"
print Kconv.toutf8(%q|こんにちは\nお元気ですか|), "\n"
'end
ヒアドキュメントによる複数行文字列の作成
文字列の中に式を展開
name = "東京"
print("出身は #{name*10} です")
'end'

便利で,よく使います。

文字列 methods

クラス・モジュールの概念

クラス・モジュールの概念 Ruby

ここでクラスとモジュールの概念について学ぶ。

例 Panda モジュール

module Panda

  def visit_to_Japan
    "Mr.TonTon"
  end

  def panda
    @panda = "panda"
  end

end
'end'

Pandの型,Pandが受け継いでいる型は何でしょう?

Panda.class ## Pandaの型
Panda.ancestors ## Panda型の階層
'end'

Panda は Moduleクラスのオブジェクト, Pand = Module.new

module Panda; … ;end は,Panda のトップレベルを開いて, 実行すること。

Panda.new
'end'

Panda.new とかはできない

module Panda
  def panda
    @panda = "panda"
  end
end
'end'
Panda.pand
'end'
Panda.instance_methods(false)

'end'
module Panda; def m ; end 

つまり,Panda にメソッドを定義できる。

module Panda; CONST = 'panda const'; end 
Panda::CONST
CONST

つまり,Panda は名前空間。

定数 Module

Module の class は Class, つまり Module は Classクラスのオブジェクト, つまりクラス

Module.new で Module型のオブジェクト(モジュール)を作る

例 Zooクラス

class Zoo
  def the_zoo
    "there are lots of animal"
  end
end
'end'
## Zooの型
Zoo.class
(Zoo.class).ancestors

## Zoo型の階層
Zoo.ancestors

## クラス?
Zoo.new
'end'

Zoo は Classクラスのオブジェクト, Zoo = Class.new

class Zoo; … ; end は, Zoo のトップレベルを開いて,実行すること

Zoo.new ができる。Zoo.class の ancestors に Class が入っているから

例: UenoZoo を Zoo を継承して作る

class UenoZoo < Zoo    # Zooクラスの継承
  include Panda        # Pandaモジュールを mix-in
  def monkey
    @monkey = "monkey"
  end
  def elephant
    @elephant = "elephant"
  end
  def lion
    @lion = "lion"
  end
  def self.name        # UenoZooクラスの特異メソッド
    "Ueno Zoo"
  end
end
(UenoZoo.class).ancestors
UenoZoo.ancestors
UenoZoo.new
'end'

説明

mix-in

モジュールをクラスに取り込む事をmix-inといい、ソフトクリームの上に 載せるトッピングがその名の由来。

継承

Rubyのクラスは継承ができ、親のクラスのインスタンスメソッドを子が受け継ぐ。 1つのクラスに二つ以上のクラスは継承ができなく、これを単純継承という。

継承とMix-in

上記のコードはUenoZooクラスはZooクラスのメソッドを継承している。またUenoZooク ラスはPandaモジュールをmixinしている。

Zooクラスで定義されているインスタンスメソッドはUenoZooクラスで使えて、Pandaモ ジュールをインクルードすることによって、Zooクラスでインスタンスメソッドとして 使う事ができる。

extend

モジュールはクラスの使い方にバリエーションを与える。

もしModuleをクラスメソッドとして定義したい場合は extend を使用する 事によって使う事ができる。

class UenoZoo
  extend Panda
end
(UenoZoo.class).ancestors
UenoZoo.ancestors
UenoZoo.singleton_methods
UenoZoo.singleton_class
UenoZoo.new
'end'
UenoZoo.visit_to_Japan
UenoZoo.name
UenoZoo.panda
'end'

また prepend を使えば継承関係を一番手前にしてモジュールにあるメソッドにsuperを 使ってオーバーライド(メソッド上書き)できるようになる、Railsのコントローラーで 使われるbefore actionのような機能を実装できる。 super メソッドは継承されているクラスのメソッド、もしくはモジュールでmixinされ たメソッドで同名のメソッドを呼ぶ事ができるメソッド。

module Panda

def visit_to_Japan super + " and " + "Mr.TonTon" end

def panda @panda = "panda" end end

class UenoZoo < Zoo prepend Panda def monkey @monkey = "monkey" end

def elephant @elephant = "elephant" end

def lion @lion = "lion" end

def self.name "Ueno Zoo" end

end

> UenoZoo.ancestors

=> [Panda, UenoZoo, Zoo, Object, Kernel, BasicObject]

UenoZoo.new.visit_to_Japan

=> "Mr.RanRan and Mr.TonTon"

ちなみにクラスにはinitializeメソッドという便利なメソッドが定義されている。 このメソッドはオブジェクトが作成された時に呼ばれるメソッドである。

例えば、上のコードでmonkeyメソッドとelephantメソッドとlionメソッドはインスタン ス変数を定義してメソッドに格納しているが下記のメソッドのようにすれば短くなる。

class UenoZoo

 def initialize(monkey="monkey", elephant="elephant", lion="lion")
   @monkey = monkey
   @elephant = elephant
   @lion = lion
 end

end

UenoZoo.new.instance_variables

=> [:@monkey, :@elephant, :@lion]

このままだとメソッドで変数を呼び出せないので, attr_readerを使う。

class UenoZoo
 attr_reader :monkey, :elephant, :lion  

 def initialize(monkey="monkey", elephant="elephant", lion="lion")
    @monkey = monkey
    @elephant = elephant
    @lion = lion
 end

end

UenoZoo.new.monkey

=> "monkey"
Ueno.new.monkey = "pokey"
=>  undefined method `monkey=' for #<UenoZoo:0x007fa782157008> (NoMethodError)

ただこのメソッドは格納したインスタンス変数を呼び出す機能しかないので、 書き込み機能も加えるためにattr_accessorを使う。書き込みのみの場合は attr_writerを使う。

class UenoZoo
 attr_accessor :monkey, :elephant, :lion  

 def initialize(monkey="monkey", elephant="elephant", lion="lion")
    @monkey = monkey
    @elephant = elephant
    @lion = lion
 end

end

UenoZoo.new.monkey

=> "monkey"
Ueno.new.monkey = "pokey"

=> "pokey"

モジュールの使い方

2種類ある

  • メソッドの格納庫として使う
  • 名前空間として使う
名前空間としての使い方

同じクラスを定義して、既存のメソッドとは知らずに新たに定義し直して、将来 的なバグに繋がる可能性になる。

またクラス名とモジュール名は定数で定義されていて、 module名で定義された定数はclass名で定義できない。 その場合は名前空間として使う。下記のコードを参照してほしい。

class Cat
  def tuna
    "delicious"
  end
end

module Zoo

  class Cat  

    def tuna
      "delicious"
    end
  end

end

> Zoo::Cat.new.tuna
=> "delicious"
> Cat.new.tuna
=> "delicious"

CatクラスとZoo::Catクラスは別々のオブジェクトになる。module名と class名は定数だが定数の中から定数を呼ぶ場合はコロンを二個つけて:: で呼び出す。

まとめ

クラスはインスタンス化能力をもちメソッドを定義できる、モジュールは インスタンス化能力を持たないがメソッドを格納できる。モジュールの利 用法はメソッドを格納するか名前空間として利用する。

クラスにモジュールを取り込むことをmixinといってincludeを使う。

またクラスメソッドとして取り込む場合はextend、継承関係に着目して取 り込む場合はprepend。attr属性(attr_accessor, attr_writer, attr_reader)を使えば、そのクラスに属性を与えられる。initializeメソッ ドを使えば、オブジェクトが生成された時に値を格納したりする事ができ る。

モジュールの先祖

module GiantPanda
end
'end'
module GiantPanda
  include Panda
end
'end'
(GiantPanda.class).ancestors
GiantPanda.ancestors
'end'

meta

クラス

  • インスタンス化能力を持つ。
  • インスタンスメソッドを格納できる。
  • クラスもオブジェクトである。
  • クラスメソッドを格納できる。

モジュール

  • インスタンス化能力は持たない
  • インスタンスメソッドを格納できる
  • モジュールもオブジェクトである。
  • クラスメソッドを格納できる

Class と Module

Class.class
Class.ancestors
C = Class.new
C.class
C.ancestors
c = C.new
c.class
c.ancestors
'end'

定数 Class はクラス(クラス型のオブジェクト)である。

  • C = Class.new は,クラス(クラス型のオブジェクト)を生成する
    [Class, Module, Object, Kernel, BasicObject] 
    
  • C.new は,オブジェクトを生成する
  • Class と C では new の振る舞いは異なる

定数 Module はクラスでありクラス型のオブジェクトである。

  • Module = Class.new(Object)

あるオブジェクト obj が クラス型であるとは, (obj.class).ancestors に Class が含まれること

クラス - モジュール

  • インスタンス化能力
(Class.new).class
(Module.new).class

(Class.new).new
(Module.new).new

(Class.new).ancestors - (Module.new).ancestors
(Class.new).ancestors
(Module.new).ancestors

(Class).ancestors - (Module).ancestors

'end'

メタプログラミング

2016.01.25 オブジェクトモデル

class定義
what_is_self_in_class_def =
 class MyClass
   CONSTANT = 'MyClassの定数'
   self
 end
p what_is_self_in_class_def
'end'
irb(main):002:0* irb(main):003:1> irb(main):004:1> irb(main):005:1> => MyClass
MyClass
=> MyClass

class MyClass は,

  • =Class=型のオブジェクトを生成し,
  • 定数 MyClass にその値をセットし,
  • self を MyClass オブジェクトにし,
  • self のトップレベルで,
  • end までの ruby 式を評価し,
  • 最後の式の値を返す。
class MyClass
  p CONSTANT
  KONSTANT = 'MyClassの別の定数'
end
p CONSTANT
p MyClass::CONSTANT
p MyClass::KONSTANT
MyClass.constants

'end'
irb(main):012:1> irb(main):013:1> "MyClassの定数"
=> "MyClassの別の定数"
NameError: uninitialized constant CONSTANT
	from (irb):14
	from /home/staff/suzuki/.rbenv/versions/2.0.0-dev/bin/irb:11:in `<main>'
"MyClassの定数"
=> "MyClassの定数"
"MyClassの別の定数"
=> "MyClassの別の定数"
=> [:CONSTANT, :KONSTANT]
  • class MyClass で,=MyClass= (クラス)オブジェクトのトップレベルに入 る
  • ruby のクラスは変更に対し,開かれている (オープン・クラス)
  • ▼定数=CONSTANT= はMyClass の名前空間に定義されている
object のクラス階層
obj= MyClass.new
obj.class
(obj.class).ancestors
'end'
=> #<MyClass:0x007fd4425309d0>
=> MyClass
=> [MyClass, Object, Kernel, BasicObject]

objの型

クラスのクラス階層
MyClass.class
(MyClass.class).ancestors
'end'
=> Class
=> [Class, Module, Object, Kernel, BasicObject]

MyClassのオブジェクトとしての型階層

メタクラスのクラス階層
MyClass.singleton_class
(MyClass.singleton_class).ancestors
'end'
=> #<Class:MyClass>
=> [#<Class:MyClass>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

MyClassのオブジェクトとしての型階層

特異クラスと特異メソッド
特異メソッド

あるオブジェクトにだけ実行できるメソッドを定義できる:

obj1 = Object.new
obj2 = Object.new
def obj1.m
  "obj's singleton method"
end

obj1.m
obj2.m

obj1.methods.include?(:m)
obj2.methods.include?(:m)

'end'
=> #<Object:0x007f5711dd60e8>
=> #<Object:0x007f5711daf420>
irb(main):004:1> irb(main):005:1> => :m
irb(main):007:0* => "obj's singleton method"
NoMethodError: undefined method `m' for #<Object:0x007f5711daf420>
	from (irb):8
	from /home/staff/suzuki/.rbenv/versions/2.0.0-dev/bin/irb:11:in `<main>'
irb(main):010:0* => true
=> false
m は何処にあるか?
  • obj1とobj2 の class は,Object.
  • class はリンク。
  • obj1 から Object へのリンクの途中に在る
obj1.class
obj1.singleton_class
(obj1.singleton_class).class
(obj1.singleton_class).instance_methods(false)
'end'
=> Object
=> #<Class:#<Object:0x007f5711dd60e8>>
=> Class
=> [:m]

m の居場所は,#<Class:#<Object:0x007f5711dd60e8>> 特異クラス

'end'
MyClass.ancestors.each do |k|
  if k.singleton_class
    print k, ": ", (k.singleton_class).instace_methods, "\n"

'end'
test class hier
def find_instance_method(klass, method)
  prev = nil
  klass.ancestors.each do |k|
    break unless  k.instance_methods.include?(method)
    prev = k
  end
  return prev
end

def find_singleton_method(klass, method)
  prev = nil
  klass.ancestors.each do |k|
    break unless  k.instance_methods.include?(method)
    prev = k
  end
  return prev
end


find_instance_method(MyClass,:constants)
find_singleton_method(MyClass,:constants)
find_instance_method(Kernel,:constants)
find_singleton_method(Kernel,:constants)
find_instance_method(Module,:constants)
find_singleton_method(Module,:constants)
'end'

2016.02.01 method

method_missing
  • メソッド が class 階層中にない時,
  • missing_method が呼ばれる
  • class 階層中に missing_method がない時,
  • エラーになる
動的methodの仕組み
  • 動的定義 define_method (:method_id) block
  • 動的呼び出し send("method", *args)
method_missing(method, *args)の利用
  • 動的に未定義のメソッドと引数が取得できる
  • 他のメソッドへ委譲したり (動的proxy)
  • メソッドを on-demand で定義できたり (ghost method) openstruct
最終形

様々なComputer の様々な付属品を扱う多種のデータベースへのアクセス を簡単にする:

2016.02.09 ブロック

この章で理解すべきこと

  • スコープ
  • クロージャ
  • クロージャによるスコープの操作
  • 呼び出し可能オブジェクトへの変換
ブロックの基本
ブロックの作成
  • do … end が block
  • メソッド呼び出しの時のみ
ブロックが与えられているか?
  • block_given? で調べられる
ブロックの呼び出し
  • 呼ばれたメソッド側で yield により呼び出せる
  • しかし,block は,block が作られた*環境*で実行される
クロージャ
コードの実行
  • ブロックはコード
  • self が実行の主体 (場)
    • self は 環境 を持つ

      環境は,スコープ上の変数とその値のペア(束縛)の集まり

      • 局所変数 (一方向) のスコープ
        • block の入れ子構造 (nesting) のスコープ
      • インスタンス変数 (一通り) のスコープ
      • クラス変数 (一通り) のスコープ
        • class の継承方向のスコープ
      • 定数 (2方向)のスコープ
        • module の入れ子構造 (nesting) のスコープ
        • class の継承方向のスコープ
  • クロージャ = block + self (環境)
  • ブロックが生まれるとき,自身が生まれた環境を閉じ込めた ((クロージャ)) となる
  • クロージャが実行される時は,その環境で実行される
    • 定数はselfのクラスから辿れる
    • インスタンス変数、特異メソッドには self から辿れる
スコープのまとめ
  • Rubyのスコープには束縛がある
  • スコープは class, module, def のスコープゲートで区切られ。
  • スコープゲートは,Class.new(), Module.new(), Moduel#define_method() で置き換え,それらに束縛を閉じこめたクロージャを与える。
  • クロージャにより,束縛の共有も可能となる

(s) この辺りは,SICP の lambda による実現の方が,シンプルでわかりや すい。

instance_eval()
obj.instance_eval block
  • オブジェクトobjのコンテキストで,
  • ブロックblockを評価する
(no term)
obj を self にして, クロージャを実行するということ
カプセル化の破壊

instance_eval を使うとカプセル化が破壊できる

呼び出し可能オブジェクト

ブロックの使用

  • コードの保管
  • yieldを使ったブロックの呼び出し

コードを保管できる状況

  • (({Proc})) の中.ブロックがオブジェクトになる
  • (({lambda})) の中.
  • メソッドの中
Proc 対 lambda

ブロックを Proc にする方法

  • Proc.new()
  • lambda { } 
  • &修飾
  • Proc, lambda, return

    Proc のリターンは,Proc の定義された環境から return (直前の環境へ戻る)

  • Proc, lambda, arity

    引数の確認方法の違い

    • lambda は厳格 (メソッドに準拠)
    • Proc は柔軟
  • Proc対lambda: 判定

    lambda がメソッドに似ている [/]

    1. [ ] 項数に厳しく
    2. [ ] return で自身を終える

    Proc はコンテキスト中のコードの一部, lambda は独立したコード

メソッド再び
  • Object#method() でメソッドを,Method オブジェクトとして取得可
  • Method オブジェクトは,Method#call() で呼び出し可能
  • Method オブジェクトは,属するオブジェクトのスコープで実行される
  • Method#unbind() は属するオブジェクトを引き離し,UnboundMethod オブジェクトが返る
  • UnboundMethodはMethod#bind()でメソッドに戻せる クラスが異なると,例外が発生
呼び出し可能オブジェクトのまとめ

呼び出し可能オブジェクト [/]

  1. [ ] ブロック
    • オブジェクトではないが,呼び出し可能
    • 定義されたスコープで評価される
  2. [ ] Proc
    • 定義されたスコープで評価される
    • 定義されたコンテキストの制御にしたがう
  3. [ ] lambda
    • Proc クラスのオブジェクト,クロージャ
    • 定義されたスコープで評価される
    • 独立した method のように振る舞う
  4. [ ] メソッド
    • オブジェクトにつながれ,
    • オブジェクトのスコープで評価される

memo コード

class 階層

1.class
(1.class).superclass
(1.class).superclass.superclass
(1.class).superclass.superclass.superclass
(1.class).superclass.superclass.superclass.superclass
(1.class).superclass.superclass.superclass.superclass.superclass
'end'
1.methods
(Object.new).methods
(BasicObject.new).methods
'end'
  • method メソッドはBasicObjectのインスタンス・メソッドではない
  • method メソッドはObjectのインスタンス・メソッド
(1.class).ancestors
(Object.instance_methods).include?(:methods)
(Kernel.instance_methods).include?(:methods)
(BasicObject.instance_methods).include?(:methods)
'end'
(1.class)
((1.class).class)
((1.class).class).superclass
((1.class).class).superclass.superclass
((1.class).class).superclass.superclass.superclass
((1.class).class).superclass.superclass.superclass.superclass
:end
Class
(Class.class)
(Class.class).superclass
(Class.class).superclass.superclass
(Class.class).superclass.superclass.superclass
(Class.class).superclass.superclass.superclass.superclass
:end

Class Class Module Object BasicObject nil

Module
(Module.class)
(Module.class).superclass
(Module.class).superclass.superclass
(Module.class).superclass.superclass.superclass
(Module.class).superclass.superclass.superclass.superclass
:end
def class_hier(obj)
  if obj.superclass
    print " => ", obj.superclass
    class_hier(obj.superclass)
  end
end
class_hier(Class)
class_hier(Integer)

'end'
Class.singleton_class
(Class.singleton_class).superclass
(Class.singleton_class).superclass.superclass
(Class.singleton_class).superclass.superclass.superclass
(Class.singleton_class).superclass.superclass.superclass.superclass
:end
(Class.singleton_class).singleton_class
(Class.singleton_class).singleton_class.singleton_class
:end
(Class.singleton_class).singleton_class
(Class.singleton_class).singleton_class.superclass
(Class.singleton_class).singleton_class.superclass.superclass
(Class.singleton_class).singleton_class.superclass.superclass.superclass
:end
Class.ancestors
Module.ancestors
(Class.new).ancestors
(Module.new).ancestors
'end'
Class.singleton_class
(Class.singleton_class).ancestors
'end'

self

self
self.class

class H
  $selfH = self
  def m
    $selfm = self
    puts "m is called."
    'm'
  end
end
print "$selfH = ", $selfH
h = H.new
h.m
print "$selfm = ", $selfm
:end

methods

1.methods - (Numeric.new).methods
Integer(1001)
String("abc")
Array(2)
Array(1..100)
Kernel.Array(2)
self.Array(2)


'end'
Kernel.methods.include?(:Array)
Kernel.methods.include?(:Integer)
'end'

sqlite3

sqlite3-ruby

gem

gem install sqlite3

sqlite

SQLite (wikipedia) 手軽なローカル・ファイル型の軽量データベース

setup

rm -f database.db

ruby

# coding: utf-8

require 'rubygems'
require 'sqlite3'

db = SQLite3::Database.new("database.db")

sql = <<EOT
create table Person (
 name varchar(10),
 age integer,
 post varchar(200)
);
EOT

db.execute(sql)
puts "New file is created."

db.transaction do
  sql = "insert into Person values (?, ?, ?)"
  db.execute(sql, 'hoge', 26, 'hage')
  db.execute(sql, 'hage', 62, 'hoge')
end

db.execute('select * from Person') do |row|
  puts row.join("\t")
end
db.close

'end'

firefox sqlite database handling

プロファイル | Firefox ヘルプ

firefox が使っている sqlite データベースをコピーして, テーブルのレコードを出力する。

cp -p ~/.mozilla/firefox/5rot7npz.default/content-prefs.sqlite .
# coding: utf-8

require 'rubygems'
require 'sqlite3'
require 'pp'

file = "content-prefs.sqlite"

db = SQLite3::Database.open(file)

tables = db.execute("select tbl_name FROM sqlite_master WHERE type == 'table'")

tables.flatten.each do |tbl|
  puts "== ",  tbl
  db.results_as_hash = true
  db.execute("select * from #{tbl}") do |row|
    # puts row.join("\t")
    pp row
  end
end

p tables

db.close

'end'

https://www.dropbox.com/s/kf035hpu5r7dkqo/._%20(Masayuki%20Suzuki%20%E3%81%AE%E7%AB%B6%E5%90%88%E3%82%B3%E3%83%94%E3%83%BC%202016-01-07%20(3))._Icon%0D?dl=0

firefox sqlite database handling 2

ls -l ~/.mozilla/firefox/*/*sqlite
  • *.sqlite3 をみんな出力してみましょう。
  • lock されて開けないのもあるので,エラー処理をしましょう。
  • 出力には,=pp= を使いましょう。
  • 各dbの master record を読んでみましょう。
require 'rubygems'
require 'sqlite3'
require 'pp'

dir = '/users/home/masayuki/.mozilla/firefox/1dtrhim2.default-1450953083451/'
Dir.chdir(dir) do
  Dir.glob("*.sqlite").each do |db|
    puts "** #{db}"
    begin
      db = SQLite3::Database.open(db)
      results = db.execute("select * from sqlite_master")
      pp results
    rescue  => e
      puts e
    end
  end
end
ruby babel/sqlite3-master.rb

# coding: utf-8

require 'rubygems'
require 'sqlite3'

file = "content-prefs.sqlite"

db = SQLite3::Database.open(file)

tables = db.execute("select tbl_name FROM sqlite_master WHERE type == 'table'")

tables.flatten.each do |tbl|
  puts "== ",  tbl
  db.execute("select * from #{tbl}") do |row|
    puts row.join("\t")
  end
end

p tables

db.close

'end'

https://www.dropbox.com/s/kf035hpu5r7dkqo/._%20(Masayuki%20Suzuki%20%E3%81%AE%E7%AB%B6%E5%90%88%E3%82%B3%E3%83%94%E3%83%BC%202016-01-07%20(3))._Icon%0D?dl=0

sinatra-org

references

what

./notes にある .org 文書を表示する Webサービスを作成する。

how

  • rubygems の sinatra,org-convergeを用いる
  • readme.org に全てを記述する

directory

.
+-- readme.org 
|
+-- org +-- run.org
|
+-- src +-- app.rb
|       +-- Gemfile
|       +-- config.ru
|
+-- notes@

sinatraのための設定

bundler

bundler を gem install

gem install bundler

gemfile

必要な gem を記述

# src/Gemfile
gem 'sinatra'
gem 'org-converge'

config.ru

sinatraアプリケーションを起動するための設定

# src/config.ru
require './app.rb'
run Sinatra::Application

service

application

sinatra のDSLで,Webサービスを記述:

# src/app.rb
require 'sinatra'

get '/' do
  'OK'
end

get '/org' do
  Dir.glob('../notes/*.org').join("\n")
end

get '/org/*.org' do |doc|
  `(cd ../notes; org2html #{doc}.org)`
  `cat ../notes/#{doc}.html`
end

ここでは,org->HTML変換には,~suzuki/COMM/bin/org2html コマンドを利用しています。

代わりに,((% pandoc -f html -t org %))コマンドを使ってもいいですし, rubygem/org-ruby を使ってもいいかもしれません。

起動

この文書を,emacs org-mode で C-c C-v C-t して,書き出し, 下記コマンドでサーバを立ち上げる。

org-converge org/run.org
確認

ブラウザで,下記URLにアクセスする:

  • 127.0.0.1:9292/,
  • 127.0.0.1:9292/org,
  • 127.0.0.1:9292/org/ORG文書
起動用 org 文書 (org/run.org)
#+title: running the application
#+include "org/app.org"

** run it

#+name: server
#+BEGIN_SRC sh :dir src

bundle install
bundle exec rackup

#+END_SRC

** access

#+name: getit
#+BEGIN_SRC sh :wait 1

  curl 127.0.0.1:9292/ 2>/dev/null
  sleep 2
  curl 127.0.0.1:9292/org  2>/dev/null
  sleep 2
  curl 127.0.0.1:9292/org/ruby-note.org  2>/dev/null
  sleep 2

#+END_SRC

著者: suzuki@cis.iwate-u.ac.jp

Created: 2016-02-15 月 08:14

Emacs 24.5.1 (Org mode 8.2.10)

Validate