rib 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
require 'rib/more/multiline' # dependency
|
3
|
+
|
4
|
+
module Rib::MultilineHistory
|
5
|
+
include Rib::Plugin
|
6
|
+
Shell.use(self)
|
7
|
+
|
8
|
+
def loop_eval input
|
9
|
+
return super if MultilineHistory.disabled?
|
10
|
+
value = super
|
11
|
+
rescue Exception
|
12
|
+
# might be multiline editing, ignore
|
13
|
+
raise
|
14
|
+
else
|
15
|
+
if multiline_buffer.size > 1
|
16
|
+
# so multiline editing is considering done here
|
17
|
+
(multiline_buffer.size + (@multiline_trash || 0)).times{ history.pop }
|
18
|
+
history << "\n" + multiline_buffer.join("\n")
|
19
|
+
end
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
def handle_interrupt
|
24
|
+
return super if MultilineHistory.disabled?
|
25
|
+
if multiline_buffer.size > 1
|
26
|
+
@multiline_trash ||= 0
|
27
|
+
@multiline_trash += 1
|
28
|
+
end
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
require 'rib/more/multiline_history'
|
3
|
+
|
4
|
+
module Rib::MultilineHistoryFile
|
5
|
+
include Rib::Plugin
|
6
|
+
Shell.use(self)
|
7
|
+
|
8
|
+
def before_loop
|
9
|
+
return super if MultilineHistoryFile.disabled?
|
10
|
+
config[:multiline_history_file_token] ||= ' '
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def read_history
|
15
|
+
return super if MultilineHistoryFile.disabled?
|
16
|
+
buffer = []
|
17
|
+
File.exist?(history_file) && history.empty? &&
|
18
|
+
IO.readlines(history_file).each{ |line|
|
19
|
+
if line.end_with?(
|
20
|
+
"#{config[:multiline_history_file_token]}\n")
|
21
|
+
buffer << line[0...
|
22
|
+
-config[:multiline_history_file_token].size-1] + "\n"
|
23
|
+
else
|
24
|
+
history << (buffer.join + line).chomp
|
25
|
+
buffer = []
|
26
|
+
end
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def write_history
|
31
|
+
return super if MultilineHistoryFile.disabled?
|
32
|
+
@history = history.to_a.map{ |line|
|
33
|
+
line.gsub("\n", "#{config[:multiline_history_file_token]}\n")
|
34
|
+
}
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
require 'rib/core/history_file'
|
3
|
+
|
4
|
+
module Rib::SqueezeHistory
|
5
|
+
include Rib::Plugin
|
6
|
+
Shell.use(self)
|
7
|
+
|
8
|
+
# squeeze history on memory too
|
9
|
+
def eval_input input
|
10
|
+
return super if SqueezeHistory.disabled?
|
11
|
+
history.pop if input.strip == '' ||
|
12
|
+
(history.size > 1 && input == history.to_a[-2])
|
13
|
+
# EditLine is really broken, to_a is needed for it
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
# write squeezed history
|
18
|
+
def write_history
|
19
|
+
return super if SqueezeHistory.disabled?
|
20
|
+
@history = P.squeeze_history(history)
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
module Imp
|
25
|
+
def squeeze_history history
|
26
|
+
history.to_a.inject([]){ |result, item|
|
27
|
+
if result.last == item || item.strip == ''
|
28
|
+
result
|
29
|
+
else
|
30
|
+
result << item
|
31
|
+
end
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
Plugin.extend(Imp)
|
37
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
|
4
|
+
module Rib::StripBacktrace
|
5
|
+
include Rib::Plugin
|
6
|
+
Shell.use(self)
|
7
|
+
|
8
|
+
# strip backtrace until ripl
|
9
|
+
def format_error e
|
10
|
+
return super if StripBacktrace.disabled?
|
11
|
+
message, backtrace = get_error(e, P.strip_backtrace(e, config[:name]))
|
12
|
+
"#{message}\n #{backtrace.join("\n ")}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_error e, backtrace=e.backtrace
|
16
|
+
return super if StripBacktrace.disabled?
|
17
|
+
["#{e.class}: #{e.message}", backtrace]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
module Imp
|
22
|
+
def strip_backtrace e, name
|
23
|
+
home(cwd(snip(e, name)))
|
24
|
+
end
|
25
|
+
|
26
|
+
def home b
|
27
|
+
b.map{ |p| p.sub(ENV['HOME'], '~') }
|
28
|
+
end
|
29
|
+
|
30
|
+
def cwd b
|
31
|
+
b.map{ |p| p.sub(Dir.pwd, '.') }
|
32
|
+
end
|
33
|
+
|
34
|
+
def snip e, name
|
35
|
+
return [] if e.kind_of?(SyntaxError)
|
36
|
+
e.backtrace[
|
37
|
+
0..
|
38
|
+
e.backtrace.rindex{ |l| l =~ /\(#{name}\):\d+:in `.+?'/ } || -1]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Plugin.extend(Imp)
|
43
|
+
end
|
data/lib/rib/plugin.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
module Rib; end
|
3
|
+
module Rib::Plugin
|
4
|
+
Rib::P = self
|
5
|
+
|
6
|
+
def self.included mod
|
7
|
+
mod.send(:include, Rib)
|
8
|
+
|
9
|
+
class << mod
|
10
|
+
attr_accessor :disabled
|
11
|
+
|
12
|
+
def enable
|
13
|
+
self.disabled = false
|
14
|
+
if block_given? then yield else enabled? end
|
15
|
+
end
|
16
|
+
|
17
|
+
def disable
|
18
|
+
self.disabled = true
|
19
|
+
if block_given? then yield else enabled? end
|
20
|
+
end
|
21
|
+
|
22
|
+
def enabled?
|
23
|
+
!disabled
|
24
|
+
end
|
25
|
+
|
26
|
+
def disabled?
|
27
|
+
!!disabled
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
snake_name = mod.name[/::\w+$/].tr(':', ''). # remove namespaces
|
32
|
+
gsub(/([A-Z][a-z]*)/, '\\1_').downcase[0..-2]
|
33
|
+
|
34
|
+
code = (%w[enable disable].map{ |meth|
|
35
|
+
<<-RUBY
|
36
|
+
def #{meth}_#{snake_name} &block
|
37
|
+
#{mod.name}.#{meth}(&block)
|
38
|
+
end
|
39
|
+
RUBY
|
40
|
+
} + %w[enabled? disabled?].map{ |meth|
|
41
|
+
<<-RUBY
|
42
|
+
def #{snake_name}_#{meth} &block
|
43
|
+
#{mod.name}.#{meth}(&block)
|
44
|
+
end
|
45
|
+
RUBY
|
46
|
+
}).join("\n")
|
47
|
+
|
48
|
+
meta_rib = if respond_to?(:singleton_class)
|
49
|
+
Rib.singleton_class
|
50
|
+
else
|
51
|
+
class << Rib; self; end
|
52
|
+
end
|
53
|
+
|
54
|
+
meta_rib.module_eval(code, __FILE__, __LINE__)
|
55
|
+
end
|
56
|
+
end
|
data/lib/rib/runner.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
|
4
|
+
module Rib::Runner
|
5
|
+
module_function
|
6
|
+
def name
|
7
|
+
File.basename($PROGRAM_NAME)
|
8
|
+
end
|
9
|
+
|
10
|
+
def options
|
11
|
+
{ # Ruby OPTIONS
|
12
|
+
'-e, --eval LINE' =>
|
13
|
+
'Evaluate a LINE of code' ,
|
14
|
+
|
15
|
+
'-d, --debug' =>
|
16
|
+
'Set debugging flags (set $DEBUG to true)' ,
|
17
|
+
|
18
|
+
'-w, --warn' =>
|
19
|
+
'Turn warnings on for your script (set $-w to true)' ,
|
20
|
+
|
21
|
+
'-I, --include PATH' =>
|
22
|
+
'Specify $LOAD_PATH (may be used more than once)' ,
|
23
|
+
|
24
|
+
'-r, --require LIBRARY' =>
|
25
|
+
'Require the library, before executing your script' ,
|
26
|
+
|
27
|
+
# Rib OPTIONS
|
28
|
+
'-c, --config FILE' => 'Load config from FILE' ,
|
29
|
+
'-n, --no-config' => 'Suppress loading ~/.config/rib/config.rb',
|
30
|
+
'-h, --help' => 'Print this message' ,
|
31
|
+
'-v, --version' => 'Print the version' }
|
32
|
+
end
|
33
|
+
|
34
|
+
def run argv=ARGV
|
35
|
+
if command = argv.find{ |a| a =~ /^[^-]/ }
|
36
|
+
argv.delete(command)
|
37
|
+
plugin = "rib-#{command}"
|
38
|
+
path = `which #{plugin}`.strip
|
39
|
+
if path == ''
|
40
|
+
puts("Can't find `#{plugin}' in $PATH.\n" \
|
41
|
+
"Please make sure `#{plugin}' is installed.\n" \
|
42
|
+
"e.g. run `gem install #{plugin}`")
|
43
|
+
else
|
44
|
+
load(path)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
start(*argv)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def start *argv
|
52
|
+
unused = parse(argv.dup)
|
53
|
+
warn "#{name}: Unused arguments: #{unused.inspect}" unless unused.empty?
|
54
|
+
Rib.shell.loop
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse argv
|
58
|
+
unused = []
|
59
|
+
until argv.empty?
|
60
|
+
case arg = argv.shift
|
61
|
+
when /-e=?(.*)/, /--eval=?(.*)/
|
62
|
+
eval($1 || argv.shift, __FILE__, __LINE__)
|
63
|
+
|
64
|
+
when '-d', '--debug'
|
65
|
+
$DEBUG = true
|
66
|
+
|
67
|
+
when '-w', '--warn'
|
68
|
+
$-w = true
|
69
|
+
|
70
|
+
when /-I=?(.*)/, /--include=?(.*)/
|
71
|
+
paths = ($1 || argv.shift).split(':')
|
72
|
+
$LOAD_PATH.unshift(*paths)
|
73
|
+
|
74
|
+
when /-r=?(.*)/, /--require=?(.*)/
|
75
|
+
require($1 || argv.shift)
|
76
|
+
|
77
|
+
when /-c=?(.*)/, /--config=?(.*)/
|
78
|
+
Rib.config[:config] = $1 || argv.shift
|
79
|
+
|
80
|
+
when '-n', '--no-config'
|
81
|
+
Rib.config.delete(:config)
|
82
|
+
|
83
|
+
when '-h', '--help'
|
84
|
+
puts(help)
|
85
|
+
exit
|
86
|
+
|
87
|
+
when '-v', '--version'
|
88
|
+
require 'rib/version'
|
89
|
+
puts(Rib::VERSION)
|
90
|
+
exit
|
91
|
+
|
92
|
+
else
|
93
|
+
unused << arg
|
94
|
+
end
|
95
|
+
end
|
96
|
+
unused
|
97
|
+
end
|
98
|
+
|
99
|
+
def help
|
100
|
+
maxn = options.keys .map(&:size).max
|
101
|
+
maxd = options.values.map(&:size).max
|
102
|
+
"Usage: #{name} [Ruby OPTIONS] [Rib COMMAND] [Rib OPTIONS]\n" +
|
103
|
+
options.map{ |name, desc|
|
104
|
+
sprintf(" %-*s %-*s", maxn, name, maxd, desc) }.join("\n")
|
105
|
+
end
|
106
|
+
end
|
data/lib/rib/shell.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
require 'rib/plugin'
|
3
|
+
require 'rib/api'
|
4
|
+
|
5
|
+
class Rib::Shell
|
6
|
+
include Rib::API
|
7
|
+
trap('INT'){ raise Interrupt }
|
8
|
+
|
9
|
+
def self.use mod
|
10
|
+
include mod
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :config
|
14
|
+
def initialize(config={})
|
15
|
+
self.config = {
|
16
|
+
:name => 'rib' ,
|
17
|
+
:result_prompt => '=> ' ,
|
18
|
+
:prompt => '>> ' ,
|
19
|
+
:binding => TOPLEVEL_BINDING ,
|
20
|
+
:exit => [nil, 'exit', 'quit'] ,
|
21
|
+
:line => 1
|
22
|
+
}.merge(config)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Loops shell until user exits
|
26
|
+
def loop
|
27
|
+
before_loop
|
28
|
+
@running = true
|
29
|
+
in_loop
|
30
|
+
self
|
31
|
+
ensure
|
32
|
+
@running = false
|
33
|
+
after_loop
|
34
|
+
end
|
35
|
+
|
36
|
+
def running?
|
37
|
+
!!@running
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
attr_writer :config
|
42
|
+
attr_accessor :error_raised
|
43
|
+
end
|
data/lib/rib/test.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
require 'bacon'
|
3
|
+
require 'rr'
|
4
|
+
require 'fileutils'
|
5
|
+
Bacon.summary_on_exit
|
6
|
+
include RR::Adapters::RRMethods
|
7
|
+
|
8
|
+
require 'rib'
|
9
|
+
|
10
|
+
shared :rib do
|
11
|
+
before do
|
12
|
+
Rib.disable_plugins
|
13
|
+
end
|
14
|
+
|
15
|
+
after do
|
16
|
+
RR.verify
|
17
|
+
Rib.enable_plugins
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module Kernel
|
22
|
+
def eq? rhs
|
23
|
+
self == rhs
|
24
|
+
end
|
25
|
+
end
|
data/lib/rib/version.rb
ADDED
data/lib/rib/zore.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
require 'rib'
|
3
|
+
|
4
|
+
module Rib::Anchor
|
5
|
+
include Rib::Plugin
|
6
|
+
Shell.use(self)
|
7
|
+
|
8
|
+
def loop_eval(str)
|
9
|
+
case obj_or_binding = (Rib.vars[:anchor] ||= []).last
|
10
|
+
when NilClass
|
11
|
+
super
|
12
|
+
|
13
|
+
when Binding
|
14
|
+
@binding = obj_or_binding
|
15
|
+
super
|
16
|
+
|
17
|
+
else
|
18
|
+
obj_or_binding.instance_eval(str, "(#{config[:name]})", config[:line])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def prompt
|
23
|
+
if Rib.const_defined?(:Color) && kind_of?(Rib::Color) &&
|
24
|
+
obj_or_binding = (Rib.vars[:anchor] ||= []).last
|
25
|
+
|
26
|
+
super.sub(config[:name], format_color(obj_or_binding, config[:name]))
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# if the object is the same, then we're exiting from an anchor,
|
33
|
+
# so don't print anything.
|
34
|
+
def print_result result
|
35
|
+
super unless !result.nil? &&
|
36
|
+
result.object_id == Rib.vars[:anchor_last].object_id
|
37
|
+
end
|
38
|
+
|
39
|
+
module Imp
|
40
|
+
def short_inspect obj_or_binding
|
41
|
+
obj_or_binding.inspect[0..9]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module AnchorImp
|
46
|
+
def anchor obj_or_binding
|
47
|
+
return if Rib::Anchor.disabled?
|
48
|
+
|
49
|
+
(Rib.vars[:anchor] ||= []) << obj_or_binding
|
50
|
+
name = Rib::P.short_inspect(obj_or_binding)
|
51
|
+
|
52
|
+
Rib.shells <<
|
53
|
+
Rib::Shell.new(Rib.config.merge(
|
54
|
+
:name => name,
|
55
|
+
:prompt => "#{name}(#{Rib.vars[:anchor].size})" +
|
56
|
+
(Rib.config[:prompt] || '>> ')))
|
57
|
+
|
58
|
+
Rib.shell.loop
|
59
|
+
|
60
|
+
ensure
|
61
|
+
# stores to check if we're exiting from an anchor
|
62
|
+
Rib.vars[:anchor_last] = Rib.vars[:anchor].pop
|
63
|
+
Rib.shells.pop
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
Plugin.extend(Imp)
|
68
|
+
Rib .extend(AnchorImp)
|
69
|
+
end
|