rack_console 0.3.2 → 0.4.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.
- checksums.yaml +4 -4
- data/Rakefile +9 -0
- data/example/ex01/config.ru +2 -0
- data/example/ex01/template/haml/layout.haml +12 -13
- data/lib/rack_console/ansi2html.rb +9 -8
- data/lib/rack_console/app.rb +17 -27
- data/lib/rack_console/app_helpers.rb +17 -346
- data/lib/rack_console/configuration.rb +74 -0
- data/lib/rack_console/expr_helpers.rb +1 -1
- data/lib/rack_console/formatting.rb +214 -0
- data/lib/rack_console/method_introspection.rb +85 -0
- data/lib/rack_console/template/css/rack_console.css +49 -13
- data/lib/rack_console/template/haml/console/file.haml +1 -1
- data/lib/rack_console/template/haml/console/result/module.haml +3 -3
- data/lib/rack_console/template/haml/layout.haml +10 -11
- data/lib/rack_console/version.rb +1 -1
- data/rack_console.gemspec +1 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8dfdd6cd65e2383e4704cdf422bb10cdd53ccfd5
|
4
|
+
data.tar.gz: ba1b0816dfe7c7d16e2eb68f1e97f05a6ba511fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b6370d265af9ec4fb74841c59c2d17925daa8d46d8fac04ce583bd688625e68ba250f711fdf1417108d264d0dfc4d0f60e0aa611dcd6d210f188c929e9946da
|
7
|
+
data.tar.gz: e3f1e23ceb918f495c83ca4896b33e8a5840f5354ecefefba84c8124b968cc7161b15c42c8cce153aef832bbac2b7f280d74396d8f00b4b250cb9244894f1139
|
data/Rakefile
CHANGED
@@ -4,3 +4,12 @@ require "rspec/core/rake_task"
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
5
|
|
6
6
|
task :default => :spec
|
7
|
+
|
8
|
+
task :coverage => [ :enable_coverage, :spec ]
|
9
|
+
task :enable_coverage do
|
10
|
+
ENV['COVERAGE'] = "1"
|
11
|
+
end
|
12
|
+
|
13
|
+
task :run do
|
14
|
+
system "cd example/ex01 && exec bundle exec rackup -p 9999"
|
15
|
+
end
|
data/example/ex01/config.ru
CHANGED
@@ -2,9 +2,11 @@ $:.unshift "../../lib"
|
|
2
2
|
$:.unshift "."
|
3
3
|
require 'rack_console/app'
|
4
4
|
require 'app'
|
5
|
+
require 'ostruct'
|
5
6
|
use Rack::Reloader
|
6
7
|
run Rack::URLMap.new(
|
7
8
|
"/console" => RackConsole::App.new(
|
9
|
+
eval_target: OpenStruct.new,
|
8
10
|
awesome_print: true,
|
9
11
|
url_root_prefix: "/console",
|
10
12
|
views: [ 'template/haml', :default ]),
|
@@ -2,18 +2,17 @@
|
|
2
2
|
%html
|
3
3
|
%head
|
4
4
|
%title rack_console
|
5
|
-
%link
|
6
|
-
%link
|
5
|
+
%link{rel: "stylesheet", href: url_root("/css/rack_console.css")}
|
6
|
+
%link{rel: "stylesheet", href: url_root("/css/ansi.css")}
|
7
7
|
%body
|
8
|
-
.
|
9
|
-
.
|
10
|
-
|
11
|
-
%
|
12
|
-
|
8
|
+
.rack_console
|
9
|
+
.wrapper
|
10
|
+
.header
|
11
|
+
%h1
|
12
|
+
%a{href:"/console"}rack_console
|
13
|
+
%p Test layout
|
14
|
+
.content
|
15
|
+
=yield
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
.footer
|
18
|
-
%p
|
19
|
-
This is the footer.
|
17
|
+
.footer
|
18
|
+
%hr
|
@@ -2,8 +2,7 @@ require 'rack/utils'
|
|
2
2
|
|
3
3
|
module RackConsole
|
4
4
|
class Ansi2Html
|
5
|
-
@@
|
6
|
-
@@tag_e = { }
|
5
|
+
@@tag_cache = { }
|
7
6
|
|
8
7
|
def self.convert str, out = nil
|
9
8
|
new.convert(str, out)
|
@@ -41,12 +40,14 @@ module RackConsole
|
|
41
40
|
|
42
41
|
def tag name, cls
|
43
42
|
if cls
|
44
|
-
|
45
|
-
@@
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
tag_be =
|
44
|
+
(@@tag_cache[name] ||= { })[cls] ||=
|
45
|
+
[
|
46
|
+
%Q{<#{name} class="#{cls}">}.freeze,
|
47
|
+
%Q{</#{name}>}.freeze,
|
48
|
+
].freeze
|
49
|
+
@tags << tag_be
|
50
|
+
@out << tag_be[0]
|
50
51
|
else
|
51
52
|
tag_pop!
|
52
53
|
end
|
data/lib/rack_console/app.rb
CHANGED
@@ -9,52 +9,42 @@ module RackConsole
|
|
9
9
|
class App < Sinatra::Application
|
10
10
|
set :views, :default
|
11
11
|
|
12
|
+
before do
|
13
|
+
check_access! unless request.path_info =~ %r{^/css/}
|
14
|
+
end
|
15
|
+
|
12
16
|
get '/?' do
|
13
|
-
|
14
|
-
console!
|
15
|
-
end
|
17
|
+
console!
|
16
18
|
end
|
17
19
|
|
18
20
|
post '/?' do
|
19
|
-
|
20
|
-
console!
|
21
|
-
end
|
21
|
+
console!
|
22
22
|
end
|
23
23
|
|
24
24
|
get "/module/:expr" do
|
25
|
-
|
26
|
-
|
27
|
-
haml :'console/module', locals: locals, layout: layout
|
28
|
-
end
|
25
|
+
evaluate_module!
|
26
|
+
haml :'console/module', locals: locals, layout: layout
|
29
27
|
end
|
30
28
|
|
31
29
|
get "/method/:expr/:kind/:name" do
|
32
|
-
|
33
|
-
|
34
|
-
haml :'console/method', locals: locals, layout: layout
|
35
|
-
end
|
30
|
+
evaluate_method!
|
31
|
+
haml :'console/method', locals: locals, layout: layout
|
36
32
|
end
|
37
33
|
|
38
34
|
get "/methods/:owner/:kind/:name" do
|
39
|
-
|
40
|
-
|
41
|
-
haml :'console/methods', locals: locals, layout: layout
|
42
|
-
end
|
35
|
+
evaluate_methods!
|
36
|
+
haml :'console/methods', locals: locals, layout: layout
|
43
37
|
end
|
44
38
|
|
45
39
|
get "/file/*" do
|
46
|
-
|
47
|
-
|
48
|
-
haml :'console/file', locals: locals, layout: layout
|
49
|
-
end
|
40
|
+
prepare_file!
|
41
|
+
haml :'console/file', locals: locals, layout: layout
|
50
42
|
end
|
51
43
|
|
52
44
|
get "/methods/file/*" do
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
haml :'console/methods', locals: locals, layout: layout
|
57
|
-
end
|
45
|
+
prepare_file!
|
46
|
+
@methods = methods_within_file(@source_file.file) if @source_file
|
47
|
+
haml :'console/methods', locals: locals, layout: layout
|
58
48
|
end
|
59
49
|
|
60
50
|
get "/css/:path" do | path |
|
@@ -1,55 +1,14 @@
|
|
1
1
|
require 'active_support/core_ext/class/subclasses'
|
2
2
|
require 'active_support/core_ext/object/blank'
|
3
|
-
require 'pp'
|
4
3
|
require 'stringio'
|
5
|
-
require 'rack_console/ansi2html'
|
6
4
|
require 'rack_console/expr_helpers'
|
7
|
-
require 'rack_console/
|
5
|
+
require 'rack_console/configuration'
|
6
|
+
require 'rack_console/method_introspection'
|
7
|
+
require 'rack_console/formatting'
|
8
8
|
|
9
9
|
module RackConsole
|
10
10
|
module AppHelpers
|
11
|
-
include ExprHelpers
|
12
|
-
|
13
|
-
def has_console_access?
|
14
|
-
case a = config[:authorized?]
|
15
|
-
when true, false
|
16
|
-
a
|
17
|
-
when Proc
|
18
|
-
a.call
|
19
|
-
else
|
20
|
-
true
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def has_file_access? file
|
25
|
-
! ! (file != '(eval)' && $".include?(file))
|
26
|
-
end
|
27
|
-
|
28
|
-
def url_root url
|
29
|
-
"#{config[:url_root_prefix]}#{url}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def locals
|
33
|
-
@locals ||= { }
|
34
|
-
end
|
35
|
-
|
36
|
-
def layout
|
37
|
-
config[:layout] || :layout
|
38
|
-
end
|
39
|
-
|
40
|
-
def find_template(views, name, engine, &block)
|
41
|
-
views = config[:views] || views
|
42
|
-
Array(views).each do |v|
|
43
|
-
v = config[:views_default] if v == :default
|
44
|
-
super(v, name, engine, &block)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def css_dir
|
49
|
-
config[:css_dir]
|
50
|
-
end
|
51
|
-
|
52
|
-
###############################
|
11
|
+
include ExprHelpers, Configuration, MethodIntrospection, Formatting
|
53
12
|
|
54
13
|
def with_access
|
55
14
|
if has_console_access?
|
@@ -75,8 +34,7 @@ module RackConsole
|
|
75
34
|
@result_evaled = true
|
76
35
|
Timeout.timeout(config[:eval_timeout] || 120) do
|
77
36
|
capture_stdio! do
|
78
|
-
|
79
|
-
@result = eval(expr_str)
|
37
|
+
@result = eval_expr(eval_target, @expr)
|
80
38
|
@result_ok = true
|
81
39
|
end
|
82
40
|
end
|
@@ -84,6 +42,18 @@ module RackConsole
|
|
84
42
|
end
|
85
43
|
end
|
86
44
|
|
45
|
+
def eval_expr et, expr
|
46
|
+
expr_str = "begin; #{@expr} \n; end"
|
47
|
+
case et
|
48
|
+
when nil, false
|
49
|
+
eval(expr_str)
|
50
|
+
when Module
|
51
|
+
et.module_eval(expr_str)
|
52
|
+
else
|
53
|
+
et.instance_eval(expr_str)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
87
57
|
def evaluate_module!
|
88
58
|
evaluate_expr!
|
89
59
|
@show_stdio = @show_result = false
|
@@ -172,310 +142,11 @@ module RackConsole
|
|
172
142
|
end
|
173
143
|
end
|
174
144
|
|
175
|
-
def server_info
|
176
|
-
thr = Thread.current
|
177
|
-
(config[:server_info] || { }).merge(
|
178
|
-
host: Socket.gethostname,
|
179
|
-
pid: Process.pid,
|
180
|
-
ppid: Process.ppid,
|
181
|
-
thread: thr[:name] || thr.object_id,
|
182
|
-
)
|
183
|
-
end
|
184
|
-
|
185
|
-
def format_object obj, inline = false
|
186
|
-
case obj
|
187
|
-
when Module
|
188
|
-
format_module obj
|
189
|
-
else
|
190
|
-
format_other obj, inline
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
def format_other obj, inline = false
|
195
|
-
if inline
|
196
|
-
literal_tag(h(limit_string(safe_format(obj), 80)))
|
197
|
-
else
|
198
|
-
safe_format_structured(obj)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
145
|
def const_get_safe m, name
|
203
146
|
m.const_get(name)
|
204
147
|
rescue Object
|
205
148
|
"ERROR: #{$!.inspect}"
|
206
149
|
end
|
207
150
|
|
208
|
-
def format_source_location source_location, meth = nil, kind = nil, owner = nil
|
209
|
-
file, line = source_location
|
210
|
-
if file
|
211
|
-
"<a href='#{file_line_to_href file, line}' class='file_name'>#{file_name_tag("#{file}:#{line}")}</a>"
|
212
|
-
else
|
213
|
-
if meth
|
214
|
-
# Assume meth is Ruby Core and link to rdocs on ruby-doc.org.
|
215
|
-
name = meth.name
|
216
|
-
owner ||= meth.owner
|
217
|
-
owner_name = (owner.name || '').gsub('::', '/')
|
218
|
-
kind ||= (owner.instance_method(name) rescue nil) ? :i : :c
|
219
|
-
a_name = name.to_s.gsub(/([^a-z0-9_])/i){|m| "-%X" % [ m.ord ]}
|
220
|
-
a_name.sub!(/^-/, '')
|
221
|
-
a_name = "method-#{kind}-#{a_name}"
|
222
|
-
ruby_core_link = "http://www.ruby-doc.org/core-#{RUBY_VERSION}/#{owner_name}.html\##{a_name}"
|
223
|
-
"<a href='#{ruby_core_link}' class='ruby_core_doc'>#{h ruby_core_link}</a>"
|
224
|
-
else
|
225
|
-
"NONE"
|
226
|
-
end
|
227
|
-
end
|
228
|
-
end
|
229
|
-
|
230
|
-
def methods_matching params
|
231
|
-
name_p = match_pred(params[:name], :to_sym)
|
232
|
-
kind_p = match_pred(params[:kind], :to_sym)
|
233
|
-
owner_p = match_pred(params[:owner])
|
234
|
-
file_p = match_pred(params[:file])
|
235
|
-
|
236
|
-
methods = [ ]
|
237
|
-
seen = { }
|
238
|
-
ObjectSpace.each_object(::Module) do | owner |
|
239
|
-
next unless (owner.name rescue nil)
|
240
|
-
next if owner_p && owner_p != owner.name
|
241
|
-
methods_for_module(owner, name_p, kind_p, file_p, seen, methods)
|
242
|
-
end
|
243
|
-
sort_methods! methods
|
244
|
-
methods
|
245
|
-
end
|
246
|
-
|
247
|
-
def match_pred value, m = nil
|
248
|
-
if value != nil && value != '*' && value != ''
|
249
|
-
value = value.send(m) if m
|
250
|
-
else
|
251
|
-
value = nil
|
252
|
-
end
|
253
|
-
value
|
254
|
-
end
|
255
|
-
|
256
|
-
def methods_for_module owner, name_p = nil, kind_p = nil, file_p = nil, seen = { }, to_methods = nil
|
257
|
-
methods = to_methods || [ ]
|
258
|
-
kind = :i
|
259
|
-
unless kind_p && kind_p != kind
|
260
|
-
instance_method_names(owner).each do | name |
|
261
|
-
next if name_p && name_p != (name = name.to_sym)
|
262
|
-
if meth = (owner.instance_method(name) rescue nil) and key = [ owner, kind, name ] and ! seen[key]
|
263
|
-
seen[key] = true
|
264
|
-
if file_p
|
265
|
-
f = meth.source_location and f = f.first
|
266
|
-
next if f != file_p
|
267
|
-
end
|
268
|
-
methods << MockMethod.new(meth, name, kind, owner)
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
kind = :c
|
274
|
-
unless kind_p && kind_p != kind
|
275
|
-
singleton_method_names(owner).each do | name |
|
276
|
-
next if name_p && name_p != (name = name.to_sym)
|
277
|
-
if meth = (owner.singleton_method(name) rescue nil) and key = [ owner, kind, name ] and ! seen[key]
|
278
|
-
seen[key] = true
|
279
|
-
if file_p
|
280
|
-
f = meth.source_location and f = f.first
|
281
|
-
next if f != file_p
|
282
|
-
end
|
283
|
-
methods << MockMethod.new(meth, name, kind, owner)
|
284
|
-
end
|
285
|
-
end
|
286
|
-
end
|
287
|
-
sort_methods! methods unless to_methods
|
288
|
-
methods
|
289
|
-
end
|
290
|
-
|
291
|
-
def sort_methods! methods
|
292
|
-
methods.sort_by!{|x| [ x.owner.to_s, x.kind, x.name ]}
|
293
|
-
end
|
294
|
-
|
295
|
-
def instance_method_names owner
|
296
|
-
( owner.instance_methods(false) |
|
297
|
-
owner.private_instance_methods(false) |
|
298
|
-
owner.protected_instance_methods(false)
|
299
|
-
).sort
|
300
|
-
end
|
301
|
-
|
302
|
-
def singleton_method_names owner
|
303
|
-
owner.singleton_methods(false)
|
304
|
-
end
|
305
|
-
|
306
|
-
def methods_within_file file
|
307
|
-
methods = methods_matching(file: file)
|
308
|
-
sort_methods_by_source_location! methods
|
309
|
-
end
|
310
|
-
|
311
|
-
def sort_methods_by_source_location! methods
|
312
|
-
methods.sort_by!{|x| x.source_location || DUMMY_SOURCE_LOCATION }
|
313
|
-
end
|
314
|
-
DUMMY_SOURCE_LOCATION = [ "".freeze, 0 ].freeze
|
315
|
-
|
316
|
-
def file_line_to_href name, lineno = nil
|
317
|
-
link = name.sub(%r{^/}, '-')
|
318
|
-
link = link.split('/').map{|s| e s}.join('/')
|
319
|
-
link = url_root("/file/#{link}")
|
320
|
-
link << ":#{lineno}\##{lineno - 2}" if lineno
|
321
|
-
link
|
322
|
-
end
|
323
|
-
|
324
|
-
def href_to_file_line path
|
325
|
-
path.to_s =~ /^([^:]+)(:([^:]+))?/
|
326
|
-
file, line = $1, $3
|
327
|
-
file.sub!(/^-/, '/')
|
328
|
-
[ file, line && line.to_i ]
|
329
|
-
end
|
330
|
-
|
331
|
-
def source_file_methods_href file
|
332
|
-
link = file.sub(%r{^/}, '-')
|
333
|
-
link = url_root("/methods/file/#{link}")
|
334
|
-
end
|
335
|
-
|
336
|
-
def source_file source_location
|
337
|
-
source_location && SourceFile.new(source_location).load!
|
338
|
-
end
|
339
|
-
|
340
|
-
def h(text)
|
341
|
-
Rack::Utils.escape_html(text.to_s)
|
342
|
-
end
|
343
|
-
|
344
|
-
def e(text)
|
345
|
-
Rack::Utils.escape(text.to_s)
|
346
|
-
end
|
347
|
-
|
348
|
-
def limit_string(text, len)
|
349
|
-
text = text.to_s
|
350
|
-
if text.size > len
|
351
|
-
text = text[0 .. len] + ' ...'
|
352
|
-
end
|
353
|
-
text
|
354
|
-
end
|
355
|
-
|
356
|
-
def format_module obj
|
357
|
-
return module_name_tag(h(obj.inspect)) unless obj && obj.name
|
358
|
-
path = obj.name.to_s.split('::')
|
359
|
-
result = ''
|
360
|
-
name = ''; pre = ''
|
361
|
-
path.each do | n |
|
362
|
-
name << n
|
363
|
-
href = url_root("/module/#{name}")
|
364
|
-
result << "<a href='#{href}' class='module_name'>#{module_name_tag("#{pre}#{h n}")}</a>"
|
365
|
-
name << '::'
|
366
|
-
pre = '::'
|
367
|
-
end
|
368
|
-
module_name_tag(result)
|
369
|
-
end
|
370
|
-
|
371
|
-
def format_method m, kind, owner = nil
|
372
|
-
owner ||= m.owner
|
373
|
-
source_location = m.source_location
|
374
|
-
source_location &&= source_location * ":"
|
375
|
-
href = method_href(m, kind, owner)
|
376
|
-
"<a href='#{href}' title='#{source_location}' class='method_name'>#{method_name_tag(h(m.name))}</a>"
|
377
|
-
end
|
378
|
-
|
379
|
-
def method_href m, kind, owner = nil
|
380
|
-
owner ||= m.owner
|
381
|
-
href = url_root("/method/#{owner.name}/#{e kind.to_s}/#{e m.name}")
|
382
|
-
end
|
383
|
-
|
384
|
-
def format_methods obj
|
385
|
-
case obj
|
386
|
-
when nil
|
387
|
-
return nil
|
388
|
-
when ::Method, ::UnboundMethod, MockMethod
|
389
|
-
name = obj.name or return nil
|
390
|
-
else
|
391
|
-
name = obj.to_s
|
392
|
-
end
|
393
|
-
href = url_root("/methods/*/*/#{e name}")
|
394
|
-
"<a href='#{href}' title='Other methods named #{h name.inspect}' class='method_name'>#{method_name_tag(h(name))}</a>"
|
395
|
-
end
|
396
|
-
|
397
|
-
def file_name_tag str
|
398
|
-
%Q{<span class="file_name">#{str}</span>}
|
399
|
-
end
|
400
|
-
|
401
|
-
def module_name_tag str
|
402
|
-
%Q{<span class="module_name">#{str}</span>}
|
403
|
-
end
|
404
|
-
|
405
|
-
def method_name_tag str
|
406
|
-
%Q{<span class="method_name">#{str}</span>}
|
407
|
-
end
|
408
|
-
|
409
|
-
def literal_tag str
|
410
|
-
%Q{<span class="literal">#{str}</span>}
|
411
|
-
end
|
412
|
-
|
413
|
-
def format_backtrace line
|
414
|
-
line = line.to_s
|
415
|
-
html =
|
416
|
-
if line =~ /^(.*):(\d+):(in .*)$/ && File.exist?($1)
|
417
|
-
"#{format_source_location([$1, $2.to_i])}:#{h $3}"
|
418
|
-
else
|
419
|
-
file_name_tag(h line)
|
420
|
-
end
|
421
|
-
%Q{<span class="backtrace">#{html}</span>}
|
422
|
-
end
|
423
|
-
|
424
|
-
def wrap_lines str, width = nil
|
425
|
-
str.to_s.split("\n").map do | line |
|
426
|
-
wrap_line line, width
|
427
|
-
end * "\n"
|
428
|
-
end
|
429
|
-
|
430
|
-
def wrap_line str, width = nil
|
431
|
-
width ||= config[:wrap_width] || 80
|
432
|
-
str = str.to_s
|
433
|
-
out = ''
|
434
|
-
pos = 0
|
435
|
-
while pos < str.size
|
436
|
-
out << h(str[pos, width])
|
437
|
-
pos += width
|
438
|
-
out << " \u21B5\n" if pos < str.size
|
439
|
-
end
|
440
|
-
out
|
441
|
-
end
|
442
|
-
|
443
|
-
def safe_format_structured obj
|
444
|
-
begin
|
445
|
-
if config[:awesome_print] && defined?(::AwesomePrint)
|
446
|
-
ansi = obj.ai(indent: 2, html: false, index: false)
|
447
|
-
ansi2html(ansi)
|
448
|
-
else
|
449
|
-
'<pre>' << wrap_lines(safe_pp(obj)) << '</pre>'
|
450
|
-
end
|
451
|
-
rescue
|
452
|
-
STDERR.puts " #{$!.inspect}: falling back to #inspect for #{obj.class}\n #{$!.backtrace * "\n "}"
|
453
|
-
'<pre>' << wrap_lines(obj.inspect) << '</pre>'
|
454
|
-
end
|
455
|
-
end
|
456
|
-
|
457
|
-
def safe_format obj
|
458
|
-
safe_pp(obj)
|
459
|
-
end
|
460
|
-
|
461
|
-
def safe_pp obj
|
462
|
-
::PP.pp(obj, '')
|
463
|
-
rescue
|
464
|
-
STDERR.puts " #{$!.inspect}: falling back to #inspect for #{obj.class}\n #{$!.backtrace * "\n "}"
|
465
|
-
obj.inspect
|
466
|
-
end
|
467
|
-
|
468
|
-
def format_as_terminal str
|
469
|
-
str &&= str.to_s.force_encoding('UTF-8')
|
470
|
-
if str.blank?
|
471
|
-
%Q{<span class="none">NONE</span>}
|
472
|
-
else
|
473
|
-
ansi2html(str)
|
474
|
-
end
|
475
|
-
end
|
476
|
-
|
477
|
-
def ansi2html ansi
|
478
|
-
Ansi2Html.new.convert(ansi, '')
|
479
|
-
end
|
480
151
|
end
|
481
152
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'date'
|
3
|
+
require 'rack_console/mock_method'
|
4
|
+
|
5
|
+
module RackConsole
|
6
|
+
module Configuration
|
7
|
+
def has_console_access?
|
8
|
+
case a = config[:authorized?]
|
9
|
+
when true, false
|
10
|
+
a
|
11
|
+
when Proc
|
12
|
+
a.call
|
13
|
+
else
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_access!
|
19
|
+
unauthorized! unless has_console_access?
|
20
|
+
end
|
21
|
+
|
22
|
+
def unauthorized!
|
23
|
+
raise Error, "not authorized"
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_file_access? file
|
27
|
+
! ! (file != '(eval)' && $".include?(file))
|
28
|
+
end
|
29
|
+
|
30
|
+
def url_root url
|
31
|
+
"#{config[:url_root_prefix]}#{url}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def locals
|
35
|
+
@locals ||= { }
|
36
|
+
end
|
37
|
+
|
38
|
+
def layout
|
39
|
+
config[:layout] || :layout
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_template(views, name, engine, &block)
|
43
|
+
views = config[:views] || views
|
44
|
+
Array(views).each do |v|
|
45
|
+
v = config[:views_default] if v == :default
|
46
|
+
super(v, name, engine, &block)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def css_dir
|
51
|
+
config[:css_dir]
|
52
|
+
end
|
53
|
+
|
54
|
+
def eval_target
|
55
|
+
case et = config[:eval_target]
|
56
|
+
when Proc
|
57
|
+
et.call
|
58
|
+
else
|
59
|
+
et
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def server_info
|
64
|
+
thr = Thread.current
|
65
|
+
(config[:server_info] || { }).merge(
|
66
|
+
host: Socket.gethostname,
|
67
|
+
pid: Process.pid,
|
68
|
+
ppid: Process.ppid,
|
69
|
+
thread: thr[:name] || thr.object_id,
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'time'
|
3
|
+
require 'date'
|
4
|
+
require 'pp'
|
5
|
+
require 'rack_console/ansi2html'
|
6
|
+
|
7
|
+
module RackConsole
|
8
|
+
module Formatting
|
9
|
+
def format_object obj, inline = false
|
10
|
+
case obj
|
11
|
+
when Module
|
12
|
+
format_module obj
|
13
|
+
else
|
14
|
+
format_other obj, inline
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def format_other obj, inline = false
|
19
|
+
if inline
|
20
|
+
literal_tag(h(limit_string(safe_format(obj).strip, 80)))
|
21
|
+
else
|
22
|
+
safe_format_structured(obj)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def format_source_location source_location, meth = nil, kind = nil, owner = nil
|
27
|
+
file, line = source_location
|
28
|
+
if file
|
29
|
+
"<a href='#{file_line_to_href file, line}' class='file_name'>#{file_name_tag("#{file}:#{line}")}</a>"
|
30
|
+
else
|
31
|
+
if meth
|
32
|
+
# Assume meth is Ruby Core and link to rdocs on ruby-doc.org.
|
33
|
+
name = meth.name
|
34
|
+
owner ||= meth.owner
|
35
|
+
owner_name = (owner.name || '').gsub('::', '/')
|
36
|
+
kind ||= (owner.instance_method(name) rescue nil) ? :i : :c
|
37
|
+
a_name = name.to_s.gsub(/([^a-z0-9_])/i){|m| "-%X" % [ m.ord ]}
|
38
|
+
a_name.sub!(/^-/, '')
|
39
|
+
a_name = "method-#{kind}-#{a_name}"
|
40
|
+
ruby_core_link = "http://www.ruby-doc.org/core-#{RUBY_VERSION}/#{owner_name}.html\##{a_name}"
|
41
|
+
"<a href='#{ruby_core_link}' class='ruby_core_doc'>#{h ruby_core_link}</a>"
|
42
|
+
else
|
43
|
+
"NONE"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def file_line_to_href name, lineno = nil
|
49
|
+
link = name.sub(%r{^/}, '-')
|
50
|
+
link = link.split('/').map{|s| e s}.join('/')
|
51
|
+
link = url_root("/file/#{link}")
|
52
|
+
link << ":#{lineno}\##{lineno - 2}" if lineno
|
53
|
+
link
|
54
|
+
end
|
55
|
+
|
56
|
+
def href_to_file_line path
|
57
|
+
path.to_s =~ /^([^:]+)(:([^:]+))?/
|
58
|
+
file, line = $1, $3
|
59
|
+
file.sub!(/^-/, '/')
|
60
|
+
[ file, line && line.to_i ]
|
61
|
+
end
|
62
|
+
|
63
|
+
def source_file_methods_href file
|
64
|
+
link = file.sub(%r{^/}, '-')
|
65
|
+
link = url_root("/methods/file/#{link}")
|
66
|
+
end
|
67
|
+
|
68
|
+
def source_file source_location
|
69
|
+
source_location && SourceFile.new(source_location).load!
|
70
|
+
end
|
71
|
+
|
72
|
+
def h(text)
|
73
|
+
Rack::Utils.escape_html(text.to_s)
|
74
|
+
end
|
75
|
+
|
76
|
+
def e(text)
|
77
|
+
Rack::Utils.escape(text.to_s)
|
78
|
+
end
|
79
|
+
|
80
|
+
def limit_string(text, len)
|
81
|
+
text = text.to_s
|
82
|
+
if text.size > len
|
83
|
+
text = text[0 .. len] + ' ...'
|
84
|
+
end
|
85
|
+
text
|
86
|
+
end
|
87
|
+
|
88
|
+
def format_module obj
|
89
|
+
return module_name_tag(h(obj.inspect)) unless obj && obj.name
|
90
|
+
path = obj.name.to_s.split('::')
|
91
|
+
result = ''
|
92
|
+
name = ''; pre = ''
|
93
|
+
path.each do | n |
|
94
|
+
name << n
|
95
|
+
href = url_root("/module/#{name}")
|
96
|
+
result << "<a href='#{href}' class='module_name'>#{module_name_tag("#{pre}#{h n}")}</a>"
|
97
|
+
name << '::'
|
98
|
+
pre = '::'
|
99
|
+
end
|
100
|
+
module_name_tag(result)
|
101
|
+
end
|
102
|
+
|
103
|
+
def format_method m, kind, owner = nil
|
104
|
+
owner ||= m.owner
|
105
|
+
source_location = m.source_location
|
106
|
+
source_location &&= source_location * ":"
|
107
|
+
href = method_href(m, kind, owner)
|
108
|
+
"<a href='#{href}' title='#{source_location}' class='method_name'>#{method_name_tag(h(m.name))}</a>"
|
109
|
+
end
|
110
|
+
|
111
|
+
def method_href m, kind, owner = nil
|
112
|
+
owner ||= m.owner
|
113
|
+
href = url_root("/method/#{owner.name}/#{e kind.to_s}/#{e m.name}")
|
114
|
+
end
|
115
|
+
|
116
|
+
def format_methods obj
|
117
|
+
case obj
|
118
|
+
when nil
|
119
|
+
return nil
|
120
|
+
when ::Method, ::UnboundMethod, MockMethod
|
121
|
+
name = obj.name or return nil
|
122
|
+
else
|
123
|
+
name = obj.to_s
|
124
|
+
end
|
125
|
+
href = url_root("/methods/*/*/#{e name}")
|
126
|
+
"<a href='#{href}' title='Other methods named #{h name.inspect}' class='method_name'>#{method_name_tag(h(name))}</a>"
|
127
|
+
end
|
128
|
+
|
129
|
+
def file_name_tag str
|
130
|
+
%Q{<span class="file_name">#{str}</span>}
|
131
|
+
end
|
132
|
+
|
133
|
+
def module_name_tag str
|
134
|
+
%Q{<span class="module_name">#{str}</span>}
|
135
|
+
end
|
136
|
+
|
137
|
+
def method_name_tag str
|
138
|
+
%Q{<span class="method_name">#{str}</span>}
|
139
|
+
end
|
140
|
+
|
141
|
+
def literal_tag str
|
142
|
+
%Q{<span class="literal">#{str}</span>}
|
143
|
+
end
|
144
|
+
|
145
|
+
def format_backtrace line
|
146
|
+
line = line.to_s
|
147
|
+
html =
|
148
|
+
if line =~ /^(.*):(\d+):(in .*)$/ && File.exist?($1)
|
149
|
+
"#{format_source_location([$1, $2.to_i])}:#{h $3}"
|
150
|
+
else
|
151
|
+
file_name_tag(h line)
|
152
|
+
end
|
153
|
+
%Q{<span class="backtrace">#{html}</span>}
|
154
|
+
end
|
155
|
+
|
156
|
+
def wrap_lines str, width = nil
|
157
|
+
str.to_s.split("\n").map do | line |
|
158
|
+
wrap_line line, width
|
159
|
+
end * "\n"
|
160
|
+
end
|
161
|
+
|
162
|
+
def wrap_line str, width = nil
|
163
|
+
width ||= config[:wrap_width] || 80
|
164
|
+
str = str.to_s
|
165
|
+
out = ''
|
166
|
+
pos = 0
|
167
|
+
while pos < str.size
|
168
|
+
out << h(str[pos, width])
|
169
|
+
pos += width
|
170
|
+
out << " \u21B5\n" if pos < str.size
|
171
|
+
end
|
172
|
+
out
|
173
|
+
end
|
174
|
+
|
175
|
+
def safe_format_structured obj
|
176
|
+
begin
|
177
|
+
if config[:awesome_print] && defined?(::AwesomePrint)
|
178
|
+
ansi = obj.ai(indent: 2, html: false, index: false)
|
179
|
+
ansi2html(ansi)
|
180
|
+
else
|
181
|
+
'<pre>' << wrap_lines(safe_pp(obj)) << '</pre>'
|
182
|
+
end
|
183
|
+
rescue
|
184
|
+
STDERR.puts " #{$!.inspect}: falling back to #inspect for #{obj.class}\n #{$!.backtrace * "\n "}"
|
185
|
+
'<pre>' << wrap_lines(obj.inspect) << '</pre>'
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def safe_format obj
|
190
|
+
safe_pp(obj)
|
191
|
+
end
|
192
|
+
|
193
|
+
def safe_pp obj
|
194
|
+
::PP.pp(obj, '')
|
195
|
+
rescue
|
196
|
+
STDERR.puts " #{$!.inspect}: falling back to #inspect for #{obj.class}\n #{$!.backtrace * "\n "}"
|
197
|
+
obj.inspect
|
198
|
+
end
|
199
|
+
|
200
|
+
def format_as_terminal str
|
201
|
+
str &&= str.to_s.force_encoding('UTF-8')
|
202
|
+
if str.blank?
|
203
|
+
%Q{<span class="none">NONE</span>}
|
204
|
+
else
|
205
|
+
ansi2html(str)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def ansi2html ansi
|
210
|
+
Ansi2Html.new.convert(ansi, '')
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'rack_console/mock_method'
|
2
|
+
|
3
|
+
module RackConsole
|
4
|
+
module MethodIntrospection
|
5
|
+
def methods_matching params
|
6
|
+
name_p = match_pred(params[:name], :to_sym)
|
7
|
+
kind_p = match_pred(params[:kind], :to_sym)
|
8
|
+
owner_p = match_pred(params[:owner])
|
9
|
+
file_p = match_pred(params[:file])
|
10
|
+
|
11
|
+
methods = [ ]
|
12
|
+
seen = { }
|
13
|
+
ObjectSpace.each_object(::Module) do | owner |
|
14
|
+
next unless (owner.name rescue nil)
|
15
|
+
next if owner_p && owner_p != owner.name
|
16
|
+
methods_for_module(owner, name_p, kind_p, file_p, seen, methods)
|
17
|
+
end
|
18
|
+
sort_methods! methods
|
19
|
+
methods
|
20
|
+
end
|
21
|
+
|
22
|
+
def match_pred value, m = nil
|
23
|
+
if value != nil && value != '*' && value != ''
|
24
|
+
value = value.send(m) if m
|
25
|
+
else
|
26
|
+
value = nil
|
27
|
+
end
|
28
|
+
value
|
29
|
+
end
|
30
|
+
|
31
|
+
def methods_for_module owner, name_p = nil, kind_p = nil, file_p = nil, seen = { }, to_methods = nil
|
32
|
+
methods = to_methods || [ ]
|
33
|
+
methods_for_module_by_kind([ :i, :instance_method_names, :instance_method ],
|
34
|
+
owner, name_p, kind_p, file_p, seen, methods)
|
35
|
+
methods_for_module_by_kind([ :c, :singleton_method_names, :singleton_method ],
|
36
|
+
owner, name_p, kind_p, file_p, seen, methods)
|
37
|
+
sort_methods! methods unless to_methods
|
38
|
+
methods
|
39
|
+
end
|
40
|
+
|
41
|
+
def methods_for_module_by_kind access, owner, name_p, kind_p, file_p, seen, methods
|
42
|
+
kind, method_names, method_getter = *access
|
43
|
+
unless kind_p && kind_p != kind
|
44
|
+
send(method_names, owner).each do | name |
|
45
|
+
next if name_p && name_p != (name = name.to_sym)
|
46
|
+
if meth = (owner.send(method_getter, name) rescue nil) and key = [ owner, kind, name ] and ! seen[key]
|
47
|
+
seen[key] = true
|
48
|
+
if file_p
|
49
|
+
f = meth.source_location and f = f.first
|
50
|
+
next if f != file_p
|
51
|
+
end
|
52
|
+
methods << MockMethod.new(meth, name, kind, owner)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
methods
|
57
|
+
end
|
58
|
+
|
59
|
+
def sort_methods! methods
|
60
|
+
methods.sort_by!{|x| [ x.owner.to_s, x.kind, x.name ]}
|
61
|
+
end
|
62
|
+
|
63
|
+
def instance_method_names owner
|
64
|
+
( owner.instance_methods(false) |
|
65
|
+
owner.private_instance_methods(false) |
|
66
|
+
owner.protected_instance_methods(false)
|
67
|
+
).sort
|
68
|
+
end
|
69
|
+
|
70
|
+
def singleton_method_names owner
|
71
|
+
owner.singleton_methods(false)
|
72
|
+
end
|
73
|
+
|
74
|
+
def methods_within_file file
|
75
|
+
methods = methods_matching(file: file)
|
76
|
+
sort_methods_by_source_location! methods
|
77
|
+
end
|
78
|
+
|
79
|
+
def sort_methods_by_source_location! methods
|
80
|
+
methods.sort_by!{|x| x.source_location || DUMMY_SOURCE_LOCATION }
|
81
|
+
end
|
82
|
+
DUMMY_SOURCE_LOCATION = [ "".freeze, 0 ].freeze
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
@@ -1,5 +1,7 @@
|
|
1
1
|
.rack_console {
|
2
|
-
|
2
|
+
color: white;
|
3
|
+
background-color: black;
|
4
|
+
border: 1px solid white;
|
3
5
|
padding: 1em;
|
4
6
|
font-family: sans-serif;
|
5
7
|
}
|
@@ -10,7 +12,7 @@
|
|
10
12
|
|
11
13
|
.rack_console dt {
|
12
14
|
font-size: 80%;
|
13
|
-
color: #
|
15
|
+
color: #888;
|
14
16
|
}
|
15
17
|
|
16
18
|
.rack_console dd {
|
@@ -48,7 +50,7 @@
|
|
48
50
|
}
|
49
51
|
|
50
52
|
.rack_console a.hover_show:hover span {
|
51
|
-
color: #
|
53
|
+
color: #aaa;
|
52
54
|
display: initial;
|
53
55
|
font-style: bold;
|
54
56
|
}
|
@@ -62,6 +64,7 @@
|
|
62
64
|
}
|
63
65
|
|
64
66
|
.rack_console .result pre {
|
67
|
+
border: 1px solid white;
|
65
68
|
font-family: monospace;
|
66
69
|
font-size: 13px;
|
67
70
|
background-color: #000;
|
@@ -89,24 +92,31 @@
|
|
89
92
|
padding: 0.5em;
|
90
93
|
}
|
91
94
|
|
95
|
+
.rack_console .constant .name {
|
96
|
+
color: #af4;
|
97
|
+
}
|
98
|
+
.rack_console .constant td {
|
99
|
+
padding-right: 1em;
|
100
|
+
}
|
101
|
+
|
92
102
|
.rack_console span.module_name {
|
93
103
|
font-family: monospace;
|
94
|
-
color: #
|
104
|
+
color: #f66;
|
95
105
|
}
|
96
106
|
|
97
107
|
.rack_console span.method_name {
|
98
108
|
font-family: monospace;
|
99
|
-
color: #
|
109
|
+
color: #6f6;
|
100
110
|
}
|
101
111
|
|
102
112
|
.rack_console span.file_name {
|
103
113
|
font-family: monospace;
|
104
|
-
color: #
|
114
|
+
color: #aaf;
|
105
115
|
}
|
106
116
|
|
107
117
|
.rack_console span.literal {
|
108
118
|
font-family: monospace;
|
109
|
-
color: #
|
119
|
+
color: #6ff;
|
110
120
|
}
|
111
121
|
|
112
122
|
.rack_console .source_listing {
|
@@ -115,7 +125,7 @@
|
|
115
125
|
|
116
126
|
.rack_console .ruby_core_doc {
|
117
127
|
font-family: monospace;
|
118
|
-
color: #
|
128
|
+
color: #ff6;
|
119
129
|
}
|
120
130
|
|
121
131
|
.rack_console tr.constant {
|
@@ -123,11 +133,30 @@
|
|
123
133
|
}
|
124
134
|
|
125
135
|
.rack_console .source_listing .unselected_line {
|
126
|
-
color: #
|
136
|
+
color: #aba;
|
127
137
|
}
|
128
138
|
|
129
139
|
.rack_console .source_listing .selected_line {
|
130
|
-
font-weight:
|
140
|
+
font-weight: bolder;
|
141
|
+
color: #fff;
|
142
|
+
}
|
143
|
+
|
144
|
+
.rack_console .source_listing .block_begin {
|
145
|
+
font-weight: bolder;
|
146
|
+
color: #fff;
|
147
|
+
text-decoration: underline;
|
148
|
+
}
|
149
|
+
|
150
|
+
.rack_console .source_listing .block_body {
|
151
|
+
color: #eee;
|
152
|
+
}
|
153
|
+
|
154
|
+
.rack_console .file_name * {
|
155
|
+
color: #aaf;
|
156
|
+
}
|
157
|
+
|
158
|
+
.rack_console .file_name .methods {
|
159
|
+
color: #eee;
|
131
160
|
}
|
132
161
|
|
133
162
|
.rack_console .error dl.error {
|
@@ -146,16 +175,23 @@
|
|
146
175
|
font-size: 75%;
|
147
176
|
}
|
148
177
|
|
149
|
-
.rack_console .
|
178
|
+
.rack_console tr.method td.class {
|
150
179
|
text-align: right;
|
151
180
|
}
|
152
181
|
|
153
|
-
.rack_console .
|
182
|
+
.rack_console tr.method td.kind * {
|
154
183
|
font-family: monospace;
|
184
|
+
color: #cab;
|
155
185
|
}
|
156
186
|
|
157
|
-
.rack_console .
|
187
|
+
.rack_console tr.method td.source_location * {
|
158
188
|
padding-left: 2em;
|
189
|
+
color: #aaf;
|
190
|
+
}
|
191
|
+
|
192
|
+
.rack_console tr.method td.source_location a.ruby_core_doc {
|
193
|
+
padding-left: 6em;
|
194
|
+
color: #77c;
|
159
195
|
}
|
160
196
|
|
161
197
|
.rack_console .ansi {
|
@@ -37,10 +37,10 @@
|
|
37
37
|
%table.constants
|
38
38
|
- @constants.each do | name, value |
|
39
39
|
%tr.constant
|
40
|
-
%td
|
40
|
+
%td.name
|
41
41
|
%tt=h name
|
42
|
-
%td= format_module(value.class)
|
43
|
-
%td= format_object(value, :inline)
|
42
|
+
%td.value_class= format_module(value.class)
|
43
|
+
%td.value= format_object(value, :inline)
|
44
44
|
%dt
|
45
45
|
Methods:
|
46
46
|
%dd
|
@@ -5,14 +5,13 @@
|
|
5
5
|
%link{rel: "stylesheet", href: url_root("/css/rack_console.css")}
|
6
6
|
%link{rel: "stylesheet", href: url_root("/css/ansi.css")}
|
7
7
|
%body
|
8
|
-
.
|
9
|
-
.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
This is the footer.
|
8
|
+
.rack_console
|
9
|
+
.wrapper
|
10
|
+
.header
|
11
|
+
%h1 rack_console
|
12
|
+
|
13
|
+
.content
|
14
|
+
=yield
|
15
|
+
|
16
|
+
.footer
|
17
|
+
%hr
|
data/lib/rack_console/version.rb
CHANGED
data/rack_console.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack_console
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kurt Stephens
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sinatra
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0.10'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: simplecov
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0.11'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0.11'
|
153
167
|
description: A Rack App that provides a basic interactive Ruby console and introspection.
|
154
168
|
email:
|
155
169
|
- ks.github@kurtstephens.com
|
@@ -173,7 +187,10 @@ files:
|
|
173
187
|
- lib/rack_console/ansi2html.rb
|
174
188
|
- lib/rack_console/app.rb
|
175
189
|
- lib/rack_console/app_helpers.rb
|
190
|
+
- lib/rack_console/configuration.rb
|
176
191
|
- lib/rack_console/expr_helpers.rb
|
192
|
+
- lib/rack_console/formatting.rb
|
193
|
+
- lib/rack_console/method_introspection.rb
|
177
194
|
- lib/rack_console/mock_method.rb
|
178
195
|
- lib/rack_console/source_file.rb
|
179
196
|
- lib/rack_console/template/css/ansi.css
|