フォーチュンサモナーズ
«前の日記(2007-04-04) 最新 次の日記(2007-04-06)» 編集

Don'tStopMusic

2003|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|12|
2006|01|02|03|04|05|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|08|09|10|

カテゴリ別 2003年 | 2004年 | 2005年 | 2006年 | 2007年 | 2008年

知り合いサイト: よんだもの / 暴想 / Linuxでやる夫 / 新宿Vipper / 僕だけが幸せになればいいのに。


2007-04-05

_ [Ruby] 人力検索はてな - Rubyでメソッド名とローカル変数名を見分ける易いコーディング規約について教えてください。 このエントリーを含むブックマーク

Rubyでメソッド名とローカル変数名を見分ける易いコーディング規約について教えてください。

Rubyコーディング規約
http://shugo.net/ruby-codeconv/codeconv.html

によると、ローカル変数もメソッドも小文字とアンダースコア(_)で書くことになっていますが、これだとパッと見で混乱してしまうことが多いので。

大抵の場合は見分けがつくのでそんなに気にすることではないと思います。どちらか分からないことで混乱するようなクラスやメソッドはリファクタリングしましょう。

メソッドだとすぐわかるケース

  • 引数を渡している : puts "hello, world"
  • ブロックがある : open{|f| ... }
  • ! ? が末尾にある : visible? delete!
  • 組み込み関数 : そのうち覚えます
  • converter メソッド : to_s to_a

レシーバも引数もない場合は見た目上変数と区別がつきづらい可能性があります。ただし、

  • 動詞なら、それはまずメソッド
  • 組み込みライブラリでメソッドなら、それはまずメソッド
  • 代入やメソッド呼び出しを伴わず単独で書かれているならメソッド
  • 単純代入の右辺ならメソッド

といえます。2、3、4 番目の補足説明をします。

組み込みライブラリでメソッドなら、それはまずメソッド

新しいメソッドの名前にはよく使われているメソッドの名前を選ぶからです。読み書きなら read/write gets/puts、イテレートは each など。メソッドの働きを類推しやすくするためや duck typing のためです。

代入やメソッド呼び出しを伴わず単独で書かれているならメソッド

filename = "/etc/hosts"
dir = File.dirname(filename)
filename

このようなコードがあった場合、変数 filename が単独で書かれている 3 行目は ruby プログラムとして正しいですが意味がありません。 識別子が単独で書かれている場合は、

def parse
 do_preprocess
 do_parse
 do_postprocess
end

のように処理の一部分を抽出したメソッドである可能性が高いでしょう。

単純代入の右辺ならメソッド

page = fetch

Ruby は変数のコピーをしたりはしないので、上記のような例で右側が変数の場合には単に同じオブジェクトに異なる変数名をつけるだけになります。意味がないのでそのような書き方はしないでしょう。

もうここまでで 90% (適当)は区別がつくのではないかと思います。

さらに

  • public や protected メソッドのレシーバを省略しない : self.foo と必ず self. をつける
  • 引数のないメソッドでも括弧を省略しない : foo()
  • Java のように CamelCase で書く

とすれば完全に区別がつきますが個人的にはこれらの書き方はしません。記述が冗長だったり、慣習とそぐいません。

さて、上の 3 つを採用しない場合に区別がつかないのは

  • setter メソッド
  • getter あるいはプロパティを返すメソッド

です。

setter

class Foo
  attr_accessor :bar
  def foo
    bar = 10
    hoge = 15
  end
end

bar = 10 は self.bar=(10) というメソッド呼び出しに他なりませんが、hoge = 15 は変数への代入です。 クラスが小さければ bar= が setter メソッドだと分かりますが、クラスが大きいと困ることがあるかもしれません。

上のようにアクセサを介して自分のインスタンス変数にアクセスすることを Indirect Variable Access といいます。 インスタンス変数へのアクセスを Direct Variable Access、つまり

class Foo
  attr_accessor :bar
  def foo
    @bar = 10
    hoge = 15
  end
end

と書くようにすればこの曖昧さは解消できますが、Indirect Variable Access が必要なケースもありますので規約化はできないと思います。

getter あるいはプロパティを返すメソッド

これらは引数がなく括弧もつけず動詞でもないメソッドです。Object#object_id、Object#class、Array#size などが該当します。

私の場合変数だったものをこのようなメソッドに置き換えることが良くあります。例えば

class Score
  def initialize
    @scores = []
  end
  def add(score)
    @scores << score
  end
  def print_score
    total = @scores.inject(0){|sum, i| sum += i}
    puts "your score: #{@scores.join(', ')}"
    puts "your total score: #{total}"
  end
end
score = Score.new
score.add(0)
score.add(2)
score.add(1)
score.add(3)
score.print_score
#=> your score: 0, 2, 1, 3
#=> your total score: 6

というクラスがあるとします。で、合計点だけ出力したくなってメソッドを追加します。

class Score
  def initialize
    @scores = []
  end
  def add(score)
    @scores << score
  end
  def print_score
    total = @scores.inject(0){|sum, i| sum += i}
    puts "your score: #{@scores.join(', ')}"
    puts "your total score: #{total}"
  end
  def print_total_score
    total = @scores.inject(0){|sum, i| sum += i}
    puts "total score: #{total}"
  end
end

total を求める部分が重複しています。気になるのでメソッドに括りだします。 このとき名前を get_total とでもすればメソッドだと明らかですが、

  def print_score
    puts "your score: #{@scores.join(', ')}"
    puts "your total score: #{get_total}"
  end
  def print_total_score
    total = get_total
    puts "total score: #{total}"
  end
  def get_total
    @scores.inject(0){|sum, i| sum += i }
  end

のように、リテラルに get_total と埋め込むのはキレイじゃないし、一度 total 変数に代入するのもなんだか無駄な気がします。 どのように書くかといえば、

class Score
  def initialize
    @scores = []
  end
  def add(score)
    @scores << score
  end
  def print_score
    puts "your score: #{@scores.join(', ')}"
    puts "your total score: #{total}"
  end
  def print_total_score
    puts "total score: #{total}"
  end
  def total
    @scores.inject(0){|sum, i| sum += i }
  end
end

としています。total が親クラスで定義されてたりすると変数かメソッドか分かりにくくなりますが、 それを区別しやすくするために get_total のような書き方をするよりもクラス構成やメソッドの長さや名前の付け方を良くするほうが はるかに可読性が向上するんじゃないかなと思います。

本日のツッコミ(全2件) [ツッコミを入れる]
_ kjana (2007-04-06 15:47)

setter の方は実は ruby も変数への代入と区別出来ないので self.foo = bar と書く必要があったりするわけですが。

_ だて (2007-04-07 13:44)

あああ。ほんとですね。昔 self と () を省略せずできるだけ形式的に書こうとしたことがあったのですが、p はどうするとかメソッドに見えないメソッドにも括弧つけるべきかとか、結局統一するのは無理だったので止めました。

[]

最近のコメント:

  1. mpmjrgtmpw (10-03)
  2. ORDER PHENTERMINE (09-16)
  3. fopikolijok (09-14)

RSS
Creative Commons License
This work is licensed under a Creative Commons License
(note: text only. w/o web design, citations, (re)distributed softwares).