From: Logan Capaldo Date: 2006-05-08T09:52:36+09:00 Subject: Re: A major ruby annoyance! And now I shall go off on a tangent, demonstrating the seeds of methods for "declaring variables" in ruby. It's not complete or perfect by any means, but I'm sure it can be improved by greater coders than I. It makes use of Binding.of_caller which for convenience I have stuck in the actual source file. It also makes use of an Evil Global Variable� % cat locals.rb # File lib/extensions/binding.rb, line 107 def Binding.of_caller(&block) old_critical = Thread.critical Thread.critical = true count = 0 cc, result, error = Continuation.create(nil, nil) error.call if error tracer = lambda do |*args| type, context = args[0], args[4] 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) 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(Exception, error_msg ) }) end end unless result set_trace_func(tracer) return nil else Thread.critical = old_critical yield result end end # File lib/extensions/continuation.rb, line 61 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 def declare_locals(*symbols) $__LVARS ||= [] $__LVARS.concat(symbols) end def ensure_locals Binding.of_caller do |b| lvar_set = eval('local_variables', b) undecld_vars = lvar_set - ($__LVARS || []) unless undecld_vars.empty? warn "Undeclared var(s): #{undecld_vars}" end end end declare_locals 'a', 'b' a = 1 b = 2 c = 4 puts a + b ensure_locals % ruby locals.rb 3 Undeclared var(s): c Originally I tried to do this with 'set_trace_func' but that doesn't apparently have an event for setting a variable.