2011-09-27 17 views
8

Tôi biết rằng tôi có thể xác định động các phương thức trên một lớp bằng cách sử dụng define_method và rằng tôi chỉ định các tham số mà phương thức này sử dụng tính chất của khối.Tôi có thể xác định động một phương thức Ruby có một khối không?

Tôi muốn xác định động phương thức chấp nhận cả thông số tùy chọn và khối. Trong Ruby 1.9, điều này là dễ dàng bởi vì việc truyền một khối tới một khối bây giờ được cho phép.

Thật không may, Ruby 1.8 không cho phép điều này, vì vậy sau đây sẽ không hoạt động:

#Ruby 1.8 
class X 
    define_method :foo do |bar, &baz| 
    puts bar 
    baz.call if block_given? 
    end 
end 

x = X.new 
x.foo("foo") { puts "called!"} #=> LocalJumpError: no block given 

Thay thế rõ ràng block.call với yield không sửa chữa vấn đề một trong hai.
Không thể tùy chọn nâng cấp lên Ruby 1.9. Đây có phải là một vấn đề khó hiểu, hay có cách nào đó xung quanh nó?

Trả lời

6

này hoạt động với Ruby 1.8.7, nhưng không phải 1.8.6:

class X 
    define_method(:foo) do |bar, &baz| 
    puts bar 
    baz.call if baz 
    end 
end 

thử nghiệm với:

X.new.foo("No block") 
X.new.foo("With block") { puts " In the block!"} 
p = proc {puts " In the proc!"} 
X.new.foo("With proc", &p) 

cho:

No block 
With block 
    In the block! 
With proc 
    In the proc! 

(với 1.8.6 nó cung cấp syntax error, unexpected tAMPER, expecting '|'.)

Nếu bạn muốn đối số tùy chọn cũng như khối, bạn có thể thử một cái gì đó như thế này:

class X 
    define_method(:foo) do |*args, &baz| 
    if args[0] 
     bar = args[0] 
    else 
     bar = "default" 
    end 
    puts bar 
    baz.call if baz 
    end 
end 

thử nghiệm với:

X.new.foo 
X.new.foo { puts " No arg but block"} 

cho:

default 
default 
    No arg but block 
4

Việc bạn có thể làm là sử dụng class_eval bằng chuỗi thay vì define_method. Nhược điểm này (ngoài việc không được thanh lịch) là bạn mất phạm vi từ vựng. Nhưng điều này thường không cần thiết.

+0

Tôi có cần phải vượt qua một chuỗi đến class_eval? Tôi không thể vượt qua một khối, mà sẽ giữ cho phạm vi? – andrewdotnich

+2

@andrewdotnich Vâng, sau đó bạn quay lại vấn đề về cách bạn định nghĩa phương thức động. –

+1

https://github.com/agrimm/zombie-chaser/blob/master/lib/zombie-chaser/chaser.rb có một ví dụ và liên kết đến một bài đăng trên blog ở giữa chừng tệp. –