Joining array of strings into a quoted comma-separated list - arrays

If I have a array of strings like so:
arr = ["one", "two", "three"]
How would I convert it into a backtick-quoted comma-separated string like so:
"`one`, `two`, `three`"
I have accomplished it using three calls like so:
arr = arr.join "`, `"
arr = arr.prepend "`"
arr = arr += "`"
but I was wondering if there was a cleaner way to achieve this or if there was a better function to use besides join. Preferably a one liner.

I would use map and join:
arr = ["one", "two", "three"]
arr
.map { |e| "`#{e}`" }
.join(', ')
You could even put it on a single line:
arr.map { |e| "`#{e}`" }.join(', ')
Now, I'm not entirely sure of this, but it looks like you might be using this to perhaps quote parameters for an SQL query? If you are, then please don't do it like this, but use a proper SQL escaping function or parameterized queries.
In response to the confirmation that you're using this for an SQL query, a better way would be to use (assuming you're using sqlite3-ruby):
db = SQLite3::Database.new 'my_database.sqlite3'
arr = ["one", "two", "three"]
db.execute('select * from foo where a=? and b=? and c=?', arr) do |row|
p row
end
This will make sure it always works. Adding backticks may seem like a good idea at first, but:
There are ways to work around this and do an SQL injection attack. This is bad and allows anyone to read or destroy data.
Even if it's just for personal use, it's good to do it the "proper way", since sooner or later you'll run into the problem that your data has a ` or some other special character you didn't think of, at which point your program breaks.

Related

How to find which element failed comparison between arrays in Kotlin?

I'm writing automated tests for one site. There's a page with all items added to the cart. Maximum items is 58. Instead of verification of each element one by one I decided to create 2 arrays filled with strings: 1 with correct names : String and 1 with names : String I got from the site. Then I compare those 2 arrays with contentEquals.
If that comparison fails, how do I know which element exactly caused comparison fail?
Short simple of what I have now:
#Test
fun verifyNamesOfAddedItems () {
val getAllElementsNames = arrayOf(materials.text, element2.text,
element3.text...)
val correctElementsNames = arrayOf("name1", "name2", "name3"...)
val areArraysEqual = getAllElementsNames contentEquals correctElementsNames
if (!areArraysEqual) {
assert(false)
} else {
assert(true)
}
}
This test fails if 2 arrays are not the same but it doesn't show me the details, so is there a way to see more details of fail, e.g. element that failed comparison?
Thanks.
I recommend using a matcher library like Hamcrest or AssertJ in tests. They provide much better error messages for cases like this. In this case with Hamcrest it would be:
import org.hamcrest.Matchers.*
assertThat(getAllElementsNames, contains(*correctElementsNames))
// or just
assertThat(getAllElementsNames, contains("name1", "name2", "name3", ...))
There are also matcher libraries made specifically for Kotlin: https://github.com/kotlintest/kotlintest, https://yobriefca.se/expect.kt/, https://github.com/winterbe/expekt, https://github.com/MarkusAmshove/Kluent, probably more. Tests using them should be even more readable, but I haven't tried any of them. Look at their documentation and examples and pick the one you like.
You need to find the intersection between the two collections. Intersection will be the common elements. After than removing the intersection collection from the collection you want to perform the test will give you the complementary elements.
val intersection = getAllElementsNames.intersect(correctElementsNames)
getAllElementsNames.removeAll(intersection)

Include a regex string in an array

I have an array made up of several strings that I am searching for in another array, like so:
strings_array = ["string1", "string2", "string3"]
main_array = [ ## this is populated with string values outside of my script ## ]
main_array.each { |item|
if strings_array.any? { |x| main_array.include?(x) }
main_array.delete(item)
end
}
This is a simplified version of what my script is actually doing, but that's the gist. It works as is, but I'm wondering how I can make it so that the strings_array can include strings made out of regex. So let's say I have a string in the main_array called "string-4385", and I want to delete any string that is composed of string- + a series of integers (without manually adding in the numerical suffix). I tried this:
strings_array = ["string1", "string2", "string3", /string-\d+/.to_s]
This doesn't work, but that's the logic I'm aiming for. Basically, is there a way to include a string with regex like this within an array? Or is there perhaps a better way than this .any? and include? combo that does the job (without needing to type out the complete string value)?
Thank you for any help!
You can use methods like keep_if and delete_if, so if you want to delete strings that match a regex you could do something like this:
array = ['string-123', 'test']
array.delete_if{|n| n[/string-\d+/] }
That will delete the strings in the array that do not match your regex. Same thing with keep_if method.
Hope it helps!
A good way to do this is with Regexp.union, which combines multiple regular expressions into a single regex handy for matching.
patterns = [/pattern1/, /pattern2/, /string-\d+/]
regex = Regexp.union(patterns)
main_array.delete_if{|string| string.match(regex)}

using ruby to extract the values in a hash in a DRY way

My app passes to different methods a json_element for which the keys are different, and sometimes empty.
To handle it, I have been hard-coding the extraction with the following sample code:
def act_on_ruby_tag(json_element)
begin
# logger.progname = __method__
logger.debug json_element
code = json_element['CODE']['$'] unless json_element['CODE'].nil?
predicate = json_element['PREDICATE']['$'] unless json_element['PREDICATE'].nil?
replace = json_element['REPLACE-KEY']['$'] unless json_element['REPLACE-KEY'].nil?
hash = json_element['HASH']['$'] unless json_element['HASH'].nil?
I would like to eliminate hardcoding the values, and not quite sure how.
I started to think through it as follows:
keys = json_element.keys
keys.each do |k|
set_key = k.downcase
instance_variable_set("#" + set_key, json_element[k]['$']) unless json_element[k].nil?
end
And then use #code for example in the rest of the method.
I was going to try to turn into a method and then replace all this hardcoded code.
But I wasn't entirely sure if this is a good path.
It's almost always better to return a hash structure from a method where you have things like { code: ... } rather than setting arbitrary instance variables. If you return them in a consistent container, it's easier for callers to deal with delivering that to the right location, storing it for later, or picking out what they want and discarding the rest.
It's also a good idea to try and break up one big, clunky step with a series of smaller, lighter operations. This makes the code a lot easier to follow:
def extract(json)
json.reject do |k, v|
v.nil?
end.map do |k, v|
[ k.downcase, v['$'] ]
end.to_h
end
Then you get this:
extract(
'TEST' => { '$' => 'value' },
'CODE' => { '$' => 'code' },
'NULL' => nil
)
# => {"test"=>"value", "code"=>"code"}
If you want to persist this whole thing as an instance variable, that's a fairly typical pattern, but it will have a predictable name that's not at the mercy of whatever arbitrary JSON document you're consuming.
An alternative is to hard-code the keys in a constant like:
KEYS = %w[ CODE PREDICATE ... ]
Then use that instead, or one step further, define that in a YAML or JSON file you can read-in for configuration purposes. It really depends on how often these will change, and what sort of expectations you have about the irregularity of the input.
This is a slightly more terse way to do what your original code does.
code, predicate, replace, hash = json_element.values_at *%w{
CODE PREDICATE REPLACE-KEY HASH
}.map { |x| x.fetch("$", nil) if x }

Passing Ruby array elements to a method

I'm not a programmer, but I find myself writing some simple ruby and aren't sure about a few things.
I have the following function
def resolve_name(ns_name)
ip = Resolv.getaddress(ns_name)
return ip
end
and the array
array = ['ns-1.me.com', 'ns-2.me.com']
What I want to do is to pass every element in the array to the function to be evaluated, and spit out to... something. Probably a variable. Once I have the resolved IPs I'll be passing them to an erb template. Not quite sure yet how to handle when there may be 1 to 4 possible results either.
What I want think I need to do is do an each.do and typecast to string into my function, but I haven't been able to figure out how to actually do that or phrase my problem properly for google to tell me.
http://ruby-doc.org/core-2.0.0/doc/syntax/calling_methods_rdoc.html#label-Array+to+Arguments+Conversion Doesn't quite have what I'm looking for.
irb(main):010:0> resolved = resolve_name(array)
TypeError: no implicit conversion of Array into String
Any suggestions?
Take a look at the documentation for ruby's Enumerable, which arrays implement. What you're looking for is the map method, which takes each element of an enumerable (i.e. an array) and passes it to a block, returning a new array with the results of the blocks. Like this:
array.map{|element| resolve_name(element) }
As an aside, in your method, you do not need to use a local variable if all you're doing with it is returning its value; and the return statement is optional - ruby methods always return the result of the last executed statement. So your method could be shortened to this:
def resolve_name(ns_name)
Resolv.getaddress(ns_name)
end
and then you really all it's doing is wrapping a method call in another. So ultimately, you can just do this (with array renamed to ns_names to make it self-explanatory):
ns_names = ['ns-1.me.com', 'ns-2.me.com']
ip_addresses = ns_names.map{|name| Resolv.getaddress(name) }
Now ip_addresses is an array of IP addresses that you can use in your template.
If you pass an array you could do:
def resolve_name(ns_name)
res = []
ns_name.each do |n|
res << {name: n, ip: Resolv.getaddress(name) }
end
res
end
And get an array of hashes so you know which address has which ip

Check if each string from array is contained by another string array

Sorry I'am new on Ruby (just a Java programmer), I have two string arrays:
Array with file paths.
Array with patterns (can be a path or a file)
I need to check each patter over each "file path". I do with this way:
#flag = false
["aa/bb/cc/file1.txt","aa/bb/cc/file2.txt","aa/bb/dd/file3.txt"].each do |source|
["bb/cc/","zz/xx/ee"].each do |to_check|
if source.include?(to_check)
#flag = true
end
end
end
puts #flag
This code is ok, prints "true" because "bb/cc" is in source.
I have seen several posts but can not find a better way. I'm sure there should be functions that allow me to do this in fewer lines.
Is this is possible?
As mentioned by #dodecaphonic use Enumerable#any?. Something like this:
paths.any? { |s| patterns.any? { |p| s[p] } }
where paths and patterns are arrays as defined by the OP.
While that will work, that's going to have geometric scaling problems, that is it has to do N*M tests for a list of N files versus M patterns. You can optimize this a little:
files = ["aa/bb/cc/file1.txt","aa/bb/cc/file2.txt","aa/bb/dd/file3.txt"]
# Create a pattern that matches all desired substrings
pattern = Regexp.union(["bb/cc/","zz/xx/ee"])
# Test until one of them hits, returns true if any matches, false otherwise
files.any? do |file|
file.match(pattern)
end
You can wrap that up in a method if you want. Keep in mind that if the pattern list doesn't change you might want to create that once and keep it around instead of constantly re-generating it.

Resources