pretty_debug 0.0.1

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.
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: []