Почему я не вижу переменную экземпляра после создания?(читатель attr) - PullRequest
0 голосов
/ 09 октября 2018

У меня следующий код, который динамически создает переменные экземпляра.Если переменная экземпляра не существует, я использую ошибку no method для динамического создания методов attr_reader и attr_writer.Все работает нормально, но я не понимаю, почему я не вижу переменную экземпляра @anything после создания первого attr_reader.

require "pry-byebug"

class UberHash
  attr_accessor :color
  def initialize
    @color = nil
  end

  def method_missing(m, *args, &block)
    if m.match(/=/)
      puts "create attr writer"
      self.instance_variable_set("@#{m[0..-2]}", args[0])
    else
      puts "create attr reader"
      self.instance_variable_get("@#{m}")
    end
  end
end

uber_hash = UberHash.new
puts "call 1 .................."
p "uber_hash.anything: #{uber_hash.anything}"
p "uber_hash.inspect: #{uber_hash.inspect}"
p uber_hash.anything = "hola"
p uber_hash.inspect

со следующими результатами:

call 1 ..................
create attr reader
"uber_hash.anything: "
"uber_hash.inspect: #<UberHash:0x00007f851b1e41a8 @color=nil>"
"#<UberHash:0x00007f851b1e41a8 @color=nil>"
create attr writer
"hola"
"#<UberHash:0x00007f851b1e41a8 @color=nil, @anything=\"hola\">"

После создания первой переменной экземпляра anything с помощью метода instnace_variable_set я понимаю, что я правильно создаю attr_reader?

Почему я не вижу переменную @anything instance, если я проверяю экземпляр?

Ответы [ 2 ]

0 голосов
/ 13 октября 2018

После создания первой переменной экземпляра что-нибудь с помощью метода instnace_variable_set я понимаю, что я создаю attr_reader, верно?

Нет, это не правильно.Ваш класс никогда не создает (или не запускает) attr_reader.Попробуйте это (после запуска ваших примеров команд)

p( uber_hash.methods - Object.new.methods )

, и вы увидите, что только методы, дополнительно определенные в вашем классе, будут [:color, :color=, :method_missing] в вашем классе.

Метод :color определениз-за attr_accessor :color.Помните, attr_accessor и т. Д. - это просто ярлык для определения методов.В отличие от этого, метод :anything не определен , поскольку ваш класс никогда не определял этот метод.Вместо этого в вашем классе каждый раз, когда вызывается метод uber_hash.anything, uber_hash.method_missing запускается и выполняет работу, то есть манипулирует или просматривает переменную экземпляра @anything.

Во-вторых, в то время как instance_variable_set устанавливает значение переменной экземпляра (и создает его, если оно не существует), instance_variable_get ссылается на него, только если оно существует, в противном случае возвращает nil и не создает переменную экземпляра.Вот почему @anything создается после instance_variable_set, а не только после instance_variable_get.Попробуйте это, чтобы понять смысл (после того, как вы определили класс).

class UberHash
  def test_pr
    print 'color='; p instance_variable_get("@color")
    print 'other='; p instance_variable_get("@other")
    p instance_variables  # => @other is not defined
    print 'other='; p instance_variable_set("@other", 99)
    p instance_variables  # => @other is NOW defined
  end
end

uber_hash.test_pr

Следовательно, поведение, которое вы видите, совершенно законно.

Примечание: этот последний ответ объясняет это.

0 голосов
/ 09 октября 2018

Вы не видите переменную экземпляра в первой проверке.Вы ожидаете, что это произойдет, потому что в предыдущей строке вы вызываете uber_hash.anything, верно?

Что ж, вызов uber_hash.anything оценивает else в условном выражении #method_missing: self.instance_variable_get("@#{m}") - поэтому нетпеременная экземпляра установлена.

Кроме того, в условном выражении #method_missing вы печатаете два сообщения: puts "create attr writer" и puts "create attr reader" - они неверны.Должно быть: puts "create instance variable" и puts "read instance variable"

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