pretty_debug 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/pretty_debug.rb +226 -0
  3. metadata +43 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 63d046bb64c02a4934a7552366ac1bbda9b7eb48
4
+ data.tar.gz: 7234ce3741b46d5330503d39eaa1d420c48af558
5
+ SHA512:
6
+ metadata.gz: 4fd77aec4709afb9dd87655766060311bcac256881b76bbcd4f352e1b0ac934d010d00d6d0629ccc42a4a84855316aba9266b92e6b305b4bdbebeee42a0eeb3f
7
+ data.tar.gz: 53fc2eda6b9662257774bd1af2b4958b6bcbabe9f530fbd4a905126370db7e5a96f4204a01826cc49f907961d2c8bbbec56346df7f996c5740b559b6a57e127a
@@ -0,0 +1,226 @@
1
+ #!ruby
2
+ require "string"
3
+ require "ruby-prof"
4
+
5
+ module Kernel
6
+ at_exit do
7
+ case $!
8
+ when SystemStackError
9
+ puts PrettyDebug.mesage
10
+ ##TODO Parse the backtrace and attempt to extract a call cycle.
11
+ # PrettyDebug.clean($@)
12
+ when nil, SystemExit, Interrupt
13
+ else
14
+ puts PrettyDebug.message
15
+ puts PrettyDebug.clean($@).align(":").map(&:indent)
16
+ end
17
+ $stderr.reopen(IO::NULL)
18
+ $stdout.reopen(IO::NULL)
19
+ end
20
+ end
21
+
22
+ class ValidationError < Exception; end
23
+
24
+ class Object
25
+ def expect s; raise ArgumentError.new("Expecting `#{s.inspect}`: #{inspect}") end
26
+ def case? *kases; kases.any?{|kase| kase === self} end
27
+ end
28
+
29
+ class Array
30
+ def compatible? other
31
+ other.case?(Array) and
32
+ other.length == length
33
+ end
34
+ end
35
+
36
+ class Hash
37
+ def compatible? other
38
+ other.case?(Hash) and
39
+ other.size == size and
40
+ other.keys.all?{|k| key?(k)}
41
+ end
42
+ end
43
+
44
+ class PrettyDebug
45
+ attr_accessor :backtrace, :message
46
+ def self.new_internal
47
+ new.tap do |error|
48
+ called_location = clean(caller)[2]
49
+ error.backtrace = clean($@).take_while{|a| a != called_location}
50
+ error.message = $!.message
51
+ end
52
+ end
53
+ Stackline = /\A(?'f'.+?):(?'l'\d+)(?::in `(?'m'.*)'|(?'m'.*))?\z/m
54
+ NoncallLine = /\Ablock(?: \(\d+ levels\))? in |\A\</
55
+ def self.message; $!.message.dup.tap{|s| s[0] = s[0].upcase}.sub(/(?<=[^.])\z/, ".") end
56
+ def self.clean stack
57
+ raise "Cannot parse. No backtrace given" unless stack
58
+ return [] if stack.empty?
59
+ caller_file_i = $LOADED_FEATURES.index(caller.first.match(Stackline)[:f]).to_i
60
+ stack
61
+ .map{|l| m = l.match(Stackline); [m[:f].ellipsis(55), m[:l].to_i, m[:m]]}
62
+ .transpose.tap do |_, _, m|
63
+ m.rotate!(-1)
64
+ m[0] = ""
65
+ while i = m.index{|m| m == "method_missing"}; m[i] = m[i - 1] end
66
+ end.transpose
67
+ .reject{|_, _, m| m =~ NoncallLine}
68
+ # .reject{|f, _, _| $LOADED_FEATURES.include?(f)}
69
+ # .reject{|f, _, _| $LOADED_FEATURES.index(f).to_i > caller_file_i}
70
+ end
71
+ end
72
+
73
+ #############################################
74
+ # Terminal formatting
75
+ #############################################
76
+
77
+ class Object
78
+ def intercept &pr
79
+ tap{|x| puts "[Debug] #{caller[2][/.*?:\d+/]}:".color(:yellow); pr ? pr.call(x) : p(x)}
80
+ end
81
+ def forwardtrace sym
82
+ tap{puts "#{inspect}##{sym} defined at:", method(sym).source_location.join(":").indent}
83
+ end
84
+ def follow m; tap{puts "Next step: #{method(m).source_location
85
+ .chain{|a| a ? a.join(":") : "Unknown #{self}.#{m}"}
86
+ }"} end
87
+ def _?; tap{Test.testee.push(self)} end
88
+ end
89
+
90
+ =begin
91
+ class Module
92
+ def inspect
93
+ ans = ancestors.map{|m| "#{m.class.send(:to_s).downcase} #{m}"}.join(" < ")
94
+ var = (class_variables + instance_variables).join(", ")
95
+ var.empty? ? ans : "#{ans}#$/#{var}"
96
+ end
97
+ end
98
+ =end
99
+
100
+ class Proc
101
+ def source_location
102
+ to_s.match(/\A\#\<#{self.class}:.+?@(.+)\:(\d+)(?: \(lambda\))?\>\z/).values_at(1, 2)
103
+ end
104
+ def inspect
105
+ f, l = source_location
106
+ "Proc@#{File.basename(f)}:#{l}"
107
+ rescue
108
+ "Proc@source_unknown"
109
+ end
110
+ end
111
+
112
+ class Method
113
+ def inspect; to_s end
114
+ def to_s; "#{receiver}.#{name}" end
115
+ end
116
+
117
+ class UnboundMethod
118
+ def inspect; to_s end
119
+ def to_s; "#{owner}##{name}" end
120
+ end
121
+
122
+ class Array
123
+ def inspect
124
+ map(&:inspect)
125
+ .chain{|s| length < 2 ? "[#{s.join}]" : "[#$/#{s.join(",#$/").indent}#$/]"}
126
+ end
127
+ def align sep = " ", ellipsis_limit = nil
128
+ col_widths = transpose.map{|col| col.map{|cell| cell.to_s.length}.max}
129
+ map{|row| [row, col_widths].parallel{|col, l|
130
+ max = ellipsis_limit || l
131
+ l = l.at_most(max)
132
+ case col
133
+ when Numeric then col.to_s.ellipsis(max).rjust(l)
134
+ else col.to_s.ellipsis(max).ljust(l)
135
+ end
136
+ }.join(sep)}
137
+ end
138
+ end
139
+
140
+ class Hash
141
+ KeyLengthMax = 30
142
+ def inspect
143
+ keys = self.keys.map{|k| k.inspect.utf8}
144
+ # When `self == empty?`, `...max` becomes `nil`. `to_i` turns it to `0`.
145
+ w = keys.map(&:length).max.to_i.at_most(KeyLengthMax)
146
+ [keys, values].parallel{|k, v| "#{k.ljust(w)} => #{v.inspect}"}
147
+ .chain{|s| length < 2 ? "{#{s.join}}" : "{#$/#{s.join(",#$/").indent}#$/}"}
148
+ end
149
+ end
150
+
151
+ module Test
152
+ def self.testee; @@testee end
153
+ def self.raise? exception = Exception, &pr
154
+ pr.call; false
155
+ rescue Exception => e
156
+ e.kind_of?(exception)
157
+ end
158
+ def self.testee_clear; @@testee = [] end
159
+ def self.testee_refer; @@testee end
160
+ def self.test title = "Test", &pr
161
+ testee_clear
162
+ t = Time.now
163
+ if pr.call == true
164
+ puts "#{title}. Succeeded (#{"%.2e" % t.till_now} secs)".color(:green)
165
+ else
166
+ puts "#{title}. Failed".color(:red),
167
+ *(testee_refer.map{|o| o.inspect.indent.color(:red)} unless testee_refer.empty?)
168
+ end
169
+ rescue Exception
170
+ puts "#{title} ... Test Error".color(:red),
171
+ [$!.message, *PrettyDebug.clean($@).align(":")].map{|l| l.indent.color(:red)}
172
+ end
173
+ end
174
+
175
+ module Kernel
176
+ def test *args, &pr; Test.test(*args, &pr) end
177
+ def raise? *args, &pr; Test.raise?(*args, &pr) end
178
+ def timer
179
+ t = Time.now
180
+ yield
181
+ puts "(#{"%.2e" % t.till_now} secs)".color(:green)
182
+ end
183
+ end
184
+
185
+ =begin
186
+ module Kernel
187
+ def benchmark i, &pr
188
+ Benchmark.prs = []
189
+ pr.call()
190
+ Benchmark.bm(i){|br| Benchmark.prs.each{|pr| br.report(""){pr.call()}}}
191
+ end
192
+ def alternative &pr; Benchmark.prs.push(pr) end
193
+ end
194
+
195
+ require "benchmark"
196
+ Benchmark.singleton_class.class_eval{attr_accessor :prs}
197
+ =end
198
+
199
+
200
+ =begin
201
+ require "ruby-prof"
202
+ $prof_begin = false
203
+ def profile_on; $prof_begin = true; end
204
+ def profile switch = nil
205
+ yield if switch && $prof_begin.!
206
+ RubyProf.resume{$prof_result = yield}
207
+ open("/tmp/profile", "w"){|io|
208
+ # RubyProf::CallStackPrinter. # for kcachegring
209
+ RubyProf::GraphHtmlPrinter.
210
+ # RubyProf::GraphPrinter.
211
+ # RubyProf::AbstractPrinter.
212
+ new(RubyProf.stop).print(io)}
213
+ # IO.popen("kcachegrind /tmp/profile > #{File::NULL} 2>&1")
214
+ # IO.popen("firefox >#{File::NULL} /tmp/profile ")
215
+ IO.popen("google-chrome >#{File::NULL} /tmp/profile ")
216
+ $prof_result
217
+ end
218
+
219
+ module Profiling
220
+ def self.start; RubyProf.start end
221
+ def self.stop
222
+ result = RubyProf.stop
223
+ RubyProf::FlatPrinter.new(result).print
224
+ end
225
+ end
226
+ =end
metadata ADDED
@@ -0,0 +1,43 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pretty_debug
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - sawa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-29 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: ''
14
+ email: []
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/pretty_debug.rb
20
+ homepage: http://sawa.github.io/pretty_debug
21
+ licenses: []
22
+ metadata: {}
23
+ post_install_message:
24
+ rdoc_options: []
25
+ require_paths:
26
+ - lib
27
+ required_ruby_version: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ required_rubygems_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ requirements: []
38
+ rubyforge_project:
39
+ rubygems_version: 2.0.6
40
+ signing_key:
41
+ specification_version: 4
42
+ summary: ''
43
+ test_files: []