Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy-evaluation of a "#{}"-string in ruby

Tags:

string

ruby

eval

I started to put print-statements throughout my code. So as not to clutter up the output, I did something like:

dputs LEVEL, "string"

where LEVEL is 0 for errors, 1 for important .. 5 for verbose and is compared to DEBUG_LEVEL. Now my problem is, that in a statement like:

dputs 5, "#{big_class.inspect}"

the string is always evaluated, also if I set DEBUG_LEVEL to 1. And this evaluation can take a long time. My favourite solution would be something like:

dputs 5, '#{big_class.inspect}'

and then evaluate the string if desired. But I don't manage to get the string in a form I can evaluate. So the only think I could come up with is:

dputs( 5 ){ "#{big_class.inspect}" }

but this looks just ugly. So how can I evaluate a '#{}' string?

like image 734
ineiti Avatar asked Feb 18 '23 18:02

ineiti


2 Answers

You could do this by having dputs use sprintf (via %). That way it can decide not to build the interpolated string unless it knows it's going to print it:

def dputs(level, format_str, *vars)
  puts(format_str % vars) if level <= LEVEL
end

LEVEL = 5
name = 'Andrew'
dputs 5, 'hello %s', name
#=> hello Andrew

Or, as you suggest, you can pass a block which would defer the interpolation till the block actually runs:

def dputs(level, &string)
  raise ArgumentError.new('block required') unless block_given?
  puts string.call if level <= LEVEL
end
like image 52
Andrew Marshall Avatar answered Feb 27 '23 21:02

Andrew Marshall


I think it's of no value whatsoever, but I just came up with:

2.3.1 :001 > s = '#{a}'
 => "\#{a}"
2.3.1 :002 > a = 1
 => 1
2.3.1 :003 > instance_eval s.inspect.gsub('\\', '')
 => "1"
2.3.1 :004 > s = 'Hello #{a} and #{a+1}!'
 => "Hello \#{a} and \#{a+1}!"
2.3.1 :005 > instance_eval s.inspect.gsub('\\', '')
 => "Hello 1 and 2!"

Don't use that in production :)

like image 38
no-dashes Avatar answered Feb 27 '23 21:02

no-dashes