-
Notifications
You must be signed in to change notification settings - Fork 6
/
api.rb
148 lines (125 loc) · 3.44 KB
/
api.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# frozen_string_literal: true
module Rib; module API
# Called before shell starts looping
def before_loop
self
end
# Called after shell finishes looping
def after_loop
self
end
# Handle interrupt (control-c)
def handle_interrupt; puts ; end
# The prompt string of this shell
def prompt ; config[:prompt] ; end
# The result prompt string of this shell
def result_prompt; config[:result_prompt] ; end
# The name of this shell
def name ; config[:name] ; end
# The binding for evaluation
def eval_binding ; config[:binding] ; end
# The line number for next evaluation
def line ; config[:line] ; end
# When the application loaded
def started_at ; config[:started_at] ; end
# Main loop
def in_loop
input = catch(:rib_exit){ loop_once while running? }
puts if input == nil && running?
end
# Loop iteration: REPL
def loop_once
input, result, err = get_input, nil, nil
throw(:rib_exit, input) if config[:exit].include?(input)
result, err = eval_input(input)
if err
print_eval_error(err)
elsif input.strip != '' && !equal_rib_skip(result)
print_result(result)
else
# print nothing for blank input or Rib::Skip
end
flush_warnings
[result, err]
rescue Interrupt
handle_interrupt
end
# Get user input. This is most likely overrided in Readline plugin
def get_input
print(prompt)
if input = $stdin.gets
input.chomp
else
nil
end
end
# Evaluate the input using #loop_eval and handle it
def eval_input input
[loop_eval(input), nil]
rescue SystemExit
throw(:rib_exit, input)
rescue Exception => e
[nil, e]
ensure
config[:line] += 1
end
# Evaluate user input with #eval_binding, name and line
def loop_eval input
if eval_binding.kind_of?(Binding)
eval_binding.eval(input, "(#{name})", line)
else
eval_binding.instance_eval(input, "(#{name})", line)
end
end
def puts str=''
super
end
# Print result using #format_result
def print_result result
puts(format_result(result))
rescue StandardError, SyntaxError => e
warn("Error while printing result:\n #{format_error(e)}")
end
# Print evaluated error using #format_error
def print_eval_error err
puts(format_error(err))
rescue StandardError, SyntaxError => e
warn("Error while printing error:\n #{format_error(e)}")
end
def warn message
warnings << message
end
# Format result using #result_prompt
def format_result result
"#{result_prompt}#{inspect_result(result)}"
end
def inspect_result result
string = result.inspect
warn("#{result.class}#inspect is not returning a string") unless
string.kind_of?(String)
string
end
# Format error raised in #loop_eval with #get_error
def format_error err
message, backtrace = get_error(err)
"#{message}\n #{backtrace.join("\n ")}"
end
module_function :format_error
# Get error message and backtrace from a particular error
def get_error err
["#{err.class}: #{err.message}", format_backtrace(err.backtrace)]
end
module_function :get_error
def format_backtrace backtrace
backtrace
end
private
def equal_rib_skip result
result == Rib::Skip
rescue
# do nothing, it cannot respond to == correctly, it can't be Rib::Skip
end
def flush_warnings
Rib.warn(warnings.shift) until warnings.empty?
end
end; end