blab 0.0.0 → 0.0.1.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7d7fc1c9db347fe57115c358bc1c0769e633587e
4
- data.tar.gz: 04141e00b10ed64cc29c2d98cae44584fe5af0b3
2
+ SHA256:
3
+ metadata.gz: e0f2fa8c029f19b494bc57a4fddf76cb8c5b5265e208c7630e1d56cdaf52cb1d
4
+ data.tar.gz: 16b98eb6a98c16491e650169e4b0bfeea0c6b43b31cfdff9741a2a97443c0c33
5
5
  SHA512:
6
- metadata.gz: fc9c53060f3b2e8041aeb81d4457b28e43024b80f9926183dc5a4c0ea2b7b4bb95a04afdb73078bcef6ceb0d599622c1f7786c10e581e2c98017d2d951ad7513
7
- data.tar.gz: 24b68ce8bee102e0352e37b6033de0c357a79f1bbb1f5e7af66f820215adcb59b0f2e24d661523597e3e0781788c59548a3d6e26de7457eecf12f91b240157cc
6
+ metadata.gz: 5b0ce5055f845ad8eeb3cc1daf1c93532cb927e471830413baba7b2b75565d0b91cd6bcdf0d340c352a3e8c2a6fe95bac3e531d74c6ac61a80c462953e1590c5
7
+ data.tar.gz: da14317d5e95869fbadd1c57d809a8878341dcd6dd6c9c65216c2f8c0d3757cba593b8681ef284f333f85d46aa7bb72c57be440284271f8996f515bd0aa4a334
data/README.md CHANGED
@@ -1,2 +1,157 @@
1
1
  # blab
2
- A debugging tool
2
+ [![Gem Version](https://badge.fury.io/rb/blab.svg)](https://badge.fury.io/rb/blab)
3
+
4
+ A debugging tool.
5
+
6
+ The gem allows to trace local variables and memory usage for a specific Ruby code. It's rather experemental and is intended for use in a development environment only. \
7
+ Blab is inspired by [PySnooper](https://github.com/cool-RR/PySnooper).
8
+
9
+
10
+ ## Installation
11
+
12
+ Put this line in your Gemfile
13
+
14
+ ```ruby
15
+ gem "blab", group: :development
16
+ ```
17
+
18
+ Then run
19
+
20
+ ```
21
+ bundle install
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ Include `Blab` module and the destionation class and use the `blab` decorator in front of a method defenition.
27
+
28
+ ```ruby
29
+ require "blab"
30
+
31
+ class Test
32
+ include Blab
33
+
34
+ blab def longest_rep(str)
35
+ max = str.chars.chunk(&:itself).map(&:last).max_by(&:size)
36
+ max ? [max[0], max.size] : ["", 0]
37
+ end
38
+ end
39
+
40
+ Test.new.longest_rep("cbaaabb")
41
+
42
+ ```
43
+
44
+ The output to STDOUT:
45
+
46
+ ```
47
+ Var......... str="cbaaabb"
48
+ 18:17:26.042 call test/support/test.rb:46 13463552 blab def longest_rep(str)
49
+ 18:17:26.042 line test/support/test.rb:47 13508608 max = str.chars.chunk(&:itself).map(&:last).max_by(&:size)
50
+ Var......... max=["a", "a", "a"]
51
+ 18:17:26.043 line test/support/test.rb:48 13516800 max ? [max[0], max.size] : ["", 0]
52
+ 18:17:26.043 return test/support/test.rb:49 13516800 end
53
+ ```
54
+
55
+ The output is configurable. Within the example the 4th item in a table is `ru_maxss` - a memory amount used by the Ruby process. The value is in bytes on Mac OS X (Darwin), but in kilobytes on BSD and Linux. In the example it's in bytes and is roughly 13MB total.
56
+ Note, that blab itself adds some overhead, and the program'll take lesser memory running without it.
57
+
58
+ The gem allows to wrap only a piece of code in a block:
59
+
60
+ ```ruby
61
+ class Test
62
+ include Blab
63
+
64
+ def shuffle(arr)
65
+ for n in 0...arr.size
66
+ targ = n + rand(arr.size - n)
67
+ arr[n], arr[targ] = arr[targ], arr[n] if n != targ
68
+ end
69
+ end
70
+
71
+ def pairs(a, b)
72
+ with_blab do
73
+ a << "Insane"
74
+ shuffle(b)
75
+ end
76
+ b.each { |x| shuffle(a); a.each { |y| print y, " ", x, ".\n" } }
77
+ end
78
+ end
79
+
80
+ Test.new.pairs(["Bored", "Curious"], ["cat", "frog"])
81
+ ```
82
+
83
+ The output:
84
+
85
+ ```
86
+ Var......... a=["Bored", "Curious"]
87
+ Var......... b=["cat", "frog"]
88
+ 18:38:15.188 line test/support/test.rb:54 13770752 a << "Insane"
89
+ 18:38:15.188 line test/support/test.rb:55 13807616 shuffle(b)
90
+ Var......... arr=["cat", "frog"]
91
+ 18:38:15.188 call test/support/test.rb:45 13807616 def shuffle(arr)
92
+ 18:38:15.189 line test/support/test.rb:46 13807616 for n in 0...arr.size
93
+ Var......... n=0
94
+ 18:38:15.189 line test/support/test.rb:47 13811712 targ = n + rand(arr.size - n)
95
+ Var......... targ=0
96
+ 18:38:15.189 line test/support/test.rb:48 13811712 arr[n], arr[targ] = arr[targ], arr[n] if n != targ
97
+ Var......... n=1
98
+ 18:38:15.189 line test/support/test.rb:47 13811712 targ = n + rand(arr.size - n)
99
+ Var......... targ=1
100
+ 18:38:15.189 line test/support/test.rb:48 13811712 arr[n], arr[targ] = arr[targ], arr[n] if n != targ
101
+ 18:38:15.189 return test/support/test.rb:50 13811712 end
102
+ ```
103
+
104
+ ## Configuration
105
+
106
+ Output to a file:
107
+
108
+ ```ruby
109
+ Blab::Config.log_output = "log/blab.log"
110
+ ```
111
+
112
+ Datetime format:
113
+
114
+ ```ruby
115
+ Blab::Config.datetime_format = "%H:%M:%S.%L"
116
+ ```
117
+
118
+ Custom logger:
119
+
120
+ ```ruby
121
+ Blab::Config.logger = MyCustomLogger.new
122
+ ```
123
+
124
+ Trace C calls your program makes from Ruby:
125
+
126
+ ```ruby
127
+ Blab::Config.trace_c_calls = true
128
+ ```
129
+
130
+ Trace only within the original scope. \
131
+ It means that the trace will be showed only for the current method and it will skip all external call's traces.
132
+
133
+ ```ruby
134
+ Blab::Config.original_scope_only = true
135
+ ```
136
+
137
+ Format output. Available config is:
138
+
139
+ ```ruby
140
+ output_order = [
141
+ { type: :time, order: 1, width: 12 },
142
+ { type: :event, order: 2, width: 6 },
143
+ { type: :file_lines, order: 3, width: 30 },
144
+ { type: :class_name, order: 4, width: 10 },
145
+ { type: :method_name, order: 5, width: 12 },
146
+ { type: :ru_maxss, order: 6, width: 12 },
147
+ { type: :code_lines, order: 7, width: 120 }
148
+ ]
149
+
150
+ Blab::Config.output_order = output_order
151
+ ```
152
+ By default it doesn't show current class name and method name. You can adjust the width, change the order, skip/add the desired output info.
153
+
154
+ ## License
155
+
156
+ MIT
157
+
data/ext/Makefile ADDED
@@ -0,0 +1,266 @@
1
+
2
+ SHELL = /bin/sh
3
+
4
+ # V=0 quiet, V=1 verbose. other values don't work.
5
+ V = 0
6
+ Q1 = $(V:1=)
7
+ Q = $(Q1:0=@)
8
+ ECHO1 = $(V:1=@ :)
9
+ ECHO = $(ECHO1:0=@ echo)
10
+ NULLCMD = :
11
+
12
+ #### Start of system configuration section. ####
13
+
14
+ srcdir = .
15
+ topdir = /Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0
16
+ hdrdir = $(topdir)
17
+ arch_hdrdir = /Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16
18
+ PATH_SEPARATOR = :
19
+ VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
20
+ prefix = $(DESTDIR)/Users/july/.rbenv/versions/2.6.0
21
+ rubysitearchprefix = $(rubylibprefix)/$(sitearch)
22
+ rubyarchprefix = $(rubylibprefix)/$(arch)
23
+ rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
24
+ exec_prefix = $(prefix)
25
+ vendorarchhdrdir = $(vendorhdrdir)/$(sitearch)
26
+ sitearchhdrdir = $(sitehdrdir)/$(sitearch)
27
+ rubyarchhdrdir = $(rubyhdrdir)/$(arch)
28
+ vendorhdrdir = $(rubyhdrdir)/vendor_ruby
29
+ sitehdrdir = $(rubyhdrdir)/site_ruby
30
+ rubyhdrdir = $(includedir)/$(RUBY_VERSION_NAME)
31
+ vendorarchdir = $(vendorlibdir)/$(sitearch)
32
+ vendorlibdir = $(vendordir)/$(ruby_version)
33
+ vendordir = $(rubylibprefix)/vendor_ruby
34
+ sitearchdir = $(sitelibdir)/$(sitearch)
35
+ sitelibdir = $(sitedir)/$(ruby_version)
36
+ sitedir = $(rubylibprefix)/site_ruby
37
+ rubyarchdir = $(rubylibdir)/$(arch)
38
+ rubylibdir = $(rubylibprefix)/$(ruby_version)
39
+ sitearchincludedir = $(includedir)/$(sitearch)
40
+ archincludedir = $(includedir)/$(arch)
41
+ sitearchlibdir = $(libdir)/$(sitearch)
42
+ archlibdir = $(libdir)/$(arch)
43
+ ridir = $(datarootdir)/$(RI_BASE_NAME)
44
+ mandir = $(datarootdir)/man
45
+ localedir = $(datarootdir)/locale
46
+ libdir = $(exec_prefix)/lib
47
+ psdir = $(docdir)
48
+ pdfdir = $(docdir)
49
+ dvidir = $(docdir)
50
+ htmldir = $(docdir)
51
+ infodir = $(datarootdir)/info
52
+ docdir = $(datarootdir)/doc/$(PACKAGE)
53
+ oldincludedir = $(SDKROOT)/usr/include
54
+ includedir = $(prefix)/include
55
+ localstatedir = $(prefix)/var
56
+ sharedstatedir = $(prefix)/com
57
+ sysconfdir = $(prefix)/etc
58
+ datadir = $(datarootdir)
59
+ datarootdir = $(prefix)/share
60
+ libexecdir = $(exec_prefix)/libexec
61
+ sbindir = $(exec_prefix)/sbin
62
+ bindir = $(exec_prefix)/bin
63
+ archdir = $(rubyarchdir)
64
+
65
+
66
+ CC_WRAPPER =
67
+ CC = clang
68
+ CXX = clang++
69
+ LIBRUBY = $(LIBRUBY_A)
70
+ LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
71
+ LIBRUBYARG_SHARED =
72
+ LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static -framework Security -framework Foundation $(MAINLIBS)
73
+ empty =
74
+ OUTFLAG = -o $(empty)
75
+ COUTFLAG = -o $(empty)
76
+ CSRCFLAG = $(empty)
77
+
78
+ RUBY_EXTCONF_H =
79
+ cflags = $(optflags) $(debugflags) $(warnflags)
80
+ cxxflags = $(optflags) $(debugflags) $(warnflags)
81
+ optflags = -O3
82
+ debugflags = -ggdb3
83
+ warnflags = -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens
84
+ cppflags =
85
+ CCDLFLAGS = -fno-common
86
+ CFLAGS = $(CCDLFLAGS) $(cflags) -pipe $(ARCH_FLAG)
87
+ INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
88
+ DEFS =
89
+ CPPFLAGS = -DHAVE_VM_CORE_H -DHAVE_ISEQ_H -I/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0
90
+ CXXFLAGS = $(CCDLFLAGS) $(cxxflags) $(ARCH_FLAG)
91
+ ldflags = -L. -L/Users/july/.rbenv/versions/2.6.0/lib -fstack-protector-strong -L/usr/local/lib
92
+ dldflags = -L/Users/july/.rbenv/versions/2.6.0/lib -Wl,-undefined,dynamic_lookup -Wl,-multiply_defined,suppress
93
+ ARCH_FLAG =
94
+ DLDFLAGS = $(ldflags) $(dldflags) $(ARCH_FLAG)
95
+ LDSHARED = $(CC) -dynamic -bundle
96
+ LDSHAREDXX = $(CXX) -dynamic -bundle
97
+ AR = libtool -static
98
+ EXEEXT =
99
+
100
+ RUBY_INSTALL_NAME = $(RUBY_BASE_NAME)
101
+ RUBY_SO_NAME = ruby.2.6
102
+ RUBYW_INSTALL_NAME =
103
+ RUBY_VERSION_NAME = $(RUBY_BASE_NAME)-$(ruby_version)
104
+ RUBYW_BASE_NAME = rubyw
105
+ RUBY_BASE_NAME = ruby
106
+
107
+ arch = x86_64-darwin16
108
+ sitearch = $(arch)
109
+ ruby_version = 2.6.0
110
+ ruby = $(bindir)/$(RUBY_BASE_NAME)
111
+ RUBY = $(ruby)
112
+ ruby_headers = $(hdrdir)/ruby.h $(hdrdir)/ruby/backward.h $(hdrdir)/ruby/ruby.h $(hdrdir)/ruby/defines.h $(hdrdir)/ruby/missing.h $(hdrdir)/ruby/intern.h $(hdrdir)/ruby/st.h $(hdrdir)/ruby/subst.h $(arch_hdrdir)/ruby/config.h
113
+
114
+ RM = rm -f
115
+ RM_RF = $(RUBY) -run -e rm -- -rf
116
+ RMDIRS = rmdir -p
117
+ MAKEDIRS = mkdir -p
118
+ INSTALL = /usr/bin/install -c
119
+ INSTALL_PROG = $(INSTALL) -m 0755
120
+ INSTALL_DATA = $(INSTALL) -m 644
121
+ COPY = cp
122
+ TOUCH = exit >
123
+
124
+ #### End of system configuration section. ####
125
+
126
+ preload =
127
+ libpath = . $(libdir)
128
+ LIBPATH = -L. -L$(libdir)
129
+ DEFFILE =
130
+
131
+ CLEANFILES = mkmf.log
132
+ DISTCLEANFILES =
133
+ DISTCLEANDIRS =
134
+
135
+ extout =
136
+ extout_prefix =
137
+ target_prefix =
138
+ LOCAL_LIBS =
139
+ LIBS =
140
+ ORIG_SRCS = blab_trace.c
141
+ SRCS = $(ORIG_SRCS)
142
+ OBJS = blab_trace.o
143
+ HDRS = $(srcdir)/extconf.h
144
+ LOCAL_HDRS =
145
+ TARGET = blab_trace
146
+ TARGET_NAME = blab_trace
147
+ TARGET_ENTRY = Init_$(TARGET_NAME)
148
+ DLLIB = $(TARGET).bundle
149
+ EXTSTATIC =
150
+ STATIC_LIB =
151
+
152
+ TIMESTAMP_DIR = .
153
+ BINDIR = $(bindir)
154
+ RUBYCOMMONDIR = $(sitedir)$(target_prefix)
155
+ RUBYLIBDIR = $(sitelibdir)$(target_prefix)
156
+ RUBYARCHDIR = $(sitearchdir)$(target_prefix)
157
+ HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
158
+ ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
159
+ TARGET_SO_DIR =
160
+ TARGET_SO = $(TARGET_SO_DIR)$(DLLIB)
161
+ CLEANLIBS = $(TARGET_SO)
162
+ CLEANOBJS = *.o *.bak
163
+
164
+ all: $(DLLIB)
165
+ static: $(STATIC_LIB)
166
+ .PHONY: all install static install-so install-rb
167
+ .PHONY: clean clean-so clean-static clean-rb
168
+
169
+ clean-static::
170
+ clean-rb-default::
171
+ clean-rb::
172
+ clean-so::
173
+ clean: clean-so clean-static clean-rb-default clean-rb
174
+ -$(Q)$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES) .*.time
175
+
176
+ distclean-rb-default::
177
+ distclean-rb::
178
+ distclean-so::
179
+ distclean-static::
180
+ distclean: clean distclean-so distclean-static distclean-rb-default distclean-rb
181
+ -$(Q)$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
182
+ -$(Q)$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
183
+ -$(Q)$(RMDIRS) $(DISTCLEANDIRS) 2> /dev/null || true
184
+
185
+ realclean: distclean
186
+ install: install-so install-rb
187
+
188
+ install-so: $(DLLIB) $(TIMESTAMP_DIR)/.sitearchdir.time
189
+ $(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
190
+ clean-static::
191
+ -$(Q)$(RM) $(STATIC_LIB)
192
+ install-rb: pre-install-rb do-install-rb install-rb-default
193
+ install-rb-default: pre-install-rb-default do-install-rb-default
194
+ pre-install-rb: Makefile
195
+ pre-install-rb-default: Makefile
196
+ do-install-rb:
197
+ do-install-rb-default:
198
+ pre-install-rb-default:
199
+ @$(NULLCMD)
200
+ $(TIMESTAMP_DIR)/.sitearchdir.time:
201
+ $(Q) $(MAKEDIRS) $(@D) $(RUBYARCHDIR)
202
+ $(Q) $(TOUCH) $@
203
+
204
+ site-install: site-install-so site-install-rb
205
+ site-install-so: install-so
206
+ site-install-rb: install-rb
207
+
208
+ .SUFFIXES: .c .m .cc .mm .cxx .cpp .o .S
209
+
210
+ .cc.o:
211
+ $(ECHO) compiling $(<)
212
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
213
+
214
+ .cc.S:
215
+ $(ECHO) translating $(<)
216
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
217
+
218
+ .mm.o:
219
+ $(ECHO) compiling $(<)
220
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
221
+
222
+ .mm.S:
223
+ $(ECHO) translating $(<)
224
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
225
+
226
+ .cxx.o:
227
+ $(ECHO) compiling $(<)
228
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
229
+
230
+ .cxx.S:
231
+ $(ECHO) translating $(<)
232
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
233
+
234
+ .cpp.o:
235
+ $(ECHO) compiling $(<)
236
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
237
+
238
+ .cpp.S:
239
+ $(ECHO) translating $(<)
240
+ $(Q) $(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
241
+
242
+ .c.o:
243
+ $(ECHO) compiling $(<)
244
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
245
+
246
+ .c.S:
247
+ $(ECHO) translating $(<)
248
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
249
+
250
+ .m.o:
251
+ $(ECHO) compiling $(<)
252
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $(CSRCFLAG)$<
253
+
254
+ .m.S:
255
+ $(ECHO) translating $(<)
256
+ $(Q) $(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -S $(CSRCFLAG)$<
257
+
258
+ $(TARGET_SO): $(OBJS) Makefile
259
+ $(ECHO) linking shared-object $(DLLIB)
260
+ -$(Q)$(RM) $(@)
261
+ $(Q) $(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
262
+ $(Q) $(POSTLINK)
263
+
264
+
265
+
266
+ $(OBJS): $(HDRS) $(ruby_headers)
Binary file
data/ext/blab_trace.c ADDED
@@ -0,0 +1,186 @@
1
+ #include "extconf.h"
2
+
3
+ #define TRUE 1
4
+ #define FALSE 0
5
+
6
+ PUREFUNC(static rb_callable_method_entry_t *check_method_entry(VALUE obj, int can_be_svar));
7
+ static rb_callable_method_entry_t *check_method_entry(VALUE obj, int can_be_svar)
8
+ {
9
+ if (obj == Qfalse) return NULL;
10
+
11
+ #if VM_CHECK_MODE > 0
12
+ if (!RB_TYPE_P(obj, T_IMEMO)) rb_bug("check_method_entry: unknown type: %s", rb_obj_info(obj));
13
+ #endif
14
+
15
+ switch (imemo_type(obj)) {
16
+ case imemo_ment:
17
+ return (rb_callable_method_entry_t *)obj;
18
+ case imemo_cref:
19
+ return NULL;
20
+ case imemo_svar:
21
+ if (can_be_svar) {
22
+ return check_method_entry(((struct vm_svar *)obj)->cref_or_me, FALSE);
23
+ }
24
+ default:
25
+ #if VM_CHECK_MODE > 0
26
+ rb_bug("check_method_entry: svar should not be there:");
27
+ #endif
28
+ return NULL;
29
+ }
30
+ }
31
+
32
+ MJIT_STATIC const rb_callable_method_entry_t *rb_vm_frame_method_entry(const rb_control_frame_t *cfp)
33
+ {
34
+ const VALUE *ep = cfp->ep;
35
+ rb_callable_method_entry_t *me;
36
+
37
+ while (!VM_ENV_LOCAL_P(ep)) {
38
+ if ((me = check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], FALSE)) != NULL) return me;
39
+ ep = VM_ENV_PREV_EP(ep);
40
+ }
41
+
42
+ return check_method_entry(ep[VM_ENV_DATA_INDEX_ME_CREF], TRUE);
43
+ }
44
+
45
+
46
+ int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, ID *called_idp, VALUE *klassp)
47
+ {
48
+ const rb_callable_method_entry_t *me = rb_vm_frame_method_entry(cfp);
49
+
50
+ if (me) {
51
+ if (idp) *idp = me->def->original_id;
52
+ if (called_idp) *called_idp = me->called_id;
53
+ if (klassp) *klassp = me->owner;
54
+ return TRUE;
55
+ }
56
+ else {
57
+ return FALSE;
58
+ }
59
+ }
60
+
61
+ int rb_ec_frame_method_id_and_class(const rb_execution_context_t *ec, ID *idp, ID *called_idp, VALUE *klassp)
62
+ {
63
+ return rb_vm_control_frame_id_and_class(ec->cfp, idp, called_idp, klassp);
64
+ }
65
+
66
+ inline static int calc_lineno(const rb_iseq_t *iseq, const VALUE *pc)
67
+ {
68
+ size_t pos = (size_t)(pc - iseq->body->iseq_encoded);
69
+ if (LIKELY(pos)) {
70
+ /* use pos-1 because PC points next instruction at the beginning of instruction */
71
+ pos--;
72
+ }
73
+ return rb_iseq_line_no(iseq, pos);
74
+ }
75
+
76
+ int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
77
+ {
78
+ if (VM_FRAME_RUBYFRAME_P(cfp) && cfp->iseq) {
79
+ const rb_iseq_t *iseq = cfp->iseq;
80
+ int line = calc_lineno(iseq, cfp->pc);
81
+ if (line != 0) {
82
+ return line;
83
+ }
84
+ else {
85
+ return FIX2INT(rb_iseq_first_lineno(iseq));
86
+ }
87
+ }
88
+ else {
89
+ return 0;
90
+ }
91
+ }
92
+
93
+ static const char * get_event_name(rb_event_flag_t event)
94
+ {
95
+ switch (event) {
96
+ case RUBY_EVENT_LINE: return "line";
97
+ case RUBY_EVENT_CLASS: return "class";
98
+ case RUBY_EVENT_END: return "end";
99
+ case RUBY_EVENT_CALL: return "call";
100
+ case RUBY_EVENT_RETURN: return "return";
101
+ case RUBY_EVENT_C_CALL: return "c-call";
102
+ case RUBY_EVENT_C_RETURN: return "c-return";
103
+ case RUBY_EVENT_RAISE: return "raise";
104
+ default: return "unknown";
105
+ }
106
+ }
107
+
108
+ static void get_path_and_lineno(const rb_execution_context_t *ec, const rb_control_frame_t *cfp, rb_event_flag_t event, VALUE *pathp, int *linep)
109
+ {
110
+ cfp = rb_vm_get_ruby_level_next_cfp(ec, cfp);
111
+
112
+ if (cfp) {
113
+ const rb_iseq_t *iseq = cfp->iseq;
114
+ *pathp = rb_iseq_path(iseq);
115
+
116
+ if (event & (RUBY_EVENT_CLASS | RUBY_EVENT_CALL | RUBY_EVENT_B_CALL)) {
117
+ *linep = FIX2INT(rb_iseq_first_lineno(iseq));
118
+ }
119
+ else {
120
+ *linep = rb_vm_get_sourceline(cfp);
121
+ }
122
+ }
123
+ else {
124
+ *pathp = Qnil;
125
+ *linep = 0;
126
+ }
127
+ }
128
+
129
+ static void blab_trace_func(rb_event_flag_t event, VALUE proc, VALUE self, ID id, VALUE klass)
130
+ {
131
+ int line;
132
+ VALUE filename;
133
+ VALUE eventname = rb_str_new2(get_event_name(event));
134
+ VALUE argv[7];
135
+ const rb_execution_context_t *ec = GET_EC();
136
+
137
+ // RUSAGE_SELF/RUSAGE_CHILDREN/RUSAGE_THREAD
138
+ struct rusage r_usage;
139
+ getrusage(RUSAGE_SELF, &r_usage);
140
+
141
+ get_path_and_lineno(ec, ec->cfp, event, &filename, &line);
142
+
143
+ if (!klass) {
144
+ rb_ec_frame_method_id_and_class(ec, &id, 0, &klass);
145
+ }
146
+
147
+ if (klass) {
148
+ if (RB_TYPE_P(klass, T_ICLASS)) {
149
+ klass = RBASIC(klass)->klass;
150
+ }
151
+ else if (FL_TEST(klass, FL_SINGLETON)) {
152
+ klass = rb_ivar_get(klass, id__attached__);
153
+ }
154
+ }
155
+
156
+ argv[0] = eventname;
157
+ argv[1] = filename;
158
+ argv[2] = INT2FIX(line);
159
+ argv[3] = id ? ID2SYM(id) : Qnil;
160
+ argv[4] = (self && (filename != Qnil)) ? rb_binding_new() : Qnil;
161
+ argv[5] = klass ? klass : Qnil;
162
+ argv[6] = INT2FIX(r_usage.ru_maxrss); // maximum resident set size
163
+
164
+ rb_proc_call_with_block(proc, 7, argv, Qnil);
165
+ }
166
+
167
+ static VALUE rb_blab_trace(VALUE obj, VALUE trace)
168
+ {
169
+ rb_remove_event_hook(blab_trace_func);
170
+
171
+ if (NIL_P(trace)) {
172
+ return Qnil;
173
+ }
174
+
175
+ if (!rb_obj_is_proc(trace)) {
176
+ rb_raise(rb_eTypeError, "trace_func needs to be Proc");
177
+ }
178
+
179
+ rb_add_event_hook(blab_trace_func, RUBY_EVENT_ALL, trace);
180
+ return trace;
181
+ }
182
+
183
+ void Init_blab_trace()
184
+ {
185
+ rb_define_global_function("blab_trace", rb_blab_trace, 1);
186
+ }
data/ext/blab_trace.o ADDED
Binary file
data/ext/extconf.h ADDED
@@ -0,0 +1,9 @@
1
+ #ifndef EXTCONF_H
2
+ #define EXTCONF_H 1
3
+
4
+ #include <ruby.h>
5
+ #include <vm_core.h>
6
+ #include <iseq.h>
7
+ #include <sys/resource.h>
8
+
9
+ #endif
data/ext/extconf.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mkmf"
4
+ require "debase/ruby_core_source"
5
+
6
+ if RUBY_VERSION < "2.6"
7
+ STDERR.print("Ruby version must be 2.6 or older\n")
8
+ exit(1)
9
+ end
10
+
11
+ hdrs = proc { have_header("vm_core.h") and have_header("iseq.h") }
12
+
13
+ if !Debase::RubyCoreSource::create_makefile_with_core(hdrs, "blab_trace")
14
+ exit(1)
15
+ end
data/ext/mkmf.log ADDED
@@ -0,0 +1,86 @@
1
+ have_header: checking for vm_core.h... -------------------- no
2
+
3
+ "clang -o conftest -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -L. -L/Users/july/.rbenv/versions/2.6.0/lib -L. -L/Users/july/.rbenv/versions/2.6.0/lib -fstack-protector-strong -L/usr/local/lib -lruby.2.6-static -framework Security -framework Foundation -lpthread -lgmp -ldl -lobjc "
4
+ checked program was:
5
+ /* begin */
6
+ 1: #include "ruby.h"
7
+ 2:
8
+ 3: int main(int argc, char **argv)
9
+ 4: {
10
+ 5: return 0;
11
+ 6: }
12
+ /* end */
13
+
14
+ "clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -D_DARWIN_UNLIMITED_SELECT -D_REENTRANT -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
15
+ conftest.c:3:10: fatal error: 'vm_core.h' file not found
16
+ #include <vm_core.h>
17
+ ^~~~~~~~~~~
18
+ 1 error generated.
19
+ checked program was:
20
+ /* begin */
21
+ 1: #include "ruby.h"
22
+ 2:
23
+ 3: #include <vm_core.h>
24
+ /* end */
25
+
26
+ --------------------
27
+
28
+ have_header: checking for vm_core.h... -------------------- no
29
+
30
+ "clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby-2.6.0-p0 -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
31
+ conftest.c:3:10: fatal error: 'vm_core.h' file not found
32
+ #include <vm_core.h>
33
+ ^~~~~~~~~~~
34
+ 1 error generated.
35
+ checked program was:
36
+ /* begin */
37
+ 1: #include "ruby.h"
38
+ 2:
39
+ 3: #include <vm_core.h>
40
+ /* end */
41
+
42
+ --------------------
43
+
44
+ have_header: checking for vm_core.h... -------------------- yes
45
+
46
+ "clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0 -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
47
+ In file included from conftest.c:3:
48
+ In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/vm_core.h:75:
49
+ In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/method.h:14:
50
+ /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/internal.h:125:10: warning: '__msan_allocated_memory' macro redefined [-Wmacro-redefined]
51
+ # define __msan_allocated_memory(x, y)
52
+ ^
53
+ /Library/Developer/CommandLineTools/usr/lib/clang/9.0.0/include/sanitizer/msan_interface.h:113:9: note: previous definition is here
54
+ #define __msan_allocated_memory(data, size)
55
+ ^
56
+ In file included from conftest.c:3:
57
+ In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/vm_core.h:75:
58
+ In file included from /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/method.h:14:
59
+ /Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0/internal.h:127:10: warning: '__msan_unpoison' macro redefined [-Wmacro-redefined]
60
+ # define __msan_unpoison(x, y)
61
+ ^
62
+ /Library/Developer/CommandLineTools/usr/lib/clang/9.0.0/include/sanitizer/msan_interface.h:112:9: note: previous definition is here
63
+ #define __msan_unpoison(a, size)
64
+ ^
65
+ 2 warnings generated.
66
+ checked program was:
67
+ /* begin */
68
+ 1: #include "ruby.h"
69
+ 2:
70
+ 3: #include <vm_core.h>
71
+ /* end */
72
+
73
+ --------------------
74
+
75
+ have_header: checking for iseq.h... -------------------- yes
76
+
77
+ "clang -E -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/x86_64-darwin16 -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0/ruby/backward -I/Users/july/.rbenv/versions/2.6.0/include/ruby-2.6.0 -I. -I/Users/july/.rbenv/versions/2.6.0/lib/ruby/gems/2.6.0/gems/debase-ruby_core_source-0.10.4/lib/debase/ruby_core_source/ruby-2.6.0-p0 -O3 -ggdb3 -Wall -Wextra -Wdeclaration-after-statement -Wdeprecated-declarations -Wdivision-by-zero -Wimplicit-function-declaration -Wimplicit-int -Wpointer-arith -Wshorten-64-to-32 -Wwrite-strings -Wmissing-noreturn -Wno-constant-logical-operand -Wno-long-long -Wno-missing-field-initializers -Wno-overlength-strings -Wno-parentheses-equality -Wno-self-assign -Wno-tautological-compare -Wno-unused-parameter -Wno-unused-value -Wunused-variable -Wextra-tokens -pipe conftest.c -o conftest.i"
78
+ checked program was:
79
+ /* begin */
80
+ 1: #include "ruby.h"
81
+ 2:
82
+ 3: #include <iseq.h>
83
+ /* end */
84
+
85
+ --------------------
86
+
data/lib/blab.rb CHANGED
@@ -1,12 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../ext/blab_trace"
4
+ require_relative "blab/config"
5
+ require_relative "blab/formatter"
6
+ require_relative "blab/printer"
7
+ require_relative "blab/tracer"
8
+
3
9
  module Blab
4
- def Blab.included(base)
10
+ def self.included(base)
5
11
  base.define_singleton_method(:blab) do |name|
6
12
  old_m = base.instance_method(name)
13
+
7
14
  base.send(:define_method, name) do |*args|
8
- puts "you have been decorated"
9
- old_m.bind(self).call(*args)
15
+ begin
16
+ blab_trace(Blab::Tracer.trace)
17
+ old_m.bind(self).call(*args)
18
+ ensure
19
+ blab_trace(nil)
20
+ Blab::Tracer.reset
21
+ end
22
+ end
23
+ end
24
+
25
+ def with_blab
26
+ begin
27
+ blab_trace(Blab::Tracer.trace)
28
+ yield
29
+ ensure
30
+ blab_trace(nil)
31
+ Blab::Tracer.reset
10
32
  end
11
33
  end
12
34
  end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module Blab
6
+ module Config
7
+ extend self
8
+
9
+ DATETIME_FORMAT = "%H:%M:%S.%L"
10
+
11
+ DEFAULT_OUTPUT = [
12
+ { type: :time, order: 1, width: 12 },
13
+ { type: :event, order: 2, width: 6 },
14
+ { type: :file_lines, order: 3, width: 50 },
15
+ #{ type: :class_name, order: 4, width: 10 },
16
+ #{ type: :method_name, order: 5, width: 12 },
17
+ { type: :ru_maxss, order: 4, width: 12 },
18
+ { type: :code_lines, order: 5, width: 120 }
19
+ ].freeze
20
+
21
+ attr_writer :logger,
22
+ :datetime_format,
23
+ :log_output,
24
+ :trace_c_calls,
25
+ :output_config,
26
+ :output_order,
27
+ :original_scope_only
28
+
29
+ def logger
30
+ @logger ||= begin
31
+ logger = Logger.new(log_output)
32
+ logger.formatter = proc { |severity, datetime, progname, msg| "#{msg}\n" }
33
+ logger
34
+ end
35
+ end
36
+
37
+ def log_output
38
+ @log_output ||= STDOUT
39
+ end
40
+
41
+ def output_config
42
+ @output_config ||= (@output_order || DEFAULT_OUTPUT).sort_by { |h| h[:order] }.map! { |h| [h[:type], h[:width]] }
43
+ end
44
+
45
+ def datetime_format
46
+ @datetime_format ||= DATETIME_FORMAT
47
+ end
48
+
49
+ def trace_c_calls?
50
+ @trace_c_calls ||= false
51
+ end
52
+
53
+ def original_scope_only?
54
+ @original_scope_only ||= false
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blab
4
+ module Formatter
5
+ extend self
6
+
7
+ ELLIPSIS = "..."
8
+ MAX_LENGTH = 100
9
+
10
+ def format(object)
11
+ formatted = prepare_for_inspection(object).inspect
12
+ return formatted if formatted.length < MAX_LENGTH
13
+
14
+ beginning = truncate(formatted, 0, MAX_LENGTH / 2)
15
+ ending = truncate(formatted, -MAX_LENGTH / 2, -1)
16
+ "#{beginning}#{ELLIPSIS}#{ending}"
17
+ end
18
+
19
+ def prepare_for_inspection(object)
20
+ case object
21
+ when Array
22
+ prepare_array(object)
23
+ when Hash
24
+ prepare_hash(object)
25
+ else
26
+ object
27
+ end
28
+ end
29
+
30
+ def prepare_array(array)
31
+ array.map { |element| prepare_for_inspection(element) }
32
+ end
33
+
34
+ def prepare_hash(input_hash)
35
+ input_hash.inject({}) do |output_hash, key_and_value|
36
+ key, value = key_and_value.map { |element| prepare_for_inspection(element) }
37
+ output_hash[key] = value
38
+ output_hash
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def truncate(str, start_ind, end_ind)
45
+ str[start_ind..end_ind].sub(/\e\[\d+$/, '')
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Printer
4
+ DEFAULT_CLASS_NAME_WIDTH = 5
5
+ DEFAULT_CODE_LINES_WIDTH = 120
6
+ DEFAULT_EVENT_WIDTH = 6
7
+ DEFAULT_FILE_LINES_WIDTH = 60
8
+ DEFAULT_RU_MAXSS_WIDTH = 50
9
+ DEFAULT_METHOD_NAME_WIDTH = 10
10
+ DEFAULT_TIME_WIDTH = 12
11
+
12
+ PRINT_FIELDS = [
13
+ :class_name,
14
+ :event,
15
+ :method_name,
16
+ :time,
17
+ :ru_maxss
18
+ ].freeze
19
+
20
+ attr_reader :config, :logger
21
+
22
+ def initialize(config, logger)
23
+ @config = config
24
+ @logger = logger
25
+ end
26
+
27
+ def print(options = {})
28
+ strings = config.map do |(type, width)|
29
+ send(type, options.merge(width: width))
30
+ end
31
+
32
+ config_length = config.length
33
+ final = strings.map { |e| e.first.length }.max.times.map do |i|
34
+ config_length.times.map do |j|
35
+ str = strings[j][0][i] || ""
36
+ # TODO: do not ljust the last element
37
+ config_length == (j + 1) ? str : str.ljust(strings[j][1])
38
+ end.join(" ")
39
+ end
40
+ logger.info(final.join("\n"))
41
+ end
42
+
43
+ def file_lines(options = {})
44
+ file = options[:file]
45
+ line = options[:line]
46
+ width = options[:width] || DEFAULT_FILE_LINES_WIDTH
47
+ ["#{file}:#{line}".scan(/.{#{width}}|.+/), width]
48
+ end
49
+
50
+ def code_lines(options= {})
51
+ file = options[:file]
52
+ line = options[:line]
53
+ width = options[:width] || DEFAULT_CODE_LINES_WIDTH
54
+ [source_line(file, line).scan(/.{#{width}}|.+/), width]
55
+ end
56
+
57
+ PRINT_FIELDS.each do |name|
58
+ define_method(name) do |options = {}|
59
+ val = options[name]
60
+ width = options[:width] || const_get("DEFAULT_#{name.upcase}_WIDTH")
61
+ [val.scan(/.{#{width}}|.+/), width]
62
+ end
63
+ end
64
+
65
+ def reset_files
66
+ @files_map && @files_map.keys.each { |key| @files_map.delete(key) }
67
+ end
68
+
69
+ def files_map
70
+ @files_map ||= Hash.new do |h, f|
71
+ h[f] = File.readlines(f)
72
+ end
73
+ end
74
+
75
+ # TODO: show all relevant file-lines
76
+ def source_line(file, line)
77
+ begin
78
+ files_map[file][line - 1]
79
+ rescue
80
+ "source is unavailable"
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Blab
4
+ module Tracer
5
+ extend self
6
+
7
+ FILE_NAME = /.+\/blab\.rb$/
8
+ C_CALLS = ["c-call", "c-return"].freeze
9
+
10
+ def reset
11
+ printer.reset_files
12
+ @defined_vars = {}
13
+ end
14
+
15
+ def trace
16
+ proc do |event, file, line, method_name, context, class_name, ru_maxss|
17
+ next if file =~ FILE_NAME
18
+ next if skip_c_calls? && C_CALLS.include?(event)
19
+ next if original_scope_only? && !original_scope?(file, method_name, class_name)
20
+
21
+ context.local_variables.each do |v|
22
+ next unless context.local_variable_defined?(v)
23
+
24
+ val = context.local_variable_get(v)
25
+ old_v = defined_vars[v]
26
+
27
+ next if val == old_v
28
+
29
+ formatted_output(v, val)
30
+ defined_vars[v] = val
31
+ end
32
+
33
+ printer.print(
34
+ time: Time.now.strftime(datetime_format),
35
+ event: event,
36
+ file: file,
37
+ line: line,
38
+ method_name: method_name.to_s,
39
+ class_name: class_name.to_s,
40
+ # ru_maxss is in bytes on Mac OS X (Darwin), but in kilobytes on BSD and Linux
41
+ ru_maxss: ru_maxss.to_s
42
+ )
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def printer
49
+ @printer ||= Printer.new(Blab::Config.output_config, logger)
50
+ end
51
+
52
+ def logger
53
+ Blab::Config.logger
54
+ end
55
+
56
+ def datetime_format
57
+ Blab::Config.datetime_format
58
+ end
59
+
60
+ def formatted_output(key, val)
61
+ logger.info("Var......... #{key}=#{Blab::Formatter.format(val)}")
62
+ end
63
+
64
+ def defined_vars
65
+ @defined_vars ||= {}
66
+ end
67
+
68
+ def original_scope_only?
69
+ Blab::Config.original_scope_only?
70
+ end
71
+
72
+ def skip_c_calls?
73
+ !Blab::Config.trace_c_calls?
74
+ end
75
+
76
+ def original_scope?(file, method_name, class_name)
77
+ @original_file ||= file
78
+ @original_method_name ||= method_name
79
+ @orinal_class_name ||= class_name
80
+
81
+ @original_file == file &&
82
+ @original_method_name == method_name &&
83
+ @orinal_class_name == class_name
84
+ end
85
+ end
86
+ end
data/lib/blab/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Blab
4
- VERSION = "0.0.0"
4
+ VERSION = "0.0.1-alpha"
5
5
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+ require_relative "../../lib/blab"
3
+ require "set"
4
+
5
+ class Y
6
+ include Blab
7
+
8
+ blab def x(name, &block)
9
+ a = 15
10
+ b = 30
11
+ d, c = 12, 67
12
+ puts(name)
13
+ yo = z(2)
14
+ 10.times do |i|
15
+ a += i
16
+ c = 8
17
+ end
18
+ se = Set.new
19
+ hello(
20
+ a,
21
+ a,
22
+ b
23
+ )
24
+ hsh = {
25
+ xx: 1,
26
+ a: 200,
27
+ z: 300
28
+ }
29
+ end
30
+
31
+ def z(n)
32
+ 7 + n
33
+ end
34
+
35
+ def hello(a, b, c)
36
+ puts(a)
37
+ end
38
+ end
39
+
40
+ # Blab::Config.original_scope_only = true
41
+
42
+ class Test
43
+ include Blab
44
+
45
+ def shuffle(arr)
46
+ for n in 0...arr.size
47
+ targ = n + rand(arr.size - n)
48
+ arr[n], arr[targ] = arr[targ], arr[n] if n != targ
49
+ end
50
+ end
51
+
52
+ def pairs(a, b)
53
+ with_blab do
54
+ a << "Insane"
55
+ shuffle(b)
56
+ end
57
+ b.each { |x| shuffle(a); a.each { |y| print y, " ", x, ".\n" } }
58
+ end
59
+ end
60
+ Blab::Config.log_output = "blab.log"
61
+
62
+ Test.new.pairs(["Bored", "Curious"], ["cat", "frog"])
63
+
metadata CHANGED
@@ -1,25 +1,52 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1.pre.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yulia Oletskaya
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-01 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2019-05-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: debase-ruby_core_source
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.10'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.10'
13
27
  description: A debugging tool
14
28
  email: yulia.oletskaya@gmail.com
15
29
  executables: []
16
- extensions: []
30
+ extensions:
31
+ - ext/extconf.rb
17
32
  extra_rdoc_files: []
18
33
  files:
19
34
  - LICENSE
20
35
  - README.md
36
+ - ext/Makefile
37
+ - ext/blab_trace.bundle
38
+ - ext/blab_trace.c
39
+ - ext/blab_trace.o
40
+ - ext/extconf.h
41
+ - ext/extconf.rb
42
+ - ext/mkmf.log
21
43
  - lib/blab.rb
44
+ - lib/blab/config.rb
45
+ - lib/blab/formatter.rb
46
+ - lib/blab/printer.rb
47
+ - lib/blab/tracer.rb
22
48
  - lib/blab/version.rb
49
+ - test/support/test.rb
23
50
  homepage: http://rubygems.org/gems/blab
24
51
  licenses:
25
52
  - MIT
@@ -35,13 +62,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
35
62
  version: '0'
36
63
  required_rubygems_version: !ruby/object:Gem::Requirement
37
64
  requirements:
38
- - - ">="
65
+ - - ">"
39
66
  - !ruby/object:Gem::Version
40
- version: '0'
67
+ version: 1.3.1
41
68
  requirements: []
42
- rubyforge_project:
43
- rubygems_version: 2.6.13
69
+ rubygems_version: 3.0.1
44
70
  signing_key:
45
71
  specification_version: 4
46
72
  summary: Blab
47
- test_files: []
73
+ test_files:
74
+ - test/support/test.rb