retrieve column # of calling function

P

Phlip

Rubies:

Consider this excellent trace_{} method, based on code posted here by one
Carlos, many winters ago:

def trace_(&b)
file, line_nr, funkshun = caller()[0].split(':')

# sorry, folks - split's the only stringey function I know ;-)

funkshun = funkshun.split('in `')[1]
funkshun = funkshun.split("'")[0]
line_nr=line_nr.to_i
linecnt=1
expr=nil

File.open(file).each_line do |line|
if linecnt==line_nr
if line =~ /(^|\W)trace_\s*\{\s*(.*?)\s*\}/
expr = $2
end
break
end
linecnt+=1
end

if expr
puts "(#{line_nr})#{funkshun} #{expr}: #{eval(expr,
b).inspect}"
end #{file}
end

All it does is this:

require 'trace'

def foo()
complicatedThing = "simple thing"
trace_{complicatedThing}
end

foo()
....
(6)foo complicatedThing: "simple thing"

It prints out the file name (if any), function name, and line number of
'complicatedThing', and it reflects 'complicatedThing' itself

(A side question: This trace_ is nice, but does the latest Ruby have any
better ways to do all this?)

Here's the question. That code parses the calling source file, and uses
/(^|\W)trace_\s*\{\s*(.*?)\s*\}/ stuff to find itself.

Is there a way to extract the column number from caller(), or its relatives,
so we can accurately grab the {} and not worry about its relative location
in a file?

Long post; short question.
 
F

Florian Gross

Phlip said:
require 'trace'

def foo()
complicatedThing = "simple thing"
trace_{complicatedThing}
end

You can also do that with Binding.of_caller (see attachment), btw:

def trace(code)
Binding.of_caller do |context|
file, line = eval("[__FILE__, __LINE__]", context)
result = eval(code.to_s, context)
STDERR.puts "In #{file} at #{line}: #{code} => #{result}"
end
end

something = 5
trace :something
trace "[self, something]"

Regards,
Florian Gross


begin
require 'simplecc'
rescue LoadError
def Continuation.create(*args, &block)
cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
result ||= args
return *[cc, *result]
end
end

# This method returns the binding of the method that called your
# method. It will raise an Exception when you're not inside a method.
#
# It's used like this:
# def inc_counter(amount = 1)
# Binding.of_caller do |binding|
# # Create a lambda that will increase the variable 'counter'
# # in the caller of this method when called.
# inc = eval("lambda { |arg| counter += arg }", binding)
# # We can refer to amount from inside this block safely.
# inc.call(amount)
# end
# # No other statements can go here. Put them inside the block.
# end
# counter = 0
# 2.times { inc_counter }
# counter # => 2
#
# Binding.of_caller must be the last statement in the method.
# This means that you will have to put everything you want to
# do after the call to Binding.of_caller into the block of it.
# This should be no problem however, because Ruby has closures.
# If you don't do this an Exception will be raised. Because of
# the way that Binding.of_caller is implemented it has to be
# done this way.
def Binding.of_caller(&block)
old_critical = Thread.critical
Thread.critical = true
count = 0
cc, result, error, extra_data = Continuation.create(nil, nil)
error.call if error

tracer = lambda do |*args|
type, filename, context, extra_data = args[0], args[1], args[4], args
if type == "return"
count += 1
# First this method and then calling one will return --
# the trace event of the second event gets the context
# of the method which called the method that called this
# method.
if count == 2
# It would be nice if we could restore the trace_func
# that was set before we swapped in our own one, but
# this is impossible without overloading set_trace_func
# in current Ruby.
set_trace_func(nil)
cc.call(eval("binding", context), nil, extra_data)
end
elsif type != "line"
set_trace_func(nil)
error_msg = "Binding.of_caller used in non-method context or " +
"trailing statements of method using it aren't in the block."
cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
end
end

unless result
set_trace_func(tracer)
return nil
else
Thread.critical = old_critical
case block.arity
when 1 then yield(result)
else yield(result, extra_data)
end
end
end
 
P

Phlip

Florian said:
Phlip said:
require 'trace'

def foo()
complicatedThing = "simple thing"
trace_{complicatedThing}
end

You can also do that with Binding.of_caller (see attachment), btw:

def trace(code)
Binding.of_caller do |context|
file, line = eval("[__FILE__, __LINE__]", context)
result = eval(code.to_s, context)
STDERR.puts "In #{file} at #{line}: #{code} => #{result}"
end
end

something = 5
trace :something
trace "[self, something]"

Thanks; that's good to know. But...

....I'm primarily interested in the _column_number_. Upgrading trace_{} is a
nice second.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top