Ruby中的字典对象

时间:2013-03-05 16:46:52

标签: ruby rspec

所以我正在尝试在Ruby中创建一个字典对象,让它通过一堆RSPEC测试作为项目的一部分。到目前为止它一直很好,但我坚持一个特定的测试。在此测试之前,这是RSPEC:

require 'dictionary'

describe Dictionary do
  before do
    @d = Dictionary.new
  end

  it 'is empty when created' do
    @d.entries.should == {}
  end

  it 'can add whole entries with keyword and definition' do
    @d.add('fish' => 'aquatic animal')
    @d.entries.should == {'fish' => 'aquatic animal'}
    @d.keywords.should == ['fish']
  end

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

  it 'can check whether a given keyword exists' do
    @d.include?('fish').should be_false
  end

  it "doesn't cheat when checking whether a given keyword exists" do
    @d.include?('fish').should be_false # if the method is empty, this test passes with nil returned
    @d.add('fish')
    @d.include?('fish').should be_true # confirms that it actually checks
    @d.include?('bird').should be_false # confirms not always returning true after add
  end
end

到目前为止,除了最后一次测试之外,所有内容都已通过“在检查给定关键字是否存在时不会作弊”。我试图绕过如何通过,但到目前为止没有成功。任何帮助将不胜感激。这是我到目前为止所做的:

class Dictionary
  attr_accessor :keywords, :entries
  def initialize 
    @entries = {}
     end
 def add(defs)
    defs.each do |word, definition|
      @entries[word] = definition
    end
  end
  def keywords
    input = []
    @entries.each do |key, value|
    input << key
    end
    input.sort  
  end
  def  include?(key)
    self.keywords.include?(keywords.to_s) 
  end
end

提前致谢!

3 个答案:

答案 0 :(得分:3)

有一个错误:

self.keywords.include?(keywords.to_s) 

keywords返回一个数组。您不能将keywords.to_s用作keywords.include?的参数,并希望它找到匹配项:

irb(main):002:0> keywords = %w[a b c]
=> ["a", "b", "c"]
irb(main):003:0> keywords.to_s
=> "[\"a\", \"b\", \"c\"]"
irb(main):004:0> keywords.include?(keywords.to_s)
=> false
irb(main):005:0> keywords.include?('a')
=> true

因为如果要查找它,您需要在keywords数组中使用单个元素。请注意,keywords.to_s是数组的字符串化版本,也可以是:'["a", "b", "c"]'。希望这会帮助您在下次遇到问题时识别问题。

来自include?的{​​{1}}:

  a = [ "a", "b", "c" ]
  a.include?("b")   #=> true
  a.include?("z")   #=> false

所以,改变:

  def  include?(key)
    self.keywords.include?(keywords.to_s) 
  end

为:

  def  include?(key)
    self.keywords.include?(key) 
  end

“不作弊”是什么意思?代码怎么骗?它只做你说的话。之前的所有测试看起来都像是排除了“不作弊”区块中正在测试的条件,而这只是:

@d.include?('bird').should be_false # confirms not always returning true after add
值得包括在里面。你可以使用:

@d.add('fish')
@d.include?('bird').should be_false # confirms not always returning true after add

如果你真的不确定代码的工作原理。

而不是使用数组构建keywords,而@entries列表越大,速度就会越慢,并且只要你调用它就会导致include?运行速度变慢, 利用@entries已经是哈希并使用其方法的事实:

def keywords
  @entries.keys.sort
end

def include?(key)
  !!@entries[key]
end

或者将其用于include?

def include?(key)
  @entries.key?(key)
end

答案 1 :(得分:1)

正如评论中提到的那样,你想要的大部分功能已经存在于Hash中。对于您想要的稍微不同的接口,您应该继承Hash

class Dictionary < Hash
  def add(defs)
    defs = {defs => nil} unless defs.kind_of?(Hash)
    merge!(defs)
  end
  alias entries dup
  def keywords; keys.sort end
end

答案 2 :(得分:0)

这是否能让您了解如何通过“在检查给定关键字是否存在时不作弊”?

@h = Hash.new{|h,k,v| h[k] = nil}
@h["fish"]
p @h #=> {"fish"=>nil}

当哈希中的键时,{|h,k,v| h[k] = nil}部分运行。它添加了密钥并给它一个零值。