Turn Ruby array into strings - problem with my code? - ruby

I want to turn this array of cards into a string (output I want is at the bottom) Here's my code:
# Returns an array of 5 cards in player's hand:
# => Eg: ['6♠', '3♦', 'A♣', 'J♦', 'J♥']
private
def cards
%w(6♠ 3♦ A♣ J♦ J♥)
end
def to_s
cards.map {|card| "-" + card.to_s}.join("-")
end
end
The output I want is a string of the cards like this: - 6♠ - 3♦ - A♣ - J♦ - J♥ -

As the question is currently posed, you have 3 things going wrong:
First, you're trying to create private methods without first calling a class. This also explains the extra end. To fix that, we can add the class call at the beginning like so:
class Test
private
def cards
%w(6♠ 3♦ A♣ J♦ J♥)
end
def to_s
cards.map {|card| "-" + card.to_s}.join("-")
end
end
Second, we need to actually use the class somehow. We can use Class.new for this, like so:
class Test
private
def cards
%w(6♠ 3♦ A♣ J♦ J♥)
end
def to_s
cards.map {|card| "-" + card.to_s}.join("-")
end
end
puts Test.new
#=> "-6♠--3♦--A♣--J♦--J♥"
I can only assume your posted code section was just incomplete, that you weren't having issues with the first couple things, and that you're just having problems with the formatting in that output line. If so, there are many different ways to do this, but your main issue is the following section of your code:
"-" + card.to_s}.join("-")
You are iterating over the array and adding a "-" before every element. You are then joining up those elements with a redundant "-" to create your string. You need to get rid of one or the other. I suggest just getting rid of the latter like so:
cards.map {|card| "-" + card.to_s}.join
Its also worth noting that your array elements are already strings, so the .to_s is unnecessary. Your line could therefore be reduced to:
cards.map {|card| "-" + card}.join
This will result in #=> "-6♠-3♦-A♣-J♦-J♥"
The only thing missing now is that last dash. To fix that, we just add the dash independently at the end of your newly joined array like so:
cards.map {|card| "-" + card}.join + "-"
The completed test would then look like this:
class Test
private
def cards
%w(6♠ 3♦ A♣ J♦ J♥)
end
def to_s
cards.map {|card| "-" + card}.join + "-"
end
end
puts Test.new
#=> "-6♠-3♦-A♣-J♦-J♥-"
At the end of the day though, your string formatting issues could essentially be addressed by just replacing ("-") with +"-"

Join with Format String
From inside a class, you can do this fairly easily with a combination of cards.join and a format string. For example:
def cards
%w(6♠ 3♦ A♣ J♦ J♥)
end
def to_s
sprintf "- %s -", cards.join(" - ")
end
You can test this in irb outside of a class by defining your #cards method, and then invoking Kernel#sprintf with the format string and the String formed by joining your cards as arguments.
sprintf "- %s -", cards.join(" - ")
#=> "- 6♠ - 3♦ - A♣ - J♦ - J♥ -"
There are other interpolation methods available as well, such as Kernel#format, embedded expressions, and %-style interpolation expressions, but this seems both simple and well-supported with any reasonably recent Ruby version.

Related

Why is Ruby printing object.method before string?

class Bike
attr_accessor :color, :gear_numbers, :style
def spin
puts " spins! Woosh!"
end
end
gw = Bike.new
gw.color = "white"
gw.gear_numbers = 11
gw.style = "compact"
puts "This bike is #{gw.color} and it has #{gw.gear_numbers} gears. Oh, and it has a #{gw.style} design. Did I mention that my bike #{gw.spin}?"
Using IRB, this is what I get:
**spins! Woosh!
This bike is white and it has 11 gears. Oh, and it
has a compact design. Did I mention that my bike ?**
Why is "spins! Woosh!" coming BEFORE the string and why isn't it IN the string?
Because you're not returning the string from your method, you're printing it directly.
To do what you want to do, simply remove the puts from your spin method and you're good to go.
class Bike
attr_accessor :color, :gear_numbers, :style
def spin
"spins! Woosh!"
end
end
Because to interpolate the string Ruby needs to call spin. Then Ruby includes the return value of the spin method (which is nil, because puts returns nil) into the string and prints the generated string.
The issue here is that string interpolation needs to be fully complete before the string is passed through to the main puts you have there. As part of figuring out what's in there it must execute each of the methods referenced in the order which they appear.
Your spin method causes an immediate puts and it doesn't return anything, as that's how puts works. If you want to supply a string to go in there, simply leave it:
def spin
" spins! Woosh!"
end
Think of this string interpolation:
"a #{b} c #{d} e"
This is roughly equivalent to:
"a " + b.to_s + " c " + d.to_s + " e"
Where those .to_s calls are to force it into a string. You'd expect b and d to be exercised before the whole string is returned.
When anticipating what code will do, trace execution to the bottom first, then work back up. Simple programs work in very predictable ways.

Calling functions inside functions when the inner function's arguments will always be the same as the outer's

The inner_method is only ever called within outer_method, and its argument will always be identical to outer_method's.
This works:
def outer_method(word)
inner_method(word)
puts word + " are like candy."
end
def inner_method(same_word)
puts "I really love " + same_word + "!"
end
outer_method("onions")
but this doesn't:
def outer_method(word)
inner_method
puts word + "tastes like candy."
end
def inner_method
puts "I really love " + word + "!"
end
outer_method("onions")
It seems that inner_method's reference to word is not being registered by outer_method. Is there a better way to do this?
(I realize there's no reason to have a separate inner_method in the above example; this is simplified for clarity's sake)
I honestly think your first technique is the best way to go and perfectly idiomatic. Still, here's another option:
def outer_method(word)
inner_lambda = lambda do
puts "I really love " + word + "!"
end
inner_lambda.call
puts word + " tastes like candy."
end
outer_method("onions")
lambda creates a lexical closure, which means it captures the surrounding environment, including the reference to word.
There are two concerns with your question. The shallow one is your learning Ruby syntax. The deeper one is learning proper coding patterns. In your case, word object begs to exist:
class MyWord < String
def singular?; #singular end
def initialize **setup
singular, plural = setup[:singular], setup[:plural]
if singular then #singular = true
super singular
elsif plural then #singular = false
super plural
else fail ArgumentError, "Bad MyWord constructor arguments!" end
end
def interjection_1
"I really love #{self}!"
end
def interjection_2
"#{capitalize} #{singular? ? 'is' : 'are'} like cand#{singular? ? 'y' : 'ies'}!"
end
def hysteria
puts interjection_1
puts interjection_2
end
end
And then:
MyWord.new( plural: "onions" ).hysteria

How to finetune map function and avoid using flatten

I have the following code to list all possible permutations of a give string. But due to my awkward list (ruby array) manipulation and limited knowledge on functional programming, I have to use flatten to get the result array. It is pretty much a hack. How can I refactor the code and avoid using (abusing) flatten?
class String
def remove_char_at(i)
if i==0
self[1..-1]
else
self[0..i-1] + self[i+1..-1]
end
end
end
def permute(str,prefix="")
if str.size==0
prefix
else
str.chars.each_with_index.map do |s,i|
permute(str.remove_char_at(i),prefix+s)
end.flatten
end
end
You can find intresting things about functional programming in first chapters of SICP
def permute2(str,prefix="")
if str.size==0
[prefix] #revise for concatenate with memo
else
str.chars.each_with_index.inject([]) do |memo, ary|
s = ary[0]
i = ary[1]
memo += permute2(str.remove_char_at(i),prefix+s) #memoize
end
end
end
Ruby has done much of the hard work for you. To get all permutations for a string, myString, do the following:
myString.split('').permutation.map(&:join).uniq
This splits the string components into an array; gets all the permutations of the array; joins those back into strings; weeds out duplicates.
class String
def remove_char_at(i)
if i==0
self[1..-1]
else
self[0..i-1] + self[i+1..-1]
end
end
end
can be refactored as follows by using ... instead of ..
class String
def remove_char_at(i)
self[0...i] + self[i+1..-1]
end
end
I'm specifically answering the How can I refactor the code and avoid using (abusing) flatten? part:
Instead of map + flatten, you can just use flat_map which was introduced in 1.9.2.

Adding conversion method to Numeric causes SystemStackError

I'm attempting to add conversion methods to the Numeric class but when I run the following lines of code I get a SystemStackError
puts 5.dollars.in(:euros) # => 6.5
puts 1.dollar.in(:yen)
Here is my Numeric class
class Numeric
##conversion_hash = {:dollar => {:yen => 0.013, :euros => 1.292, :rupees => 0.019}}
def method_missing(method_id)
name = method_id.to_s
if name =~ /^dollar|yen|euros|rupee|$/
self.send(name + 's')
else
super # pass the buck to superclass
end
end
def dollars()
puts "Called Dollars method"
#current_currency = :dollar
return self
end
def in(key)
if ##conversion_hash.has_key?(#current_currency)
puts "Current currency: #{#current_currency}"
conversion_rate = ##conversion_hash[#current_currency]
puts "Current conversion rate: #{conversion_rate}"
if conversion_rate.has_key?(key)
puts "we have that key"
puts"What am I? #{self}"
rate = conversion_rate[key]
puts "Rate to multiply by #{rate}"
return self.to_int * conversion_rate[key]
end
end
end
end
Any help is greatly appreciated.
You're getting infinite recursion in your method_missing because your regex isn't quite right. Try changing the line:
if name =~ /^dollar|yen|euros|rupee|$/
to:
if name =~ /^dollar|yen|euros|rupee$/
That extra | is causing anything to match the regex, so any other method is recursing with a continually extending suffix of s.
In this case it looks like puts seems to be trying to call to_ary when it's trying to determine the type its argument. I'm not exactly sure why it's not just using respond_to? though - it's deep in the C internals so I don't really know what's happening.
Your solution overcomplicated.
- You don't need to modify method_missing. Armando version works fine.
- You should simple dollar definition to hash plus
- find the way to call method_missing again from method in(this is your homework).
Working solution have only 1 line of code + 2 lines def surronding.

Implicit return values in Ruby

I am somewhat new to Ruby and although I find it to be a very intuitive language I am having some difficulty understanding how implicit return values behave.
I am working on a small program to grep Tomcat logs and generate pipe-delimited CSV files from the pertinent data. Here is a simplified example that I'm using to generate the lines from a log entry.
class LineMatcher
class << self
def match(line, regex)
output = ""
line.scan(regex).each do |matched|
output << matched.join("|") << "\n"
end
return output
end
end
end
puts LineMatcher.match("00:00:13,207 06/18 INFO stateLogger - TerminationRequest[accountId=AccountId#66679198[accountNumber=0951714636005,srNumber=20]",
/^(\d{2}:\d{2}:\d{2},\d{3}).*?(\d{2}\/\d{2}).*?\[accountNumber=(\d*?),srNumber=(\d*?)\]/)
When I run this code I get back the following, which is what is expected when explicitly returning the value of output.
00:00:13,207|06/18|0951714636005|20
However, if I change LineMatcher to the following and don't explicitly return output:
class LineMatcher
class << self
def match(line, regex)
output = ""
line.scan(regex).each do |matched|
output << matched.join("|") << "\n"
end
end
end
end
Then I get the following result:
00:00:13,207
06/18
0951714636005
20
Obviously, this is not the desired outcome. It feels like I should be able to get rid of the output variable, but it's unclear where the return value is coming from. Also, any other suggestions/improvements for readability are welcome.
Any statement in ruby returns the value of the last evaluated expression.
You need to know the implementation and the behavior of the most used method in order to exactly know how your program will act.
#each returns the collection you iterated on. That said, the following code will return the value of line.scan(regexp).
line.scan(regex).each do |matched|
output << matched.join("|") << "\n"
end
If you want to return the result of the execution, you can use map, which works as each but returns the modified collection.
class LineMatcher
class << self
def match(line, regex)
line.scan(regex).map do |matched|
matched.join("|")
end.join("\n") # remember the final join
end
end
end
There are several useful methods you can use depending on your very specific case. In this one you might want to use inject unless the number of results returned by scan is high (working on arrays then merging them is more efficient than working on a single string).
class LineMatcher
class << self
def match(line, regex)
line.scan(regex).inject("") do |output, matched|
output << matched.join("|") << "\n"
end
end
end
end
In ruby the return value of a method is the value returned by the last statement. You can opt to have an explicit return too.
In your example, the first snippet returns the string output. The second snippet however returns the value returned by the each method (which is now the last stmt), which turns out to be an array of matches.
irb(main):014:0> "StackOverflow Meta".scan(/[aeiou]\w/).each do |match|
irb(main):015:1* s << match
irb(main):016:1> end
=> ["ac", "er", "ow", "et"]
Update: However that still doesn't explain your output on a single line. I think it's a formatting error, it should print each of the matches on a different line because that's how puts prints an array. A little code can explain it better than me..
irb(main):003:0> one_to_three = (1..3).to_a
=> [1, 2, 3]
irb(main):004:0> puts one_to_three
1
2
3
=> nil
Personally I find your method with the explicit return more readable (in this case)

Resources