Redis client using Ruby - ruby

I am trying to get user input for AGE attribute and comparing it with my key value pair and trying to return those records which match the user input value.
Code:
require "redis"
require "csv"
require "json"
begin
redis = Redis.new(:url => "redis://h:petr08jsjnofis211gmbq8fdd8#ec2-54-83-9-36.compute-1.amazonaws.com:11959")
puts "Connected"
health = CSV.read('6339_Dataset_1.csv')
health.each do |data_row|
redis.hmset(data_row[21],"AGE",data_row[0],"SEX",data_row[1],"RACE",data_row[2],"DAY_OF_ADMISSION",data_row[3],"DISCHARGE_STATUS",data_row[4],"STAY_INDICATOR",data_row[5],"ID",data_row[21])
end
value = redis.keys('*')
puts "QUERY 2"
puts "Enter the AGE:"
age = gets
value.each do |data|
#puts id
val = redis.hgetall(data)
val.each do |key, value|
if key == "AGE" && value == age
puts redis.hgetall(data)
else
puts "NO"
end
end
end
end
Problem:
I am able to get the output if I hard coded AGE but if I get the user input it just goes to the else section.

Try using .to_i in the line you check for AGE key, like:
if key == "AGE" && value.to_i == age.to_i
Also, the second value variable shadows outer value variable.
Better to change value = redis.keys('*') to something like,
keys = redis.keys('*')

Related

Converting Ruby Hash into string with escapes

I have a Hash which needs to be converted in a String with escaped characters.
{name: "fakename"}
and should end up like this:
'name:\'fakename\'
I don't know how this type of string is called. Maybe there is an already existing method, which I simply don't know...
At the end I would do something like this:
name = {name: "fakename"}
metadata = {}
metadata['foo'] = 'bar'
"#{name} AND #{metadata}"
which ends up in that:
'name:\'fakename\' AND metadata[\'foo\']:\'bar\''
Context: This query a requirement to search Stripe API: https://stripe.com/docs/api/customers/search
If possible I would use Stripe's gem.
In case you can't use it, this piece of code extracted from the gem should help you encode the query parameters.
require 'cgi'
# Copied from here: https://github.com/stripe/stripe-ruby/blob/a06b1477e7c28f299222de454fa387e53bfd2c66/lib/stripe/util.rb
class Util
def self.flatten_params(params, parent_key = nil)
result = []
# do not sort the final output because arrays (and arrays of hashes
# especially) can be order sensitive, but do sort incoming parameters
params.each do |key, value|
calculated_key = parent_key ? "#{parent_key}[#{key}]" : key.to_s
if value.is_a?(Hash)
result += flatten_params(value, calculated_key)
elsif value.is_a?(Array)
result += flatten_params_array(value, calculated_key)
else
result << [calculated_key, value]
end
end
result
end
def self.flatten_params_array(value, calculated_key)
result = []
value.each_with_index do |elem, i|
if elem.is_a?(Hash)
result += flatten_params(elem, "#{calculated_key}[#{i}]")
elsif elem.is_a?(Array)
result += flatten_params_array(elem, calculated_key)
else
result << ["#{calculated_key}[#{i}]", elem]
end
end
result
end
def self.url_encode(key)
CGI.escape(key.to_s).
# Don't use strict form encoding by changing the square bracket control
# characters back to their literals. This is fine by the server, and
# makes these parameter strings easier to read.
gsub("%5B", "[").gsub("%5D", "]")
end
end
params = { name: 'fakename', metadata: { foo: 'bar' } }
Util.flatten_params(params).map { |k, v| "#{Util.url_encode(k)}=#{Util.url_encode(v)}" }.join("&")
I use it now with that string, which works... Quite straigt forward:
"email:\'#{email}\'"
email = "test#test.com"
key = "foo"
value = "bar"
["email:\'#{email}\'", "metadata[\'#{key}\']:\'#{value}\'"].join(" AND ")
=> "email:'test#test.com' AND metadata['foo']:'bar'"
which is accepted by Stripe API

Why is this string value converted to an array?

I have the following function:
def parse_var(var)
value = instance_variable_get(var)
puts(value)
puts(value.to_s)
value.is_a?(Numeric) ? value.to_s : "\"#{value}\""
end
Variables of certain form are converted into an array when they are interpolated. In the above function, when value equals (684) 029-6183 x01024, value.to_s comes out to be ["(684) 029-6183 x01024", nil]. The same thing also happens when I try "#{value}".
What is causing this?
Here's the context of the code in question:
Entity.rb (context of above code)
require 'securerandom'
# Entity.rb
class Entity
def initialize
generate_uuid
end
def to_cypher
first_char = self.class.name.chr.downcase
"MERGE (#{first_char}:#{self.class.name} {#{attrs_to_cypher.join(', ')}}) RETURN #{first_char};"
end
protected
def rand_bool
[true, false].sample
end
private
def attrs_to_cypher
self.instance_variables.map do |var|
"#{camelize(var.to_s[1..-1])}:#{parse_var(var)}"
end
end
def generate_uuid
#uuid = SecureRandom.uuid
end
def parse_var(var)
value = instance_variable_get(var)
puts(value)
puts(value.to_s)
value.is_a?(Numeric) ? value.to_s : "\"#{value}\""
end
def camelize(s)
(s == "uuid") ? "UUID" : s.downcase.split('_').map(&:capitalize).join
end
end
PhoneNumber.rb (where the value is coming from)
require 'faker'
require_relative 'Entity'
# PhoneNumber.rb
class PhoneNumber < Entity
def initialize(**opts)
super()
#type = opts[:type] || rand_bool ? "cell" : "home"
#number = opts[:number] || #type == "cell" ? Faker::PhoneNumber.cell_phone : Faker::PhoneNumber.phone_number,
#country_code = opts[:country_code] || nil
#area_code = opts[:area_code] || nil
end
end
The following line of code is causing a couple of issues
#number = opts[:number] || #type == "cell" ? Faker::PhoneNumber.cell_phone : Faker::PhoneNumber.phone_number,
First, the || operator has a higher precedence than the ? operator, so it actually looks like:
#number = (opts[:number] || #type == "cell") ? Faker::PhoneNumber.cell_phone : Faker::PhoneNumber.phone_number,
and you probably were wanting this:
#number = opts[:number] || (#type == "cell" ? Faker::PhoneNumber.cell_phone : Faker::PhoneNumber.phone_number),
As it stands, it doesn't matter what you pass into opts[:number], you'll always get a Faker::PhoneNumber assigned. (The line above, assigning type, looks like it would have this same precedence issue)
Second, you have a stray comma at the end of the line. This is turning the entire line into the first element of an array, and doesn't interfere with assigning the variable on the next line, so it's hard to catch:
opts = { number: '123' }
type = "cell"
number = opts[:number] || type == "cell" ? "truthy" : "falsey",
country = "some value"
p number # => ["truthy", "some value"]
p country # => "some value"
Your variable contains ["(684) 029-6183 x01024", nil], not a string. You rely on puts(value) output to determine it’s value which is plain wrong:
puts ["(684) 029-6183 x01024", nil]
#⇒ (684) 029-6183 x01024
#
puts(nil) returns an empty string, making you think the original value is a string.
To overcome this issue you might:
value = [*value].compact.join

I can't interpolate my hash because apparently it is nil class? Could anyone shed some light on this?

Is there an alternative to iteration or a condition I can make that will allow me to interpolate the values of just one hash? I've inspected the results of my input and apparently the array that i'm saving my hashes into disappears when there is only one hash. I've also tested the results and they're of Nil class.
def print_with_index(students)
students.each_with_index do |student, index|
index_plus_one = index + 1
puts "#{index_plus_one}. #{students[:name]} (#{students[:cohort]} cohort)"
end
end
How do i solve my problem and also why do hashes behave this way?
Full code:
def print_header
puts "The students of Villains Academy"
puts "--------------"
end
def print_footer(names)
puts "Overall, we have #{names.count} great students"
end
def input_students
puts "Please enter the names and then the cohort of the students"
puts "To finish, just hit return twice"
#created an empty array
students = []
#getting the first name
name = gets.chomp
cohort = gets.chomp.to_sym
if cohort.empty?
cohort = :november
end
if cohort !~ /january|february|march|april|may|june|july|august|september|october|november|december/
puts "Please enter a valid month"
puts "Warning months are case sensitive. Please enter in lowercase characters."
cohort = gets.chomp.to_sym
end
while !name.empty? do
# add the student hash to the array called students
students << {name: name, cohort: cohort}
if students.count > 1
puts "Now we have #{students.count} students"
else students.count == 1
puts "Now we have #{students.count} student"
end
#getting another name from the user
name = gets.chomp
cohort = gets.chomp.to_sym
if cohort.empty?
cohort = :november
end
if cohort !~ /january|february|march|april|may|june|july|august|september|october|november|december/
puts "Please enter a valid month"
puts "Warning months are case sensitive. Please enter in lowercase characters."
cohort = gets.chomp.to_sym
end
end
bycohort = students.sort_by { |v| v[:cohort] }
filter = students.select! { |student| student[:cohort] == :november }
puts bycohort #This allows me to see all of my hashes before they are filtered
puts ""
bycohort
filter
end
def print_with_index(students)
students.each_with_index do |students, index|
index_plus_one = index + 1
puts "#{index_plus_one}. #{students[:name]} (#{students[:cohort]} cohort)"
end
end
### body ###
students = input_students
print_header
print_with_index(students)
print_footer(students)
this works for me though, i think with each_with_index enum, you have to pass in an array of hashes i.e. [{...}, {...}, {...}], not a single hash with multiple keys-values
def print_with_index(students)
students.each_with_index do |students, index|
index_plus_one = index + 1
puts "#{index_plus_one}. #{students[:name]} (#{students[:cohort]} cohort)"
end
end
print_with_index([{name:"b", cohort: "c"}])
# 1. b (c cohort)
You should use student instead of students as the block parameter. You can check if the student object is nil.
def print_with_index(students)
students.each_with_index do |student, index|
if !student.nil?
index_plus_one = index + 1
puts "#{index_plus_one}. #{student[:name]} (#{student[:cohort]} cohort)"
end
end
end

Student Marks Hash

I've seen solutions posted in other languages but not Ruby so I'm asking here.
I'm trying to create a student marks system using Ruby, this should take the student’s name and two marks from the user for that particular student.
I decided to try and store these in a hash so it would end up looking something like:
student_marks = {
"Steve" => 45, 65,
"James" => 20, 75,
"Scott" => 30, 90
}
My code attempt is as follows:
continue = "y"
student_grades = Hash.new
while continue == "y"
puts "Please enter student name"
name = gets.chomp
puts "Please enter the first grade for #{name}"
grade_one = gets.chomp.to_i
puts "Please enter the second grade for #{name}"
grade_two = gets.chomp.to_i
student_grades.each do |key, value|
student_grades[key] = name
student_grades[value] = grade_one
student_grades[value][1] = grade_two
end
puts "Do you want to continue? y or n"
continue = gets.chomp
end
puts student_grades
Obviously there is a problem with my logic in trying to populate the hash using each/iteration because I keep getting nil return. I guess I could use arrays and populate the hash from them, but is there a way to populate the hash both the keys and values using iteration from user input?
You seem to be misunderstanding how hashes work in Ruby. I would suggest reading up on it a bit.
In the meantime, try this:
student_grades = Hash.new {|h,k| h[k] = [] }
Now every time you get a student grade, you can push it into the array value for that student's hash key.
For example:
student_grades
=> {}
student_grades['Mark'] << 95
student_grades['Mark'] << 86
student_grades
=> {'Mark' => [95, 86]}
You don't need to iterate over the hash at all in each run of your loop, you should only be doing that if you need to extract some information from it.

Ruby returning from inside a method but outside a loop

Try running this code.
When method1 is run, the hash is returned twice, meaning the hash is returned and printed as intended by the 'puts method1().inspect' command.
When method2 is run, and the loop is exited second time-around, by typing "no" or "n", a bunch of seemingly random numbers are printed, instead of a lovely hash. Why is this????
def method1
loop do
print "Item name: "
item_name = gets.chomp
print "How much? "
quantity = gets.chomp.to_i
hash = {"Item"=> item_name, "quantity"=> quantity}
puts hash.inspect
return hash
end
end
puts method1().inspect
def method2
loop do
print "Item name: "
item_name = gets.chomp
print "How much? "
quantity = gets.chomp.to_i
hash = {"Item"=> item_name, "quantity"=> quantity}
puts hash.inspect
print "Add another item? "
answer = gets.chomp.downcase
break if (answer == "no") || (answer == "n")
end
return hash
end
puts method2().inspect
You've accidentally discovered the Object#hash method. You don't declare hash outside the loop, so it is not in scope to return at the end. Instead, it returns the hash() method value, which is a big negative number for that instance.
Fire up irb, and just type hash, you'll see the same thing:
(505)⚡️ irb
2.1.2 :001 > hash
=> -603961634927157790
So instead, try this:
def method2
hash = {}
loop do
# ...
Also be aware you aren't adding to the hash, you're re-creating it every time.
In method2, you're trying to return something (hash) that has gone out of scope.
In method1, you're still inside the loop where hash was defined when you return it. In method2, you're outside of the scope where hash was defined, so it has an undocumented outcome. Redefined method2 like so:
def method2
hash = nil
loop do
print "Item name: "
item_name = gets.chomp
print "How much? "
quantity = gets.chomp.to_i
hash = {"Item"=> item_name, "quantity"=> quantity}
puts hash.inspect
print "Add another item? "
answer = gets.chomp.downcase
break if (answer == "no") || (answer == "n")
end
return hash
end
Now, even though hash was initially set to nil, its scope includes the entire method, and the value will be retained.

Resources