hash中的ruby哈希和单例方法访问实例变量

时间:2010-10-15 02:56:16

标签: ruby scope singleton-methods

#!/usr/bin/env ruby

# this is the data I have
@data = {
  :student => {
    :id => '123477',
    :first_name => 'Lazlo',
    :last_name =>'Fortunatus',
    :email=>'Lazlo@fortunatus.org' 
  },
  :contact_info => {
    :telephone=>'1 415 222-2222',
    :address => '123 Main St',
    :city =>'Beverly Hills',
    :state=>'California',
    :zip_code=>90210,
    :social_security_number =>'111-11-1111' 
  }
} 

class Student  
  # not fully implemented - this is what I need help on.
  def get_id_original
    # I need this to return the value @data[:student][:id]
  end 

  def get_city_original
    # I need this to return the value @data[:contact_info][:city]
  end
end 

s = Student.new
# this is the original method
# how can I access the @data variable here I tried @data[:student][:id] doesnt work
# I realize that data is outside of the scope of this method. However, is there any way!
s.get_id_original

# My goal is to have a singleton method that acts exactly like get_id_original,
# but get_id_original doesn't work.
def s.id
  get_id_original
end

6 个答案:

答案 0 :(得分:1)

首先,你的id方法实际上必须进入课堂。

您可以尝试这样的事情:

@data = { :student => { :id => '123477'} }

class Student
  attr_accessor :id

  def initialize(student)
    self.id = student[:id]
  end
end

s = Student.new(@data[:student])
puts s.id

答案 1 :(得分:1)

可以做到!


它最初没有工作,因为@data是顶级对象的实例属性,所以即使Student派生自Object,属性不在新实例中。

但您可以将self传递给s.id,因此您需要添加的唯一内容是数据属性的访问者。

然而,这有点棘手,因为attr_reader等人是私有类方法所以你不能直接使用它们,而你不能(因为它是私有的)只是说{{ 1}},您必须打开self.class.attr_reader并执行此操作...通过这些更改,您的程序可以正常工作......

Object

答案 2 :(得分:0)


#!/usr/bin/ruby
@data = { :student => { :id => '123477', :first_name => 'Lazlo', :last_name =>'Fortunatus', :email=>'Lazlo@fortunatus.org' }, :contact_info => { :telephone=>'1 415 222-2222', :address => '123 Main St', :city =>'Beverly Hills', :state=>'California', :zip_code=>90210, :social_security_number =>'111-11-1111' } } 

 class Student  
    def initialize( data )
        @data = data
    end

    def get_id_override
        @data[:student][:id]
    end 

    def get_first_name_override
        @data[:student][:first_name]
    end 

    def get_last_name_override
        @data[:student][:last_name]
    end 
        def get_email_override
        @data[:student][:email]
    end 

    def get_telephone_override
        @data[:contact_info][:telephone]
    end 
        def get_city_override
        @data[:contact_info][:city]
    end 

    def get_state_override
        @data[:contact_info][:state]
    end 

    def get_zip_code_override
        @data[:contact_info][:zip_code]
    end 

    def get_social_security_number_override
        @data[:contact_info][:social_security_number]
    end 




end 

s = Student.new(@data)

def s.id
    get_id_override
end 
def s.first_name
    get_first_name_override
end 

def s.last_name
    get_last_name_override
end 

def s.email
    get_email_override
end 

def s.contact_info
    get_telephone_override
end 

def s.city
    get_city_override
end

def s.state
    get_state_override
end

def s.zipcode
    get_zip_code_override
end

def s.ssn
    get_social_security_number_override
end

puts s.id
puts s.first_name
puts s.last_name
puts s.email
puts s.contact_info
puts s.city
puts s.state
puts s.zipcode
puts s.ssn

以下是一些工作后的答案。任何人都有比我更好的答案让我知道。

答案 3 :(得分:0)

你真的应该传递数据对象,以便它s有自己的引用。

@data = { :student => { :id => '123477'} }

class Student
  attr_accessor :data
  def initialize(data)
    @data = data
  end
end

s = Student.new(@data)
# or you can use s.data = @data

def s.id
  @data[:student][:id]
end

puts s.id

谨慎一点。对最外层范围内@data的任何修改都将反映在s中,因为两个@data变量都指向内存中的同一对象。

但是如果你不想修改Student课程怎么办?您只需将访问者添加到s

即可
@data = { :student => { :id => '123477'} }

class Student
end

s = Student.new
class << s
  attr_accessor :data
end
def s.id
  @data[:student][:id]
end

s.data = @data
puts s.id

答案 4 :(得分:0)

此代码与您自己的答案相同,但有一些改进。 (只有阅读,我才意识到你要完成的任务。)为了避免过于复杂,我试图避免动态生成方法名称。

#!/usr/bin/env ruby

require 'forwardable'

@data = {
  :student => {
    :id => '123477',
    :first_name => 'Lazlo',
    :last_name =>'Fortunatus',
    :email=>'Lazlo@fortunatus.org' 
  },
  :contact_info => {
    :telephone=>'1 415 222-2222',
    :address => '123 Main St',
    :city =>'Beverly Hills',
    :state=>'California',
    :zip_code=>90210,
    :social_security_number =>'111-11-1111' 
  }
} 

class ContactInfo
  def initialize( data )
    @data = data
  end
  def get_telephone_override
    @data[:telephone]
  end 
  def get_city_override
    @data[:city]
  end 

  def get_state_override
    @data[:state]
  end 

  def get_zip_code_override
    @data[:zip_code]
  end 

  def get_social_security_number_override
    @data[:social_security_number]
  end 
end

class Student  
  extend Forwardable # enables delegation (see ruby-doc.org's standard library)

  # delegates multiple methods to @contact_info, so they can be called on Student.
  # Remember to have the leading colon.
  def_delegators :@contact_info,
    :get_telephone_override,
    :get_city_override,
    :get_state_override,
    :get_zip_code_override,
    :get_social_security_number_override

  def initialize( data )
    @data = data[:student]
    # this is an example of composing objects to achieve separation of concerns.
    # we use delegators so ContactInfo methods are available on the Student instance.
    @contact_info = ContactInfo.new(data[:contact_info])
  end

  def get_id_override
    @data[:id]
  end 

  def get_first_name_override
    @data[:first_name]
  end 

  def get_last_name_override
    @data[:last_name]
  end 
  def get_email_override
    @data[:email]
  end 
end 

s = Student.new(@data)
class << s
  alias_method :id, :get_id_override
  alias_method :first_name, :get_first_name_override
  alias_method :last_name, :get_last_name_override
  alias_method :email, :get_email_override
  alias_method :contact_info, :get_telephone_override
  alias_method :city, :get_city_override
  alias_method :state, :get_state_override
  alias_method :zipcode, :get_zip_code_override
  alias_method :ssn, :get_social_security_number_override
end

puts s.id
puts s.first_name
puts s.last_name
puts s.email
puts s.contact_info
puts s.city
puts s.state
puts s.zipcode
puts s.ssn

我认为,如果你发布了代码,那么你的问题会更加清晰。我打算建议编辑。

答案 5 :(得分:-2)

您是否应该在类定义之外定义实例变量(以“@”为前缀)?

此外,您无法定义名称为

的句点的方法