Есть ли способ переопределить оператор << в Ruby?

Я пытаюсь сделать что-то вроде:

account.users << User.new

Но мне нужно, чтобы пользователи были методом в учетной записи. Поэтому я пробовал такие вещи, как:

def users<<(obj)

Но мне не повезло с этим. Возможно ли это сделать в Ruby? Я бы предположил так потому, что отношения ActiveRecord, похоже, работают таким образом в Rails.

6 ответов

Отметьте этот ответ: Rails: переопределить метод ассоциации ActiveRecord

[этот код полностью из другого ответа, здесь для будущих поисковиков]

has_many :tags, :through => :taggings, :order => :name do
 def << (value)
 "overriden" #your code here
 end 
 end


Кажется, что вы не можете описывать свою реальную проблему, но чтобы ответить на ваш вопрос - да, вы можете переопределить оператор <<:

class Foo def <<(x) puts "hi! #{x}" end end f=Foo.new=> #<foo:0x00000009b389f0> > f << "there" hi! there </foo:0x00000009b389f0>


Я предполагаю, что у вас есть такая модель:

class Account < ActiveRecord::Base
 has_and_belongs_to_many :users
end

Чтобы переопределить Account#users<<, вам нужно определить его в блоке, который вы передаете в has_and_belongs_to_many:

class Account < ActiveRecord::Base
 has_and_belongs_to_many :users do
 def <<(user)
 # ...
 end
 end
end

Вы можете получить доступ к соответствующему объекту Account, обратившись к proxy_association.owner:

def <<(user)
 account = proxy_association.owner
end

Чтобы вызвать исходный Account#users<<, вызовите Account#users.concat:

def <<(user)
 account = proxy_association.owner
 # user = do_something(user)
 account.users.concat(user)
end

Подробнее см. на этой странице: Расширения ассоциации - ActiveRecord


В этом случае это << вашего класса пользователя. Так может быть Array или AssociationProxy.

Самый простой способ - создать новый способ делать то, что вы хотите.

Вместо этого вы можете переопределить метод.

account.users.instance_eval do
 def <<(x)
 put 'add'
 end
end
account.users << User.new
# add

Но вам нужно делать это все время, прежде чем добавить к < <


Если вы пытаетесь выполнить действие после добавления коллекции User в коллекцию users, вы можете использовать обратные вызовы ассоциации вместо over-riding << (так как есть много способов добавить объект в ассоциацию).

class Account has_many :users, :after_add => :on_user_add def on_user_add(user) p "Added user : #{user.name} to the account: #{name}" end end


users возвращает объект, который переопределил оператор <<, например Array, IO, String, или любой тип, который вы создаете. Вы переопределяетесь следующим образом:

class SomeType
 def <<(obj)
 puts "Appending #{obj}"
 end
end

licensed under cc by-sa 3.0 with attribution.