2013-03-05 3 views
0

Итак, я пытаюсь создать объект словаря в Ruby и получить его, чтобы передать кучу тестов RSPEC как часть проекта. Пока это было хорошо, но я застрял на одном конкретном тесте. Здесь нет на Rspec до этого теста:Словарь Object в Ruby

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 

Заранее благодарен!

+2

Какой из них «не обманывает, проверяя, существует ли данное ключевое слово», терпит неудачу? – sawa

+5

Простите меня, если это грубо, но могу ли я спросить, какова точка этого объекта? Я не вижу никаких функциональных возможностей, которые не предоставляются Hash .. –

+3

Вы пренебрегаете упоминанием о том, как это происходит. –

ответ

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"]'. Надеюсь, это поможет вам распознать проблему в следующий раз, когда вы столкнетесь с ней.

От the documentation для include?:

 
    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) 
    [email protected][key] 
end 

Или использовать это для include?:

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

Спасибо за помощь, я действительно ценю это. – PaperKraftMike

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 
+0

@Joshua Вы добавили 'entries', что бесполезно в этой реализации, которая использует подкласс. И вы неправильно заменили определение «ключевые слова» на то, что не сортирует. – sawa

+0

Ему нужны записи, чтобы передать спецификацию, и в спецификации нет ничего о сортируемых ключах. –

+2

@sawa, wow спасибо. Этот ответ действительно заставил меня по-новому взглянуть на существующие классы в Ruby. Спасибо! – PaperKraftMike

0

Придает ли это вам представление о том, как получить, чтобы пройти «d oesn't чит, проверяя, существует ли данное ключевое слово »?

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

{|h,k,v| h[k] = nil} часть запускается, когда ключ не присутствует в хэш. Он добавляет ключ и дает ему значение nil.

Смежные вопросы