Ruby joining error - ruby

I am trying to unpack some variables then have them joined when passed to the def this is what i'm trying, but it errors.
class Try
def test
#name = "bob"
#password = "password"
self.send(#name,#password)
end
def send(*data)
print data #prints orginal data
print ":".join(data) #errors
end
end
Is there something I'm doing wrong?

Here you should do as below using Array#join:
class Try
def test
#name = "bob"
#password = "password"
self.send(#name,#password)
end
def send(*data)
print data.join(":")
end
end
Try.new.test
# >> bob:password
The join is for Array instances. It is not a String instance method. See below:
Array.instance_methods.include?(:join) # => true
String.instance_methods.include?(:join) # => false

I think perhaps you are confusing the built-in function join of a Python string with the join method of the Ruby Array class.
From help(":".join) in Python:
Return a string which is the concatenation of the strings in the
iterable. The separator between elements is S.
And from the docs on Ruby's Array:
Returns a string created by converting each element of the array to a string,
separated by the given separator.
So you see, the Python join built-in function concatenates the strings of the given list argument, while in Ruby the Array#join method will convert the elements into their String equivalents, and then concatenate them using the separator argument.
Hope this clears up the confusion between Python's join and Ruby's Array#join!

Related

How best to get all the format sequence keys from a string in ruby?

When given a string that is intended to be formatted with a hash of values to write into the string, is there a clean way to get all the keys that string is expecting values for?
I'm putting together text in a situation where there is a lot of room for customization, and several options for dynamic values to insert into the text. Some of the values are more expensive to get than others, so I'd like to be able to prepare my hash to send in to % to only include the values that are needed in the string.
Ideally I'd be able to query the system that performs the formatting on the string, but I'm not seeing any documentation of such an interface. What I'd like is something like:
"Your request for %{item} is at position %<pos>d".formatting_keys
>>> [:item, :pos]
When passing a hash to String#%, it will call the hash's default proc if a key is missing. You could utilize this behavior and make the proc sneakily collect the passed keys:
def format_keys(format_string)
keys = []
format_string % Hash.new { |_, k| keys << k ; 0 }
keys
end
format_keys("Your request for %{item} is at position %<pos>d")
#=> [:item, :pos]
Note that the proc's return value has to be a valid object for the various field types. I'm using 0 here which seems to work fine.
I'd like to be able to prepare my hash to send in to % to only include the values that are needed in the string.
Instead of a Hash, use an object that does the calculation on demand. That will be useful everywhere.
Use string interpolation to call the methods instead of format sequences.
class Whatever
def item
#item ||= calculate_item
end
def pos
#pos ||= calculate_pos
end
private
def calculate_item
# do something expensive
end
def calculate_pos
# do something expensive
end
end
obj = Whatever.new
puts "Your request for #{obj.item} is at position #{obj.pos.to_i}"
Using Ruby's own sequence parsing as per https://stackoverflow.com/a/74728162 is ideal, but you can also do your own:
class String
def format_keys
scan(
/
(?<!%) # don't match escaped sequence starts, e.g. "%%{"
(?:
(?<=%\{) [^\}]+ (?=\}) # contents of %{...}
| # OR
(?<=%\<) [^\>]+ (?=\>) # contents of %<...>
)
/x
)
end
end

Ruby: how to concat two return values to two strings in one line

I am trying to concat two strings that are returned by a function to two existing strings in one line.
this is my code with extra steps
def my_function()
return "foo", "bar"
end
foo = String.new
bar = String.new
ret1, ret2 = my_function()
foo.concat(ret1)
bar.concat(ret2)
I am trying something like the following, but it is not working
foo.concat(ret1), bar.concat(ret2) = my_function()
some more information as requested:
I am basically trying to write a config converter. The config files need to be plain text files. To make the code more structured, i created the following module, and then call the module functions whenever i need to genereate a specific part of the config. After that, I write the return into a string, which is then written to a file once everything is done:
module L4_LB
extend self
def build_ssl(some_vars)
returns string_a, string_b
end
def build_vip(some_vars)
returns string_a, string_b
end
def build_pool(some_vars)
returns string_a, string_b
end
end
config_file_a = String.new
config_file_b = String.new
ret_a, ret_b = L4_LB.build_ssl(some_vars)
config_file_a.concat(ret_a)
config_file_a.concat(ret_b)
ret_a, ret_b = L4_LB.build_vip(some_vars)
config_file_a.concat(ret_a)
config_file_a.concat(ret_b)
ret_a, ret_b = L4_LB.build_pool(some_vars)
config_file_a.concat(ret_a)
config_file_a.concat(ret_b)
It depends on how concat is defined. If it accepts multiple arguments, you should be able to do:
config_file_a.concat(*L4_LB.build_pool(some_vars))
Note the * which ensures that each element in the array returned by build_pool is passed as an individual argument to concat.
On the other hand, if concat only accepts a single argument you can define a helper function:
def my_concat(what, values)
values.each do |element|
what.concat(element)
end
end
my_concat(config_file_a, L4_LB.build_pool(some_vars))
If you want the result to be concatenated to two different strings, you could use:
def my_concat2(cs, vs)
cs.each_with_index do |c, index|
c.concat(vs[index])
end
end
cs = [config_file_a, config_file_b]
my_concat2(cs, *L4_LB.build_ssl(some_vars))
my_concat2(cs, *L4_LB.build_vip(some_vars))
my_concat2(cs, *L4_LB.build_pool(some_vars))

Passing Hash values as parameters to methods in Ruby

I have a method met1 that takes hash values as parameters.
For example: met1('abc' => 'xyz')
What should be the syntax when I define the method? Can it be something like this?
def met1(options)
puts options
end
I know the above syntax works. But how can I access the individual hash key and value inside the met1? (where key is abc and value is xyz?) Thank you!
Thats easy
met1("abc" => "xyz")
def met1(options)
puts options
# with key
puts options["abc"]
end
I assume you know what the options might contain in terms of keys right? if not,
def met1(options)
puts options.keys # options is the hash you passed it, use it like one
end
Your syntax is correct. simply use options['key'] (in case 'key' is a string) in your method. It's customary to use symbols as keys, so in your example:
met1(:abc => 'xyz')
def met1(options)
puts options[:abc]
end

Passing original string PLUS matches when using gsub and block?

Rails fans are familiar with params[:terms] or a hash of 'things' passed to the controller collected form the url. E.g.:
params
=> {"term"=>"Warren Buffet",
"controller"=>"search",
"format"=>"json",
"action"=>"index"}
If I want to use "Warren Buffet", "Warren" and "Buffet" in the code below, does anyone know which method I should be using instead? gsub is close, but it takes each match and not the original string too. Unless I'm doing it wrong, which is totally possible:
#potential_investors = []
params[:term].gsub(/(\w{1,})/) do |term|
#potential_investors &lt&lt User.where(:investor => true)
.order('first_name ASC, last_name ASC')
.search_potential_investors(term)
end
Thoughts?
How about:
s = "Filthy Rich"
s.split(" ").push(s)
>> ["Filthy", "Rich", "Filthy Rich"]
Or with scan if you prefer to use the regexp instead:
s.scan(/\w+/).push(s)
>> ["Filthy", "Rich", "Filthy Rich"]
params["term"].gsub(/(\w{1,})/)
returns an enumerator. You could convert it to an array and append the original term to it:
ary = params["term"].gsub(/(\w{1,})/).to_a + [params["term"]]
then process it:
ary.each do |term|
...

How does one populate an array in Ruby?

Here is the code I'm working with:
class Trader
def initialize(ticker ="GLD")
#ticker = ticker
end
def yahoo_data(days=12)
require 'yahoofinance'
YahooFinance::get_historical_quotes_days( #ticker, days ) do |row|
puts "#{row.join(',')}" # this is where a solution is required
end
end
end
The yahoo_data method gets data from Yahoo Finance and puts the price history on the console. But instead of a simple puts that evaporates into the ether, how would you use the preceding code to populate an array that can be later manipulated as object.
Something along the lines of :
do |row| populate_an_array_method(row.join(',') end
If you don't give a block to get_historical_quotes_days, you'll get an array back. You can then use map on that to get an array of the results of join.
In general since ruby 1.8.7 most iterator methods will return an enumerable when they're called without a block. So if foo.bar {|x| puts x} would print the values 1,2,3 then enum = foo.bar will return an enumerable containing the values 1,2,3. And if you do arr = foo.bar.to_a, you'll get the array [1,2,3].
If have an iterator method, which does not do this (from some library perhaps, which does not adhere to this convention), you can use foo.enum_for(:bar) to get an enumerable which contains all the values yielded by bar.
So hypothetically, if get_historical_quotes_days did not already return an array, you could use YahooFinance.enum_for(:get_historical_quotes_days).map {|row| row.join(",") } to get what you want.

Resources