debug_me 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 03f8c0541fab13dc5ea656fdd5ef697075132bb00a4662345d4d27f3f935bc99
4
+ data.tar.gz: 0d1d53bbedf84a6d9e17fcccb1565eaecd25ff0fa58ce09daeafb7386482999b
5
+ SHA512:
6
+ metadata.gz: 6531b542b0b28d5dd0d5b0dee66b3e15d316a0ee05b54be0dedfb1a38f7a78e1cf9ba366404dd2a5d8867e5bb35af7add5254b1a58187a5be610b0f750b1ad24
7
+ data.tar.gz: 36df84f99c1ab56ea168a7e693904244cf2b5c46660da6326e0649c5cdf5685190eb01155f1cbee548914babbbe02e9726ef6418de67e490a9a9f75d387c30fd
data/README.md CHANGED
@@ -1,13 +1,24 @@
1
1
  # DebugMe
2
2
 
3
- This thing is pretty old. There are much better
3
+ A tool to print the labeled value of variables.
4
+
5
+ This thing is pretty old; but, so am I. Even with the gray
6
+ in our hair we still do the job.
7
+
8
+ There are much more complex/comprehensive
4
9
  ways of debugging in a complex application. But,
5
10
  you know, I keep returning to this little method
6
11
  time after time. I guess that marks me as a geezer.
7
12
 
8
- A tool to print the labeled value of variables.
9
13
 
10
- Works with local, instance and class variables.
14
+ DebugMe::debug_me(){} works with local, instance and class variables.
15
+
16
+ ## Recent Changes
17
+
18
+ * 1.1.0 Changes the output formatting w/r/t the use of levels option; add :backtrace option for full backtrace
19
+ * 1.0.6 Added support for variable backtrack length via the :levels option
20
+ * 1.0.5 Added support for an instance of a Logger class.
21
+ * 1.0.4 Added :strftime to the options; changed the default format from decimal seconds since epic to something that is more easy comprehend on a clock.
11
22
 
12
23
  ## Installation
13
24
 
@@ -35,6 +46,11 @@ debug_me # Prints only the header banner consisting of tag, method name, file na
35
46
 
36
47
  debug_me('INFO') # Also prints only the header but with a different tag
37
48
 
49
+ debug_me(levels: 5) # Along with the header, show the call stack back this many levels
50
+ debug_me{:backtrace} # show the entire call stack
51
+ debug_me{[ :backtrace ]} will # show the entire call stack
52
+ debug_me(levels: 5){[ :backtrace ]} # will only show the first 5 levels of the backtrace - ie. the levels parameter supersedes :backtrace
53
+
38
54
  debug_me {} # prints the default header and __ALL__ variables
39
55
 
40
56
  debug_me {:just_this_variable} # prints the default header and the value of only one specific variable
@@ -45,9 +61,9 @@ debug_me { [:this_one, :that_one, :that_other_one] } # prints default header and
45
61
  # Each element of the array is 'eval'ed with the context binding of the caller
46
62
  debug_me(){[ :my_var, 'my_complex_var_or_method[my_var]' ]}
47
63
 
48
- debug_me(:header => false) {} # disables the printing of the header; prints all variables
64
+ debug_me(header: false) {} # disables the printing of the header; prints all variables
49
65
 
50
- debug_me(:tag => 'MyTag', :header => false) {} # disables header, sets different tag, prints all variables
66
+ debug_me(tag: 'MyTag', :header => false) {} # disables header, sets different tag, prints all variables
51
67
 
52
68
  debug_me('=== LOOK ===') {} # changes the tag and prints all variables with a header line
53
69
 
@@ -55,8 +71,140 @@ debug_me('=== LOOK ===') {:@foo} # changes the tag, prints a header line and a s
55
71
 
56
72
  debug_me('=== LOOK ===') {:@@foo} # changes the tag, prints a header line and a specific class variable
57
73
 
58
- debug_me(:ivar => false, :cvar => false) {} # print only the local variables with the default tag and a header line
74
+ debug_me(ivar: false, cvar: false) {} # print only the local variables with the default tag and a header line
75
+
76
+ ```
77
+
78
+ Most of the examples above use symbols to designate the variables that you want
79
+ to be shown with their name as a label. You can also use strings. With strings
80
+ you are not limited to just variables. Consider these examples:
81
+
82
+ ```ruby
83
+ debug_me {[ 'some_array.size', 'SomeDatabaseModel.count' ]}
84
+
85
+ # What a backtrace with your variables?
86
+
87
+ debug_me {[
88
+ :my_variable,
89
+ 'some_hash.keys.reject{|k| k.to_s.start_with?('A')}',
90
+ 'caller' ]} # yes, caller is a kernel method that will give a backtrace
91
+
92
+ # You can also get into trouble so be careful. The symbols and strings
93
+ # are evaluated in the context of the caller. Within the string any
94
+ # command or line of code can be given. SO DO NOT try to use
95
+ # something silly like debug_me{ 'system("rm -fr /")'}
96
+
97
+ ```
98
+
99
+ ## Default Options
100
+
101
+ The default options is a global constant `DebugMeDefaultOptions` that is outside of the `DebugMe` name space. I did that so that if you do `include DebugMe` to make access to the method easier you could still have the constant with a function specific name that would be outside of anything that you may have already coded in you program.
102
+
103
+ Notice that this constant is outside of the DebugMe's module namespace.
59
104
 
105
+ ```ruby
106
+ DebugMeDefaultOptions = {
107
+ tag: 'DEBUG', # A tag to prepend to each output line
108
+ time: true, # Include a time-stamp in front of the tag
109
+ strftime: '%Y-%m-%d %H:%M:%S.%6N', # timestamp format
110
+ header: true, # Print a header string before printing the variables
111
+ levels: 0, # Number of additional backtrack entries to display
112
+ skip1: false, # skip 1 blank line in front of a new output block
113
+ skip2: false, # skip 2 blank lines in front of a new output block
114
+ lvar: true, # Include local variables
115
+ ivar: true, # Include instance variables in the output
116
+ cvar: true, # Include class variables in the output
117
+ cconst: true, # Include class constants
118
+ logger: nil, # Pass in a logger class instance like Rails.logger
119
+ file: $stdout # The output file
120
+ }
121
+ ```
122
+
123
+ If you want the output of the method to always go to STDERR then do this:
124
+
125
+ ```ruby
126
+ require 'debug_me'
127
+ DebugMeDefaultOptions[:file] = $stderr # or STDERR
128
+ ```
129
+ If you want the `debug_me` output to go to a real file:
130
+
131
+ ```ruby
132
+ DebugMeDefaultOptions[:file] = File.open('debug_me.log', 'w')
133
+
134
+ ```
135
+
136
+ ## Using a Logger class instance
137
+
138
+ If you are working in Rails and want all the `debug_me` output to go to the Rails.logger its as easy as:
139
+ ```ruby
140
+ DebugMeDefaultOptions[:logger] = Rails.logger
141
+
142
+ ```
143
+
144
+ Or while working in rails you only want to add a marker to the Rails.logger do this:
145
+ ```ruby
146
+ debug_me(logger: Rails.logger, tag: 'Hello World')
147
+ ```
148
+
149
+ If you are working in Rails and want to use both the standard `debug_me` functions and occassionally put stuff into the Rails.logger but do not want to always remember the option settings then do something line this in a `config/initializers/aaaaa_debug_me.rb` file:
150
+
151
+ ```ruby
152
+ # config/initializers/aaaaa_debug_me.rb
153
+
154
+ require 'debug_me'
155
+
156
+ module DebugMe
157
+ def log_me(message, options={}, &block)
158
+ options = {logger: Rails.logger, time: false, header: false, tag: message}
159
+ block_given? ? debug_me(options, block) : debug_me(options)
160
+ end
161
+ end
162
+
163
+ include DebugMe
164
+
165
+ # Just setup the base name. The parent path will be added below ...
166
+ debug_me_file_name = 'debug_me'
167
+
168
+ # NOTE: you could add a timestamp to the filename
169
+ # debug_me_file_name += '_' + Time.now.strftime('%Y%m%d%H%M%S')
170
+
171
+ debug_me_file_name += '_' + Process.argv0.gsub('/',' ').split(' ').last
172
+ # NOTE: by using the Process.argv0 ... you get multiple log files for
173
+ # rails, rake, sidekiq etc.
174
+
175
+ debug_me_file_name += '.log'
176
+
177
+ debug_me_filepath = Rails.root + 'log' + debug_me_file_name
178
+
179
+ debug_me_file = File.open(debug_me_filepath, 'w')
180
+
181
+ debug_me_file.puts <<~RULER
182
+
183
+ ==================== Starting New Test Run --------->>>>>>
184
+
185
+ RULER
186
+
187
+ # Set application wide options in the DebugMeDefaultOptions hash
188
+ DebugMeDefaultOptions[:file] = debug_me_file
189
+
190
+ debug_me{['ENV']}
191
+
192
+ ```
193
+
194
+ What that does for your Rails application is dump all of your system environment variables and their values to a debug_me log file in the log directory of the application.
195
+
196
+ It also adds a new method `log_me` which you can use to send stuff to the `Rails.logger` instance. The method used by `debug_me` for the `logger` instance is always the `debug` method.
197
+
198
+ ## Conclusion
199
+
200
+ The rest of the default options are obvious.
201
+
202
+ You can always over-ride the default options on a case by case basis like this:
203
+
204
+ ```
205
+ debug_me {...}
206
+ ...
207
+ debug_me(header: false){...}
60
208
  ```
61
209
 
62
210
  ## Contributing
data/debug_me.gemspec CHANGED
@@ -5,7 +5,7 @@ require 'debug_me/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'debug_me'
8
- spec.version = DebugMe::VERSION
8
+ spec.version = DebugMe::DEBUG_ME_VERSION
9
9
  spec.authors = ['Dewayne VanHoozer']
10
10
  spec.email = ['dvanhoozer@gmail.com']
11
11
  spec.summary = 'A tool to print the labeled value of variables.'
@@ -21,6 +21,6 @@ time after time. I guess that marks me as a geezer.'
21
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
22
  spec.require_paths = ['lib']
23
23
 
24
- spec.add_development_dependency 'bundler', '~> 1.7'
25
- spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'bundler'
25
+ spec.add_development_dependency 'rake'
26
26
  end
data/lib/debug_me.rb CHANGED
@@ -1,43 +1,66 @@
1
1
  require 'pp'
2
2
  require_relative 'debug_me/version'
3
3
 
4
+ DebugMeDefaultOptions = {
5
+ tag: 'DEBUG', # A tag to prepend to each output line
6
+ time: true, # Include a time-stamp in front of the tag
7
+ strftime: '%Y-%m-%d %H:%M:%S.%6N', # timestamp format
8
+ header: true, # Print a header string before printing the variables
9
+ levels: 0, # Number of additional backtrack entries to display
10
+ skip1: false, # skip 1 lines between different outputs
11
+ skip2: false, # skip 2 lines between different outputs
12
+ lvar: true, # Include local variables
13
+ ivar: true, # Include instance variables in the output
14
+ cvar: true, # Include class variables in the output
15
+ cconst: true, # Include class constants
16
+ logger: nil, # Pass in an instance of logger class like Rails.logger
17
+ # must respond_to? :debug
18
+ file: $stdout # The output file
19
+ }
20
+
4
21
  module DebugMe
5
22
  def debug_me(options = {}, &block)
6
- default_options = {
7
- tag: 'DEBUG:', # A tag to prepend to each output line
8
- time: true, # Include a time-stamp in front of the tag
9
- header: true, # Print a header string before printing the variables
10
- lvar: true, # Include local variables
11
- ivar: true, # Include instance variables in the output
12
- cvar: true, # Include class variables in the output
13
- cconst: true, # Include class constants
14
- file: $stdout # The output file
15
- }
16
-
17
23
 
18
24
  if 'Hash' == options.class.to_s
19
- options = default_options.merge(options)
25
+ options = DebugMeDefaultOptions.merge(options)
20
26
  else
21
- options = default_options.merge(tag: options)
27
+ options = DebugMeDefaultOptions.merge(tag: options)
22
28
  end
23
29
 
24
- out_string = ''
30
+ skip = ''
31
+ skip = "\n" if options[:skip1]
32
+ skip = "\n\n" if options[:skip2]
33
+ out_string = ''
25
34
 
26
35
  f = options[:file]
36
+ l = options[:logger]
27
37
  s = ''
28
- s += "#{sprintf('%010.6f', Time.now.to_f)} " if options[:time]
29
- s += " #{options[:tag]}"
30
- wf = caller # where_from under 1.8.6 its a stack trace array under 1.8.7 is a string
31
- wf = wf[0] if 'Array' == wf.class.to_s
32
-
33
- out_string = sprintf("%s Source: %s\n",s,wf) if options[:header]
38
+ s += Time.now.strftime(options[:strftime])+' ' if options[:time]
39
+ s += "#{options[:tag]}"
40
+ bt = caller # where_from under 1.8.6 its a stack trace array under 1.8.7+ as a string
41
+ bt_out = []
34
42
 
35
- if block_given?
43
+ if options[:header]
44
+ cf = bt.is_a?(Array) ? bt[0] : bt
45
+ out_string = sprintf("%s Source: %s\n", skip+s, cf)
46
+ if options[:levels] > 0
47
+ levels = options[:levels].to_i
48
+ bt[1..levels].each_with_index do |cff, level |
49
+ bt_out << [level, cff]
50
+ end
51
+ end
52
+ end
36
53
 
37
- block_value = [block.call].flatten.compact
54
+ if block_given? || bt_out.size > 0
55
+ block_value = []
56
+ block_value << 'backtrace' if bt_out.size > 0
57
+ if block_given?
58
+ [block.call].flatten.compact.each do |v|
59
+ block_value << v
60
+ end
61
+ end
38
62
 
39
63
  if block_value.empty?
40
- block_value = []
41
64
  block_value += [eval('local_variables', block.binding)] if options[:lvar]
42
65
  block_value += [eval('instance_variables', block.binding)] if options[:ivar]
43
66
  block_value += [self.class.send('class_variables')] if options[:cvar]
@@ -48,7 +71,12 @@ module DebugMe
48
71
  block_value.map!(&:to_s)
49
72
 
50
73
  block_value.each do |v|
51
- ev = eval("defined?(#{v})",block.binding).nil? ? '<undefined>' : eval(v, block.binding)
74
+
75
+ ev = if 'backtrace' == v
76
+ bt_out.size > 0 ? bt_out : bt[1..10000]
77
+ else
78
+ eval("defined?(#{v})",block.binding).nil? ? '<undefined>' : eval(v, block.binding)
79
+ end
52
80
  out_string += sprintf( "%s %s -=> %s", s,v,ev.pretty_inspect)
53
81
  end
54
82
 
@@ -59,10 +87,14 @@ module DebugMe
59
87
  f.flush
60
88
  end
61
89
 
90
+ unless l.nil?
91
+ l.debug(out_string) if l.respond_to? :debug
92
+ end
93
+
62
94
  return out_string
63
95
  end ## def debug_me( options={}, &block )
64
96
 
65
97
  # def log_me(msg, opts={})
66
- # debug_me({:tag => msg, :header => false}.merge(opts))
98
+ # debug_me({tag: msg, header: false}.merge(opts))
67
99
  # end
68
100
  end # module DebugMe
@@ -1,3 +1,8 @@
1
1
  module DebugMe
2
- VERSION = '1.0.2'
2
+ # I know. Its weird to duplicate the name space; but,
3
+ # doing this allows you to include DebugMe in your code
4
+ # to get direct access to the debug_me method without
5
+ # poluting your code with an object name that is so
6
+ # common.
7
+ DEBUG_ME_VERSION = '1.1.0'
3
8
  end
@@ -1,5 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'amazing_print'
4
+ require 'logger'
5
+ require 'pathname'
6
+
3
7
  require_relative '../lib/debug_me'
4
8
  include DebugMe
5
9
 
@@ -34,6 +38,27 @@ describe DebugMe do
34
38
 
35
39
  end # describe "source header included" do
36
40
 
41
+
42
+
43
+ describe "Add more from the call stack" do
44
+
45
+ before do
46
+ @my_world_view = WorldView.new
47
+ end
48
+
49
+ it 'supports multiple levels from the call stack' do
50
+ result = @my_world_view.one
51
+ # debug_me returns everything as one big long string
52
+ # with embedded new lines. In the WorldView class
53
+ # method six is called from five, which is called from four, three, two, one.
54
+ # The ":levels" options is set to 5 so expect the
55
+ # normal source header followed by 5 additional
56
+ # entries from the call stack.
57
+ assert_equal(result.split("\n").size, 6)
58
+ end
59
+ end
60
+
61
+
37
62
  describe "source header excluded" do
38
63
 
39
64
  before do
@@ -224,6 +249,45 @@ describe DebugMe do
224
249
 
225
250
  end # describe "works with class CONSTANTS" do
226
251
 
252
+ describe "works with a Logger class" do
253
+
254
+ it 'default logger class is nil' do
255
+ DebugMeDefaultOptions[:logger].must_equal nil
256
+ end
257
+
258
+ it 'works with standard ruby Logger class' do
259
+ logger_output_path = Pathname.pwd + 'logger_class_output.txt'
260
+ logger_output_path.exist?.must_equal false
261
+
262
+ logger = Logger.new(logger_output_path)
263
+ logger.level = Logger::DEBUG
264
+
265
+ out_string = debug_me(
266
+ logger: logger, # Use instance of Ruby's Logger
267
+ time: false, # turn off debug_me's timestamp
268
+ file: nil, # don't write to STDOUT the default
269
+ tag: 'Hello World' # say hello
270
+ )
271
+ # Generates an entry like this:
272
+ =begin
273
+ # Logfile created on 2020-04-27 16:16:38 -0500 by logger.rb/v1.4.2
274
+ D, [2020-04-27T16:16:38.580889 #54662] DEBUG -- : Hello World Source: debug_me_test.rb:244:in `block (3 levels) in <main>'
275
+ =end
276
+
277
+ lines = logger_output_path.read.split("\n")
278
+
279
+ lines.size.must_equal 2
280
+
281
+ lines[0].start_with?('# Logfile created on').must_equal true
282
+ lines[1].start_with?('D, [').must_equal true
283
+ lines[1].include?('DEBUG').must_equal true
284
+ lines[1].include?('Hello World').must_equal true
285
+ lines[1].include?('debug_me_test.rb').must_equal true
286
+ lines[1].include?(out_string.chomp).must_equal true
287
+
288
+ logger_output_path.delete
289
+ end
227
290
 
291
+ end
228
292
 
229
293
  end # describe DebugMe do
data/tests/world_view.rb CHANGED
@@ -3,20 +3,23 @@ class WorldView
3
3
  A = 1
4
4
  B = 2
5
5
  C = 3
6
+
6
7
  def initialize
7
- @a,@b,@c = 1,2,3
8
- @@d, @@e, @@f = 4,5,6
8
+ @a,@b,@c = 1,2,3
9
+ @@d, @@e, @@f = 4,5,6
9
10
  end
11
+
10
12
  def everything
11
13
  debug_me(
12
- file:nil,
13
- header:true,
14
- lvar: true,
15
- ivar: true,
16
- cvar: true,
14
+ file: nil,
15
+ header: true,
16
+ lvar: true,
17
+ ivar: true,
18
+ cvar: true,
17
19
  cconst: true
18
20
  ){}
19
21
  end
22
+
20
23
  def my_constants
21
24
  debug_me(
22
25
  file:nil,
@@ -26,6 +29,15 @@ class WorldView
26
29
  cvar: false,
27
30
  cconst: true
28
31
  ){}
32
+ end
33
+
34
+ def one; two; end
35
+ def two; three; end
36
+ def three; four; end
37
+ def four; five; end
38
+ def five; six; end
29
39
 
40
+ def six
41
+ debug_me(tag:'How did I get here?', levels: 5)
30
42
  end
31
43
  end # class WorldView
metadata CHANGED
@@ -1,63 +1,56 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: debug_me
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
5
- prerelease:
4
+ version: 1.1.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Dewayne VanHoozer
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2015-01-19 00:00:00.000000000 Z
11
+ date: 2021-04-23 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - ">="
20
18
  - !ruby/object:Gem::Version
21
- version: '1.7'
19
+ version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - ">="
28
25
  - !ruby/object:Gem::Version
29
- version: '1.7'
26
+ version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rake
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
- version: '10.0'
33
+ version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
- version: '10.0'
46
- description: ! 'This thing is pretty old. There are much better
47
-
40
+ version: '0'
41
+ description: |-
42
+ This thing is pretty old. There are much better
48
43
  ways of debugging in a complex application. But,
49
-
50
44
  you know, I keep returning to this little method
51
-
52
- time after time. I guess that marks me as a geezer.'
45
+ time after time. I guess that marks me as a geezer.
53
46
  email:
54
47
  - dvanhoozer@gmail.com
55
48
  executables: []
56
49
  extensions: []
57
50
  extra_rdoc_files: []
58
51
  files:
59
- - .gitignore
60
- - .rultor.yml
52
+ - ".gitignore"
53
+ - ".rultor.yml"
61
54
  - Gemfile
62
55
  - LICENSE.txt
63
56
  - README.md
@@ -71,26 +64,24 @@ files:
71
64
  homepage: http://github.com/MadBomber/debug_me
72
65
  licenses:
73
66
  - You want it, its yours
74
- post_install_message:
67
+ metadata: {}
68
+ post_install_message:
75
69
  rdoc_options: []
76
70
  require_paths:
77
71
  - lib
78
72
  required_ruby_version: !ruby/object:Gem::Requirement
79
- none: false
80
73
  requirements:
81
- - - ! '>='
74
+ - - ">="
82
75
  - !ruby/object:Gem::Version
83
76
  version: '0'
84
77
  required_rubygems_version: !ruby/object:Gem::Requirement
85
- none: false
86
78
  requirements:
87
- - - ! '>='
79
+ - - ">="
88
80
  - !ruby/object:Gem::Version
89
81
  version: '0'
90
82
  requirements: []
91
- rubyforge_project:
92
- rubygems_version: 1.8.23
93
- signing_key:
94
- specification_version: 3
83
+ rubygems_version: 3.2.15
84
+ signing_key:
85
+ specification_version: 4
95
86
  summary: A tool to print the labeled value of variables.
96
87
  test_files: []