Ruby: Print un-printable data string - ruby

If I have a variable, x, that will sometime be a normal printable string, and sometimes be some random hex data (including unprintable chars), how can I reliably print that will space padding? ex:
def print(x)
puts("%-15s" % x)
end
x = "test"
print(x)
x = Array.new(256) { rand(256) }.pack('c*')
print(x)

def print(x)
puts "%-15s" % [x.inspect]
end
And if you want to get rid of the "...":
puts "%-15s" % [x.inspect[1..-2]]

Related

In Ruby, why doesn't ternary operator work when using a puts function inside an each statement?

Given that you write the code on IRB:
array = [1,2,3]
array.each {|x| x > 2 ? puts "lower" : puts "higher"}
The program doesn't execute the line and it somehow according to the program is an incomplete line. Any help would be appreciated.
This is caused by ambiguous arguments. Ruby, unlike many other languages such as JavaScript, is really lax about requiring brackets puts x and puts(x) are equivalent. Where this breaks down is when it's not clear which are arguments, and which are part of other syntax.
For example, if f is a method that takes 1-3 arguments and x and y are variables, then what is the meaning of:
f x, f x, y
Is that f(x, f(x,y)), f(x), f(x), y or f(x, f(x), y)? Ruby throws an error rather than presume the wrong thing.
Easy fix is to eliminate the duplication of effort here and use a single puts with a ternary used to determine the value:
array = [1,2,3]
array.each { |x| puts x > 2 ? "lower" : "higher"}
Now it works because there's no ambiguity on arguments, there's only one method call so it's easy.
The previous answer explains clearly what is happening. However you may note that this syntax will also work, but here you are duplicating the method call on both sides of the ternary operator:
array.each {|x| x > 2 ? (puts "lower") : (puts "higher")}
By wrapping the duplicate method call on both sides, that code is executed on both sides. But it definitely is better style to do it the more correct way where you are passing the result of ternary to puts
array.each { |x| puts x > 2 ? "lower" : "higher"}
which is the same as:
array.each { |x| puts (x > 2 ? "lower" : "higher") }
The puts method takes a single string argument and that's what we are passing it.

Shorthand for x ? x : y

Is there a shorthand for x ? x : y? A relatively tame example:
def find_or_create_by_name(name)
self.find_by_name(name) ? self.find_by_name(name) : self.create(name)
end
Of course I could do something like
def find_or_create_by_name(name)
x = self.find_by_name(name)
x ? x : self.create(name)
end
but then I'm starting to lose the space I've saved with the ternary operator in the first place. (and if I use a full if statement, the same redundancy would occur.
you can just use || operator:
def find_or_create_by_name(name)
find_by_name(name) || create(name)
end

Converting int to escaped octal character

Given an integer - say, x=20, I'd like to convert this into a string containing its escaped octal character. I.e. ...
x=20
# y = ... Some magic
p y # => "\024"
The closest I've managed to get is by using:
x.to_s(8) # => "24"
However, I'm completely stumpted on how to convert this string into an escaped octal character! Any ideas, internet?
Just use Kernel#sprintf to format the number.
Like this
x = 20
y = sprintf('\%03o', x)
puts y
output
\024
Update
Maybe I misunderstood you. If you just want a character with the given code point then just use Integer#chr.
Like this
x = 20
y = x.chr
p y
output
"\x14"
You could use Array#pack:
[20].pack("C") #=> "\x14"
x = 20
y = '\%03o' % x
puts y
If you use p to display y you would see 2 backslashes as p outputs ruby parsable strings.

adequate solution to hand over variables in nested functions (in ruby)

I have several step_1-methods which are based on x and y variables.
step_2 creates new methods based on step_1-methods but the variables aren't needed (just passed through)!
The same goes for step_3 (based on step_2-methods).
My problem is I have about 20 step_2-methods which consists dozens of step_1-methods (5 differents kinds). And for each one I have to pass the same two variables.
I need this kind of construction for iteration purposes.
Now, is there a way to hand over the variables directly form step_3(x, y) to step_1 (x, y) without using global variables?
# example
def step_1 (x, y)
return x + y
end
def step_2 (*foo)
return step_1(*foo)
end
def step_3 (*foo)
return step_2(*foo)
end
x, y = 2, 2 # example
puts step_3(x, y) # ==> 4
Thanks for any suggestion
When I read "I have to pass the same two variables", this naturally brings to mind the idea of creating a simple container you can pass around instead:
class NumberTuple
attr_accessor :x
attr_accessor :y
def initialize(x, y)
#x = x
#y = y
end
end
tuple = NumberTuple.new(2,2)
step_3(tuple)
This often leads to the conclusion that creating a simple calculation class that can internalize all of this state. That's what class instances excel at:
class NumberCalculator
def initialize(x, y)
#x = x
#y = y
end
def step_3
step_2
end
def step_2
step_1
end
def step_1
#x + #y
end
end
calculator = NumberCalculator.new(2,2)
calculator.step_3
alias step_3 :step_1
or if you want to go through intermediate steps,
alias step_2 :step_1
alias step_3 :step_2

Reading lists from a file in Ruby

I have a txt file which contains data in the following format:
X1 Y1
X2 Y2
etc..
I want to read the data from this file and create two lists in ruby (X containing X1, X2 and Y containing Y1, Y2). How can I do this in Ruby?
Thanks.
A real one-liner:
x, y = File.foreach("filename").collect {|line| line.split}.transpose
Pseudocode
File.new("source.txt", "r").each_line do |line|
x, y = line.split
xs << x
ys << y
end
You might want to checkout the Rdoc for detail API.
I prefer using the readlines method for things such as this.
x = []
y = []
File.readlines(filename).each do |line|
x << line.split[0]
y << line.split[1]
end
As Mladen (from the comments of this answer) suggests, I am splitting it twice which is probably slower than assigning it to a variable and referencing that. He also mentions that using foreach is better than readlines, and I agree. Using their advice, this is how we would both go about doing it:
x = []
y = []
File.foreach(filename).each do |line|
line = line.split
x << line[0]
y << line[1]
end
Something like this if you have exactly two columns:
one = Array.new
two = Array.new
File.open("filename") do |file|
while line = file.gets
one << line.split[0]
two << line.split[1]
end
end

Resources