Leon's Blogging

Coding blogging for hackers.

Ruby - Dynamic Classes & Methods

| Comments

ruby 可以很方便的動態產生 Classes 和 Methods

Struct

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Post
  attr_accessor :user, :status
  def initialize(user, status)
    @user, @status = user, status
  end

  def to_s
    "#{user}: #{status}"
  end
end

#上下相等

Post = Struct.new(:user, :status) do
  def to_s
    "#{user}: #{status}"
  end
end

send()

1
2
3
4
5
post.say
= post.send(:say)
= post.send("say")

#也可以 call 到 private 的 method

alias_method

1
2
3
4
5
6
7
8
9
class Post
  attr_reader :foo #=> return @foo
  #一定要在定義好的 method 後面還 call 得到
  alias_method :bar, :foo #=> the same method 別名/原名

  def initialize(foo = [])
    @foo = foo
  end
end

可改成 alias

1
2
3
alias_method :bar, :foo
#上下相等
alias bar foo

alias_attribute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Content < ActiveRecord::Base
  # has a title attribute
end

class Email < Content
  alias_attribute :subject, :title
end

e = Email.find(1)
e.title    # => "Superstars"
e.subject  # => "Superstars"
e.subject? # => true
e.subject = "Megastars"
e.title    # => "Megastars"

define_method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Post
  def draft
    @status = :draft
  end

  def posted
    @status = :posted
  end

  def deleted
    @status = :deleted
  end
end

#上下相等

class Post
  states = [:draft, :posted, :deleted]
  states.each do |status|
    define_method status do
      @status = status
    end
  end
end

method()

1
2
3
4
5
6
7
8
9
10
11
class Post
  def initialize(foo)
    @posts = posts
  end
  def contents
    @foo
  end
  def show_tweet(index)
    puts @foo[index]
  end
end
1
2
3
4
5
6
7
8
9
10
11
12
13
foo = ['Compiling!', 'Bundling...']
post = Post.new(foo)

content_method = post.method(:contents)
content_method.call
#=> ["Compiling!", "Bundling..."]

show_method = post.method(:show_tweet)

(0..1).each(&show_method)
#上下相等
show_method.call(0)
show_method.call(1)

EX: log_method

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class MethodLogger
  def log_method(klass, method_name)
    klass.class_eval do
      alias_method "#{method_name}_original", method_name
      define_method method_name do |*args, &block|
        puts "#{Time.now}: Called #{method_name}"
        send "#{method_name}_original", *args, &block
      end
    end
  end
end

class Post
  def say_hi
    puts "Hi"
  end
end

logger = MethodLogger.new
logger.log_method(Post, :say_hi)
Post.new.say_hi

#=> 2016-04-05 12:14:01 +0800: Called say_hi
#=> Hi

eval

可以機字串當成表達是去做處理

1
2
3
4
5
6
def get_binding(str)
  return binding
end
str = "hello"
eval "str + ' Fred'"                      #=> "hello Fred"
eval "str + ' Fred'", get_binding("bye")  #=> "bye Fred"

官方文件:

參考文件:

Comments