blab 0.0.0 → 0.0.1.pre.alpha

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 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