Method works outside of Class, but not inside - ruby

The method "find" seems to work when I pull it out of the Class and test it, but for some reason it is returning empty when it is inside the Class. I can't figure out why...
class Dictionary
def entries
#entries ||= {}
end
def add(entry)
if entry.is_a?(String) == true
#entries = {entry => nil}
else
#entries= entry
end
end
def keywords
#entries.keys.sort
end
def include?(word)
entries.keys.include?(word)
end
def find(word)
result = {}
entries.each_pair do |key, value|
if key =~ /#{word}/
result[key] = value
end
end
result
end
end
It gets stuck at this part of the spec...
it 'finds multiple matches from a prefix and returns the entire entry (keyword + definition)' do
#d.add('fish' => 'aquatic animal')
#d.add('fiend' => 'wicked person')
#d.add('great' => 'remarkable')
#d.find('fi').should == {'fish' => 'aquatic animal', 'fiend' => 'wicked person'}
end
The error says...
expected: {"fish" => "aquatic animal", "fiend" => "wicked person"}
got: {} (using ==)
Diff: ## -1, 3, +1 ##
-"fiend" => "wicked person"
-"fish" => "aquatic animal"
# ./11_dictionary/dictionary_spec.rb:67:in 'block (2 levels) in >'

Your add method replaces the entire entries hash, rather than actually adding an entry. Fix that, and the find method should work.
For completeness, here's how I would implement add:
def add(entry)
if entry.is_a?(Hash)
#entries.merge!(entry)
else
#entries[entry] = nil
end
end

Related

Dictionary Class in Ruby from TestFirst.org

I'm trying to solve the Dictionary problem from TestFirst.org. The goal is to get my codes to work with the test spec. Apparently I am getting the NoMethodError: undefined method '[]=' for nil: NilClass
I post the my codes and test spec below.
It looks like the test can not read my add and keywords methods for some reasons. Can someone help me determine why it is behaving that way?
My codes:
class Dictionary
#initialization of entries
def entries
#hash = {}
end
def add(keyvalue)
keyvalue.each do |key, value|
#hash[key] = value #create key-value pair in #hash
end
end
def keywords
key_array = []
#hash.each {|key,value| key_array.push(key)} #push key inside key_array
end
end
Test Spec:
require '11_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
it "doesn't include a prefix that wasn't added as a word in and of itself" do
#d.add('fish')
#d.include?('fi').should be false
end
it "doesn't find a word in empty dictionary" do
#d.find('fi').should be_empty # {}
end
it 'finds nothing if the prefix matches nothing' do
#d.add('fiend')
#d.add('great')
#d.find('nothing').should be_empty
end
it "finds an entry" do
#d.add('fish' => 'aquatic animal')
#d.find('fish').should == {'fish' => 'aquatic animal'}
end
it 'finds multiple matches from a prefix and returns the entire entry (keyword + definition)' do
#d.add('fish' => 'aquatic animal')
#d.add('fiend' => 'wicked person')
#d.add('great' => 'remarkable')
#d.find('fi').should == {'fish' => 'aquatic animal', 'fiend' => 'wicked person'}
end
it 'lists keywords alphabetically' do
#d.add('zebra' => 'African land animal with stripes')
#d.add('fish' => 'aquatic animal')
#d.add('apple' => 'fruit')
#d.keywords.should == %w(apple fish zebra)
end
it 'can produce printable output like so: [keyword] "definition"' do
#d.add('zebra' => 'African land animal with stripes')
#d.add('fish' => 'aquatic animal')
#d.add('apple' => 'fruit')
#d.printable.should == %Q{[apple] "fruit"\n[fish] "aquatic animal"\n[zebra] "African land animal with stripes"}
end
end
It's because every test block executes separately, so, for example, in can add whole entries with keyword and definition you execute:
#d.add('fish' => 'aquatic animal')
but #hash instance variable in #d object is uninitialized. To fix it, you should initialize #hash upon object initialization:
class Dictionary
def initialize
#hash = {}
end
def entries
#hash
end
# etc.
end
or, instead of operating directly on #hash instance variable, you can create private accessor:
class Dictionary
def entries
hash
end
def keywords
key_array = []
hash.each {|key,value| key_array.push(key)} #push key inside key_array
end
# etc.
private
def hash
#hash ||= {}
end
end

rspec test not passing

I'm working through the learn ruby tutorials and I'm trying pass the last example where it tests the printable method. I tested the method by calling the method directly within my ruby program and it spits out exactly whats needed. What is preventing my code from properly passing? Any help is greatly appreciated.
Here's the rspec file:
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
it "doesn't include a prefix that wasn't added as a word in and of itself" do
#d.add('fish')
#d.include?('fi').should be_false
end
it "doesn't find a word in empty dictionary" do
#d.find('fi').should be_empty # {}
end
it 'finds nothing if the prefix matches nothing' do
#d.add('fiend')
#d.add('great')
#d.find('nothing').should be_empty
end
it "finds an entry" do
#d.add('fish' => 'aquatic animal')
#d.find('fish').should == {'fish' => 'aquatic animal'}
end
it 'finds multiple matches from a prefix and returns the entire entry (keyword + definition)' do
#d.add('fish' => 'aquatic animal')
#d.add('fiend' => 'wicked person')
#d.add('great' => 'remarkable')
#d.find('fi').should == {'fish' => 'aquatic animal', 'fiend' => 'wicked person'}
end
it 'lists keywords alphabetically' do
#d.add('zebra' => 'African land animal with stripes')
#d.add('fish' => 'aquatic animal')
#d.add('apple' => 'fruit')
#d.keywords.should == %w(apple fish zebra)
end
it 'can produce printable output like so: [keyword] "definition"' do
#d.add('zebra' => 'African land animal with stripes')
#d.add('fish' => 'aquatic animal')
#d.add('apple' => 'fruit')
#d.printable.should == %Q{[apple] "fruit"\n[fish] "aquatic animal"\n[zebra] "African land animal with stripes"}
end
end
and here's what I've created so far for the printable function:
class Dictionary
def initialize(opts = {})
#opts = opts
end
def entries
#opts
end
def add(opts)
opts.is_a?(String) ? #opts.merge!(opts => nil) : #opts.merge!(opts)
end
def keywords
#opts.keys.sort
end
def include?(key)
#opts.has_key?(key)
end
def find(key)
#opts.select { |word,defin| word.scan(key).join == key }
end
def printable
opts_sorted = #opts.sort_by { |word,defin| word}
opts_sorted.each do |word,defin|
print "[#{word}] \"#{defin}\"\n"
end
end
end
and here's the error:
1) Dictionary can produce printable output like so: [keyword] "definition"
Failure/Error: #d.printable.should == %Q{[apple] "fruit"\n[fish] "aquatic animal
"\n[zebra] "African land animal with stripes"}
expected: "[apple] \"fruit\"\n[fish] \"aquatic animal\"\n[zebra] \"African lan
d animal with stripes\""
got: [["apple", "fruit"], ["fish", "aquatic animal"], ["zebra", "African
land animal with stripes"]] (using ==)
Diff:
## -1,4 +1,4 ##
-[apple] "fruit"
-[fish] "aquatic animal"
-[zebra] "African land animal with stripes"
+["apple", "fruit"]
+["fish", "aquatic animal"]
+["zebra", "African land animal with stripes"]
# ./11_dictionary/dictionary_spec.rb:81:in `block (2 levels) in <top (required)>
'
Lucky for you I did this whole thing just now! Below is the answer code with comments for the explanation! I hope this still helps even after 4 years!
class Dictionary # Create the class
attr_accessor :entries # Attribute Accessor; this is our setter and getter
def initialize(entries = {}) # Create constructor; if there is no value passed the default value is {}
#entries = {} # Declare instance variable with empty hash
if entries.is_a? Hash # is_a? is a method where it sees if its a class; Hash is the class we compare it to
entries.each {|key, value| #entries[key] = value} # if there is a value that's passed we copy the hash to our instance variable
end # End conditional
end # End constructor
def keywords # Main purpose of this method is to return what's inside our keys
keywords = [] # Create empty keyword variable
#entries.each_key {|key| keywords.push(key.to_s)} # each_key method only takes the keys in our hash and pushes them into the keywords array
keywords.sort # We sort the keywords variable
end # End method
def add(entry) # add method adds in an entry either a hash or a string
if entry.is_a? Hash # If the argument belongs to the class Hash; or if its a hash
entry.each {|key, value| #entries[key] = value} # Then we copy the key and values to our instance variable
elsif entry.is_a? String # If the arguemnt belongs to the class String; or if its a String
#entries[entry] = nil # We create a key for that string and set the value to nil
end # End conditional
end # End method
def include?(entry) # include? method this checks if the argument is in our entries and returns a boolean value
#entries.has_key?(entry) # has_key? checks the instance variable if it has the key
end # End method
def find(entry) # find method finds if certain letters are in our keys
#entries.select {|key| /#{entry}/.match(key)} # select gets the keys that match a certain keyword in our entries
# if #entries.has_key?(entry) # First attepmt to solve the test case
# #entries.select {|key,value| key == entry}
# else
# puts {}
# end
end # End method
def printable # printable method just prints out our entries like a dictionary
printable = [] # Create an empty array
#entries.sort.each do |key,value| # Sort and iterate to each key-value pair
printable.push("[#{key}] \"#{value}\"") # push the key-value pair formatted accordingly to the test case
end # End hash iteration
printable.join("\n") # join with newlines to get desired result
end # End method
end # End class
I think the problem is that your printable method is not returning what you want it to return.
The return value of printable is the value of the method's last statement (opts_sorted.each ...). You are using print to output the expected string but this does not change the return value of the method (which is what you are testing).
If you want to return the string you are printing instead try this:
def printable
opts_sorted = #opts.sort_by { |word, defin| word}
opts_sorted.map{ |word, defin| "[#{word}] \"#{defin}\"\n" }.join
end
map will transform the key-value pairs in the hash into an array of strings formatted the way you want them and then join will append them into a single string.

can I use hash.each even if i'm passing only a string key? Dictionary without definition

This is the error I'm getting. I need to pass a string key to a method that usually accepts string key and string symbol combo
Dictionary
is empty when created`
can add whole entries with keyword and definition
add keywords (without definition) (FAILED - 1)
Failures:
1) Dictionary add keywords (without definition)
**Failure/Error: #d.add('fish')
NoMethodError:
undefined method `each' for "fish":String
# ./11_dictionary/dictionary.rb:9:in `add'**
# ./11_dictionary/dictionary_spec.rb:27:in `block (2 levels) in <top (required)>'
This is the following spec. the #d.add('fish') passes a string without definition.
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
my code:
I think my definition.each is where it goes wrong. From what I understand each goes through the array or hash in this example but only has one value so it doesn't know how to loop through it? So I thought about setting a default nil value for meaning and word but it doesn't accept it and comes with different errors.
class Dictionary
attr_accessor :keywords, :entries
def initialize
#entries = {}
end
def add(definition)
definition.each do |word, meaning|
#entries[word] = meaning
end
end
def keywords
#entries.keys.sort
end
def include?(key)
#entries.key?(key)
end
def find(query)
#entries.select { |word, definition| word.scan(query).join == query}
end
def entries
#entries
end
end
Thanks for you help in advance!
You're trying to call each on a String in #d.add('fish'), which isn't allowed. You could just add the following line above definition.each do |word, meaning|:
definition = { definition => nil } unless definition.is_a? Hash
although this could have unexpected consequences if you are passing different kinds of objects to add.
My code is rough.. This works too.
def add(hash)
if (hash.is_a? Hash)
#d=hash
else
#d = {hash => nil}
end

How to push keys and values into an empty hash w/ Ruby?

I have a dictionary class and want to be able to push keys (as keywords) and values (as definitions) into an empty hash with an 'add' method. I don't understand how to syntactically write that. I have included an RSPEC file too.
ruby:
class Dictionary
attr_accessor :keyword, :definition
def entries
#hash = {}
end
def add(options)
options.map do |keyword, definition|
#hash[keyword.to_sym] = definition
end
end
end
Rspec:
require 'dictionary'
describe Dictionary do
before do
#d = Dictionary.new
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
Any help is appreciated. Thank you!
UPDATE:
Thank you Dave Newton for replying. I used your code and got this error:
ERROR:
*Failure/Error: #d.keywords.should == ['fish']
NoMethodError:
undefined method `keywords' for #<Dictionary:0x007fb0c31bd458
#hash={"fish"=>"aquatic animal"}>*
I get a different error when I convert 'word' into a symbol using #hash[word.to_sym] = defintion
*Failure/Error: #d.entries.should == {'fish' => 'aquatic animal'}
expected: {"fish"=>"aquatic animal"}
got: {:fish=>"aquatic animal"} (using ==)
Diff:
## -1,2 +1,2 ##
-"fish" => "aquatic animal"
+:fish => "aquatic animal"*
Instantiate your hash in Dictionary's initialize:
class Dictionary
def initialize
#hash = {}
end
def add(defs)
defs.each do |word, definition|
#hash[word] = definition
end
end
end
Right now you have no hash until you call entries, which you don't.
entries should return the existing hash, not create a new one.
keywords should return the hash's keys.
You do not need accessors for keyword and definition. Such singular items are meaningless in a dictionary class. You might want something like lookup(word) that returned a definition.
Also, you convert words to symbols, but I don't know why–particularly since you use string keys in your spec. Pick one, although I'm not convinced this is a case where symbols add value.
Please consider variable naming carefully to provide as much context as possible.
Looking at your Rspec, It looks like you need this setup.
class Dictionary
def initialize
#hash = {}
end
def add(key_value)
key_value.each do |key, value|
#hash[key] = value
end
end
def entries
#hash
end
def keywords
#hash.keys
end
end
Do not use key.to_sym in add method, just key
To give flexibility to add method, I can return the self object to continuesly add.
def add(key_value)
key_value.each do |key, value|
#hash[key] = value
end
self
end
So, I can do this now.
#d.add("a" => "apple").add("b" => "bat")

rspec Ruby Method to insert into Hash

I'm having trouble figuring out this challenge. Here is what I have:
class Dictionary
attr_accessor :entries
def initialize
#x = Hash.new
end
def entries
#x
end
def add(hash)
#x.merge!(hash)
end
end
#d=Dictionary.new
#d.add('fish' => 'aquatic animal')
puts #d.entries
i'm getting => "fishaquatic animal"
I'm WANTING to get => {'fish' => 'aquatic animal'}
to_s on Hash behaves less-than-ideally for some Ruby versions. Try puts #d.entries.inspect.
Update:
The following code works for me (Ruby 1.9.3 and rspec 2.12.0):
class Dictionary
def initialize
#x = Hash.new
end
def entries
#x
end
def add(hash)
#x.merge!(hash)
end
end
describe Dictionary do
before do
#d = Dictionary.new
end
it 'can add whole entries with keyword and definition' do
#d.add('fish' => 'aquatic animal')
#d.entries.should == {'fish' => 'aquatic animal'}
end
end
As written, your code is currently setting #x to a new, empty Hash and then returning it every time you call the entries method.
Try moving that setup code into an initialize method:
class Dictionary
attr_reader :entries
def initialize
#entries = Hash.new
end
def add(hash)
#entries.merge!(hash)
end
end
It looks like to me the rspec codes a bit weird. The second test does an entries method, and the entries method resets the instance variable #x back to blank. So it would better to add the instance variable as an attr_reader and then initialize it when you make a new dictionary object. So it would look something like this
class Dictionary
attr_reader #x
def initialize
#x = Hash.new
end
def add(hash)
#x.merge!(hash)
end
end
and the test would be like this
#d.add(fish: "aquatic animal")
#d.x.should == {'fish' => "aquatic animal"}

Resources