Ruby object added to meta class is not visible
I have been trying to get the hang of metaprogramming in ruby by reading other people's code on the same. I have this piece of code that is probably too cryptic for me to debug. Here is the code.
#!/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
An开发者_高级运维d the error I'm getting is this
`print_name': undefined method `name' for nil:NilClass (NoMethodError)
    from ./meta_config.rb:28
Help's highly appreciated.
I vaguely understood what you were trying to do there.. Check this out
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
Things to note:
- I guess the method name was a typo. U meant identity intead of identify and please get rid of the braces. This is ruby :)
- calling self.identity inside will cause a stackoverflow. hence, directly access the value of instance variable
- I still could not understand why you need a yield there, when you would never pass a block.
This looks like a strategy that is used for configuring attributes on a class. Something like the following:
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
This code would allow you to set up an initializer that could look like:
Foo.config do |config|
  config.hostname = "www.sometestsite.com"
end
You can then use the instance of config in your class to make a method:
class Foo
...
    def self.foo
      puts "this method is crawling: #{Foo.config.hostname}"
    end
...
end
It's similar to #{Rails.root}/config/environments/development.rb:
ApplicationName::Application.configure do
...
...
end
I found two problems:
def print_name
  p "#{Person.identify.name}"
end
There was a typo. You wrote identity, not identify.
  def identify()
    #yield(identity) if block_given?
    self.identity ||= Identity.new
  end
Why do you need the yield? You have no block, when you call it. So I commented it out. When you need the block, then I would check, if there is a block.
And your problem: You didn't return a value, as your method ended with the yield. I changed the sequence.
"#{Person.foo.name}"
is redundant. It's the equivalent of Person.foo.name.to_s, and since name is "kibet", and String#to_s returns itself (I hope!), then it's the equivalent of Person.foo.name.
 
         加载中,请稍侯......
 加载中,请稍侯......
      
精彩评论