No implicit conversion of Hash into String (Ruby) - ruby

When someone types "!disconnect", I want the bot to disconnect, using the response "PART ##{CHANNEL}".
The snippet below is not the full code, but there are end statements and everything.
CHANNEL = "SomeChannelHere"
prefix = "!"
message = "!disconnect"
commands = [
"disconnect" => "PART ##{CHANNEL}"]
commands.each do |command|
if message.include?(prefix + command)
response = commands[command]
How do I get the response?

Your commands is currently an array of hashes:
commands = ["disconnect" => "PART ##{CHANNEL}"]
#=> [{"disconnect"=>"PART #SomeChannelHere"}]
You have to use { ... } instead of [ ... ]:
commands = {"disconnect" => "PART ##{CHANNEL}"}
#=> {"disconnect"=>"PART #SomeChannelHere"}
Furthermore, the each block expects two arguments (key and value):
commands.each do |command, response|
# ...
end

You are missing the key of the hash:
commands.each do |command|
p command["disconnect"]
p command.has_key?("disconnect")
end

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

Can't create a hash inside a method

When I run this method that creates a hash of a letter counter, it runs fine
def letter_count(str)
ashh = Hash.new
str.each_char do |x|
if x != " "
ashh["#{x}"] = str.count(x)
end
end
return ashh
end
However, when I create a method that uses a hash to convert a string into morse code it wouldn't let me create the hash inside the method i have to put it outside. Why am i able to do so for the first method but not the second?
def morse_encode(str)
arrWords = str.split
Morse = {
"a" => ".-",
"b" => "-...",
"c" => "-.-.",
"q" =>"--.-",
"t" => "-",
"i" => "..",
"h" => "....",
"n" => "-."
}
output = []
word = ""
arrWords.each do |x|
word = []
currentWord = x.split("")
currentWord.each do |y|
word.push(MorseHash[y].to_s)
end
output.push(word.join(" "))
end
return output.join(" ")
end
The second code does not run unless i move the hash outside the function.
Morse is treated as a class, try changing it to any other valid form of hash definition,
you can do
morse = Hash.new
morse = {}
Hope this helps.

Gsub in-place not working

I have this code:
Firm.all.each do |firm|
url = firm.site
doc = Nokogiri::HTML(open(url))
data = doc.css("##{firm.menu_id} a")
data.each do |e|
e.text.strip!
e.text.gsub!(/[\n\t]*/,'')
puts e.text
end
end
The strings are being displayed in the same format as the input (that means, the gsub! method is not affecting the string). I think that e.text can be immutable, but I'd like to ensure that.
The text method returns a new String each time, which can be seen using object_id:
e = Nokogiri::XML('<a>text</a>')
e.text.object_id == e.text.object_id # => false
If you want to modify the node's text, set the content:
e.at_css('a').content = "foo"
e.text # => "foo"

Array iteration in Ruby

I am trying to iterate through an array in Ruby. I using eachmethod but getting the following error message: NoMethodError: undefined method ``each' for "1, 2":String.
I am using jruby-1.6.7. Not sure if that is the problem.
Here is the code:
#!/usr/bin/ruby
puts "Select one of these.\n1. ABC\n2. DEF\n3. GHI\n"
schemas = gets.chomp
len = schemas.size
puts schemas.split(",")
puts schemas[0..len]
schemas.each {|x| puts x}
I need some guidance with iterating through a simple array in Ruby?
Thanks.
You were on the right track:
schemas = gets.chomp
# => "1, 2"
# save the result of split into an array
arr = schemas.split(",")
# => [1, 2]
# loop the array
arr.each { |schema| puts schema }
# => 1
# => 2
You can also do this in one line, though the array won't get saved anywhere.
schemas = gets.chomp
schemas.split(",").each { |schema| puts schema }
# => 1
# => 2
You have the right idea, however you are calling the Array#each method on a String.
schemas = gets.chomp
puts schemas.split(",")
It's true that the String#split method converts a string to an array, however you never actually converted the data type. schemas is still recognized as a string.
What you could do is
schemas = schemas.split(",")
Then
schemas.each{|x| puts x}

Ruby: OptionParser: String Arg & Hash Assignment

Using OptionParser for string argument input and hash assignment. What is the best way to read-in multiple variables for a single argument? How do I then assign those to a hash to reference? Here is what I have so far:
large_skus = Hash.new
small_skus = Hash.new
OptionParser.new do |opts|
opts.on("-b", "--brands bName1,bName2,bNameN", String, "Check specific brands by name") do |b|
options[:brands] = b.split(",")
end
opts.on("-l", "--large lSku1,lSku2,lSkuN", String, "Large SKUs - List CSVs") do |l|
options[:large_skus] = l.split(",")
##For each sku given
brandName = options[:brands]
large_skus[brandName] = l[$sku].to_i
##
end
opts.on("-s", "--small sSku1,sSku2,sSkuN", String, "Small SKUs - List CSVs") do |s|
options[:small_skus] = s.split(",")
##For each sku given
brandName = options[:brands]
small_skus[brandName] = s[$sku].to_i
##
end
end.parse!(ARGV)
Given an input of:
ruby test.rb --brands bName1,bName2,bNameN --large lSku1,lSku2,lSkuN --small wQueue1,wQueue2,wQueueN
This code
#!/usr/bin/env ruby
require 'ap'
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.on("-b", "--brands bName1,bName2,bNameN", Array, "Check specific brands by name") do |b|
options[:brands] = b
end
opts.on("-l", "--large lSku1,lSku2,lSkuN", Array, "Large SKUs - List CSVs") do |l|
options[:large_skus] = l
end
opts.on("-s", "--small wQueue1,wQueue2,wQueueN", Array, "Small SKUs - List CSVs") do |s|
options[:small_skus] = s
end
end.parse!(ARGV)
ap options
Produces this output:
{
:brands => [
[0] "bName1",
[1] "bName2",
[2] "bNameN"
],
:large_skus => [
[0] "lSku1",
[1] "lSku2",
[2] "lSkuN"
],
:small_skus => [
[0] "wQueue1",
[1] "wQueue2",
[2] "wQueueN"
]
}
Notice that instead of using types of String for each option, I'm using Array. That lets OptionParser do the heavy lifting of parsing the elements into an array. From that point it's up to you what you do with the array elements.
I think you are approaching this the wrong way. You want your users to have to keep track of the order of the parameters they input but you don't want to do it yourself in the code!
How about you don't ask anybody to keep track of what goes with what and make it explicit:
ruby test.rb --input bName1,lSku1,wQueue1 --input bName2,lSku2,wQueue2 --input bNameN,lSkuN,wQueueN
Code:
opts.on("--input <brand,Large_Skus,Small_Skus>", "input description",
"NOTE: Can be used more than once.") do |opt|
list = opt.split(',')
unless list.lenght == 3
raise "some error because you didn't place all arguments"
end
options[:input].push list
end
result:
[ [ 'bName1', 'lSku1', 'wQueue1' ],
[ 'bName2', 'lSku2', 'wQueue2' ],
[ 'bNameN', 'lSkuN', 'wQueueN' ] ]

Resources