Donato Donato - 5 months ago 21
Ruby Question

string concatenation and yielding block based on if modifier

This is a purely ruby syntax question, even though it's in the context of Rails.

I have a method which accepts a block and converts it to proc object in its definition:

def wrapper(form, attr, options = {}, &block)
if block_given?
yield(block) +
end
form.label(form_label, class: "control-label")
end


The block is a piece of html as a string and I want to concatenate it with form.label which itself is returned as a string of html. However, I only want to concatenate the two if the block is given.

The above produces syntax error:

SyntaxError: (irb):14: syntax error, unexpected keyword_end


Using the if modifier also does not work:

def wrapper(form, attr, options = {}, &block)
yield(block) + if block_given?
form.label(form_label, class: "control-label")
end


I might also later need to do something like this (in which case I concatenate 3 strings conditionally):

def wrapper(form, attr, options = {}, &block)
form.label(options[:errors], class: "control-label required") +
yield(block) + if block_given?
form.label(form_label, class: "control-label")
end


What is the best approach to concatenate a block with a string when the block may be optional?

One solution I thought of after asking the question is maybe this:

def wrapper(form, attr, options = {}, &block)
if block_given?
content = capture(&block)
else
content = ""
end

form.label(form.object.errors[attr]) + content + form.label(form_label, class: "control-label")
end

Answer

You can't concatenate strings like that. The line yield(block) + isn't a complete line. That's why you're getting the errors. Here are two possible fixes:

def wrapper(form, attr, options = {}, &block)
  if block_given?
    return yield(block) + form.label(form_label, class: "control-label")
  end
  form.label(form_label, class: "control-label")
end

Or this

def wrapper(form, attr, options = {}, &block)
  content = ''
  if block_given?
    content = yield(block)
  end
  content + form.label(form_label, class: "control-label")
end
Comments