如何创建一个将散列(有或没有指定值)作为参数的方法?

How can I create a method that takes a hash (with or without an assigned value) as an argument?

所以我首先要完成测试,但有点卡住了。到目前为止,这是我的代码:

class Dictionary 
  attr_accessor :entries, :keywords, :item

  def initialize 
    @entries = {}
end

  def add(item)
    item.each do |words, definition| 
      @entries[words] = definition
    end
  end

  def keywords
    @entries.keys
  end

end#class

我卡在了这里的 rspec 测试中:

it 'add keywords (without definition)' do
    @d.add('fish')
    @d.entries.should == {'fish' => nil}
    @d.keywords.should == ['fish']
  end

如何切换我的 add 方法以获取 key/value 对,或者仅获取一个值为 nil 的键?第一个测试指定散列在创建时为空,所以我不能在那里给它默认值。

可能会检查传递给 add 方法的参数类型。不管它是不是Enumerable,显然是Arrays,Hashes等中包含的mixin,只需将它的值赋给nil

def add(item)
  case item
  when Enumerable
    item.each do |words, definition| 
      @entries[words] = definition
    end
  else
    @entries[item] = nil
  end
end

请注意 case 使用“case equality”来检查参数类型。

如果您总是将字符串传递给该方法,您可以只为第二个字符串设置默认值...类似于以下内容:

  def add(word, definition = nil)
      @entries[word] = definition
  end

因此您的代码可能如下所示:

class Dictionary 
  attr_accessor :entries, :keywords, :item

  def initialize 
    @entries = {}
  end

  def add(word, definition = nil)
      @entries[word] = definition
  end

  def keywords
    @entries.keys
  end

end#class

如果您想要添加多个(即 add key: "word", with: "many", options: nil),该设计可能不适合您,您需要创建一个解决方案,以按照@mudasobwa 建议的方式工作。也许:

  def add(word, definition = nil)
      return @entries[word] = definition unless word.is_a?(Enumerable)
      return @entries.update word if word.is_a?(Hash)
      raise "What?!"
  end

更新,作为标准要求

我更新了上面的方法以允许不是字符串的单词(如您所指出的)。

将散列传递给方法时,它被视为单个参数。

Key => Value 对是隐含的散列,因此将散列传递给方法时,以下内容通常相同:

Hash.new.update key: :value
Hash.new.update({key: :value})

考虑以下因素:

def test(a,b = nil)
  puts "a = #{a}"
  puts "b = #{b}"
end

test "string"
# => a = string
# => b = 
test "string", key: :value, key2: :value2
# => a = string
# => b = {:key=>:value, :key2=>:value2}
test key: :value, key2: :value2, "string"
# Wrong Ruby Syntax due to implied Hash, would raise exception:
# => SyntaxError: (irb):8: syntax error, unexpected '\n', expecting =>
test({key: :value, key2: :value2}, "string")
# correct syntax.

这就是为什么当您传递 add 'fish' => 'aquatic' 时,它只被视为一个参数,一个散列 - 而 add 'fish', 'aquatic' 则将两个参数传递给该方法。

如果您的方法必须接受不同类型的参数(字符串、哈希、数字、符号、数组),您将需要以不同的方式处理每个选项。

这就是@mudasobwa 建议检查第一个参数类型的原因。他的解决方案很不错。

我的版本代码有点短,但它运行在相同的想法上。

  def add(word, definition = nil)
      return @entries[word] = definition unless word.is_a?(Enumerable)
      return @entries.update word if word.is_a?(Hash)
      raise "What?!"
  end