irt 1.1.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.
- data/.gitignore +26 -0
- data/LICENSE +20 -0
- data/README.markdown +589 -0
- data/Rakefile +60 -0
- data/VERSION +1 -0
- data/bin/irt +101 -0
- data/bin/irt_irb +4 -0
- data/bin/irt_rails2 +6 -0
- data/goodies/nano/README +6 -0
- data/goodies/nano/irt.nanorc +86 -0
- data/goodies/vi/README +5 -0
- data/irt.gemspec +29 -0
- data/irtrc +48 -0
- data/lib/irt.rb +143 -0
- data/lib/irt/commands/core.rb +52 -0
- data/lib/irt/commands/help.rb +111 -0
- data/lib/irt/commands/log.rb +52 -0
- data/lib/irt/commands/ri.rb +59 -0
- data/lib/irt/commands/system.rb +102 -0
- data/lib/irt/commands/test.rb +60 -0
- data/lib/irt/differ.rb +87 -0
- data/lib/irt/directives.rb +28 -0
- data/lib/irt/directives/test.rb +84 -0
- data/lib/irt/extensions/irb.rb +45 -0
- data/lib/irt/extensions/irb/commands.rb +42 -0
- data/lib/irt/extensions/irb/context.rb +147 -0
- data/lib/irt/extensions/kernel.rb +18 -0
- data/lib/irt/extensions/method.rb +36 -0
- data/lib/irt/extensions/object.rb +7 -0
- data/lib/irt/hunks.rb +111 -0
- data/lib/irt/init.rb +1 -0
- data/lib/irt/log.rb +94 -0
- data/lib/irt/session.rb +59 -0
- metadata +167 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'irt/directives/test'
|
2
|
+
|
3
|
+
module IRT
|
4
|
+
module Directives
|
5
|
+
|
6
|
+
extend self
|
7
|
+
extend Test
|
8
|
+
|
9
|
+
# Evaluate a file as it were inserted at that line
|
10
|
+
# a relative file_path is considered to be relative to the including file
|
11
|
+
# i.e. '../file_in_the_same_dir.irt'
|
12
|
+
def eval_file(file_path)
|
13
|
+
parent_context = IRB.CurrentContext
|
14
|
+
new_io = IRB::FileInputMethod.new(File.expand_path(file_path, parent_context.io.file_name))
|
15
|
+
new_irb = IRB::Irb.new(parent_context.workspace, new_io)
|
16
|
+
new_irb.context.irb_name = File.basename(new_io.file_name)
|
17
|
+
new_irb.context.irb_path = new_io.file_name
|
18
|
+
IRT::Session.eval_input(new_irb.context, :file)
|
19
|
+
IRT::Session.exit
|
20
|
+
end
|
21
|
+
alias_method :insert_file, :eval_file
|
22
|
+
|
23
|
+
def irt_at_exit(&block)
|
24
|
+
IRB.conf[:AT_EXIT] << proc(&block)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module IRT
|
2
|
+
module Directives
|
3
|
+
module Test
|
4
|
+
extend self
|
5
|
+
|
6
|
+
@@tests = 0
|
7
|
+
@@oks = 0
|
8
|
+
@@diffs = 0
|
9
|
+
@@errors = 0
|
10
|
+
@@last_desc = nil
|
11
|
+
|
12
|
+
def desc(description)
|
13
|
+
@@last_desc = description
|
14
|
+
end
|
15
|
+
|
16
|
+
def _eql?(saved)
|
17
|
+
actual = IRB.CurrentContext.last_value
|
18
|
+
run_test(saved, actual, :value)
|
19
|
+
end
|
20
|
+
alias_method :test_value_eql?, :_eql?
|
21
|
+
alias_method :last_value_eql?, :_eql?
|
22
|
+
|
23
|
+
def _yaml_eql?(saved)
|
24
|
+
actual = IRT.yaml_dump(IRB.CurrentContext.last_value)
|
25
|
+
run_test(saved, actual, :yaml)
|
26
|
+
end
|
27
|
+
alias_method :last_yaml_eql?, :_yaml_eql?
|
28
|
+
alias_method :test_yaml_eql?, :_yaml_eql?
|
29
|
+
|
30
|
+
def test_summary #:nodoc:
|
31
|
+
return unless @@tests > 0
|
32
|
+
if @@tests == @@oks
|
33
|
+
str = @@tests == 1 ? " The TEST is OK! " : " All #{@@tests} TESTs are OK! "
|
34
|
+
puts str.ok_color.bold
|
35
|
+
else
|
36
|
+
puts "#{@@tests} TEST#{'s' unless @@tests == 1}: ".bold +
|
37
|
+
"#{@@oks} OK#{'s' unless @@oks == 1}, ".ok_color.bold +
|
38
|
+
"#{@@diffs} DIFF#{'s' unless @@diffs == 1}, ".diff_color.bold +
|
39
|
+
"#{@@errors} ERROR#{'s' unless @@errors == 1}.".error_color.bold
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_helper_files
|
44
|
+
return unless IRT.autoload_helper_files
|
45
|
+
irt_file_path = Pathname.new($0).realpath
|
46
|
+
container_path = Pathname.getwd.parent
|
47
|
+
down_path = irt_file_path.relative_path_from container_path
|
48
|
+
down_path.dirname.descend do |p|
|
49
|
+
helper_path = container_path.join(p, 'irt_helper.rb')
|
50
|
+
begin
|
51
|
+
require helper_path
|
52
|
+
rescue LoadError
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def run_test(saved, actual, kind)
|
60
|
+
context = IRB.CurrentContext
|
61
|
+
tno = '%3d' % @@tests += 1
|
62
|
+
d = @@last_desc || 'Test'
|
63
|
+
@@last_desc = nil
|
64
|
+
begin
|
65
|
+
if saved == actual
|
66
|
+
@@oks += 1
|
67
|
+
puts "#{tno}. OK!".ok_color.bold + " #{d}".ok_color
|
68
|
+
else
|
69
|
+
@@diffs += 1
|
70
|
+
puts "#{tno}. DIFFS!".diff_color.bold + %( #{d}\n ).diff_color +
|
71
|
+
%( at #{context.irb_path}: #{context.last_line_no} ).file_color.reversed.bold
|
72
|
+
puts IRT.differ.new(saved, actual, kind).output
|
73
|
+
IRT::Session.enter(:interactive) if IRT.irt_on_diffs
|
74
|
+
end
|
75
|
+
rescue Exception
|
76
|
+
@@errors += 1
|
77
|
+
puts "#{tno}. ERROR! ".error_color.bold + d.error_color
|
78
|
+
raise
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'irb'
|
2
|
+
require 'irt/extensions/irb/context'
|
3
|
+
require 'irt/extensions/irb/commands'
|
4
|
+
|
5
|
+
module IRB #:nodoc:
|
6
|
+
|
7
|
+
class << self
|
8
|
+
alias_method :irb_init_config, :init_config
|
9
|
+
alias_method :irb_setup, :setup
|
10
|
+
end
|
11
|
+
|
12
|
+
def IRB.setup(ap_path=nil)
|
13
|
+
irb_setup(ap_path)
|
14
|
+
IRT.init_files
|
15
|
+
end
|
16
|
+
|
17
|
+
def IRB.init_config(ap_path)
|
18
|
+
irb_init_config(ap_path)
|
19
|
+
|
20
|
+
@CONF[:AP_NAME] = 'irt'
|
21
|
+
@CONF[:PROMPT][:IRT] = { :PROMPT_I => "%02n >> ",
|
22
|
+
:PROMPT_S => ' "> ',
|
23
|
+
:PROMPT_C => "%02n ?> ",
|
24
|
+
:PROMPT_N => "%02n -> ",
|
25
|
+
:RETURN => " => %s\n" }
|
26
|
+
@CONF[:PROMPT_MODE] = :IRT
|
27
|
+
@CONF[:ECHO] = false
|
28
|
+
@CONF[:VERBOSE] = false
|
29
|
+
@CONF[:SAVE_HISTORY] = 100
|
30
|
+
@CONF[:HISTORY_FILE] = File.expand_path '~/.irt-history'
|
31
|
+
@CONF[:AT_EXIT] ||= []
|
32
|
+
@CONF[:AT_EXIT] << proc{ IRT::Session.enter(:interactive) if IRB.CurrentContext.irt_mode == :file } if !!ENV['IRT_INTERACTIVE_EOF']
|
33
|
+
@CONF[:AT_EXIT] << proc{ IRT::Directives.test_summary }
|
34
|
+
@CONF[:AT_EXIT] << proc{ print "\e[0m" if Colorer.color? } # reset colors
|
35
|
+
@CONF[:RC_NAME_GENERATOR] = proc {|rc| File.expand_path '~/.irtrc' }
|
36
|
+
|
37
|
+
IRT.init
|
38
|
+
end
|
39
|
+
|
40
|
+
def IRB.irb_exit(irb, ret)
|
41
|
+
IRT::Session.exit
|
42
|
+
throw :IRB_EXIT, ret
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'irt/commands/log'
|
2
|
+
require 'irt/commands/test'
|
3
|
+
require 'irt/commands/system'
|
4
|
+
require 'irt/commands/core'
|
5
|
+
require 'irt/commands/help'
|
6
|
+
require 'irt/commands/ri'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
module IRB
|
10
|
+
module ExtendCommandBundle #:nodoc:
|
11
|
+
|
12
|
+
include IRT::Commands::Log
|
13
|
+
include IRT::Commands::Test
|
14
|
+
include IRT::Commands::System
|
15
|
+
include IRT::Commands::Core
|
16
|
+
include IRT::Commands::Help
|
17
|
+
include IRT::Commands::Ri
|
18
|
+
include FileUtils
|
19
|
+
|
20
|
+
alias_method :x, :irb_exit
|
21
|
+
alias_method :q, :irb_exit
|
22
|
+
alias_method :xx, :abort
|
23
|
+
alias_method :qq, :abort
|
24
|
+
alias_method :irb, :irt
|
25
|
+
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
IRB.conf[:MAIN_CONTEXT] && IRB.conf[:MAIN_CONTEXT].irt_mode == :file && IRT::Directives.respond_to?(method) ?
|
28
|
+
IRT::Directives.send(method, *args, &block) :
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def ensure_session
|
35
|
+
if context.irt_mode == :file
|
36
|
+
m = caller[0].match(/`(\w*)'$/).captures[0]
|
37
|
+
raise IRT::SessionModeError, "You cannot use the :#{m} method in #{context.irt_mode} mode."
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'irb/context'
|
2
|
+
|
3
|
+
module IRB
|
4
|
+
class Context #:nodoc:
|
5
|
+
|
6
|
+
attr_accessor :parent_context, :current_line, :binding_file, :binding_line_no, :backtrace_map
|
7
|
+
attr_reader :current_line_no, :last_line_no
|
8
|
+
attr_writer :irt_mode
|
9
|
+
|
10
|
+
def file_line_pointers
|
11
|
+
file = line = nil
|
12
|
+
c = self
|
13
|
+
until file
|
14
|
+
case c.irt_mode
|
15
|
+
when :binding
|
16
|
+
file = c.binding_file
|
17
|
+
line = c.binding_line_no
|
18
|
+
when :file
|
19
|
+
file = c.irb_path
|
20
|
+
line = c.last_line_no
|
21
|
+
end
|
22
|
+
c = c.parent_context
|
23
|
+
end
|
24
|
+
[file, line]
|
25
|
+
end
|
26
|
+
|
27
|
+
def irt_mode
|
28
|
+
@irt_mode ||= :file
|
29
|
+
end
|
30
|
+
|
31
|
+
alias_method :evaluate_and_set_last_value, :evaluate
|
32
|
+
def evaluate(line, line_no)
|
33
|
+
@current_line = line
|
34
|
+
@current_line_no = line_no + line.chomp.count("\n")
|
35
|
+
if @exception_raised
|
36
|
+
IRT::Session.enter(:interactive) if irt_mode == :file
|
37
|
+
@exception_raised = false
|
38
|
+
end
|
39
|
+
log_file_line(line_no) if irt_mode == :file
|
40
|
+
begin
|
41
|
+
# ri arg to string
|
42
|
+
if m = line.match(/^(\s*ri[ \t]+)(.+)$/)
|
43
|
+
pre, to_search = m.captures
|
44
|
+
line = "#{pre}#{to_search.inspect}" unless to_search.match(/^('|").+\1$/)
|
45
|
+
else
|
46
|
+
IRT::Commands::Ri.reset_choices_map
|
47
|
+
end
|
48
|
+
# skip setting last_value for non_setting_commands
|
49
|
+
if line =~ /^\s*(#{IRT.log.non_setting_commands * '|'})\b/
|
50
|
+
self.echo = false
|
51
|
+
res = @workspace.evaluate(self, line, irb_path, line_no)
|
52
|
+
if line =~ /^\s*(#{IRT.log.ignored_echo_commands * '|'})\b/
|
53
|
+
output_ignored_echo_value(res)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
self.echo = irt_mode == :file ? false : true
|
57
|
+
evaluate_and_set_last_value(line, line_no)
|
58
|
+
end
|
59
|
+
rescue Exception => e
|
60
|
+
@exception_raised = true
|
61
|
+
process_exception(e)
|
62
|
+
print "\e[31m" if Colorer.color?
|
63
|
+
raise
|
64
|
+
else
|
65
|
+
log_session_line(line, line_no) unless irt_mode == :file
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
%w[prompt_i prompt_s prompt_c prompt_n].each do |m|
|
70
|
+
define_method(m) do
|
71
|
+
pr = instance_variable_get("@#{m}")
|
72
|
+
col_pr = pr.send "#{irt_mode}_color"
|
73
|
+
# workaround for Readline bug see http://www.ruby-forum.com/topic/213807
|
74
|
+
if IRT.fix_readline_prompt
|
75
|
+
col_pr.gsub(/^(.*)#{pr}(.*)$/, "\001\\1\002#{pr}\001\\2\002")
|
76
|
+
else
|
77
|
+
col_pr
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def return_format(color=:actual_color, ignored=false)
|
83
|
+
ret = ignored ? @return_format.sub(/=/,'#') : @return_format
|
84
|
+
ret.send color
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def process_exception(e)
|
90
|
+
return if IRT.debug
|
91
|
+
bktr = e.backtrace.reject {|m| File.expand_path(m).match(/^#{IRT.lib_path}/) || workspace.filter_backtrace(m).nil? }
|
92
|
+
e.set_backtrace( e.class.name.match(/^IRT::/) ? bktr : map_backtrace(bktr) )
|
93
|
+
end
|
94
|
+
|
95
|
+
def map_backtrace(bktr)
|
96
|
+
@backtrace_map = {}
|
97
|
+
mapped_bktr = []
|
98
|
+
reverted_error_colors = 'xxx'.error_color.match(/^(.*)xxx(.*)$/).captures.reverse
|
99
|
+
index_format = sprintf '%s%%s%s', *reverted_error_colors
|
100
|
+
bktr.each_with_index do |m, i|
|
101
|
+
unless i + 1 > back_trace_limit || m.match(/^\(.*\)/)
|
102
|
+
@backtrace_map[i] = m.split(':')[0..1]
|
103
|
+
index = sprintf index_format, " [#{i}]"
|
104
|
+
end
|
105
|
+
mapped_bktr << "#{m}#{index}"
|
106
|
+
end
|
107
|
+
mapped_bktr
|
108
|
+
end
|
109
|
+
|
110
|
+
def log_file_line(line_no)
|
111
|
+
log_lines(@current_line, line_no)
|
112
|
+
end
|
113
|
+
|
114
|
+
def log_session_line(line, line_no)
|
115
|
+
# @current_line might get changed by the IRT::Commands::Test methods,
|
116
|
+
# while the line arg is the original command
|
117
|
+
segments = line.chomp.split("\n", -1)
|
118
|
+
last_segment = segments.pop
|
119
|
+
if last_segment.match(/^[ \t]*(#{IRT::Commands::Test.own_methods * '|'})\b/)
|
120
|
+
log_lines segments.map{|s| "#{s}\n"}.join, line_no
|
121
|
+
@last_line_no = @last_line_no ? @last_line_no + 1 : line_no
|
122
|
+
@current_line.each_line do |l|
|
123
|
+
IRT.log.add_line l, @last_line_no
|
124
|
+
end
|
125
|
+
else
|
126
|
+
log_lines(@current_line, line_no)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def log_lines(str, line_no)
|
131
|
+
i = -1
|
132
|
+
str.each_line do |l|
|
133
|
+
@last_line_no = line_no + i+=1
|
134
|
+
IRT.log.add_line l, @last_line_no
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def output_ignored_echo_value(value)
|
139
|
+
if inspect?
|
140
|
+
printf return_format(:ignored_color,false), value.inspect
|
141
|
+
else
|
142
|
+
printf return_format(:ignored_color,false), value
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
module Kernel
|
3
|
+
|
4
|
+
def capture
|
5
|
+
out = StringIO.new
|
6
|
+
$stdout = out
|
7
|
+
yield
|
8
|
+
return out.string
|
9
|
+
ensure
|
10
|
+
$stdout = STDOUT
|
11
|
+
end
|
12
|
+
|
13
|
+
def irt(bind)
|
14
|
+
raise IRT::ArgumentTypeError, "You must pass binding instead of #{bind.class.name} object" unless bind.is_a?(Binding)
|
15
|
+
IRT::Session.enter :binding, bind
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Method
|
2
|
+
|
3
|
+
def location
|
4
|
+
f = l = nil
|
5
|
+
n = case
|
6
|
+
when arity >= 0
|
7
|
+
arity
|
8
|
+
when arity == -1
|
9
|
+
0
|
10
|
+
when arity < -1
|
11
|
+
arity.abs - 1
|
12
|
+
end
|
13
|
+
arr = Array.new(n)
|
14
|
+
set_trace_func proc{ |event, file, line, meth_name, binding, classname|
|
15
|
+
if event.eql?('call') && name.match(meth_name.to_s)
|
16
|
+
f = file
|
17
|
+
l = line
|
18
|
+
set_trace_func nil
|
19
|
+
throw :method_located
|
20
|
+
end
|
21
|
+
}
|
22
|
+
catch(:method_located) { call *arr }
|
23
|
+
set_trace_func nil
|
24
|
+
[f,l]
|
25
|
+
end
|
26
|
+
|
27
|
+
def info
|
28
|
+
file, line = location
|
29
|
+
{ :name => name,
|
30
|
+
:class_name => owner.name,
|
31
|
+
:file => file,
|
32
|
+
:line => line,
|
33
|
+
:arity => arity }
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/lib/irt/hunks.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module IRT
|
2
|
+
class Log
|
3
|
+
|
4
|
+
class Hunk < Array
|
5
|
+
|
6
|
+
attr_reader :header, :color
|
7
|
+
|
8
|
+
def initialize(header)
|
9
|
+
@header = header
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_line(content, line_no)
|
13
|
+
self << [content.chomp, line_no]
|
14
|
+
end
|
15
|
+
|
16
|
+
def render(wanted=nil)
|
17
|
+
return unless size > 0
|
18
|
+
Log.print_border
|
19
|
+
render_header
|
20
|
+
wanted ||= size
|
21
|
+
last(wanted).each do |content, line_no|
|
22
|
+
Log.print_border
|
23
|
+
render_line(content, line_no)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def lines_str
|
28
|
+
map{|content, line_no| content }.join("\n")
|
29
|
+
end
|
30
|
+
|
31
|
+
def last_line_no
|
32
|
+
last && last[1]
|
33
|
+
end
|
34
|
+
|
35
|
+
def header_name
|
36
|
+
@header
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_header
|
40
|
+
puts " #{header_name} ".send(color).bold.reversed.or("***** #{header_name} *****")
|
41
|
+
end
|
42
|
+
|
43
|
+
def render_line(content, line_no)
|
44
|
+
lcontent = content.send(color)
|
45
|
+
lno = ('%3d ' % line_no).send(color).reversed
|
46
|
+
puts "#{lno} #{lcontent}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def inspect
|
50
|
+
%(<#{self.class.name} #{header_name}>)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class FileHunk < Hunk
|
57
|
+
|
58
|
+
def initialize(header=nil)
|
59
|
+
@color = :file_color
|
60
|
+
@header = header || IRB.CurrentContext.irb_path
|
61
|
+
end
|
62
|
+
|
63
|
+
def header_name
|
64
|
+
File.basename(@header)
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
class InteractiveHunk < Hunk
|
71
|
+
|
72
|
+
def initialize
|
73
|
+
@color = :interactive_color
|
74
|
+
@header = IRB.CurrentContext.irb_name
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_line(content, line_no)
|
78
|
+
ignored = IRT.log.ignored_commands + %w[_]
|
79
|
+
return if content.match(/^\s*(#{ignored * '|'})\b/)
|
80
|
+
super
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
class InspectHunk < InteractiveHunk
|
87
|
+
|
88
|
+
def initialize
|
89
|
+
super
|
90
|
+
@color = :inspect_color
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_line(content, line_no)
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
class BindingHunk < InteractiveHunk
|
99
|
+
|
100
|
+
def initialize
|
101
|
+
super
|
102
|
+
@color = :binding_color
|
103
|
+
end
|
104
|
+
|
105
|
+
def add_line(content, line_no)
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|