В Ruby, как я могу инициализировать переменные экземпляра в новых объектах базовых классов, созданных из литералов - PullRequest
2 голосов
/ 27 мая 2009
class Object
  attr_reader :foo
  def initialize
    @foo = 'bar'
  end
end

Object.new.foo # => 'bar'
''.foo # => nil
//.foo # => nil
[].foo # => nil

Я хочу, чтобы они все вернулись 'bar'

Знаю, что вы уже можете сделать это:

class Object
  def foo
    'bar'
  end
end

Но я специально хочу инициализировать переменную состояния. Также обратите внимание, что это не работает.

class String
  alias_method :old_init, :initialize
  def initialize(*args)
    super
    old_init(*args)
  end
end

class Object
  attr_reader :foo
  def initialize
    @foo = 'bar'
    super
  end
end

''.foo # => nil

Также не это:

class String
  attr_reader :foo
  def initialize
    @foo = 'bar'
  end
end

''.instance_variables # => []

Я начинаю думать, что это на самом деле невозможно.

Ответы [ 3 ]

5 голосов
/ 22 апреля 2010

Это возможно .

class Object
  class << self
    Kernel.send :define_method, :foo do #Object.send to be more restrictive
      @foo = 'bar'
    end
  end
end

.

irb(main):023:0> class Object
irb(main):024:1> class << self
irb(main):025:2> Kernel.send :define_method, :foo do 
irb(main):026:3* @foo = 'bar'
irb(main):027:3> end
irb(main):028:2> end
irb(main):029:1> end
=> #<Proc:0x00007f5ac89db168@(irb):25>
irb(main):030:0> x = Object.new
=> #<Object:0x7f5ac89d6348>
irb(main):031:0> x.foo
=> "bar"
irb(main):032:0> [].foo
=> "bar"
irb(main):033:0> //.foo
=> "bar"

Важно понимать собственные классы. Каждый класс загадочно реализуется интерпретатором Ruby как скрытый тип класса:

irb(main):001:0> class Object
irb(main):002:1>   def eigenclass
irb(main):003:2>     class << self; self; end
irb(main):004:2>   end
irb(main):005:1> end
=> nil
irb(main):006:0> x = Object.new
=> #<Object:0x7fb6f285cd10>
irb(main):007:0> x.eigenclass
=> #<Class:#<Object:0x7fb6f285cd10>>
irb(main):008:0> Object.eigenclass
=> #<Class:Object>
irb(main):009:0> Object.class
=> Class

Итак, в вашем примере, когда вы пытаетесь вызвать foo для ваших объектов, он работает с классом #<Object:0x7fb6f285cd10>. Однако вы хотите, чтобы он работал с секретным классом #<Class:#<Object:0x7fb6f285cd10>>

Надеюсь, это поможет!

4 голосов
/ 27 мая 2009

Если вещь, которую вы пытаетесь вернуть (здесь 'bar'), требует гораздо больших затрат на настройку, чем небольшая строка, вы можете использовать запомненную версию ответа Германа :

class Object
  def foo
    @foo ||= begin
      'bar' # something far more complicated than just "'bar'"
    end
  end
end

Вы могли бы даже использовать памятку для дешевых вещей, таких как Strings, если вам действительно нужно установить переменную экземпляра (по какой-то причине, которую я не могу сейчас придумать):

class Object
  def foo
    @foo ||= 'bar'
  end
end
0 голосов
/ 27 мая 2009

Это не переменная экземпляра, но будет соответствовать требованиям вашего примера

class Object
  def foo
    'bar'
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...