3

How do I make this code more elegant? I have:

alpha = "lorem ipsum"
alpha = alpha + "\n" + "more text"
alpha = alpha + "\n" + "look I'm woody, howdy howdy howdy"
#etc

I would like:

alpha.puts "lorem ipsum"
alpha.puts "more text"
alpha.puts "look I'm woody, howdy howdy howdy"
# etc

or, perhaps, alpha.append as it is not taken. I attempted:

class String
  def append(apnd)
    self.to_s + "\n" + apnd
  end
end

but that doesn't modify it, only returns it. And I learned from searching you can't modify the self. I get the same problem with:

def apnd(a,b)
  a = a + "\n" + b
end

which I find very confusing as I thought Ruby passes the object by reference, rather than by value.

I saw "Custom + Method in Ruby String" and a couple other Stack Overflow posts.


Update:

Aha, for the apnd method I can follow "'pass parameter by reference' in Ruby?" but that means I can't have apnd(alpha, "stuff"), it would have to be apnd(:alpha, "stuff", binding) which doesn't reduce repetition as I have to pass binding into every single method.

5
  • 2
    did you look ruby-doc.org/core-2.1.0/String.html#method-i-concat ? Commented Mar 15, 2014 at 17:41
  • I'm a big fan of the << syntax, but do I really want to write alpha << "\n" << "stuff"? It doesn't seem very elegant to have to include the "\n" every time Commented Mar 15, 2014 at 17:44
  • would you like ["\n","stuff"].inject(alpha,:<<) ? Commented Mar 15, 2014 at 17:55
  • Looks like alpha is a collection of lines. You could use an array and invoke join("\n"). Commented Mar 15, 2014 at 18:24
  • When creating method names, it's important to consider whether they're used in other classes and what their behavior is in those places. puts is used to output to a stream, not append to an object/container. Using puts to append would be confusing to others who are using your code. append or concat are more acceptable because other classes that have that method use it to add something to a container. It might seem like a small thing, but it's important to making a language flow as we write in it. Commented Mar 15, 2014 at 19:28

3 Answers 3

4

You can get close to what you describe using a StringIO:

require 'stringio'
alpha_io = StringIO.new

alpha_io.puts "lorem ipsum"
alpha_io.puts "more text"
alpha_io.puts "look I'm woody, howdy howdy howdy"

alpha_io.string
# => "lorem ipsum\nmore text\nlook I'm woody, howdy howdy howdy\n"

However, if your string is mostly literal, you can get away easily by using a heredoc:

alpha = <<-STRING
lorem ipsum
more text
look I'm woody, howdy howdy howdy
Some interpolation #{"here".upcase}
STRING

puts alpha
# lorem ipsum
# more text
# look I'm woody, howdy howdy howdy
# Some interpolation HERE

(Even though SO got confused with the syntax, I assure you it's valid ruby ;))

Sign up to request clarification or add additional context in comments.

Comments

3
class String
  def append(apnd)
    concat("\n#{apnd}")
  end
end

But I don't think is the right way to do it. I feel code smell in this approach. If you care about ensuring a line break when additional lines are added, then you should care about that even when additional lines are not added. In your case, the endline character should be appended to the previous string, not prepended to the string to be added. From the beginning, you should keep your strings normalized in the sense that they end with an endline character. For this, I have a method in my personal library called String#unchomp and String#unchomp!:

class String
  def unchomp; sub(/#$/?\z/, $/) end
  def unchomp!; sub!(/#$/?\z/, $/) end
end

Whenever I need to ensure a string ends with an endline character, I apply this method to it.

8 Comments

I would go with this one.. +1
But you made it complete.. For this, I wouldn't prefer like others to include stdlib like - stringio..
You should definetly use {} for interpolation in a case like this!
inside //, I think {} not needed @toro2k.. Is it ?
Because it takes more than a while to recognize the sequence #$/ not as a part of the regexp but as an interpolation.
|
1
alpha = "lorem ipsum"
alpha = alpha + "\n" + "more text"
alpha = alpha + "\n" + "look I'm woody, howdy howdy howdy"

I would like:

alpha.puts "lorem ipsum"
alpha.puts "more text"
alpha.puts "look I'm woody, howdy howdy howdy"

I would counter that you're on the wrong path; That, instead of concatenating to an string, you're really looking for an array-like behavior, where you can push content onto it, then later output it however you need at that moment.

For instance:

alpha = ["lorem ipsum"]
alpha << "more text"
alpha << "look I'm woody, howdy howdy howdy"

puts alpha
# >> lorem ipsum
# >> more text
# >> look I'm woody, howdy howdy howdy

Or:

alpha.join("\n")
# => "lorem ipsum\nmore text\nlook I'm woody, howdy howdy howdy"

If you use a string as your buffer, you're going to paint yourself into corners, especially if you need to modify that buffer later in our code. Keeping it as an array allows you to easily push/pull, shift/unshift, insert/delete or sort elements then, when everything is as you want it, simply output it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.