Рубиновый метод амперсанда - PullRequest
1 голос
/ 02 января 2011

Есть ли способ переопределить метод & для объекта, чтобы он возвращал массив при вызове так:

class MyObject
end

o1, o2, o3 = MyObject.new, MyObject.new, MyObject.new

o1 # => #<MyObject0x01>
o1 & o2 # => [#<MyObject0x01>, #<MyObject0x02>]
o1 & o2 & o3 # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>]

Ответы [ 4 ]

7 голосов
/ 02 января 2011

Попытка создать собственный синтаксис кажется глупой. Почему бы вам не использовать нотацию массива Ruby?

[o1, o2, o3] # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>]

Я пропускаю что-то очевидное здесь?

4 голосов
/ 02 января 2011

Простой ответ - нет.Длинный ответ - . Если вы вернете массив, вы нарушите цепочку ссылок MyObject, которая затем начнет вызывать методы для массива .Лучшие решения в порядке желательности основаны на Принципал наименьшего удивления

  1. Использование [] << o1 << o2 << o3 или [o1,o2,o3]

  2. определить <<, чтобы вести себя как массив

  3. Создать класс, такой как

        class MyObjectCollection < Array
            def &
                # do what I mean
            end
        end
    
  4. Массив патчей Monky


Объяснение цепочки ссылок

class MyObject
end

o1, o2, o3 = MyObject.new, MyObject.new, MyObject.new

o1 # => #<MyObject0x01>              # <-- works
o1 & o2 # => [#<MyObject0x01>, #<MyObject0x02>] # <-- could work with def & because the LHS is a MyObject
o1 & o2 & o3 # => [#<MyObject0x01>, #<MyObject0x02>, #<MyObject0x03>] # <--- CANNOT work because o1 & o2 return an object of type Array and not of type MyObject
2 голосов
/ 02 января 2011

Прочитайте все остальные ответы для важных деталей.Но вот решение:

    class MyObject  
      def initialize(x)
        @x = x
      end

      def &(arg)
        return [self, arg]
      end

      def to_s
        @x
      end
    end

    class Array  
      def &(arg)
        if arg.is_a? MyObject
          return self << arg
        else
          # do what Array.& would normally do
        end
      end  
    end

    a = MyObject.new('a')
    b = MyObject.new('b')
    c = MyObject.new('c')
    x = a & b & c
    puts x.class
    puts "[#{x.join(', ')}]"

Вот еще одно решение, которое является более безопасным (т. Е. Без обезличивания):

    class MyObject  
      def initialize(x)
        @x = x
      end

      def &(arg)
        a = MyObjectArray.new
        a << self << arg
      end

      def to_s
        @x
      end
    end

    class MyObjectArray < Array
        def &(arg)
          return self << arg
        end
    end

    a = MyObject.new('a')
    b = MyObject.new('b')
    c = MyObject.new('c')
    x = a & b & c
    puts x.class
    puts "[#{x.join(', ')}]"
1 голос
/ 02 января 2011

Полагаю, но тогда вам также понадобится обезьяна Array, и тогда у вас будет конфликт, потому что Array уже определяет &.

Почему бы не определить << вместо этого? Затем, после того как первый оператор вернет [o1, o2], <<, который Array уже имеет, будет DTRT для вас.

>> class MyObject
>>   def << x
>>     raise ArgumentError unless x.is_a? self.class or is_a? x.class
>>     [self, x]
>>   end
>> end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...