Объект Ruby, добавленный в метакласс, не виден - PullRequest
1 голос
/ 18 августа 2011

Я пытался освоить метапрограммирование в ruby, читая чужой код.У меня есть этот кусок кода, который, вероятно, слишком загадочный для меня, чтобы отладить.Вот код.

#!/usr/bin/env ruby

class Person

  def print_name
    p "#{Person.identity.name}"
  end

  class << self
    attr_accessor :identity

    def identify()
      self.identity ||= Identity.new
      yield(identity)
    end
  end

  class Identity
    attr_accessor :name

    def initialize
      @name = "kibet"
    end
  end
end

me = Person.new
me.print_name

И ошибка, которую я получаю, это

`print_name': undefined method `name' for nil:NilClass (NoMethodError)
    from ./meta_config.rb:28

Помощь очень ценится.

Ответы [ 4 ]

2 голосов
/ 18 августа 2011

Я смутно понял, что вы пытались делать там ... Проверьте это

class Person

  def print_name
    p "#{Person.identity.name}"
  end

  class << self
    attr_accessor :identity

    def identity
      @identity || Identity.new
    end
  end

  class Identity
    attr_accessor :name

    def initialize
      @name = "kibet"
    end
  end
end

me = Person.new
me.print_name

На что обратить внимание:

  • Полагаю, имя метода было опечаткой. Вы имели в виду личность, целую личность и, пожалуйста, избавьтесь от скобок. Это рубин:)
  • вызов self.identity внутри приведет к переполнению стека. следовательно, непосредственно получить доступ к значению переменной экземпляра
  • Я до сих пор не мог понять, зачем вам доходность там, когда вы никогда не пройдете блок.
1 голос
/ 19 августа 2011

Это похоже на стратегию, которая используется для настройки атрибутов в классе. Примерно так:

class Foo
  class << self
    attr_accessor :config

    def configure()
      self.config ||= Configuration.new
      yield(config)
    end
  end

  class Configuration
    attr_accessor :hostname

    def initialize
      @hostname = 'www.example.com'
    end
  end
end

Этот код позволит вам настроить инициализатор, который может выглядеть следующим образом:

Foo.config do |config|
  config.hostname = "www.sometestsite.com"
end

Затем вы можете использовать экземпляр config в вашем классе для создания метода:

class Foo
...
    def self.foo
      puts "this method is crawling: #{Foo.config.hostname}"
    end
...
end

Это похоже на # {Rails.root} /config/environments/development.rb:

ApplicationName::Application.configure do
...
...
end
0 голосов
/ 19 августа 2011
"#{Person.foo.name}"

является избыточным. Это эквивалент Person.foo.name.to_s, а так как name "kibet" и String # to_s возвращает себя (я надеюсь!), То это эквивалент Person.foo.name.

0 голосов
/ 18 августа 2011

Я обнаружил две проблемы:

def print_name
  p "#{Person.identify.name}"
end

Была опечатка. Вы написали личность, а не идентифицировать.

  def identify()
    #yield(identity) if block_given?
    self.identity ||= Identity.new
  end

Зачем вам нужен урожай? У вас нет блока, когда вы звоните. Я прокомментировал это. Когда вам нужен блок, тогда я бы проверил, есть ли блок.

И ваша проблема: вы не вернули значение, так как ваш метод завершился с помощью yield. Я изменил последовательность.

...