lib/dt.rb in rails_dt-0.1.1 vs lib/dt.rb in rails_dt-0.1.2

- old
+ new

@@ -3,188 +3,225 @@ Dir[File.join(File.dirname(__FILE__), "dt/**/*.rb")].each {|fn| require fn} # Debug toolkit. # -# Allows to output debug messages from anywhere in your Rails project. +# Allows to print debug messages from anywhere in your Rails project. Do a: # -# Configure your application: -# $ script/generate rails_dt +# DT.p "Hello, world!" # -# Follow the instructions the generator gives you. +# , and see the message in log, <tt>log/dt.log</tt>, console and web. # -# Then anywhere in your application do a: -# DT.p "Hello, world!" -# DT.p "myvar", myvar +# To set up web output, in your application root do a: # -# , and see it in web output, console, and <tt>log/dt.log</tt>. +# $ rails generate rails_dt # Rails 3 +# $ script/generate rails_dt # Rails 2 +# +# Follow the instructions the generator gives you then. module DT #:doc: - # NOTE: Alphabetical order in this section. + # Maximum number of stored messages, if they're not cleared. + # If web output is configured, messages are cleared before every request. + MAX_WEB_MESSAGES = 100 - # Clear messages. - def self.clear - @messages = [] - end + # Initializer. + def self._initialize #:nodoc: + clear_web_messages - # Return messages accumulated since last cleared. - def self.messages - @messages + # NOTES: + # * Stuffing is inserted in order to work around buggy RDoc parser. + # "a""bc" => "abc", just in case. + # * Don't forget to update generator/initializers/dt.rb with these. + # * "Canonical" order of imporance: log, console, web. + @log_prefix = "[DT <""%= file_rel %>:<""%= line %>] " + @console_prefix = @log_prefix.dup + @web_prefix = '<a href="txmt://open?url=file://<''%= file %>&line=<''%= line %>"><''%= file_rel %>:<''%= line %></a> ' + + # In case of path problems @log will be nil. + @log = Logger.new(Rails.root + "log/dt.log") rescue nil end - # Dump a value or several values. Similar to Ruby's native <tt>p</tt>. - # p "my var: " + myvar.inspect - # p @myobj - def self.p(*args) - # Fetch caller information. - # NOTE: May be lacking file information, e.g. when in an irb session. - file, line = caller.first.split(":") - - # Template variables. Documented in web_prefix=. - hc = { - :file => file, - :line => line, - :file_base => (begin; File.basename(file); rescue; file; end), - :file_rel => (begin; Pathname(file).relative_path_from(Rails.root).to_s; rescue; file; end), + # On-the-fly initializer. + def self._otf_init #:nodoc: + # Consider job done, replace self with a blank. + class_eval { + def self._otf_init #:nodoc: + end } - ##return hc - - args.each do |r| - s = r.is_a?(String) ? r : r.inspect - - # NOTE: "Canonical" order of imporance: web, console, log. - - # To Web. - if self.web_prefix - pfx = ERB.new(self.web_prefix, nil, "-").result(_hash_kbinding(hc)) - - pcs = [] - pcs << pfx - pcs << CGI.escapeHTML(s).gsub("\n", "<br/>\n") - pcs << "<br/>\n" - @messages << pcs.join - end - - # To console. - if self.console_prefix - pfx = ERB.new(self.console_prefix, nil, "-").result(_hash_kbinding(hc)) - puts [pfx, s].join - end - - # To log. - if self.log_prefix and @log - pfx = ERB.new(self.log_prefix, nil, "-").result(_hash_kbinding(hc)) - @log.info [pfx, s].join - end - end - - # Be like puts -- more comfy when debugging in console. - nil + _initialize end - # Format accumulated messages as HTML. - # to_html # => Something like "<ul><li>A message!</li></ul>". - def self.to_html - pcs = [] - pcs << "<ul>" - @messages.each do |s| - pcs << ["<li>", s, "</li>"].join - end - pcs << "</ul>" - - pcs.join - end - - #--------------------------------------- Control stuff - - # Set message prefix for console. See <tt>web_prefix=</tt>. + # Set message prefix for console. See <tt>log_prefix=</tt>. def self.console_prefix=(s) + _otf_init @console_prefix = s end def self.console_prefix + _otf_init @console_prefix end # Set logger to use. Must be a <tt>Logger</tt>. + # # log = Logger.new("log/my.log") def self.log=(obj) + _otf_init raise "Logger expected, #{obj.class} given" if not obj.is_a? Logger @log = obj end def self.log + _otf_init @log end - # Set message prefix for log. See <tt>web_prefix=</tt>. + # Set message prefix for log. Syntax is ERB. + # + # log_prefix = "[DT <""%= file_rel %>:<""%= line %>] " + # + # NOTE: In the above example some stuffing was made to satisfy the buggy RDoc parser. + # Just in case, <tt>"a""bc"</tt> is <tt>"abc"</tt> in Ruby. + # + # Template variables: + # + # * <tt>file</tt> -- full path to file. + # * <tt>file_base</tt> -- file base name. + # * <tt>file_rel</tt> -- file name relative to Rails application root. + # * <tt>line</tt> -- line number. + # + # By setting prefix to <tt>nil</tt> you disable respective output. + # + # web_prefix = nil # Disable web output. def self.log_prefix=(s) + _otf_init @log_prefix = s end def self.log_prefix + _otf_init @log_prefix end - # Set message prefix for web. Syntax is ERB. - # web_prefix = '<a href="txmt://open?url=file://<%= file %>&line=<%= line %>"><%= file_rel %>:<%= line %></a> ' - # - # Template variables: - # * <tt>file</tt> -- full path to file - # * <tt>line</tt> -- line number - # * <tt>file_base</tt> -- file base name - # * <tt>file_rel</tt> -- file name relative to Rails application root - # - # By setting prefix to <tt>nil</tt> you disable respective output. - # web_prefix = nil # Web output is disabled now. + # Return messages accumulated since last cleared. + def self.web_messages + _otf_init + @web_messages + end + + # Set message prefix for web. See <tt>log_prefix=</tt>. def self.web_prefix=(s) + _otf_init @web_prefix = s end def self.web_prefix + _otf_init @web_prefix end #--------------------------------------- + # Clear messages. + def self.clear_web_messages + _otf_init + @web_messages = [] + end + + # Print a debug message or dump a value. Somewhat similar to Ruby's native <tt>p</tt>. + # + # p "Hello, world!" + # p "myvar", myvar + def self.p(*args) + _otf_init + # Fetch caller information. + # NOTE: May be lacking file information, e.g. when in an irb session. + file, line = caller.first.split(":") + + # Assign template variables. + hc = { + :file => file, + :line => line, + :file_base => (begin; File.basename(file); rescue; file; end), + :file_rel => (begin; Pathname(file).relative_path_from(Rails.root).to_s; rescue; file; end), + } + + args.each do |r| + s = r.is_a?(String) ? r : r.inspect + + # To log. + if @log_prefix + ##Kernel.p "@log", @log #DEBUG + if @log + pfx = ERB.new(@log_prefix, nil, "-").result(_hash_kbinding(hc)) + msg = [pfx, s].join + @log.info msg + Rails.logger.info msg rescue nil # In case something's wrong with `Rails.logger`. + end + end + + # To console. + if @console_prefix + pfx = ERB.new(@console_prefix, nil, "-").result(_hash_kbinding(hc)) + puts [pfx, s].join + end + + # To web. + if @web_prefix + pfx = ERB.new(@web_prefix, nil, "-").result(_hash_kbinding(hc)) + + pcs = [] + pcs << pfx + pcs << CGI.escapeHTML(s).gsub("\n", "<br/>\n") + @web_messages << pcs.join + + # Rotate messages. + @web_messages.slice!(0..-(MAX_WEB_MESSAGES + 1)) + end + end + + # Be like `puts`, return nil. + nil + end + + # Format accumulated web messages as HTML. Usually called from a view template. + # + # web_messages_as_html # => Something like "<ul><li>Message 1</li><li>Message 2</li>...</ul>". + def self.web_messages_as_html + _otf_init + + pcs = [] + pcs << "<ul>" + @web_messages.each do |s| + pcs << ["<li>", s, "</li>"].join + end + pcs << "</ul>" + + if (out = pcs.join).respond_to? :html_safe + out.html_safe + else + out + end + end + + #--------------------------------------- + # NOTE: Singletons can't be private, so mark them syntactically. # Turn hash's entries into locals and return binding. # Useful for simple templating. def self._hash_kbinding(h) #:nodoc: # NOTE: This IS important, since assignment is eval'd in this context. bnd = binding _value = nil - h.each do |k, _value| - ##puts "-- k-#{k.inspect} v-#{_value.inspect}" + h.each do |k, v| + ##puts "-- k-#{k.inspect} v-#{_value.inspect}" #DEBUG + _value = v # IMPORTANT: Ruby 1.9 compatibility hack. eval("#{k} = _value", bnd) end bnd end - #--------------------------------------- Initialization - - def self._init #:nodoc: - # Require Rails environment. - if not defined? Rails - raise "Rails environment not found. This module is meaningful in Rails only" - end - - clear - - # NOTE: Don't forget to update generator/initializers/dt.rb with these. - self.web_prefix = '<a href="txmt://open?url=file://<%= file %>&line=<%= line %>"><%= file_rel %>:<%= line %></a> ' - self.console_prefix = "[DT <%= file_rel %>:<%= line %>] " - self.log_prefix = self.console_prefix - - # In case of path problems @log will be nil. - @log = begin - Logger.new("log/dt.log") - rescue Exception - end - end - - _init - + # DO NOT invoke `_initialize` load-time, it won't see Rails3 stuff. end # DT