Если я сделаю это:

class PseudoRelationship
    def my_method(args)
         args
    end
end

a = PseudoRelationship.new

Я получил как результат

x
#<PseudoRelationship:0x109c2ebb0>

Я хотел бы, чтобы он вел себя как перечислитель или массив, поэтому я получаю, например, этот вывод

x = PseudoRelationship.new [1,2,3]
x
[1,2,3]

Pd. Это не для рельсов.

Я пытаюсь вести себя как массив.

Это то, что, похоже, использует rails 2.3, например, вы можете сделать

my_model.relationship # returns an array
my_model.relationship.find #is a method

Я пытаюсь воспроизвести это поведение.

2
Arnold Roa 21 Окт 2015 в 23:33

3 ответа

Лучший ответ

Jholtrop был близок, вы хотите перезаписать метод inspect

2.0.0p645> 
class PseudoRelationship
    def initialize(args)
        @args = args
    end

    def inspect
        @args.inspect
    end
end

2.0.0p645> PseudoRelationship.new [2, 3, 5]                                                                                                                                                                 
[2, 3, 5]

--Изменить на основании причин OP желания такого поведения -

Хотя приведенный выше класс отображает то, что мы хотим видеть в консоли, на самом деле он не предполагает никакого управления аргументами таким образом, чтобы args рассматривался как Enumerable. Вдохновением OP является конструкция Rails, ActiveRecord::Relation *. Чтобы имитировать этот стиль поведения, вы должны включить Enumerable.

class PseudoRelationship
    include Enumerable

    def initialize(args)
        @args = args
    end

    def each(&block)
       @args.each(&block)
    end

    def inspect
        @args.inspect
    end

    # Add extra functions to operate on @args
    # This is obviously a silly example
    def foo?
      @args.include? :foo
    end

    def [](key)
      @args[key]
    end

    def last
      @args[-1]
    end
end


2.0.0p645> PseudoRelationship.new [2, 3, 5]                                                                                                                                                                 
[2, 3, 5]
2.0.0p645> x = PseudoRelationship.new [2, 3, 5]
[2, 3, 5]
2.0.0p645> x.each 
#<Enumerator: [2, 3, 5]:each>
2.0.0p645> x.each_with_index
#<Enumerator: [2, 3, 5]:each_with_index>
2.0.0p645> x.each_with_index { |e, i| puts "#{i} => #{e}" }
0 => 2
1 => 3
2 => 5
[2, 3, 5]
2.0.0p645> x.foo?
false
2.0.0p645> x.first
2
2.0.0p645> x.last
5
2.0.0p645> x[1]
3
2.0.0p645> x[5]
nil
2.0.0p645> x
[2, 3, 5]

* Эта конструкция не была явно указана, но я предполагаю, исходя из контекста

1
wspurgin 21 Окт 2015 в 23:05

Если вы хотите, чтобы переменная x равнялась аргументам, переданным при создании экземпляра объекта, вам необходимо добавить в свой класс метод initialize. Примерно так должно работать:

class PseudoRelationship
  def initialize(args)
    args
  end

  def my_method(args)
    args
  end
end

x = PseudoRelationship.new [1, 2, 3]
x == [1, 2, 3] #=> true

РЕДАКТИРОВАТЬ:

Да, это действительно не сработает. Если вы хотите, чтобы он вел себя как массив, вы можете наследовать от Array, но это может привести к странным проблемам и обычно не рекомендуется. Однако приведенное ниже будет работать:

class PseudoRelationship < Array
end

x = PseudoRelationship.new [1, 2, 3]
x.class #=> PseudoRelationship < Array
x == [1, 2, 3] #=> true
-1
Devon C. Estes 23 Окт 2015 в 11:21

Похоже, вы просите изменить «представление» объекта, а не «возвращаемое значение». Чтобы дать объекту новое строковое представление, вы можете определить метод #to_s в классе. Например:

class PseudoRelationship
  def initialize(v)
    @v = v
  end

  def to_s
    @v.to_s
  end
end

Тогда в irb, например:

1.9.3-p551 :021 > x = PseudoRelationship.new [:a, 42, false]
 => [:a, 42, false]
-1
jholtrop 21 Окт 2015 в 20:43