rib 0.0.1 → 0.1.0
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 +6 -0
- data/.gitmodules +3 -0
- data/.travis.yml +9 -0
- data/2011-02-28.md +203 -0
- data/CHANGES +86 -0
- data/CONTRIBUTORS +2 -0
- data/Gemfile +4 -0
- data/LICENSE +201 -0
- data/README +190 -0
- data/README.md +190 -0
- data/Rakefile +20 -0
- data/TODO +6 -0
- data/lib/rib.rb +42 -0
- data/lib/rib/all.rb +4 -0
- data/lib/rib/api.rb +105 -0
- data/lib/rib/core.rb +5 -0
- data/lib/rib/core/completion.rb +22 -0
- data/lib/rib/core/history_file.rb +38 -0
- data/lib/rib/core/readline.rb +19 -0
- data/lib/rib/core/underscore.rb +53 -0
- data/lib/rib/debug.rb +3 -0
- data/lib/rib/more.rb +12 -0
- data/lib/rib/more/color.rb +98 -0
- data/lib/rib/more/multiline.rb +77 -0
- data/lib/rib/more/multiline_history.rb +31 -0
- data/lib/rib/more/multiline_history_file.rb +37 -0
- data/lib/rib/more/squeeze_history.rb +37 -0
- data/lib/rib/more/strip_backtrace.rb +43 -0
- data/lib/rib/plugin.rb +56 -0
- data/lib/rib/runner.rb +106 -0
- data/lib/rib/shell.rb +43 -0
- data/lib/rib/test.rb +25 -0
- data/lib/rib/version.rb +4 -0
- data/lib/rib/zore.rb +3 -0
- data/lib/rib/zore/anchor.rb +69 -0
- data/lib/rib/zore/edit.rb +33 -0
- data/rib.gemspec +104 -0
- data/screenshot.png +0 -0
- data/task/.gitignore +1 -0
- data/task/gemgem.rb +182 -0
- data/test/core/test_completion.rb +18 -0
- data/test/core/test_history_file.rb +57 -0
- data/test/core/test_readline.rb +21 -0
- data/test/core/test_underscore.rb +41 -0
- data/test/more/test_color.rb +28 -0
- data/test/more/test_squeeze_history.rb +43 -0
- data/test/test_api.rb +20 -0
- data/test/test_plugin.rb +38 -0
- data/test/test_shell.rb +82 -0
- metadata +77 -13
data/lib/rib/all.rb
ADDED
data/lib/rib/api.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
|
2
|
+
module Rib; end
|
3
|
+
module Rib::API
|
4
|
+
def before_loop
|
5
|
+
read_history
|
6
|
+
self
|
7
|
+
end
|
8
|
+
|
9
|
+
def in_loop
|
10
|
+
input = catch(:rib_exit){ loop_once while true }
|
11
|
+
puts if input == nil
|
12
|
+
end
|
13
|
+
|
14
|
+
# Runs through one loop iteration: gets input, evals and prints result
|
15
|
+
def loop_once
|
16
|
+
self.error_raised = nil
|
17
|
+
input = get_input
|
18
|
+
throw(:rib_exit, input) if config[:exit].include?(input)
|
19
|
+
if input.strip == ''
|
20
|
+
eval_input(input)
|
21
|
+
else
|
22
|
+
print_result(eval_input(input))
|
23
|
+
end
|
24
|
+
rescue Interrupt
|
25
|
+
handle_interrupt
|
26
|
+
end
|
27
|
+
|
28
|
+
# Handles interrupt (Control-C) by printing a newline
|
29
|
+
def handle_interrupt() puts end
|
30
|
+
|
31
|
+
# Sets @result to result of evaling input and print unexpected errors
|
32
|
+
def eval_input(input)
|
33
|
+
loop_eval(input)
|
34
|
+
rescue Exception => e
|
35
|
+
self.error_raised = true
|
36
|
+
print_eval_error(e)
|
37
|
+
ensure
|
38
|
+
config[:line] += 1
|
39
|
+
end
|
40
|
+
|
41
|
+
# When extending this method, ensure your plugin disables readline:
|
42
|
+
# Readline.config[:readline] = false.
|
43
|
+
# @return [String, nil] Prints #prompt and returns input given by user
|
44
|
+
def get_input
|
45
|
+
print(prompt)
|
46
|
+
if input = $stdin.gets
|
47
|
+
input.chomp
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [String]
|
54
|
+
def prompt
|
55
|
+
config[:prompt]
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_history
|
59
|
+
end
|
60
|
+
|
61
|
+
def write_history
|
62
|
+
end
|
63
|
+
|
64
|
+
def history
|
65
|
+
@history ||= []
|
66
|
+
end
|
67
|
+
|
68
|
+
# Evals user input using @binding, @name and @line
|
69
|
+
def loop_eval(input)
|
70
|
+
config[:binding].eval(input, "(#{config[:name]})", config[:line])
|
71
|
+
end
|
72
|
+
|
73
|
+
# Prints error formatted by #format_error to STDERR. Could be extended to
|
74
|
+
# handle certain exceptions.
|
75
|
+
# @param [Exception]
|
76
|
+
def print_eval_error(err)
|
77
|
+
warn format_error(err)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Prints result using #format_result
|
81
|
+
def print_result(result)
|
82
|
+
puts(format_result(result)) unless error_raised
|
83
|
+
rescue StandardError, SyntaxError => e
|
84
|
+
warn "#{config[:name]}: Error while printing result:\n" \
|
85
|
+
"#{format_error(e)}"
|
86
|
+
end
|
87
|
+
|
88
|
+
# Formats errors raised by eval of user input
|
89
|
+
# @param [Exception]
|
90
|
+
# @return [String]
|
91
|
+
def format_error(e)
|
92
|
+
"#{e.class}: #{e.message}\n #{e.backtrace.join("\n ")}"
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [String] Formats result using result_prompt
|
96
|
+
def format_result(result)
|
97
|
+
config[:result_prompt] + result.inspect
|
98
|
+
end
|
99
|
+
|
100
|
+
# Called after shell finishes looping.
|
101
|
+
def after_loop
|
102
|
+
write_history
|
103
|
+
self
|
104
|
+
end
|
105
|
+
end
|
data/lib/rib/core.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
require 'bond'
|
4
|
+
|
5
|
+
module Rib::Completion
|
6
|
+
include Rib::Plugin
|
7
|
+
Shell.use(self)
|
8
|
+
|
9
|
+
def before_loop
|
10
|
+
return super if Completion.disabled?
|
11
|
+
config[:completion] ||= {}
|
12
|
+
config[:completion][:eval_binding] ||= lambda{ config[:binding] }
|
13
|
+
(config[:completion][:gems] ||= []).concat(ripl_plugins)
|
14
|
+
Bond.start(config[:completion])
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def ripl_plugins
|
20
|
+
$LOADED_FEATURES.map{ |e| e[/ripl\/[^\/]+$/] }.compact
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
module Rib::HistoryFile
|
6
|
+
include Rib::Plugin
|
7
|
+
Shell.use(self)
|
8
|
+
|
9
|
+
def before_loop
|
10
|
+
return super if HistoryFile.disabled?
|
11
|
+
config[:history_file] ||= '~/.config/rib/history.rb'
|
12
|
+
config[:history_size] ||= 500
|
13
|
+
FileUtils.mkdir_p(File.dirname(history_file))
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_input
|
18
|
+
return super if HistoryFile.disabled?
|
19
|
+
(history << super).last
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_history
|
23
|
+
return super if HistoryFile.disabled?
|
24
|
+
File.exist?(history_file) && history.empty? &&
|
25
|
+
File.readlines(history_file).each{ |e| history << e.chomp }
|
26
|
+
end
|
27
|
+
|
28
|
+
def write_history
|
29
|
+
return super if HistoryFile.disabled?
|
30
|
+
File.open(history_file, 'w'){ |f|
|
31
|
+
f.puts(history.to_a.last(config[:history_size]).join("\n")) }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def history_file
|
36
|
+
@history_file ||= File.expand_path(config[:history_file])
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
require 'readline'
|
4
|
+
|
5
|
+
module Rib::Readline
|
6
|
+
include Rib::Plugin
|
7
|
+
Shell.use(self)
|
8
|
+
|
9
|
+
def before_loop
|
10
|
+
return super if Readline.disabled?
|
11
|
+
@history = ::Readline::HISTORY
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_input
|
16
|
+
return super if Readline.disabled?
|
17
|
+
::Readline.readline(prompt, true)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
|
4
|
+
module Rib::Underscore
|
5
|
+
include Rib::Plugin
|
6
|
+
Shell.use(self)
|
7
|
+
|
8
|
+
IVAR = {:_ => :@__rib_result__,
|
9
|
+
:__ => :@__rib_exception__}
|
10
|
+
|
11
|
+
def before_loop
|
12
|
+
return super if Underscore.disabled?
|
13
|
+
eliminate_warnings
|
14
|
+
inject_inspecter
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def loop_eval input
|
19
|
+
return super if Underscore.disabled?
|
20
|
+
bound_object.instance_variable_set(:@__rib_result__, super)
|
21
|
+
end
|
22
|
+
|
23
|
+
def print_eval_error e
|
24
|
+
return super if Underscore.disabled?
|
25
|
+
bound_object.instance_variable_set(:@__rib_exception__, e)
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def eliminate_warnings
|
31
|
+
IVAR.values.each{ |ivar| bound_object.instance_variable_set(ivar, nil) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def inject_inspecter
|
35
|
+
IVAR.each{ |k, v|
|
36
|
+
bound_singleton.send(:define_method, k){
|
37
|
+
instance_variable_get(v)
|
38
|
+
} unless bound_object.respond_to?(k) # only inject for innocences
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def bound_singleton
|
43
|
+
if respond_to?(:singleton_class)
|
44
|
+
bound_object.singleton_class
|
45
|
+
else
|
46
|
+
class << bound_object; self; end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def bound_object
|
51
|
+
config[:binding].eval('self')
|
52
|
+
end
|
53
|
+
end
|
data/lib/rib/debug.rb
ADDED
data/lib/rib/more.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
# upon session ends
|
3
|
+
require 'rib/more/squeeze_history'
|
4
|
+
require 'rib/more/multiline_history_file'
|
5
|
+
|
6
|
+
# upon formatting output
|
7
|
+
require 'rib/more/strip_backtrace'
|
8
|
+
require 'rib/more/color'
|
9
|
+
|
10
|
+
# upon input
|
11
|
+
require 'rib/more/multiline'
|
12
|
+
require 'rib/more/multiline_history'
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
|
4
|
+
module Rib::Color
|
5
|
+
include Rib::Plugin
|
6
|
+
Shell.use(self)
|
7
|
+
|
8
|
+
def before_loop
|
9
|
+
config[:color] ||= {
|
10
|
+
Numeric => :red ,
|
11
|
+
String => :green ,
|
12
|
+
Symbol => :cyan ,
|
13
|
+
Array => :blue ,
|
14
|
+
Hash => :blue ,
|
15
|
+
NilClass => :magenta,
|
16
|
+
TrueClass => :magenta,
|
17
|
+
FalseClass => :magenta,
|
18
|
+
Exception => :magenta,
|
19
|
+
Object => :yellow
|
20
|
+
}
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def format_result result
|
25
|
+
return super if Color.disabled?
|
26
|
+
config[:result_prompt] + format_color(result)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def colors
|
31
|
+
config[:color]
|
32
|
+
end
|
33
|
+
|
34
|
+
def format_color result, display=result.inspect
|
35
|
+
case result
|
36
|
+
when String ; P.send(colors[String ]){ display }
|
37
|
+
when Numeric; P.send(colors[Numeric]){ display }
|
38
|
+
when Symbol ; P.send(colors[Symbol ]){ display }
|
39
|
+
|
40
|
+
when Array ; P.send(colors[Array ]){ '[' } +
|
41
|
+
result.map{ |e | format_color(e) }.
|
42
|
+
join(P.send(colors[Array ]){ ', ' }) +
|
43
|
+
P.send(colors[Array ]){ ']' }
|
44
|
+
|
45
|
+
when Hash ; P.send(colors[Hash ]){ '{' } +
|
46
|
+
result.map{ |k, v| format_color(k) +
|
47
|
+
P.send(colors[Hash ]){ '=>' } +
|
48
|
+
format_color(v) }.
|
49
|
+
join(P.send(colors[Hash ]){ ', ' }) +
|
50
|
+
P.send(colors[Hash ]){ '}' }
|
51
|
+
|
52
|
+
else ; if color = P.find_color(colors, result)
|
53
|
+
P.send(color){ display }
|
54
|
+
else
|
55
|
+
P.send(colors[Object ]){ display }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_error e, backtrace=e.backtrace
|
61
|
+
return super if Color.disabled?
|
62
|
+
[format_color(e, "#{e.class.to_s}: #{e.message}"),
|
63
|
+
backtrace.map{ |b|
|
64
|
+
path, rest = ::File.split(b)
|
65
|
+
name, msgs = rest.split(':', 2)
|
66
|
+
msg = msgs.sub(/(\d+):/){P.red{$1}+':'}.sub(/`.+?'/){P.green{$&}}
|
67
|
+
|
68
|
+
"#{path+'/'}#{P.yellow{name}}:#{msg}"
|
69
|
+
}]
|
70
|
+
end
|
71
|
+
|
72
|
+
module Imp
|
73
|
+
def find_color colors, value
|
74
|
+
(colors.sort{ |(k1, v1), (k2, v2)|
|
75
|
+
# Class <=> Class
|
76
|
+
if k1 < k2 then -1
|
77
|
+
elsif k1 > k2 then 1
|
78
|
+
else 0
|
79
|
+
end}.find{ |(klass, _)| value.kind_of?(klass) } || []).last
|
80
|
+
end
|
81
|
+
|
82
|
+
def color rgb
|
83
|
+
"\x1b[#{rgb}m" + (block_given? ? "#{yield}#{reset}" : '')
|
84
|
+
end
|
85
|
+
|
86
|
+
def black █ color(30, &block); end
|
87
|
+
def red █ color(31, &block); end
|
88
|
+
def green █ color(32, &block); end
|
89
|
+
def yellow █ color(33, &block); end
|
90
|
+
def blue █ color(34, &block); end
|
91
|
+
def magenta █ color(35, &block); end
|
92
|
+
def cyan █ color(36, &block); end
|
93
|
+
def white █ color(37, &block); end
|
94
|
+
def reset █ color('', &block); end
|
95
|
+
end
|
96
|
+
|
97
|
+
Plugin.extend(Imp)
|
98
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
|
4
|
+
# from https://github.com/janlelis/ripl-multi_line
|
5
|
+
module Rib::Multiline
|
6
|
+
include Rib::Plugin
|
7
|
+
Shell.use(self)
|
8
|
+
|
9
|
+
# test those:
|
10
|
+
# ruby -e '"'
|
11
|
+
# ruby -e '{'
|
12
|
+
# ruby -e '['
|
13
|
+
# ruby -e '('
|
14
|
+
# ruby -e '/'
|
15
|
+
# ruby -e 'class C'
|
16
|
+
# ruby -e 'def f'
|
17
|
+
# ruby -e 'begin'
|
18
|
+
ERROR_REGEXP = Regexp.new(
|
19
|
+
[ # string or regexp
|
20
|
+
"unterminated \\w+ meets end of file",
|
21
|
+
# mri and rubinius
|
22
|
+
"syntax error, unexpected \\$end",
|
23
|
+
# rubinius
|
24
|
+
"expecting '.+'( or '.+')*",
|
25
|
+
# jruby
|
26
|
+
"syntax error, unexpected end-of-file",
|
27
|
+
].join('|'))
|
28
|
+
|
29
|
+
def prompt
|
30
|
+
return super if Multiline.disabled?
|
31
|
+
if multiline_buffer.empty?
|
32
|
+
super
|
33
|
+
else
|
34
|
+
"#{' '*(config[:prompt].size-2)}| "
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def loop_once
|
39
|
+
return super if Multiline.disabled?
|
40
|
+
catch(:multiline_cont) do
|
41
|
+
super
|
42
|
+
multiline_buffer.clear
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def loop_eval(input)
|
47
|
+
return super if Multiline.disabled?
|
48
|
+
multiline_buffer << input
|
49
|
+
super(multiline_buffer.join("\n"))
|
50
|
+
end
|
51
|
+
|
52
|
+
def print_eval_error(e)
|
53
|
+
return super if Multiline.disabled?
|
54
|
+
if e.is_a?(SyntaxError) && e.message =~ ERROR_REGEXP
|
55
|
+
throw :multiline_cont
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def handle_interrupt
|
62
|
+
return super if Multiline.disabled?
|
63
|
+
if multiline_buffer.empty?
|
64
|
+
super
|
65
|
+
else
|
66
|
+
line = multiline_buffer.pop
|
67
|
+
print "[removed this line: #{line}]"
|
68
|
+
super
|
69
|
+
throw :multiline_cont
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def multiline_buffer
|
75
|
+
@multiline_buffer ||= []
|
76
|
+
end
|
77
|
+
end
|