将一个字符串转换为已存在的类实例

3
给定一个类实例和一个字符串,我该如何将该字符串转换为引用该实例?
class Room
  def enter
    puts "Welcome!"
  end
end

# Rooms are predefined
lounge = Room.new
kitchen = Room.new
study = Room.new

puts "Which room would you like to go to?"
print "> "
room = gets.strip

# User types "lounge"

room.enter # => undefined method `enter' for "lounge":String (NoMethodError)

我理解为什么会出现NoMethodError,但是我还没想出如何将room字符串转换为指向已存在的名为lounge的Room实例。

5个回答

1

也许尝试通过键映射房间并获取它们?

class Room

  def enter
    puts "Welcome!"
  end
end

# Rooms are predefined
rooms = %w[lounge kitchen study].inject({}) { |f,c| f.update c => Room.new }

puts "Which room would you like to go to?"
print "> "
if room = rooms[gets.strip]
  room.enter
end

甚至更简单:
class Room

  def initialize room_type
    @room_type = room_type
  end

  def enter
    return puts 'Unsupported room type' unless %w[
      lounge kitchen study
    ].include?(@room_type)
    puts "Welcome to #{@room_type}!"
  end

end

puts "Which room would you like to go to?"
print "> "
room = Room.new(gets.strip)
room.enter

1
room_name = gets.strip.capitalize
room = Kernel.const_get(room_name)
room.enter

如果您需要使用 Rails 的一部分 require "active_support/all",您可以这样做:
room = gets.strip.camelize.constantize
room.new.enter

编辑:

正如铁人所指出的那样,require "active_support/core_ext/string/inflections"会更有效率。


所有的ActiveSupport都是一大块代码,不一定需要全部使用。为什么不展示如何获取只有字符串操作的部分呢? - the Tin Man
没想到你能那样做。 - user1454117
如果类实例已经定义,这似乎不起作用。在创建新实例时它非常有效:例如 Object.const_get("Room").new.enter,但是在引用现有实例时却不行:Object.const_get("lounge").enter # => wrong constant name lounge (NameError)。我认为这是因为 Room 类是一个常量,而 lounge 不是。 - Nick
需要 "active_support/core_ext/string" 会更有效率。不,require 'active_support/core_ext/string/inflections' 才是。 - the Tin Man

1
class Room
  attr_reader :name

  def initialize(name)
    @name = name
  end

  def enter
    puts "Welcome to #{@name}!"
  end
end

# Rooms are predefined
rooms = ["lounge", "kitchen", "study"].map(&Room.method(:new))

puts "Which room would you like to go to?"
print "> "
name = gets.strip

# Just an example (not using find to avoid nil.enter)
p rooms.select{ |room| room.name == name }.map(&:enter)

0
我最终将每个 Room 对象作为类变量存储在哈希中,以便在初始化时引用每个实例。这样就可以通过哈希引用每个实例:
class Room
  @@rooms = {}

  def initialize(name)
    @@rooms.store name, self
  end

  def rooms
    @@rooms
  end

  def enter
    puts "Welcome!"
  end
end

# Rooms are predefined
lounge = Room.new('lounge')
kitchen = Room.new('kitchen')
study = Room.new('study')

puts "Which room would you like to go to?"
print "> "
new_room = gets.strip

lounge.rooms[new_room].enter if lounge.rooms.has_key? new_room

0
你可以使用 `eval` 方法来动态执行一段 Ruby 脚本。在这种情况下,`eval(room)` 将给你房间实例。
然而,这是非常危险的方法,因为它允许最终用户执行代码。为了防止代码执行,最好验证它是否是已定义的房间变量之一:
eval(room).enter if local_variables.include?(room.to_sym)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接