ふつうのRubyプログラマに贈る Rubyプログラミング講座 13-B-3 青木峰郎 日本Rubyの会 自己紹介 青木峰郎 (日本Rubyの会) Rubyがらみで やってること Ruby関係のおしごと • • • • • • • 書籍『Rubyist Magazine出張版』 MYCOM 書籍『Rubyレシピブック第二版』 SBCr 書籍『Rubyソースコード完全解説』 Impress 書籍『Rubyを256倍使う本 無道編』 ASCII リファレンスマニュアル刷新計画 隊長 標準ライブラリいくつか (net/http, fileutils, ...) それ以外のアプリ各種 (BitChannel,Racc, ..) まとめ: いろいろやってます。 今日の内容 agenda 1/2 第一部:Rubyプログラミングのツボ 1. protected 2. pとpp 3. unlessとuntil 4. クラスと名前空間 5. ファイル名とクラス名 6. 大クラス主義 agenda 2/2 第二部:Rubyプログラミングの、押しすぎるとヤ バいツボのうちのいくつか 1. Visitorパターンめどい 2. 1.8と1.9でメソッド違いすぎwww 1.protected Q: protected 使ってますか? protectedは通常 必要ありません! protectedの 95%は間違い Railsも 使いかたを 間違ってた Rubyのprotectedは Java/C++のprotected とは違う Javaの可視性 可視性 意味 public 制限なくアクセスできる protected サブクラスと、パッケージ内のクラ スからアクセスできる private 同じクラスからのみアクセスできる Rubyの可視性 可視性 意味 public 制限なくアクセスできる protected そのクラスとサブクラスで、オブ ジェクトの外からアクセスできる private 同じオブジェクト内からアクセスで きる(クラスは関係ない) Java/C++はクラス単位 Rubyはオブジェクト単位 違いの出る場面 Rubyではprivateメソッドも継承する class A def m() puts “OK” end private :m end class B < A def call_m m end フツーに呼べる end protectedの使いどころ Rubyでprotectedが活用できる場面 class SomeObject attr_reader :prop protected :prop 外から (レシーバをつけた 形式で)呼べる def ==(other) @prop == other.prop end end ぶっちゃけ protectedなんて 使わない 結論: Rubyでは publicとprivateだけ 使ってればOK 2. pとpp Q: pメソッド 使ってますか? p Object.new printfデバッグ (pデバッグ?) に便利 Q: ppメソッド 使ってますか? require 'pp' pp Object.new 表示が見やすい p C:\>ruby -e "p File.stat('.')" #<File::Stat dev=0x2, ino=0, mode=040755, nlink=1, uid=0, gid=0, rdev=0x2, size=0, blksize=nil, blocks=nil, atime=Wed Feb 13 06:55:59 +0900 2008, mtime=Sun Feb 13 21:03:44 +0900 2008, ctime=Thu Jun 29 16:52:04 +0900 2006> C:\>ruby -rpp -e "pp File.stat('.')" #<File::Stat dev=0x2, ino=0, mode=040755 (directory rwxr-xr-x), nlink=1, uid=0, gid=0, rdev=0x2 (0, 0), size=0, blksize=nil, blocks=nil, atime=Wed Feb 13 06:55:59 +0900 2008 (1202853359), mtime=Sun Feb 03 21:03:44 +0900 2008 (1202040224), ctime=Thu Jun 29 16:52:04 +0900 2006 (1151567524)> pのしくみ def p(obj) puts obj.inspect end 出力先はstdout 誰もがstderrに 出力されることを期待し そして裏切られる inspectを 自分で定義すれば 表示を変更できる to_sとinspectの違い メソッド 用途 to_s オブジェクトを文字列に変換するとき。 inspect オブジェクトをデバッグのために表示すると き。 inspectは デバッグ用途にだけ 使おう! 3. unlessと until Q: unless 使ってますか? Q: until 使ってますか? unless = if not until = while not 制御構造は えり好みせず使おう ただしredoを除く 多様な意図を 表現するには 多様な制御構造を 使ったほうがいい 「if/whileで 書けるから いらない」? あらゆる制御構造は gotoで実現できます プリミティブ症候群に 陥らないこと unlessの使いどころ 前提条件の チェックに使うと いいかんじ def m(idx) raise IndexError, "out of range" \ unless idx >= 0 unless を使うときは、 「引数が満たすべき条件 (前提条件)」 を書けばよい untilの使いどころ 終了条件をはっきり 書きたいときに 使う until s.eos? tok = s.scan(/\w+/) 「スキャン中の文字列が 尽きるまで(EOSになるまで) ~~する」 4. クラスと 名前空間 モジュールの ネスト、してますか? module Cflat class Node .... end class IfNode < Node .... end class WhileNode < Node .... end end モジュール・クラスは クラスの名前空間を 兼ねている module Cflat class Node .... end end module MyCompiler class Node .... end end 別のモジュールに ネストしていれば クラス名が 同じでも大丈夫 Javaで言うパッケージ C++で言うnamespace module Cflat class Node .... end end p Cflat::Node.new ネスト構造の指針 第1レベル: アプリケーション名と 同名のモジュール 例: Cflat 第2レベル: クラス名 例: Compiler, Parser, Node, ... 以上 ネストは 深くしすぎないこと (せいぜい3段) 深くしすぎると… module Cflat module Frontend module AST class Node .... end end end end 単純に、 見た目が よろしくない! 5. ファイル名と クラス名 Rubyでの ファイル名 (ライブラリ名) の決めかた ファイル中で 最も代表的な クラスの名前を 元に決める class Node .... class IfNode < Node .... class WhileNode < Node .... 代表的なクラスは Nodeクラス ファイル名は クラス名.downcase Nodeクラス downcase node.rb クラスが ネストしている場合 module Cflat class Node .... class IfNode < Node .... class WhileNode < Node .... クラス階層を ディレクトリ階層に 反映させる Cflat::Nodeクラス downcase cflat/node.rb そのほかの指針 1. 関連するクラスは すべて1つの ファイルにまとめる Javaじゃ ないんだから 2. ネストは あまり深くしない(再) Javaじゃ ないので 6. 大クラス主義 大クラス主義… いろいろな仕事を 1つのクラスに行わせる 設計ポリシーのこと 例1 RubyのArrayは 配列とリストと スタックとキューを 兼ねている # 配列として使う array = [] array[0] = 3 array[1] = 6 p array[0] # => 3 p array[1] # => 6 # スタックとして使う stack = [] stack.push 1 stack.push 2 p stack.pop # => 2 p stack.pop # => 1 # キューとして使う queue = [] queue.push 1 queue.push 2 p queue.shift # => 1 p queue.shift # => 2 例2 RubyのStringは StringBuffer/ StringBuilderを 兼ねている # 文字列をバッファ的に使う buf = '' buf << "line 1\n" buf << "another line\n" buf << "extra line\n" puts buf それで いいのか? ぜんぜんOK だって うまくいってるじゃん マイクロカーネル VS モノリシックカーネル 論争に類似? コンポーネント (クラス)が増えると コンポーネント間の 複雑性が増す 結局はバランス 第一部 完 第二部 agenda 2/2(真) 第二部:Rubyプログラミングの、押しすぎるとヤ バいツボのうちのいくつか 1. sendを使ってクラス分岐を書く 2. リフレクションを使ってRubyのバージョン間 の差を埋める 1. sendを使って クラス分岐を書く 問題:たくさんの クラスがあって、 クラスごとに 処理を変えたい クラスごとに 処理を変えると言えば とりあえず多態 (polymorphism) class 鳥 def 鳴け() puts "ぽー" end end class 牛 def 鳴け() puts "もー" end end class 豚 def 鳴け() puts "ぶー" end end def 鳴かせる(animal) animal.鳴け end 鳴かせる(鳥.new) 鳴かせる(牛.new) 1つの処理が 複数クラスに 細切れにされてしまう 1つの処理は 1つのクラスに まとめたい! # こんな感じにまとめたい class def def def def end 動物を鳴かせる 鳴かせる(animal) ここのコードが問題 end 鳥を鳴かす() puts "ぽー" end 牛を鳴かす() puts "もー" end 豚を鳴かす() puts "ぶー" end 動物を鳴かせる.new.鳴かせる(鳥.new) 動物を鳴かせる.new.鳴かせる(牛.new) Visitorパターン? Visitorパターンは 実装がめんどくさい そこで send Object#sendは 「メソッドを呼ぶ メソッド」 obj.send(メソッド名, 本来の引数) p "str".size send化 p "str".send(:size) sendを使って クラス分岐が書ける class 動物を鳴かせる def 鳴かせる(animal) send "#{animal.class}を鳴かす" end def 鳥を鳴かす() puts "ぽー" end def 牛を鳴かす() puts "もー" end def 豚を鳴かす() puts "ぶー" end end 動物を鳴かせる.new.鳴かせる(鳥.new) 動物を鳴かせる.new.鳴かせる(牛.new) 2. Rubyのバージョン 間の差を埋める 1.9.0リリース しばらくは 1.8と1.9の 混在状態になる 対応方針は2つ (1) 1.9は無視する 現実的だが、 現実的すぎて なんか腹立たしい (2) 両方のバージョン で動くプログラム を書く Rubyの恐るべき 非互換性の罠が 待ち受ける 例:sendの場合 sendの もう1つの用途: privateメソッドを呼ぶ # Ruby 1.8の場合 class C def m() puts "OK" end private :m end C.new.m C.new.send(:m) # これはダメ # これなら通る! …ただし、 Ruby 1.8までなら。 Ruby 1.9(の一部)では funcallを使わないと privateメソッドが 呼べない # ありし日のRuby 1.9の場合 class C def m() puts "OK" end private :m end C.new.m C.new.send(:m) C.new.funcall(:m) # これはダメ # これもダメ # これなら通る! まとめ ver. Ruby 1.8 send funcall privateメソッドを呼び 存在しない 出すことができる Ruby 1.9 privateメソッドは呼 び出せない privateメソッドを呼び出 すことができる もうだめだ… そんなあなたに ダイナミック プログラミング 「メソッドがないなら 定義すれば いいじゃない」 unless Object.method_defined?(:funcall) class Object alias send funcall end end ポイント1 if文やunless文の なかにclass文が 書ける while文の中にも class文を書けるけど あんまり意味ない ポイント2 プログラムの実行時に、 (既存の)クラスに メソッドを追加できる オープンクラス (いつでも定義の 追加が可能なクラス) 第二部 完 つづきはウェブで 今日のまとめ agenda 1/2 第一部:Rubyプログラミングのツボ 1. protected 2. pとpp 3. unlessとuntil 4. クラスと名前空間 5. ファイル名とクラス名 6. 大クラス主義 agenda 2/2(真) 第二部:Rubyプログラミングの、押しすぎるとヤ バいツボのうちのいくつか 1. sendを使ってクラス分岐を書く 2. リフレクションを使ってRubyのバージョン間 の差を埋める ご静聴 ありがとう ございました Q?
© Copyright 2024 ExpyDoc