So this may seem odd, and I have done quite a bit of googling, however, I am not really a programmer, (sysops) and trying to figure out how to pass data to the AWS API in the required format, which does seem a little odd.
So, working with resources in AWS, I need to pass tags which are keys and values. The key is a string. The value is a comma separated string, in the first element of an array. So in Ruby terms, looks like this.
{env => ["stage,qa,dev"]}
and not
{env => ["stage","qa","dev"]}
I'm created an admittedly. not a very pretty little app that will allow me to run ssm documents on targeted instances in aws.
I can get the string into an array element using this class I created
class Tags
attr_accessor :tags
def initialize
#tags = {"env" => nil ,"os" => nil ,"group" => nil }
end
def set_values()
puts "please enter value/s for the following keys, using spaces or commas for multiple values"
#tags.each { |key,value|
print "enter #{key} value/s: "
#tags[key] = [gets.strip.chomp]
#tags[key] = Validate.multi_value(tags[key])
}
end
end
I then call this Validate.multi_value passing in the created Array, but it spits an array of my string value back.
class Validate
def self.multi_value(value)
if value.any?{ |sub_string| sub_string.include?(",") || sub_string.include?(" ") }
value = value[0].split(/[,\s]+/)
return value
else
return value
end
end
end
Using pry, I've seen it gets for example ["stage dev qa"] then the if statement does work, then it spits out ["stage","dev","qa"].
and I need it to output ["stage,dev,qa"] but for the life of me, I can't make it work.
I hope that's clear.
If you have any suggestions, I'd be most grateful.
I'm not hugely experienced at ruby and the may be class methods that I've missed.
If your arrays are always coming through in the format ["stage dev qa"] then first we need to split the one string into the parts we want:
arr = ["stage dev qa"]
arr.split(' ')
=> ["stage", "dev", "qa"]
Then we need to join them with the comma:
arr.split(' ').join(',')
=> "stage,dev,qa"
And finally we need to wrap it in an array:
[arr.first.split(' ').join(',')]
=> ["stage,dev,qa"]
All together:
def transform_array(arr)
[arr.first.split(' ').join(',')]
end
transform_array(['stage dev qa'])
=> ['stage,dev,qa']
More info: How do I convert an array of strings into a comma-separated string?
I see no point in creating a class here when a simple method would do.
def set_values
["env", "os", "group"].map do |tag|
puts "Please enter values for #{tag}, using spaces or commas"
print "to separate multiple values: "
gets.strip.gsub(/[ ,]+/, ',')
end
end
Suppose, when asked, the user enters, "stage dev,qa" (for"env"), "OS X" (for"OS") and "Hell's Angels" for "group". Then:
set_values
#=> ["stage,dev,qa", "OS,X", "Hell's,Angels"]
If, as I suspect, you only wish to convert spaces to commas for "env" and not for "os" or "group", write:
def set_values
puts "Please enter values for env, using spaces or commas"
print "to separate multiple values: "
[gets.strip.gsub(/[ ,]+/, ',')] +
["os", "group"].map do |tag|
print "Please enter value for #{tag}: "
gets.strip
end
end
set_values
#=> ["stage,dev,ga", "OS X", "Hell's Angels"]
See Array#map, String#gsub and Array#+.
gets.strip.gsub(/[ ,]+/, ',') merely chains the two operations s = gets.strip and s.gsub(/[ ,]+/, ','). Chaining is commonplace in Ruby.
The regular expression used by gsub reads, "match one or more spaces or commas", [ ,] being a character class, requiring one of the characters in the class be matched, + meaning that one or more of those spaces or commas are to be matched. If the string were "a , b,, c" there would be two matches, " , " and ",, "; gsub would convert both to a single comma.
Using print rather than puts displays the user's entry on the same line as the prompt, immediately after ": ", rather than on the next line. That is of course purely stylistic.
Often one would write gets.chomp rather than gets.strip. Both remove newlines and other whitespace at the end of the string, strip also removes any whitespace at the beginning of the string. strip is probably best in this case.
What do you think about this?, everything gets treated in the Validates method. I don't know if you wanted to remove repeated values, but, just in case I did, so a
"this string,, has too many,,, , spaces"
will become
"this,string,has,too,many,spaces"
and not
"this,,,,string,,,has,too,,many,,,,,,spaces"
Here's the code
class Tags
attr_accessor :tags
# initializes the class (no change)
#
def initialize
#tags = {"env" => nil ,"os" => nil ,"group" => nil }
end
# request and assign the values <- SOME CHANGES
#
def set_values
puts "please enter value/s for the following keys, using spaces or commas for multiple values"
#tags.each do |key,value|
print "enter #{key} value/s: "
#tags[key] = Validate.multi_value( gets )
end
end
end
class Validate
# Sets the array
#
def self.multi_value(value)
# Remove leading spaces, then remove special chars,
# replace all spaces with commas, then remove repetitions
#
[ value.strip.delete("\n","\r","\t","\rn").gsub(" ", ",").squeeze(",") ]
end
end
EDITED, thanks lacostenycoder
I have a list of Unicode character codes that I would like to output with rumoji. Here's the code I'm using to iterate over my data.
require "rumoji"
# this works
puts Rumoji.decode("\u{1F600}")
# feed some data
data = [
"1F600",
"1F476",
"1F474"
]
data.each do |line|
# this doesn't work
puts Rumoji.decode("\u{#{line}}")
puts Rumoji.decode("\u{" + line + "}")
end
I'm not sure how I can use variable names inside the escaped string.
One can not use \u along with string interpolation, since \u takes precedence. What one might do, is to Array#pack an array of integers:
โถ data.map { |e| e.to_i(16) }.pack 'U*'
#โ "๐๐ถ๐ด"
Can someone explain why eval is returning the string, rather than the result of the expression?
perms=["12+2","22","-2+"]
perms.each { |line|
matches=/^[\d]+[+-\/\*]{1}[\d]+$/.match(line)
s=matches.to_a
puts s
puts eval(s.to_s)
}
s = matches.to_a is an array ["12+2"], the eval(s.to_s) will return the array ["12+2"], and when you print it, you will get the output 12+2, a string representation of the array ["12+2"].
You should be evaling the element of the array, in this case, s[0] or s.first.
Fix it like this:
perms=["12+2","22","-2+"]
perms.each do |line|
matches=/^[\d]+[+-\/\*]{1}[\d]+$/.match(line)
if matches
s = matches.to_a
puts eval(s.first)
end
end
matches can be nil if there was no match. Use eval only if its not nil by checking if matches
You could further simplify the code and write something like this:
perms=["12+2","22","-2+"]
perms.each do |line|
puts eval(line) if line =~ /^[\d]+[+-\/\*]{1}[\d]+$/
end
Instead of iterating through inputs, one might directly map them to outputs:
perms.map do |p| # map inputs to outputs
eval(p) if p =~ /\A\d+[+-\/*]\d+\z/ # return evalโed or nil
end.compact # get rid of nils
#โ [14]
I have many strings following a certain pattern:
string = "Hello, #name. You did #thing." # example
Basically, my strings are a description where #word is dynamically. I need to replace each with a value at runtime.
string = "Hello, #{#name}. You did #{#thing}." # Is not an option!
The #word is basically a variable, but I just cannot use the method above.
How should I do that?
Instead doing search/replace, you can use Kernel#sprintf method, or its % shorthand. Combined with Hashes, it can come pretty handy:
'Hello, %{who}. You did %{what}' % {:who => 'Sal', :what => 'wrong'}
# => "Hello, Sal. You did wrong"
The advantage of using Hash instead of Array is that you don't have to worry about the ordering, and you can have the same value inserted on multiple places in the string.
You can format your string with placeholders that can be switched out dynamically using String's % operator.
string = "Hello, %s. You did %s"
puts string % ["Tony", "something awesome"]
puts string % ["Ronald", "nothing"]
#=> 'Hello, Tony. You did something awesome'
#=> 'Hello, Ronald. You did nothing'
Possible use case: Let's say you were writing a script that would be taking the name and action in as parameters.
puts "Hello, %s. You did %s" % ARGV
Assuming 'tony' and 'nothing' were the first two parameters, you would get 'Hello, Tony. You did nothing'.