tags:

views:

335

answers:

3
while line = gets
   next if line =~ /^\s*#/    # skip comments
   break if line =~ /^END/   # stop at end

   #substitute stuff in backticks and try again
   redo if line.gsub!(/`(.*?)`/) { eval($1) }

end

What I don't understand is this line:

line.gsub!(/`(.*?)`/) { eval($1) }
  1. What does the gsub! exactly do?
  2. the meaning of regex (.*?)
  3. the meaning of the block {eval($1)}
+4  A: 
  1. It will substitute within the matched part of line, the result of the block.
  2. It will match 0 or more of the previous subexpression (which was '.', match any one char). The ? modifies the .* RE so that it matches no more than is necessary to continue matching subsequent RE elements. This is called "non-greedy". Without the ?, the .* might also match the second backtick, depending on the rest of the line, and then the expression as a whole might fail.
  3. The block returns the result of eval ("evaluate a Ruby expression") on the backreference, which is the part of the string between the back tick characters. This is specified by $1, which refers to the first paren-enclosed section ("backreference") of the RE.

In the big picture, the result of all this is that lines containing backtick-bracketed expressions have the part within the backticks (and the backticks) replaced with the result value of executing the contained Ruby expression. And since the outer block is subject to a redo, the loop will immediately repeat without rerunning the while condition. This means that the resulting expression is also subject to a backtick evaluation.

DigitalRoss
A: 

line.gsub!(/(.*?)/) { eval($1) }

  1. gsub! replaces line (instead if using line = line.gsub).
  2. .*? so it'd match only until the first `, otherwise it'd replace multiple matches.
  3. The block executes whatever it matches (so for example if "line" contains 1+1, eval would replace it with 2.
OneOfOne
+2  A: 

Replaces everything between backticks in line with the result of evaluating the ruby code contained therein.

>> line = "one plus two equals `1+2`"
>> line.gsub!(/`(.*?)`/) { eval($1) }
>> p line
=> "one plus two equals 3"

.* matches zero or more characters, ? makes it non-greedy (i.e., it will take the shortest match rather than the longest).

$1 is the string which matched the stuff between the (). In the above example, $1 would have been set to "1+2". eval evaluates the string as ruby code.

nornagon