Module: RackConsole::AppHelpers

Includes:
ExprHelpers
Defined in:
lib/rack_console/app_helpers.rb

Defined Under Namespace

Classes: MockMethod

Instance Method Summary collapse

Methods included from ExprHelpers

#expr_for_Module, #expr_for_method, #expr_for_object, #expr_for_object!

Instance Method Details

#ansi2html(ansi) ⇒ Object



442
443
444
# File 'lib/rack_console/app_helpers.rb', line 442

def ansi2html ansi
  Ansi2Html.new.convert(ansi, '')
end

#capture_stdio!Object



107
108
109
110
111
112
113
114
115
116
# File 'lib/rack_console/app_helpers.rb', line 107

def capture_stdio!
  @captured_stdio = true
  _stdin, _stdout, _stderr = $stdin, $stdout, $stderr
  $stdin, $stdout, $stderr = @stdin, @stdout, @stderr
  begin
    yield
  ensure
    $stdin, $stdout, $stderr = _stdin, _stdout, _stderr
  end
end

#console!Object



46
47
48
49
50
51
52
# File 'lib/rack_console/app_helpers.rb', line 46

def console!
  if has_console_access?
    haml :console, locals: locals, layout: layout
  else
    raise "not authorized"
  end
end

#const_get_safe(m, name) ⇒ Object



187
188
189
190
191
# File 'lib/rack_console/app_helpers.rb', line 187

def const_get_safe m, name
  m.const_get(name)
rescue Object
  "ERROR: #{$!.inspect}"
end

#css_dirObject



40
41
42
# File 'lib/rack_console/app_helpers.rb', line 40

def css_dir
  config[:css_dir]
end

#e(text) ⇒ Object



318
319
320
# File 'lib/rack_console/app_helpers.rb', line 318

def e(text)
  Rack::Utils.escape(text.to_s)
end

#evaluate_expr!Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rack_console/app_helpers.rb', line 54

def evaluate_expr!
  return if @result_evaled
  result_capture! do
    @stdin  = StringIO.new('')
    @stdout = StringIO.new('')
    @stderr = StringIO.new('')
    @result_ok = false
    @expr = (params[:expr] || '').strip
    unless @expr.blank?
      @result_evaled = true
      Timeout.timeout(config[:eval_timeout] || 120) do
        capture_stdio! do
          expr_str = "begin; #{@expr} \n; end"
          @result = eval(expr_str)
          @result_ok = true
        end
      end
    end
  end
end

#evaluate_method!Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rack_console/app_helpers.rb', line 85

def evaluate_method!
  evaluate_expr!
  @show_stdio = @show_result = false
  if @result_ok && @result.is_a?(Module)
    result_capture! do
      @module = @result
      @method_name = params[:name]
      @method_kind = params[:kind].to_s =~ /i/ ? :instance_method : :method
      @method = @module.send(@method_kind, @method_name) rescue nil
      unless @method
        @method = @module.send(:method, @method_name)
        @method_kind = :method
      end
      @method_source_location = @method.source_location
      @method_source = @method_source_location && SourceFile.new(@method_source_location).load!.narrow_to_block!
      @result = @method
      @is_method = true
      expr_for_object! @method, @module, @method_kind
    end
  end
end

#evaluate_methods!Object



118
119
120
121
122
123
# File 'lib/rack_console/app_helpers.rb', line 118

def evaluate_methods!
  @methods = nil
  result_capture! do
    @methods = methods_matching(params)
  end
end

#evaluate_module!Object



75
76
77
78
79
80
81
82
83
# File 'lib/rack_console/app_helpers.rb', line 75

def evaluate_module!
  evaluate_expr!
  @show_stdio = @show_result = false
  if @result_ok && @result.is_a?(Module)
    result_capture! do
      @module = @result
    end
  end
end

#file_line_to_href(name, lineno = nil) ⇒ Object



295
296
297
298
299
300
301
# File 'lib/rack_console/app_helpers.rb', line 295

def file_line_to_href name, lineno = nil
  link = name.sub(%r{^/}, '-')
  link = link.split('/').map{|s| e s}.join('/')
  link = url_root("/file/#{link}")
  link << ":#{lineno}\##{lineno - 2}" if lineno
  link
end

#file_name_tag(str) ⇒ Object



363
364
365
# File 'lib/rack_console/app_helpers.rb', line 363

def file_name_tag str
  %Q{<span class="file_name">#{str}</span>}
end

#find_template(views, name, engine, &block) ⇒ Object



32
33
34
35
36
37
38
# File 'lib/rack_console/app_helpers.rb', line 32

def find_template(views, name, engine, &block)
  views = config[:views] || views
  Array(views).each do |v|
    v = config[:views_default] if v == :default
    super(v, name, engine, &block)
  end
end

#format_as_terminal(str) ⇒ Object



433
434
435
436
437
438
439
440
# File 'lib/rack_console/app_helpers.rb', line 433

def format_as_terminal str
  str &&= str.to_s.force_encoding('UTF-8')
  if str.blank?
    %Q{<span class="none">NONE</span>}
  else
    ansi2html(str)
  end
end

#format_backtrace(line) ⇒ Object



379
380
381
382
383
384
385
386
387
388
# File 'lib/rack_console/app_helpers.rb', line 379

def format_backtrace line
  line = line.to_s
  html =
    if line =~ /^(.*):(\d+):(in .*)$/ && File.exist?($1)
      "#{format_source_location([$1, $2.to_i])}:#{h $3}"
    else
      file_name_tag(h line)
    end
  %Q{<span class="backtrace">#{html}</span>}
end

#format_method(m, kind, owner = nil) ⇒ Object



345
346
347
348
349
350
351
# File 'lib/rack_console/app_helpers.rb', line 345

def format_method m, kind, owner = nil
  owner ||= m.owner
  source_location = m.source_location
  source_location &&= source_location * ":"
  href = method_href(m, kind, owner)
  "<a href='#{href}' title='#{source_location}' class='method_name'>#{method_name_tag(h(m.name))}</a>"
end

#format_methods(name) ⇒ Object



358
359
360
361
# File 'lib/rack_console/app_helpers.rb', line 358

def format_methods name
  href = url_root("/methods/*/*/#{e name}")
  "<a href='#{href}' title='Other methods named #{h name.inspect}' class='method_name'>#{method_name_tag(h(name))}</a>"
end

#format_module(obj) ⇒ Object



330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/rack_console/app_helpers.rb', line 330

def format_module obj
  return module_name_tag(h(obj.inspect)) unless obj && obj.name
  path = obj.name.to_s.split('::')
  result = ''
  name = ''; pre = ''
  path.each do | n |
    name << n
    href = url_root("/module/#{name}")
    result << "<a href='#{href}' class='module_name'>#{module_name_tag("#{pre}#{h n}")}</a>"
    name << '::'
    pre = '::'
  end
  module_name_tag(result)
end

#format_object(obj, inline = false) ⇒ Object



170
171
172
173
174
175
176
177
# File 'lib/rack_console/app_helpers.rb', line 170

def format_object obj, inline = false
  case obj
  when Module
    format_module obj
  else
    format_other obj, inline
  end
end

#format_other(obj, inline = false) ⇒ Object



179
180
181
182
183
184
185
# File 'lib/rack_console/app_helpers.rb', line 179

def format_other obj, inline = false
  if inline
    literal_tag(h(limit_string(safe_format(obj), 80)))
  else
    safe_format_structured(obj)
  end
end

#format_source_location(source_location, meth = nil, kind = nil, owner = nil) ⇒ Object



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/rack_console/app_helpers.rb', line 193

def format_source_location source_location, meth = nil, kind = nil, owner = nil
  file, line = source_location
  if file
    "<a href='#{file_line_to_href file, line}' class='file_name'>#{file_name_tag("#{file}:#{line}")}</a>"
  else
    if meth
      # Assume meth is Ruby Core and link to rdocs on ruby-doc.org.
      name = meth.name
      owner ||= meth.owner
      owner_name = (owner.name || '').gsub('::', '/')
      kind ||= (owner.instance_method(name) rescue nil) ? :i : :c
      a_name = name.to_s.gsub(/([^a-z0-9_])/i){|m| "-%X" % [ m.ord ]}
      a_name.sub!(/^-/, '')
      a_name = "method-#{kind}-#{a_name}"
      ruby_core_link = "http://www.ruby-doc.org/core-#{RUBY_VERSION}/#{owner_name}.html\##{a_name}"
      "<a href='#{ruby_core_link}' class='ruby_core_doc'>#{h ruby_core_link}</a>"
    else
      "NONE"
    end
  end
end

#h(text) ⇒ Object



314
315
316
# File 'lib/rack_console/app_helpers.rb', line 314

def h(text)
  Rack::Utils.escape_html(text.to_s)
end

#has_console_access?Boolean

Returns:

  • (Boolean)


12
13
14
# File 'lib/rack_console/app_helpers.rb', line 12

def has_console_access?
  true
end

#has_file_access?(file) ⇒ Boolean

Returns:

  • (Boolean)


16
17
18
# File 'lib/rack_console/app_helpers.rb', line 16

def has_file_access? file
  ! ! (file != '(eval)' && $".include?(file))
end

#href_to_file_line(path) ⇒ Object



303
304
305
306
307
308
# File 'lib/rack_console/app_helpers.rb', line 303

def href_to_file_line path
  path.to_s =~ /^([^:]+)(:([^:]+))?/
  file, line = $1, $3
  file.sub!(/^-/, '/')
  [ file, line && line.to_i ]
end

#instance_method_names(owner) ⇒ Object



271
272
273
274
275
276
# File 'lib/rack_console/app_helpers.rb', line 271

def instance_method_names owner
  ( owner.instance_methods(false) |
    owner.private_instance_methods(false) |
    owner.protected_instance_methods(false)
    ).sort
end

#layoutObject



28
29
30
# File 'lib/rack_console/app_helpers.rb', line 28

def layout
  config[:layout] || :layout
end

#limit_string(text, len) ⇒ Object



322
323
324
325
326
327
328
# File 'lib/rack_console/app_helpers.rb', line 322

def limit_string(text, len)
  text = text.to_s
  if text.size > len
    text = text[0 .. len] + ' ...'
  end
  text
end

#literal_tag(str) ⇒ Object



375
376
377
# File 'lib/rack_console/app_helpers.rb', line 375

def literal_tag str
  %Q{<span class="literal">#{str}</span>}
end

#localsObject



24
25
26
# File 'lib/rack_console/app_helpers.rb', line 24

def locals
  @locals ||= { }
end

#match_pred(value, m = nil) ⇒ Object



231
232
233
234
235
236
237
238
# File 'lib/rack_console/app_helpers.rb', line 231

def match_pred value, m = nil
  if value != '*' && value != ''
    value = value.send(m) if m
  else
    value = nil
  end
  value
end

#method_href(m, kind, owner = nil) ⇒ Object



353
354
355
356
# File 'lib/rack_console/app_helpers.rb', line 353

def method_href m, kind, owner = nil
  owner ||= m.owner
  href = url_root("/method/#{owner.name}/#{e kind.to_s}/#{e m.name}")
end

#method_name_tag(str) ⇒ Object



371
372
373
# File 'lib/rack_console/app_helpers.rb', line 371

def method_name_tag str
  %Q{<span class="method_name">#{str}</span>}
end

#methods_for_module(owner, name_p = nil, kind_p = nil, seen = { }, to_methods = nil) ⇒ Object



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/rack_console/app_helpers.rb', line 240

def methods_for_module owner, name_p = nil, kind_p = nil, seen = { }, to_methods = nil
  methods = to_methods || [ ]
  kind = :i
  unless kind_p && kind_p != kind
    instance_method_names(owner).each do | name |
      next if name_p && name_p != (name = name.to_sym)
      if meth = (owner.instance_method(name) rescue nil) and key = [ owner, kind, name ] and ! seen[key]
        seen[key] = true
        methods << MockMethod.new(meth, name, kind, owner)
      end
    end
  end

  kind = :c
  unless kind_p && kind_p != kind
    singleton_method_names(owner).each do | name |
      next if name_p && name_p != (name = name.to_sym)
      if meth = (owner.singleton_method(name) rescue nil) and key = [ owner, kind, name ] and ! seen[key]
        seen[key] = true
        methods << MockMethod.new(meth, name, kind, owner)
      end
    end
  end
  sort_methods! methods unless to_methods
  methods
end

#methods_matching(params) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/rack_console/app_helpers.rb', line 215

def methods_matching params
  name_p  = match_pred(params[:name], :to_sym)
  kind_p  = match_pred(params[:kind], :to_sym)
  owner_p = match_pred(params[:owner])

  methods = [ ]
  seen = { }
  ObjectSpace.each_object(::Module) do | owner |
    next unless (owner.name rescue nil)
    next if owner_p && owner_p != owner.name
    methods_for_module(owner, name_p, kind_p, seen, methods)
  end
  sort_methods! methods
  methods
end

#module_name_tag(str) ⇒ Object



367
368
369
# File 'lib/rack_console/app_helpers.rb', line 367

def module_name_tag str
  %Q{<span class="module_name">#{str}</span>}
end

#prepare_file!Object



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/rack_console/app_helpers.rb', line 125

def prepare_file!
  path = params[:splat][0]
  file, line = href_to_file_line(path)
  result_capture! do
    unless has_file_access? file
      content_type 'text/plain'
      return "NOT A LOADABLE FILE"
    end
    @source_file = SourceFile.new([ file, line ]).load!
  end
end

#result_capture!Object



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/rack_console/app_helpers.rb', line 137

def result_capture!
  @result_ok = false
  result = yield
  @result_ok = true
  result
rescue
  @error = $!
  @error_description = @error.inspect
ensure
  @result_extended = @result.singleton_class.included_modules rescue nil
  @result_class = @result.class.name
  if @is_module = Module === @result
    @module = @result
    @ancestors = @module.ancestors.drop(1)
    if @is_class = @module.is_a?(Class)
      @superclass = @module.superclass
      @subclasses = @module.subclasses.sort_by{|c| c.name || ''}
    end
    @constants = @module.constants(false).sort.map{|n| [ n, const_get_safe(@module, n) ]}
    @methods = methods_for_module(@module)
  end
end

#safe_format(obj) ⇒ Object



422
423
424
# File 'lib/rack_console/app_helpers.rb', line 422

def safe_format obj
  safe_pp(obj)
end

#safe_format_structured(obj) ⇒ Object



408
409
410
411
412
413
414
415
416
417
418
419
420
# File 'lib/rack_console/app_helpers.rb', line 408

def safe_format_structured obj
  begin
    if config[:awesome_print] && defined?(::AwesomePrint)
      ansi = obj.ai(indent: 2, html: false, index: false)
      ansi2html(ansi)
    else
      '<pre>' << wrap_lines(safe_pp(obj)) << '</pre>'
    end
  rescue
    STDERR.puts "  #{$!.inspect}: falling back to #inspect for #{obj.class}\n  #{$!.backtrace * "\n  "}"
    '<pre>' << wrap_lines(obj.inspect) << '</pre>'
  end
end

#safe_pp(obj) ⇒ Object



426
427
428
429
430
431
# File 'lib/rack_console/app_helpers.rb', line 426

def safe_pp obj
  ::PP.pp(obj, '')
rescue
  STDERR.puts "  #{$!.inspect}: falling back to #inspect for #{obj.class}\n  #{$!.backtrace * "\n  "}"
  obj.inspect
end

#server_infoObject



160
161
162
163
164
165
166
167
168
# File 'lib/rack_console/app_helpers.rb', line 160

def server_info
  thr = Thread.current
  (config[:server_info] || { }).merge(
    host: Socket.gethostname,
    pid: Process.pid,
    ppid: Process.ppid,
    thread: thr[:name] || thr.object_id,
  )
end

#singleton_method_names(owner) ⇒ Object



278
279
280
# File 'lib/rack_console/app_helpers.rb', line 278

def singleton_method_names owner
  owner.singleton_methods(false)
end

#sort_methods!(methods) ⇒ Object



267
268
269
# File 'lib/rack_console/app_helpers.rb', line 267

def sort_methods! methods
  methods.sort_by!{|x| [ x.owner.to_s, x.kind, x.name ]}
end

#source_file(source_location) ⇒ Object



310
311
312
# File 'lib/rack_console/app_helpers.rb', line 310

def source_file source_location
  source_location && SourceFile.new(source_location).load!
end

#url_root(url) ⇒ Object



20
21
22
# File 'lib/rack_console/app_helpers.rb', line 20

def url_root url
  "#{config[:url_root_prefix]}#{url}"
end

#wrap_line(str, width = 80) ⇒ Object



396
397
398
399
400
401
402
403
404
405
406
# File 'lib/rack_console/app_helpers.rb', line 396

def wrap_line str, width = 80
  str = str.to_s
  out = ''
  pos = 0
  while pos < str.size
    out << h(str[pos, width])
    pos += width
    out << "&nbsp;\u21B5\n" if pos < str.size
  end
  out
end

#wrap_lines(str, width = 80) ⇒ Object



390
391
392
393
394
# File 'lib/rack_console/app_helpers.rb', line 390

def wrap_lines str, width = 80
  str.to_s.split("\n").map do | line |
    wrap_line line, width
  end * "\n"
end