目指そうかなRubyist RSSフィード

2011-06-21

[meta] 特異メソッド  [meta] 特異メソッド - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] 特異メソッド - 目指そうかなRubyist  [meta] 特異メソッド - 目指そうかなRubyist のブックマークコメント

特定のオブジェクトにメソッドを追加できる。

str = 'hello world'

def str.title?
  self.upcase == self
end

p str.title?
p str.methods.grep(/hello/)
p str.singleton_methods

[meta] classをキーワードを使わない  [meta] classをキーワードを使わない - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] classをキーワードを使わない - 目指そうかなRubyist  [meta] classをキーワードを使わない - 目指そうかなRubyist のブックマークコメント

class MyClass < Array
  def my_method
    'Hello'
  end
end

これと同じ動きをするものを、classキーワードを用いずに書く。

class Class.new(Array)
  def my_method
    'Hello'
  end
end

class MyClass < ArrayはMyClass = Class.new(Array)で書き換えできる。

[meta] TimeDateに依存したコードのテストをどう書くか?  [meta] TimeやDateに依存したコードのテストをどう書くか? - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] TimeやDateに依存したコードのテストをどう書くか? - 目指そうかなRubyist  [meta] TimeやDateに依存したコードのテストをどう書くか? - 目指そうかなRubyist のブックマークコメント

class Loan
  def initialize(book)
    @book = book
    @time = Time.now
  end

  def to_s
    "#{@book.upcase} loaded on #{@time}"
  end
end

上記のコードではTime.nowが邪魔してテストできない。

次の用にコードを帰る

class Loan
  def initialize(book)
    @book = book
    @time = Loan.time_class.now
  end

  def self.time_class
    @time_class || Time
  end

  def to_s
    "#{@book.upcase} loaded on #{@time}"
  end
end

実際に使う際には、@time_classは常にnilになるので、Timeが呼ばれる。テストコードでは、@time_classにダミーの時間を挿入してテストすると良い。以下、テストコード

require 'test/unit'
class FakeTime
  def self.now
    '2011-06-21 21:14:44 +0900'
  end
end

class Test_Loan < Test::Unit::TestCase
  def test_conversion_to_string
    Loan.instance_eval { @time_class = FakeTime }
    loan = Loan.new('War and Peace')
    assert_equal "WAR AND PEACE loaded on #{FakeTime.now}", loan.to_s
  end
end

[meta] クラス名がわからないときにクラスをオープンにする  [meta] クラス名がわからないときにクラスをオープンにする - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] クラス名がわからないときにクラスをオープンにする - 目指そうかなRubyist  [meta] クラス名がわからないときにクラスをオープンにする - 目指そうかなRubyist のブックマークコメント

Module#class_evalを使用する

def add_method(a_class)
  a_class.class_eval do
    def m
      'Hello'
    end
  end
end

add_method String

'a'.m # => 'Hello'

2011-06-20

[meta] blockの基本  [meta] blockの基本 - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] blockの基本 - 目指そうかなRubyist  [meta] blockの基本 - 目指そうかなRubyist のブックマークコメント

復習

blockは中括弧か、do endで定義

ブロックを定義できるのは、メソッドを呼び出す時だけ。

ブロックはメソッドにそのままわ達され、メソッド側でyieldを使ってブロックをコールバックする。

def a_method(a, b)
  a + yield(a, b)
end

a_method(1, 2) {|x, y| (x + y) * 3} # => 10

block_given?

メソッドの内部からblockが渡されているか確認する方法。

def a_method
  return yield if block_given?
  'no block'
end

a_method { 'block' } # =>'block'
a_method # =>'no block'

SolangeSolange2013/09/20 03:14No conpialmts on this end, simply a good piece.

NapfeNapfe2013/09/20 13:27Wow! Great to find a post with such a clear <a href="http://anqqvwl.com">mesaegs!</a>

AliAli2013/09/22 07:41I've been looikng for a post like this for an age http://weiadvvqaz.com [url=http://urmnawcl.com]urmnawcl[/url] [link=http://ypkbppnau.com]ypkbppnau[/link]

JulioJulio2013/09/23 11:53Wow! That's a really neat <a href="http://kjcmyy.com">anwers!</a>

2011-06-11

[meta] メソッドを動的に定義する  [meta] メソッドを動的に定義する - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] メソッドを動的に定義する - 目指そうかなRubyist  [meta] メソッドを動的に定義する - 目指そうかなRubyist のブックマークコメント

class MyClass
  define_method :my_method do |my_arg|
    my_arg * 3
  end
end

obj = MyClass.new
obj.my_method(2) # => 6

動的メソッドと呼ばれる

[meta] 動的ディスパッチを用いてprivateメソッドを呼び出してみる  [meta] 動的ディスパッチを用いてprivateメソッドを呼び出してみる - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] 動的ディスパッチを用いてprivateメソッドを呼び出してみる - 目指そうかなRubyist  [meta] 動的ディスパッチを用いてprivateメソッドを呼び出してみる - 目指そうかなRubyist のブックマークコメント

class Foo
  private
  def print(text)
    p text
  end
end

Foo.new.send(:print, 'hoge')  # => "hoge"
Foo.new.public_send(:print, 'hoge')  # => error

呼び出せてしまう。public_sendを用いることでpublicのメソッドのみ読み出せるので通常はこちらをつかったほうがよさそう。ただ、privateなメソッドのテストを行うときにはsend使うと便利かも

[meta] 動的ディスパッチを用いたCampingの例  [meta] 動的ディスパッチを用いたCampingの例 - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] 動的ディスパッチを用いたCampingの例 - 目指そうかなRubyist  [meta] 動的ディスパッチを用いたCampingの例 - 目指そうかなRubyist のブックマークコメント

アプリケーションの設定情報をYAMLで保存している

admin : Bill
title : Rubyland
topic : Ruby and more

これらの設定をconfオブジェクトに格納している。普通に書いたら下記のようになる。

conf.admin = 'Bill'
conf.title = 'Rubyland'
conf.topic = 'Ruby and more'

ただ、Campingのコードには下記のようなソースはない。

YAML.load_file(conf.rc).each do |k, v|
  conf.send("#{k}=", v)
end

[meta] メソッドをダイナミックに読み出す  [meta] メソッドをダイナミックに読み出す - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] メソッドをダイナミックに読み出す - 目指そうかなRubyist  [meta] メソッドをダイナミックに読み出す - 目指そうかなRubyist のブックマークコメント

class MyClass
  def my_method(my_arg)
    my_arg * 2
  end
end

obj = MyClass.new
p obj.my_method(3)
p obj.send(:my_method, 3)

後者のsendを使えばメソッドを動的に呼び出せる。この技術を動的ディスパッチと呼ぶ。

[meta] include時の継承チェーン  [meta] include時の継承チェーン - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] include時の継承チェーン - 目指そうかなRubyist  [meta] include時の継承チェーン - 目指そうかなRubyist のブックマークコメント

module Printable
  def print; end
end

module Document
  def print; end
end

class Book
  include Document
end

class Book2
  include Document
  include Printable
end

Book.ancestors # => [Book, Document, Object, Kernel, BasicObject]
Book2.ancestors # => [Book2, Printable, Document, Object, Kernel, BasicObject]

include Documentした際にはBook2の上にDocumentの継承チェーンを作る。include Printableの時にBook2の上にPrintableが配置され、Documentはひとつ上に押し上げられる。なので、例えばBook2でprintメソッドを呼び出した場合はPrintableモジュールのprintが実行される。


[meta] self  [meta] self - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] self - 目指そうかなRubyist  [meta] self - 目指そうかなRubyist のブックマークコメント

testing_selfを呼び出すとobjがselfになる。@varはobjのインスタンス変数になる。

class MyClass
  def testing_self
    @var = 10
    my_method()
    self
  end

  def my_method
    @var = @var + 1
  end
end

obj = MyClass.new
p obj.testing_self # => #<MyClass:0x0000010092e180 @var=11>

常にselfのオブジェクトが何かを意識すること。

トップレベルのself

methodを呼び出さないとき、selfはどうなっているのか。

ruby-head :011 > self
 => main
ruby-head :012 > self.class
 => Object

class定義とself

ruby-head :013 > class X; self; end
 => X 

モジュールやクラスの定義のなかでは、selfはモジュールやクラスになる。

privateの本当の意味

class C
  def public_method
    self.private_method
  end

  private
  def private_method; end
end

C.new.public_method

これはもちろん実行できない。privateキーワードは明示的なレシーバーをつけてプライベートメソッドを呼び出すことはできない。暗黙的なレシーバーselfに対するものでなければならない。よって、上記のコードはselfを削除すれば動く

[meta] Kernelモジュール  [meta] Kernelモジュール - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] Kernelモジュール - 目指そうかなRubyist  [meta] Kernelモジュール - 目指そうかなRubyist のブックマークコメント

print()みたいなどこからでも呼び出せるメソッドはKernelモジュールのプライベートインスタンスメソッド。

ObjectクラスがKernelモジュールをincludeしている

ruby-head :010 > Kernel.private_instance_methods.grep(/^pr/)
 => [:printf, :print, :proc]

[meta] 継承チェーン  [meta] 継承チェーン - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] 継承チェーン - 目指そうかなRubyist  [meta] 継承チェーン - 目指そうかなRubyist のブックマークコメント

このメソッドで継承チェーンを知ることが可能となる

class MyClass
  def my_method
    'my_method()'
  end
end

class MySubclass < MyClass
end

obj = MySubclass.new
p obj.my_method()
p MySubclass.ancestors # => [MySubclass, MyClass, Object, Kernel, BasicObject]

[meta] メソッドを呼び出しているときに何が起きているのか?  [meta] メソッドを呼び出しているときに何が起きているのか? - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] メソッドを呼び出しているときに何が起きているのか? - 目指そうかなRubyist  [meta] メソッドを呼び出しているときに何が起きているのか? - 目指そうかなRubyist のブックマークコメント

  1. メソッドを探す(メソッド検索)
  2. メソッドを実行する

メソッド検索ってなに?

my_method()を読みだすとRubyはレシーバであるobjからMySubcclassを検索。MySbuclassクラスにもメソッドがないので、さらに上位クラスのMyclassを探す。

class MyClass
  def my_method
    'my_method()'
  end
end

class MySubclass < MyClass
end

obj = MySubclass.new
p obj.my_method()

[meta] ネームスペース  [meta] ネームスペース - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] ネームスペース - 目指そうかなRubyist  [meta] ネームスペース - 目指そうかなRubyist のブックマークコメント

module Rake
  class Task

Taskクラスの完全な名前はRake::Taskになった。これで名前が衝突することがなくなる。Rakeのような定数をまとめただけのmoduleをネームスペースと呼ぶ

[meta] Moduleクラスのconstants()メソッド  [meta] Moduleクラスのconstants()メソッド - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] Moduleクラスのconstants()メソッド - 目指そうかなRubyist  [meta] Moduleクラスのconstants()メソッド - 目指そうかなRubyist のブックマークコメント

現在のスコープにある全ての定数を返す

module M
  Y = '他の定数'
  class C
    ::M::Y
  end
end

p M.constants # => [:Y, :C]

クラス名Cも定数。

Module.constants()は現在のプログラムのトップレベルにある定数を返す。

ruby-head :008 > Module.constants
 => [:Object, :Module, :Class, :Kernel, :NilClass, :NIL, :Data, :TrueClass, :TRUE, :FalseClass, :FALSE, :Encoding, :Comparable, :Enumerable, :String, :Symbol, :Exception, :SystemExit, :SignalException, :Interrupt, :StandardError, :TypeError, :ArgumentError, :IndexError, :KeyError, :RangeError, :ScriptError, :SyntaxError, :LoadError, :NotImplementedError, :NameError, :NoMethodError, :RuntimeError, :SecurityError, :NoMemoryError, :EncodingError, :SystemCallError, :Errno, :ZeroDivisionError, :FloatDomainError, :Numeric, :Integer, :Fixnum, :Float, :Bignum, :Array, :Hash, :ENV, :Struct, :RegexpError, :Regexp, :MatchData, :Marshal, :Range, :IOError, :EOFError, :IO, :STDIN, :STDOUT, :STDERR, :ARGF, :FileTest, :File, :Dir, :Time, :Random, :Signal, :Process, :Proc, :LocalJumpError, :SystemStackError, :Method, :UnboundMethod, :Binding, :Math, :GC, :ObjectSpace, :Enumerator, :StopIteration, :RubyVM, :Thread, :TOPLEVEL_BINDING, :ThreadGroup, :Mutex, :ThreadError, :Fiber, :FiberError, :Rational, :Complex, :RUBY_VERSION, :RUBY_RELEASE_DATE, :RUBY_PLATFORM, :RUBY_PATCHLEVEL, :RUBY_REVISION, :RUBY_DESCRIPTION, :RUBY_COPYRIGHT, :RUBY_ENGINE, :ARGV, :Gem, :TSort, :RbConfig, :Config, :CROSS_COMPILING, :Exception2MessageMapper, :IRB, :RubyToken, :RubyLex, :Readline, :Date, :BasicObject] 

現在のパスが必要ならばModule.nesting()を使う

module M
  class C
    module M2
      p Module.nesting # => [M::C::M2, M::C, M]
    end
  end
end

[meta] 外部の定数を絶対パスで指定する  [meta] 外部の定数を絶対パスで指定する - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] 外部の定数を絶対パスで指定する - 目指そうかなRubyist  [meta] 外部の定数を絶対パスで指定する - 目指そうかなRubyist のブックマークコメント

::で書き始めて外部の定数を絶対パスで指定する。

module M
  Y = '他の定数'
  class C
    ::M::Y
  end
end
||<<

* [meta] classのクラス
>|ruby|
ruby-head :003 > String.class
 => Class 
ruby-head :004 > Class.class
 => Class 
ruby-head :005 > Class.superclass
 => Module 
ruby-head :006 > Module.superclass
 => Object 
ruby-head :007 > String.superclass
 => Object 

[meta] classキーワード  [meta] classキーワード - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] classキーワード - 目指そうかなRubyist  [meta] classキーワード - 目指そうかなRubyist のブックマークコメント

2回目のclassは新しくclassを定義してるのではなく既存のクラスを再オープンしている。

class D
  def x; 'x'; end
end

class D
  def y; 'y'; end
end

obj = D.new
p obj.x
p obj.y

2011-06-10

[meta] メタプログラミングの定義  [meta] メタプログラミングの定義 - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  [meta] メタプログラミングの定義 - 目指そうかなRubyist  [meta] メタプログラミングの定義 - 目指そうかなRubyist のブックマークコメント

メタプログラミングとは、言語要素を実行時に操作するコードを記述すること

# -*- coding: utf-8 -*-
require 'active_record'

class Movie < ActiveRecord::Base
end

movie = Movie.create
movie.title = "博士の異常な愛情"
p movie.title

クラスの属性ごとにアクセサメソッドを書くのではなく、ActiveRecord::Baseを継承するだけで実行時にアクセサメソッドが定義されるようなコードを書いてある。

2007-07-22

mac bookruby mac bookにrubyを - 目指そうかなRubyist を含むブックマーク はてなブックマーク -  mac bookにrubyを - 目指そうかなRubyist  mac bookにrubyを - 目指そうかなRubyist のブックマークコメント

デフォルトで入ってるけど古いので。

僕はportでいれました。

http://d.hatena.ne.jp/hakobe932/20061208/1165646618

が良記事でportsはこれでいけます。

あとは

$ sudo port install ruby

なだけ。便利だな。

LillyLilly2013/09/19 05:10Posts like this make the inrneett such a treasure trove

DavidDavid2013/09/20 10:12You've <a href="http://ofpckb.com">manaegd</a> a first class post

AlokAlok2013/09/20 22:13Wait, I cannot fathom it being so sttrgihaforward. http://szmbmf.com [url=http://vrrlyhfjcn.com]vrrlyhfjcn[/url] [link=http://qyrtzl.com]qyrtzl[/link]

AdilsonAdilson2013/09/23 15:19Findnig this post solves a problem for me. Thanks! http://zhlnnlw.com [url=http://okqnnhzet.com]okqnnhzet[/url] [link=http://cjwbwgnr.com]cjwbwgnr[/link]