Hatena::Grouprubyist

Going My Ruby Way このページをアンテナに追加 RSSフィード

Ruby ロゴ (C) Ruby Association LLC

2011年08月09日(火)

Module#property_*

| 23:12 | Module#property_* - Going My Ruby Way を含むブックマーク はてなブックマーク - Module#property_* - Going My Ruby Way Module#property_* - Going My Ruby Way のブックマークコメント

gmrw-ssh2-server では、Module#property_* として以下を設定しています。

  • property_ro
  • property_rw
  • property_roa
  • property_rwa

gmrw-ssh2-server のソース

  class C
    property_rwa :foo, '10' #=> デフォルト値は文字列で渡す
  end

  c = C.new
  p c.foo    # => 10
  c.foo(20)
  p.c.foo    # => 20

----

違いは以下の通りです。(引数で :foo を指定した場合)

メソッドデフォルト設定値の参照引数による値の設定「=」による値の設定
attr_reader不可foo不可不可
attr_writer不可不可不可foo = 10
attr_accessor不可foo不可foo = 10
property_rofoo不可不可
property_rwfoofoo(10)不可
property_roafoo不可foo = 10
property_rwafoofoo(10)foo = 10

property は property_rwa のエイリアスです。

----

(引数による値の設定ができる) property_rw、property_rwa はブロックを与えて proc を設定することができます。

  class C
    property_rw :foo
  end

  c = C.new
  c.foo do |s|
    s.upcase
  end                 # => ブロックが proc に変換されて @foo に設定される

  c.foo.call('hello') # => "HELLO"

引数とブロックの両方を指定した場合、(現在の仕様では)値が設定されます。(この仕様は変更されるかもしれません)

----

デフォルト値が設定されるのは、定義したアクセサが始めて参照された時です。

  class C
    property_rw :foo, :bar
    attr_writer :bar
  end
  
  c = C.new
  c.bar = 10
  c.bar = 20
  c.foo        # この時デフォルト値(bar)が設定される
  c.bar = 30
  c.bar = 40
  p c.foo      # => 20

引数付きでアクセサを呼びだした時もデフォルト値は設定(評価)されます。

  class C
    property_rw :foo, :bar
    attr_writer :bar
  end
  
  c = C.new
  c.bar = 10
  c.bar = 20
  c.foo(100)   # この時デフォルト値(bar)が設定された後、100 が設定される
  c.bar = 30
  c.bar = 40
  p c.foo      # => 100

foo= を参照した場合 foo には影響しません。

  class C
    property_rw :foo, :bar
    attr_writer :bar
  end
  
  c = C.new
  c.bar = 10
  c.bar = 20
  c.foo = 100 # これは C#foo の呼び出しでない
  c.bar = 30
  c.bar = 40
  p c.foo # => 100 (ただし、既に @foo が設定済みなので、bar は評価しない)

(ただし、引数付きでアクセサを呼びだした時のデフォルト値の評価についての仕様は変更される可能性があります)

mixin

| 22:59 | mixin - Going My Ruby Way を含むブックマーク はてなブックマーク - mixin - Going My Ruby Way mixin - Going My Ruby Way のブックマークコメント

gmrw-ssh2-server では、標準クラスへの mixin は以下のようにしています。

require 'gmrw/extension/extension'

module GMRW::Extension
  mixin Array do
    def to_hash
      Hash[ *flatten(1) ]
    end

    def mapping(*keys)
      keys.empty? ? mapping_by_index : mapping_by_name(*keys)
    end

    def mapping_by_name(*names)
      names.zip(self).to_hash
    end

    def mapping_by_index
      (0...count).zip(self).to_hash
    end
  end
end

GMRW::Extension#.mixin は、引数のクラス(orモジュール)にブロックから動的生成したモジュールを include させます。

クラス(orモジュール)に既に重複するメソッドがある場合は例外(RuntimeError)を発生させます。

----

(標準クラスを拡張するので)重複チェックがしたかったのと、include するためにモジュール(定数や名前)を増やしたくなかったのでこうしました。

include したモジュールは reopen されることはありません。(と、思っているが正しい???)

(2011/08/10 [追記]) 。。。正しくなかったです。reopen するには以下の方法があります。

>> require 'gmrw/extension/array'
=> true
>> Array.ancestors
=> [Array, #<Module:0x0000000223eea0>, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject]
>> M = Array.ancestors[1]
=> M
>> Array.ancestors  # モジュールが定数 M に入れられたので名前付けされた
=> [Array, M, Enumerable, Object, PP::ObjectMixin, Kernel, BasicObject]
>> p M.instance_methods
[:to_hash, :mapping, :mapping_by_name, :mapping_by_index]
=> [:to_hash, :mapping, :mapping_by_name, :mapping_by_index]
>> module M
>>   # undef_method したりとか、いろいろいじくれる
>> end

----

似たメソッドに GMRW::Extension#.compatibility があります。

こちらは、重複するメソッドがある場合は、動的生成したモジュールからそのメソッドを削除します。(オーバーライドしません)

require 'gmrw/extension/extension'

module GMRW::Extension  #:nodoc:
  compatibility Object do
    def presence  #:nodoc:
      present? ? self : nil
    end
  end
end

メソッドがない場合だけ include させたクラス(orモジュール)にメソッド定義が引き継がれます。

FizzBuzz

| 22:49 | FizzBuzz - Going My Ruby Way を含むブックマーク はてなブックマーク - FizzBuzz - Going My Ruby Way FizzBuzz - Going My Ruby Way のブックマークコメント

ans = (1..100).map do |n|
  n % 15 == 0 ? 'FizzBuzz' :
  n %  3 == 0 ? 'Fizz'     :
  n %  5 == 0 ? 'Buzz'     : n
end

剰余「%」を使わない方法。

ans = (1..100).each_slice( 3).map {|a| a[ 2] = 'Fizz'     ; a }.flatten
              .each_slice( 5).map {|a| a[ 4] = 'Buzz'     ; a }.flatten
              .each_slice(15).map {|a| a[14] = 'FizzBuzz' ; a }.flatten[0,100]

---

こんくらいしか思い浮ばない。。。

OptionParser のメモ

| 22:27 | OptionParser のメモ - Going My Ruby Way を含むブックマーク はてなブックマーク - OptionParser のメモ - Going My Ruby Way OptionParser のメモ - Going My Ruby Way のブックマークコメント

先日調べたことを忘れないうちにメモしておきます。

----

OptionParser は以下のような感じで使えます。

#!/usr/bin/env ruby

require 'optparse'
require 'ostruct'
require 'pp'

options = OpenStruct.new

OptionParser.new do |opt|
  opt.on('-p PORT', '--port=PORT','port number') {|v| options.port    = v.to_i }
  opt.on('-d',                    'debug mode')  {|v| options.debug   = v      }
  opt.on(           '--verbose',  'verbose mode'){|v| options.verbose = v      }
  opt.on('-l',      '--[no-]log', 'logging')     {|v| options.logging = v      }
  opt.on('-i [IF]',               'interface')   {|v| options.interface = v    }
  opt.on('-b',      '--[no-]bar[=VAL]')          {|v| options.bar     = v      }

  opt.parse!
end

pp ARGV
pp options

# vim:set ts=2 sw=2 et fenc=UTF-8:

オプションが引数を取らない時

  opt.on('-a'             )  {|v| ... }  # v は true
  opt.on(          '--foo')  {|v| ... }  # v は true

オプションが引数を取る時

  opt.on('-a VAL'             )  {|v| ... }  # v は引数の値(String)
  opt.on(          '--foo=VAL')  {|v| ... }  # v は引数の値(String)

オプションが引数(省略可)を取る時

  opt.on('-a [VAL]'             )  {|v| ... }  # v は String か nil(省略時)
  opt.on(          '--foo[=VAL]')  {|v| ... }  # v は String か nil(省略時)

否定オプションが指定可能な時

  opt.on('--[no-]foo')  {|v| ... }  # v は true か false(否定時)

否定オプションが指定可能、かつ、引数(省略可)を取る時

  opt.on('--[no-]foo[=VAL]')  {|v| ... }  # v は true か false か String

ただし、実行時に否定と引数指定を同時にするとエラー

  $ prog.rb --no-foo=10    # => エラーになる

オプションの -h, --help はデフォルトでヘルプが表示される。

$ ruby example_optparse.rb --help
Usage: example_optparse [options]
    -p, --port=PORT                  port number
    -d                               debug mode
        --verbose                    verbose mode
    -l, --[no-]log                   logging
    -i [IF]                          interface
    -b, --[no-]bar[=VAL]

irb 用バナー

| 10:34 | irb 用バナー - Going My Ruby Way を含むブックマーク はてなブックマーク - irb 用バナー - Going My Ruby Way irb 用バナー - Going My Ruby Way のブックマークコメント

バナーを表示するスクリプトを GitHub にアップしました。

単体実行もできますが、irb の起動時のバナー用に作りました。

バナーの色は、ruby1.8 では「緑」、ruby1.9 では「赤」です。

また、“RUBY”の部分はスクロールしながら表示されます。

----

スクリーンショット

f:id:lnznt:20110809100740j:image

f:id:lnznt:20110809100741j:image

----

GitHubWiki にスクリーンショットを載せる方法が分かりませんでした。。。