2012-04-30 21 views
6

Đó là thời gian để làm cho nó ngắn hơn:Làm thế nào để tạo initializer trong Ruby?

class Foo 
    attr_accessor :a, :b, :c, :d, :e 

    def initialize(a, b, c, d, e) 
    @a = a 
    @b = b 
    @c = c 
    @d = d 
    @e = e 
    end 
end 

Chúng tôi có 'attr_accessor' để tạo getter và setter.

Chúng ta có gì để tạo trình khởi tạo theo thuộc tính không?

+1

thể trùng lặp của [tạo đối tượng Idiomatic trong ruby] (http://stackoverflow.com/questions/1778638/idiomatic-object-creation-in-ruby) –

+0

'def khởi tạo (* args)' ... '@ a, @ b, @ c, @ d, @ e = args' –

Trả lời

1

Bạn có thể sử dụng đá quý như constructor. Từ mô tả:

Phương tiện khai báo để xác định thuộc tính đối tượng bằng cách chuyển băm cho hàm tạo, sẽ đặt các mã vạch tương ứng.

Nó có thể dễ dàng sử dụng:

Class Foo 
    constructor :a, :b, :c, :d, :e, :accessors => true 
end 

foo = Foo.new(:a => 'hello world', :b => 'b',:c => 'c', :d => 'd', :e => 'e') 
puts foo.a # 'hello world' 

Nếu bạn không muốn ivars tạo ra với accessors, bạn có thể rời khỏi: accessors => true

Hope this helps /Salernost

0
class Foo 
    class InvalidAttrbute < StandardError; end 

    ACCESSORS = [:a, :b, :c, :d, :e] 
    ACCESSORS.each{ |atr| attr_accessor atr } 

    def initialize(args) 
    args.each do |atr, val| 
     raise InvalidAttrbute, "Invalid attribute for Foo class: #{atr}" unless ACCESSORS.include? atr 
     instance_variable_set("@#{atr}", val) 
    end 
    end 
end 

foo = Foo.new(a: 1) 
puts foo.a 
#=> 1 

foo = Foo.new(invalid: 1) 
#=> Exception 
+0

Tôi nghĩ rằng câu mở đầu là một cái gì đó dọc theo dòng của "Đó là thời gian để làm cho nó ngắn hơn";) – d11wtq

+0

Yeap. Nhưng Struct làm khá giống nhau bên dưới :) – fl00r

0
class Module 
    def initialize_with(*names) 
    define_method :initialize do |*args| 
     names.zip(args).each do |name,val| 
     instance_variable_set :"@#{name}", val 
     end 
    end 
    end 
end 
+0

Điều này là khá tốt đẹp, ngoại trừ nó sẽ bỏ qua kiểm tra đối số 'initialize' bình thường:' initialize_with: a,: b' + 'Foo.new (1,2,3,4,5) 'sẽ không tạo ra lỗi. – Casper

+0

@ fl00r Cảm ơn bạn đã chỉnh sửa; iPhone ngớ ngẩn tự động viết hoa. – Phrogz

12

Dễ nhất:

Foo = Struct.new(:a, :b, :c) 

Tạo cả người truy cập và trình khởi tạo. Bạn có thể tuỳ chỉnh lớp học của bạn với:

Foo = Struct.new(…) do 
    def some_method 
    … 
    end 
end 
+1

Điều này gọn gàng. Tôi chưa bao giờ nghĩ đến việc sử dụng một Struct cho mục đích đó trước đây. Tất nhiên, nó đi kèm với những hạn chế, như không có khả năng xuống từ một số lớp khác nữa. – d11wtq

+2

Bạn cũng có thể thực hiện 'lớp Foo

+0

@ d11wtq Bạn có thể kế thừa từ hoặc đến một Cấu trúc. – steenslag

2

Chúng ta có thể tạo ra một cái gì đó giống như def_initializer như thế này:

# Create a new Module-level method "def_initializer" 
class Module 
    def def_initializer(*args) 
    self.class_eval <<END 
     def initialize(#{args.join(", ")}) 
     #{args.map { |arg| "@#{arg} = #{arg}" }.join("\n")} 
     end 
END 
    end 
end 

# Use it like this 
class Foo 
    attr_accessor :a, :b, :c, :d 
    def_initializer :a, :b, :c, :d 

    def test 
    puts a, b, c, d 
    end 
end 

# Testing 
Foo.new(1, 2, 3, 4).test 

# Outputs: 
# 1 
# 2 
# 3 
# 4 
+1

+1 để sử dụng dạng chuỗi của 'eval' để yêu cầu tính hợp pháp phù hợp. Có lẽ bạn nên đặt phương thức này trên 'Module' hoặc lớp singleton của' Class', vì không có nhiều ý nghĩa trong việc sử dụng nó trên các cá thể đối tượng ngoài các lớp. – Phrogz

+0

@Phrogz Ah right..thx. Cập nhật mã. – Casper

Các vấn đề liên quan