开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜