Getting this 'Undefined method 'fetch'' - ruby

I am learning ruby and getting this error
My code:
class New_class
hash{}
File.readlines('file.txt').each do |line|
if (line =~ /^(\w+)=>(.*)/)
hash[$1] =$2
end
end
def check
a='2345'
value = hash.fetch{a,''}
if (value == '')
puts 'Error no value found'
else
puts value
end
end
end
var=New_class.new
var.check
Error :undefined method 'fetch'
Here I want hash to run one time and store all the key/value so that I can use the hash in multiple methods and check for values. Anyone know how to fix this error or any better way to do?

The hash variable is out of scope. You can make it global by changing it to $hash.
Also fetch uses round brackets not curly brackets.
class New_class
$hash = {}
File.readlines('file.txt').each do |line|
if (line =~ /^(\w+)=>(.*)/)
$hash[$1] =$2
end
end
def check
a='2345'
value = $hash.fetch(a,'')
if (value == '')
puts 'Error no value found'
else
puts value
end
end
end

Related

Undefined method .split for Nil class Ruby

Undefined method for nil:Nilclass
In a class, a method counts the number of words in a paragraph.An error occurs when a method is called(1). I can’t understand how to pass the argument methods using send.
If I remove the class and put the def calc_1(paragraph) method into the loop, then everything works, I start calling the select method. It turns out he does not see my books variable with text, when there is a class.
#books = "You can use this knowledge to create small tools that might help."
class Filecalculation
def select
loop do
puts "# Will we search : сounting words in text File(1)".cyan
print "\n>>>>>> "
input = gets.chomp
search_method = "calc_#{input}".to_sym
if (respond_to?(search_method))
contents = send(search_method, #books)
end
end
end
def calc_1 paragraph
word_count = paragraph.split.length
puts "#{word_count} words"
end
end
Filecalculation.new.select
If replaced by search_method = "calc_#{input}".to_sym also works.
Helped add def initialize #books end.
Instead of contents = send (search_method, #books) you can use send (search_method, #books).
require "colorize"
class Filecalculation
def initialize
#books = "You can use this knowledge to create small tools that might help you."
end
def calc_1 paragraph
word_count = paragraph.strip.squeeze(' ').count(' ') + 1
puts "#{word_count} words"
end
def select
loop do
puts "# Will we search : Calculation_lines paragraph(1)".cyan
print "\n>>>>>> ".yellow
input = gets.chomp
search_method = "calc_#{input}" #.to_sym
if (respond_to?(search_method))
contents = send(search_method, #books)
else
puts "exit "
exit
end
end
end
end
Filecalculation.new.select

Ruby Metaprogramming "Depths"

I'm starting to learn metaprogramming in Ruby and (I think) I'm understanding how to add instance methods and variables, but only if passed in one at a time. For example, test.new_value = true. I'm wondering how to add an extra depth to my command with two dots test.like.this. For example:
class StackOverflow
def initialize(name)
#name = name
end
def method_missing(argument, *args)
argument = argument.to_s
if argument =~ /failing/
puts 'FOUND FAILING'
puts argument
puts args[0]
return
end
if argument =~ /this_test_is/
puts 'FOUND THIS TEST IS'
puts argument
puts args[0]
return
end
if argument =~ /this_works=/
instance_variable_set("##{argument.to_s.chop}", args[0])
return
else
return instance_variable_get("##{argument}").to_s
end
end
end
test = StackOverflow.new("post")
test.this_works = true
puts "IT WORKED: " + test.this_works
test.this_test_is.failing
gives me the following output:
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-linux]
IT WORKED: true
FOUND THIS TEST IS
this_test_is
undefined method `failing' for nil:NilClass
(repl):44:in `<main>'
What I'm looking to do is treat this as a variable and value pair. I'd like to know how to do both of these scenarios:
A: Recognise this_test_is and treat it as a variable to have it store the string (or symbol is fine) failing.
B: Recognise failing as the variable and if I see this_test_is then set failing to true, as opposed to false if I find this_test_is_not.
Thank you in advance!
You need to add some kind of recursion :
class StackOverflow
def initialize(name)
#name = name
end
def method_missing(argument, *args)
argument = argument.to_s
if argument =~ /failing/
puts 'FOUND FAILING'
puts argument
puts args[0]
return
end
if argument =~ /this_test_is/
puts 'FOUND THIS TEST IS'
puts argument
puts args[0]
return StackOverflow.new("this_test_is")
end
if argument =~ /this_works=/
instance_variable_set("##{argument.to_s.chop}", args[0])
return
else
return instance_variable_get("##{argument}").to_s
end
end
end
test = StackOverflow.new("post")
test.this_works = true
puts "IT WORKED: " + test.this_works
test.this_test_is.failing
prints this :
IT WORKED: true
FOUND THIS TEST IS
this_test_is
FOUND FAILING
failing

`parse_response': undefined method `new' for nil:NilClass (NoMethodError)

I want to implement method which raises errors based on status code. I tried to implement this code:
def parse_response
system_errors = { }
(100..199).each do |current|
system_errors[current.to_s] = SystemError
end
(200..999).each do |current|
system_errors[current.to_s] = CommunicationError
end
return params_for_success if successful_response?
# pp system_errors
pp payment_response
if valid?
raise system_errors[340].new(technical_message, response_code)
else
raise errors.full_messages.join(";\n")
end
end
def successful_response?
response_code == RESPONSE_CODE_FOR_SUCCESS
end
def params_for_success
payment_response.dig(:payment_response)
end
.....
class CommunicationError < StandardError
def initialize(current_technical_message, response_code)
#response = response
end
end
But I get error parse_response': undefined methodnew' for nil:NilClass (NoMethodError)`
What is the proper way to raise error based on a range of numbers?
This line is causing the issue: system_errors[:error_class].new(technical_message, response_code)
Unlike Javascript, Ruby does not implicitly convert between types.
(200..999).each do |current|
system_errors[current.to_s] = CommunicationError
end
# now we have
system_errors["340"] == CommunicationError
So later when you do
raise system_errors[340].new(technical_message, response_code)
It uses the interger key 340 rather than the string key "340". Missing keys return nil, so you're calling nil.new. Decide on whether you're going to use integer or string keys and stick to it when inserting/reading.

ruby title case problems

A course on ruby asks to write a Title class, which is initialized with a string. It has one method fix, which should return a title-cased version of the string. Here is what I have for my code.
class Title
attr_reader :string
def initialize(string)
#string = string
end
def fix
not_capitalized = %w{a and the of}
word_array = string.downcase.split(" ")
title_array = []
word_array.each_with_index do |word, index|
if index == 0 || !not_captialized.include?(word)
title_array << word.capitalize
else
title_array << word
end
end
title_array.join(" ")
end
end
I keep getting a NameError undefined local variable or method `not_captialized'. What am I doing wrong?
You have a typo in your variables.
The first one is not_capitalized
The second one is not_captialized
Just rename the second one and it should work
i.e. if index == 0 || !not_capitalized.include?(word)
Just as the error message says. You never defined a local variable or method not_captialized, but are trying to use it.

Debugging simple Ruby class method?

class DobbsyKretts
def initialize
#Receive idea
puts "Enter an idea, a secret or anything else you want to secretize; hit enter to stop typing and save the file"
(#idea = gets).reverse.upcase
#Filename and saving - to encrypt the file
puts "Enter the file name you'd like to have this saved as; Type PLAN at the beginning for plans and REM for reminders"
(#file_name = gets.chomp.upcase)
File::open("DobbsyKrett-"+ #file_name + ".txt", "w") do |f|
f << #idea
end
end
def unzip
puts "Do you want to withdraw PLAN or REM"
response = gets.chomp.upcase!
puts "Invalid" if !["PLAN","REM"].include?(response)
file_contents = nil
Dir['DobbsyKrett-'+response+"*.txt"].each do |file_nom|
file_contents = File.read(file_nom)
end
puts file_contents
end
end
somethingsomething1 = DobbsyKretts.new
somethingsomething1.unzip
def unzip
puts "Do you want to withdraw PLAN or REM"
#response = gets.strip
if #response.downcase != "plan" and #response.downcase != "rem"
puts "Invalid" end
Dir["DobbsyKrett-"+#response+".txt"].each do |file_nom|
#value = file.read(file_nom)
end
puts #value
end
end
The function gets will return a string with the line-ending character at the end which is not what you expected. To remove it, use the chomp function:
#response = gets.chomp
It is okay for a method (e.g. unzip) to create new instance variables (e.g. #valueholder). In general it's always better for your variables to have the smallest possible scope, so unless you need to read valueholder later, you should just use a local variable (remove the # from the name):
Dir["DobbsyKrett-"+#response+".txt"].each do |file_nom|
valueholder = File.read(file_nom)
end
puts valueholder
Also, valueholder is a terrible name for a variable but if you made it a local variable that could be excused.
Also, your block startings/endings are mismatched. Here's a fixed version of your function that shouldn't result in syntax errors:
def unzip
puts "Do you want to withdraw PLAN or REM"
response = gets.chomp.downcase
if !["plan","rem"].include? response
puts "Invalid"
else
Dir["DobbsyKrett-#{response}.txt"].each do |file_nom|
valueholder = file.read(file_nom)
end
puts valueholder
end
end
Edit: You should capitalize File to correctly call File.read.

Resources