Ruby changes multiple variables but they shouldn't change - ruby

When I try to shorten an array with '' the output from all other variables is changing too
message = "bot.start"
seperator = message
command = seperator
command[0..3] = ''
message #=> "start"
The output should be "bot.start". Ruby should have a problem separating variables from each other. What is wrong?

In the current version Ruby, strings are mutable. That is, you can change an instance of a string.
In your example, message, command and separator are all different variables that point to the same string instance. When you do [0..3] = '', you are changing the string that all the variables point to.
If you need to make distinct instances, use dup to copy the string:
command = seperator.dup
Alternatively, don't modify the string and use APIs that return a new instance of a string:
command = seperator[4..-1]

When you execute line 4
command[0..3] = ''
You grabed bot. and changed to bot. => ''
That's why it returns''start which is start
https://repl.it/repls/BlushingThoughtfulOrigin

Related

Reformat string with `Regexp`, named captures, and `String#%`

Does anyone know a way to directly use a MatchData object containing named captures as the input to a String template formatting operation (%)? When I attempt to do so, I get a "positional args mixed with named args" error.
s = "One-Two-Three"
re = /(?<first>.*?)-(?<second>.*?)-(?<third>.*)/
puts "%{second}" % s.match(re)
I found other ways to achieve the functional objective (ie by creating an array of the captures in the desired order and using positional templating), but the code is comparatively klunky.
Try this:
s = "One-Two-Three"
re = /(?<first>.*?)-(?<second>.*?)-(?<third>.*)/
match = s.match(re)
[match.names.map(&:to_sym), match.captures].transpose.to_h
# => {:first=>"One", :second=>"Two", :third=>"Three"}
What about using string interpolation directly:
puts "#{s.match(re)['second']}"
For ruby < 2.0 you want to use Hash[]:
m = s.match re
Hash[m.names.map(&:to_sym).zip m.captures]
#=> {:first=>"One", :second=>"Two", :third=>"Three"}

Read string as variable RUBY

I am pulling the following string from a CSV file, from cell A1, and storing it as a variable:
#{collector_id}
So, cell A1 reads #{collector_id}, and my code essentially does this:
test = #excel_cell_A1
However, if I then do this:
puts test
I get this:
#{collector_id}
I need #{collector_id} to read as the actual variable collector_id, not the code that I am using to call the variable. Is that possible?
Thanks for the help. I am using ruby 1.9.3.
You can use sub or gsub to replace expected input values:
collector_id = "foo"
test = '#{collector_id}'
test.sub("\#{collector_id}", "#{collector_id}") #=> "foo"
I would avoid the use of eval (or at least sanity check what you are running) to reduce the risk of running arbitrary code you receive from the CSV file.
Try this:
test_to_s = eval("\"#{ test }\"")
puts test_to_s
%q["#{ test }"] will build the string "#{collector_id}" (the double quotes are part of the string, "#{collector_id}".length == 17) which then will be evaluated as ruby code by eval

Using Ruby to automate a large directory system

So I have the following little script to make a file setup for organizing reports that we get.
#This script is to create a file structure for our survey data
require 'fileutils'
f = File.open('CustomerList.txt') or die "Unable to open file..."
a = f.readlines
x = 0
while a[x] != nil
Customer = a[x]
FileUtils.mkdir_p(Customer + "/foo/bar/orders")
FileUtils.mkdir_p(Customer + "/foo/bar/employees")
FileUtils.mkdir_p(Customer + "/foo/bar/comments")
x += 1
end
Everything seems to work before the while, but I keep getting:
'mkdir': Invalid argument - Cust001_JohnJacobSmith(JJS) (Errno::EINVAL)
Which would be the first line from the CustomerList.txt. Do I need to do something to the array entry to be considered a string? Am I mismatching variable types or something?
Thanks in advance.
The following worked for me:
IO.foreach('CustomerList.txt') do |customer|
customer.chomp!
["orders", "employees", "comments"].each do |dir|
FileUtils.mkdir_p("#{customer}/foo/bar/#{dir}")
end
end
with data like so:
$ cat CustomerList.txt
Cust001_JohnJacobSmith(JJS)
Cust003_JohnJacobSmith(JJS)
Cust002_JohnJacobSmith(JJS)
A few things to make it more like the ruby way:
Use blocks when opening a file or iterating through arrays, that way you don't need to worry about closing the file or accessing the array directly.
As noted by #inger, local vars start with lower case, customer.
When you want the value of a variable in a string usign #{} is more rubinic than concatenating with +.
Also note that we took off the trailing newline using chomp! (which changes the var in place, noted by the trailing ! on the method name)

Remove email address from string in Ruby

I have the following code which is supposed to be removing a particular email address from a string if it exists. The problem is i get the error "invalid range "y-d" in string transliteration (ArgumentError)" which I assume is because it's treating my input as a regex. I will need to do this delete by a variable in the actual code, not a string literal but this is a simplified version of the problem.
So how do I properly perform this operation?
myvar = "test1#my-domain.com test2#my-domain.com"
myvar = myvar.delete("test1#my-domain.com")
Try
myvar = "test1#my-domain.com test2#my-domain.com"
myvar = myvar.gsub("test1#my-domain.com", '').strip
String#delete(str) does not delete the literal string str but builds a set out of individual characters of str and deletes all occurrences of these characters. try this:
"sets".delete("test")
=> ""
"sets".delete("est")
=> ""
The hyphen has a special meaning, it defines a range of characters. String#delete("a-d") will delete all occurrences of a,b,c and d characters. Range boundary characters should be given in ascending order: you should write "a-d" but not "d-a".
In your original example, ruby tries to build a character range from y-d substring and fails.
Use String#gsub method instead.
You can do it like this
myvar = "test1#my-domain.com test2#my-domain.com"
remove = "test1#my-domain.com"
myvar.gsub!(remove, "")

Why doesn't this Ruby replace regex work as expected?

Consider the following string which is a C fragment in a file:
strcat(errbuf,errbuftemp);
I want to replace errbuf (but not errbuftemp) with the prefix G-> plus errbuf. To do that successfully, I check the character after and the character before errbuf to see if it's in a list of approved characters and then I perform the replace.
I created the following Ruby file:
line = " strcat(errbuf,errbuftemp);"
item = "errbuf"
puts line.gsub(/([ \t\n\r(),\[\]]{1})#{item}([ \t\n\r(),\[\]]{1})/, "#{$1}G\->#{item}#{$2}")
Expected result:
strcat(G->errbuf,errbuftemp);
Actual result
strcatG->errbuferrbuftemp);
Basically, the matched characters before and after errbuf are not reinserted back with the replace expression.
Anyone can point out what I'm doing wrong?
Because you must use syntax gsub(/.../){"...#{$1}...#{$2}..."} or gsub(/.../,'...\1...\2...').
Here was the same problem: werid, same expression yield different value when excuting two times in irb
The problem is that the variable $1 is interpolated into the argument string before gsub is run, meaning that the previous value of $1 is what the symbol gets replaced with. You can replace the second argument with '\1 ?' to get the intended effect. (Chuck)
I think part of the problem is the use of gsub() instead of sub().
Here's two alternates:
str = 'strcat(errbuf,errbuftemp);'
str.sub(/\w+,/) { |s| 'G->' + s } # => "strcat(G->errbuf,errbuftemp);"
str.sub(/\((\w+)\b/, '(G->\1') # => "strcat(G->errbuf,errbuftemp);"

Resources