2010-07-03 2 views
1

Я хотел бы добиться следующего за счет введения нового оператора (например, :=)Как создать оператор для глубокой копии/клонирования объектов в Ruby?

a := b = {} 
b[1] = 2 
p a # => {} 
p b # => {1=>2} 

Насколько я понимаю, мне нужно изменить Object класс, но я не знаю, что делать для того, чтобы получить то, что я хочу.

require 'superators' 
class Object 
    superator ":=" operand # update, must be: superator ":=" do |operand| 
    # self = Marshal.load(Marshal.dump(operand)) # ??? 
    end 
end 

Не могли бы вы мне помочь?


Update

Хорошо, superators, вероятно, не поможет мне, но я все еще хочу такой оператор. Как я могу (или вы) создать расширение для Ruby, которое я мог бы загрузить как модуль?

require 'deep_copy_operator' 
a !?= b = {} # I would prefer ":=" but don't really care how it is spelled 
b[1] = 2 
p a # => {} 
p b # => {1=>2} 

ответ

2

Прежде всего, синтаксис для superators является

superator ":=" do |operand| 
    #code 
end 

Это блок, потому что superator является метапрограммированием макрос.

Во-вторых, у вас что-то идет с Marshal ... но это немного волшебство. Не стесняйтесь использовать его, пока вы точно понимаете, что именно вы делаете.

В-третьих, то, что вы делаете, не вполне выполнимо с суператором (я считаю), потому что self не может быть изменен во время функции. (если кто-то знает иначе, пожалуйста, дайте мне знать)

Кроме того, в вашем примере a должен существовать и быть определенным до того, как сможет вызвать метод :=.

Лучше всего, наверное:

class Object 
    def deep_clone 
    Marshal::load(Marshal.dump(self)) 
    end 
end 

для создания глубокого клона объекта.

a = (b = {}).deep_clone 
b[1] = 2 
p a # => {} 
p b # => {1=>2} 
+2

Несомненно, операнд идет после дела, верно? Потому что это блок-аргумент? – Chuck

+0

Хорошо, спасибо, это действительно не блок, а метод. Использование 'deep_clone' помогло бы, но это делает его грязным, особенно если у вас нет 2, а 5 хэшей для инициализации. Поэтому мне действительно интересно, как сделать такого оператора. – Andrei

+0

@chuck - Ты прав; Я сделал опечатку; @Andrei - Это невозможно без портирования, потому что вы в основном хотите изменить 'self', а также вызывать метод для объекта, который еще не определен. –

3

ничего себе, суператоры выглядят аккуратно! Но, к сожалению, это не сработает для вас по двум причинам. Во-первых, ваш оператор не соответствует регулярному выражению (вы не можете использовать двоеточие). Достаточно легко найти нового оператора. Но второй, который я не думаю, можно преодолеть, суператор - это в основном имя метода, заданное на объекте слева. Поэтому вы не можете использовать его для операторов присваивания. Если ваша переменная не определена, вы не можете ее использовать, что вызовет ошибку. И если это определено, то вы не можете изменить его тип любым очевидным для меня способом (возможно, с некоторым уровнем рефлексии и метапрограммированием, что выходит за пределы того, что я знаю, но это, честно говоря, маловероятно ... конечно, Я бы никогда не ожидал, что можно создать суператоров, так кто знает).

Так что, я думаю, вы вернулись к взлому parse.y и восстановлению своего Ruby.

+0

Еще раз спасибо, Джошуа! У меня все еще есть надежда, что можно создать такой оператор без перекомпиляции Ruby. В противном случае мой код будет сложнее использовать другими людьми. Я надеюсь, что можно создать модуль/gem, который другие могут установить и включить такой оператор. – Andrei