Leon's Blogging

Coding blogging for hackers.

Ruby - 用 Instance_eval & Class_eval 自己加 Method!

| Comments

有時候會發現有些 object,沒有設定 setter & getter ,剛好又需要用到,這時就可以派上用場拉。

instance_eval & class_eval

instance_eval Use ClassName.instance_eval to define a class method (one associated with the class object but not visible to instances).

class_eval Use ClassName.class_eval to define an instance method (one that applies to all of the instances of ClassName).

簡單的來說,就是自己定義 class or instance 的 method

1
2
3
4
5
6
7
8
class MyClass
  def initialize(num)
    @num = num
  end
end

a = MyClass.new(1)
b = MyClass.new(2)

錯誤,因為沒有 getter or setter methods

1
2
a.num
#=>NoMethodError: undefined method `num' for #<MyClass:0x007fba5c02c858 @num="1">

自行加 instance method

1
2
a.instance_eval { @num }
#=> 1

也可以直接定義 method,這樣就可以一直重複使用

1
2
3
4
5
6
7
8
9
10
a.instance_eval do
   def num
     @num
   end
end

a.num
#=> 1
b.num
#NoMethodError: undefined method `num' for #<MyClass:0x007fba5c08e5f8 @num="2">

上述指定義了 a 的 instance method 所以 b 會錯誤。 因此可以直接定義在 class instance

1
2
3
4
5
6
7
8
9
10
MyClass.class_eval do
  def num
      @num
  end
end

a.num
#=> 1
b.num
#=> 2

另外由於 class 也是 Class 的 instance 因此也可以直接去做定義,class method

1
2
3
4
5
6
7
8
9
10
11
class A
end

A.instance_eval do
  def hi
      'hi'
  end
end

A.hi
#=> hi

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Tweet
  def initialize(user)
    @user = user
    @tweet = []
  end

  def submit_to_twitter
    tweet_text = @tweet.join(' ')
    puts "#{@user}: #{tweet_text}"
  end

  def text(str)
    @tweet << str
  end

  def hashtag(str)
    @tweet << "#" + str
    self
  end

  def mention(*users)
    users.each do |user|
      @tweet << "@" + user
    end
    self
  end

  def text(str)
    @tweet << str
    self
  end
end

def tweet_as(user, text = nil, &block)
  tweet = Tweet.new(user)
  tweet.text(text) if text
  tweet.instance_eval(&block) if block_given?
  tweet.submit_to_twitter
end

tweet_as 'markkendall' do
  mention 'foo', 'bar'
  text 'I made a DSL!'
  hashtag 'hooray'
end

參考文件:

Comments