Class: Sandbox::Shell

Inherits:
Object
  • Object
show all
Defined in:
lib/sandbox/shell.rb

Overview

Shell

Constant Summary collapse

DEFAULT_PROMPT =
'> '
DEFAULT_BANNER =
'Sandbox shell'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input = $stdin, output = $stdout, prompt: DEFAULT_PROMPT, banner: DEFAULT_BANNER, history: true, builtin_help: true, builtin_quit: true, builtin_path: true) ⇒ Shell

Creates a new shell



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
# File 'lib/sandbox/shell.rb', line 20

def initialize(
  input = $stdin,
  output = $stdout,
  prompt: DEFAULT_PROMPT,
  banner: DEFAULT_BANNER,
  history: true,
  builtin_help: true,
  builtin_quit: true,
  builtin_path: true
)
  @input = input
  @output = output
  @history = history

  @prompt = prompt
  @banner = banner

  @root = Context.new(:root, self)
  @path = []
  @running = false
  @reading = false

  add_command_help if builtin_help
  add_command_quit if builtin_quit
  add_command_path if builtin_path
end

Instance Attribute Details

Returns the value of attribute banner.



16
17
18
# File 'lib/sandbox/shell.rb', line 16

def banner
  @banner
end

#pathObject

Returns the value of attribute path.



16
17
18
# File 'lib/sandbox/shell.rb', line 16

def path
  @path
end

#promptObject

Returns the value of attribute prompt.



16
17
18
# File 'lib/sandbox/shell.rb', line 16

def prompt
  @prompt
end

#rootObject (readonly)

Returns the value of attribute root.



15
16
17
# File 'lib/sandbox/shell.rb', line 15

def root
  @root
end

Instance Method Details

#add_command(name, **options, &block) ⇒ Object

Adds a command to the root context



157
158
159
# File 'lib/sandbox/shell.rb', line 157

def add_command(name, **options, &block)
  @root.add_command(name, **options, &block)
end

#add_context(name, **options) ⇒ Object

Adds a new context to the root context



145
146
147
# File 'lib/sandbox/shell.rb', line 145

def add_context(name, **options)
  @root.add_context(name, **options)
end

#command(*path) ⇒ Object

Returns a command by the path from the root context



175
176
177
# File 'lib/sandbox/shell.rb', line 175

def command(*path)
  @root.command(*path)
end

#confirm(prompt, default: :n) ⇒ Object

Requests the confirmation

Raises:



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/sandbox/shell.rb', line 114

def confirm(prompt, default: :n)
  list = CONFIRM_LIST.join('/')
  raise ShellError, "Default should be #{list}" unless CONFIRM_LIST.include?(default)

  prompt = "#{prompt} (#{list}) [#{default}] "
  loop do
    line = readline(prompt, @history)

    if line.nil?
      puts
      return
    end

    line.strip!
    line.downcase!
    return default == CONFIRM_LIST.first if line.empty?

    next unless CONFIRM_LIST.map(&:to_s).include?(line)

    return line == CONFIRM_LIST.first.to_s
  end
end

#context(*path) ⇒ Object

Returns a context by the path from the root context



169
170
171
# File 'lib/sandbox/shell.rb', line 169

def context(*path)
  @root.context(*path)
end

#exec(line) ⇒ Object

Executes command



76
77
78
79
# File 'lib/sandbox/shell.rb', line 76

def exec(line)
  tokens = split_tokens(line)
  @root.context(*@path).exec(self, tokens)
end

#formatted_pathObject

Returns the current formatted path



139
140
141
# File 'lib/sandbox/shell.rb', line 139

def formatted_path
  "/#{@path.join('/')}"
end

Prints data



100
101
102
# File 'lib/sandbox/shell.rb', line 100

def print(data)
  @output.print(data)
end

#puts(data = '') ⇒ Object

Prints data with a line at the end



106
107
108
109
110
# File 'lib/sandbox/shell.rb', line 106

def puts(data = '')
  @output.print("\e[0G\e[J") if @reading
  @output.puts(data)
  Readline.refresh_line if @reading
end

#readline(prompt, history) ⇒ Object

Reads and returns a line



83
84
85
86
87
88
89
90
# File 'lib/sandbox/shell.rb', line 83

def readline(prompt, history)
  @reading = true
  line = Readline.readline(prompt, history)
  Readline::HISTORY.pop if line&.strip&.empty?
  Readline::HISTORY.pop if Readline::HISTORY.length >= 2 && Readline::HISTORY[-2] == line
  @reading = false
  line
end

#remove_command(name) ⇒ Object

Removes a command from the root context



163
164
165
# File 'lib/sandbox/shell.rb', line 163

def remove_command(name)
  @root.remove_command(name)
end

#remove_context(name) ⇒ Object

Removes a context from the root context



151
152
153
# File 'lib/sandbox/shell.rb', line 151

def remove_context(name)
  @root.remove_context(name)
end

#runObject

Runs the shell



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/sandbox/shell.rb', line 49

def run
  puts(@banner)
  Readline.completion_proc = proc { |line| completion_proc(line) }
  @running = true
  while @running
    begin
      line = readline("#{formatted_path}#{@prompt}", @history)
      if line.nil?
        puts
        break
      end

      line.strip!
      next if line.empty?

      exec(line)
    rescue ShellError => e
      puts(e)
      retry
    rescue Interrupt
      print("\e[0G\e[J")
    end
  end
end

#stopObject

Stops the shell



94
95
96
# File 'lib/sandbox/shell.rb', line 94

def stop
  @running = false
end