Module: Mmsh
- Defined in:
- lib/mmsh.rb
Defined Under Namespace
Classes: Cmd
Class Method Summary collapse
-
.args(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the arguments portion.
-
.cmd_from(single_cmd_str) ⇒ Object
Takes a command string containing a single command, and returns a Cmd struct containing the parts in the command.
-
.input(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the input redirection portion.
-
.io_connect(cmd_list) ⇒ Object
Takes an array of Cmd structs and does two things with them:.
- .min_strip(cmd) ⇒ Object
-
.minimize(cmd) ⇒ Object
Takes a command string that may contain leading and/or trailing whitespace, as well as the line continuation character (‘'), and produces a single string with all of that stripped out.
-
.name(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the name portion.
-
.output(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the output redirection portion.
-
.parse(multi_cmd_str) ⇒ Object
Takes a string captured from a CLI containing one or more commands, and returns an array of Cmd structs, fully connected and ready to be executed.
-
.parts_from(single_cmd_str) ⇒ Object
Takes a single command string and returns the component parts as an array of strings.
- .read(prompt) ⇒ Object
-
.strip_continuation(cmd) ⇒ Object
Takes a command that may or may not contain line continuation, and removes it if it’s present.
-
.subcmds(multi_cmd_str) ⇒ Object
Takes a string captured from a CLI containing one or more commands, and returns an array of the commands within that string.
Class Method Details
.args(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the
arguments portion.
See ::parts_from.
180 181 182 183 184 185 186 187 188 |
# File 'lib/mmsh.rb', line 180 def self.args(parts) end_index = [ (parts.index('<') || parts.length + 1), (parts.index('>') || parts.length + 1), parts.length + 1 ].compact.min - 1 parts[1..end_index].join(' ') end |
.cmd_from(single_cmd_str) ⇒ Object
Takes a command string containing a single command, and returns a Cmd struct containing the parts in the command.
Ex:
> Parser.cmd_from('baz < fizz.txt')
=> #<struct Cmd
id="6ac8aa1c-fdc8-4a63-9b4b-8cd185bd0f40",
name="baz",
args="",
input="fizz.txt",
output=nil
>
109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/mmsh.rb', line 109 def self.cmd_from(single_cmd_str) parts = parts_from(single_cmd_str) Cmd.new( SecureRandom.uuid, name(parts), args(parts), input(parts), output(parts) ) end |
.input(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the input redirection portion.
See ::parts_from.
195 196 197 198 |
# File 'lib/mmsh.rb', line 195 def self.input(parts) return nil unless parts.index('<') parts[parts.index('<') + 1] end |
.io_connect(cmd_list) ⇒ Object
Takes an array of Cmd structs and does two things with them:
For every Cmd:
-
Sets the Cmd’s #output attribute
-
Looks for uses of the pipe (‘|’) command, and where found, connect the output of the Cmd preceding the pipe to the input of the Cmd following the pipe.
The command string:
'foo | bar'
… will be split into Cmd structs that represent ‘foo’, ‘|’, and ‘bar’. This method notices that a pipe (‘|’) Cmd is being used, and connects the output of ‘foo’ to the input of ‘bar’.
137 138 139 140 141 142 143 144 145 |
# File 'lib/mmsh.rb', line 137 def self.io_connect(cmd_list) cmd_list[0][:output] ||= cmd_list[0][:id] cmd_list[1..-1].each.with_index do |c, i| c[:output] ||= c[:id] c[:input] ||= cmd_list[i - 1][:id] if cmd_list[i][:name].eql?('|') end cmd_list end |
.min_strip(cmd) ⇒ Object
55 56 57 58 59 |
# File 'lib/mmsh.rb', line 55 def self.min_strip(cmd) rpad = cmd.end_with?(' ') ? ' ' : '' "#{cmd.strip}#{rpad}" end |
.minimize(cmd) ⇒ Object
Takes a command string that may contain leading and/or trailing whitespace, as well as the line continuation character (‘'), and produces a single string with all of that stripped out. Multiple lines get combined, with continuation removed.
This:
> foo \
> bar
Becomes:
'foo bar'
This:
> foo\
>bar
Becomes:
'foobar'
43 44 45 46 47 |
# File 'lib/mmsh.rb', line 43 def self.minimize(cmd) min_strip( strip_continuation(cmd) ) end |
.name(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the name portion.
See ::parts_from.
171 172 173 |
# File 'lib/mmsh.rb', line 171 def self.name(parts) parts[0] end |
.output(parts) ⇒ Object
Takes an array of the parts of a single command string and returns the output redirection portion.
See ::parts_from.
205 206 207 208 |
# File 'lib/mmsh.rb', line 205 def self.output(parts) return nil unless parts.index('>') parts[parts.index('>') + 1] end |
.parse(multi_cmd_str) ⇒ Object
Takes a string captured from a CLI containing one or more commands, and returns an array of Cmd structs, fully connected and ready to be executed.
Ex:
> Parser.parse('foo | bar; baz < fizz.txt')
=> [
<Cmd name='foo', ... >,
<Cmd name='|', ... >,
<Cmd name='bar' ... >,
<Cmd name=';' ... >,
<Cmd name='baz', ... >
]
76 77 78 79 80 |
# File 'lib/mmsh.rb', line 76 def self.parse(multi_cmd_str) io_connect( subcmds(multi_cmd_str).map{|c| cmd_from(c) } ) end |
.parts_from(single_cmd_str) ⇒ Object
Takes a single command string and returns the component parts as an array of strings.
Ex:
> Parser.parts_from('foo bar1 bar2 bar3 < baz > fizz')
=> ["foo", "bar1", "bar2", "bar3", "<", "baz", ">", "fizz"]
name |----- arguments -----| |- input -| |- output -|
From this list, other supporting methods can extract the name, arguments, input redirection, and output redirection.
158 159 160 161 162 163 164 |
# File 'lib/mmsh.rb', line 158 def self.parts_from(single_cmd_str) single_cmd_str .split(/(<|>)/) .map{|p| p.strip } .map{|p| p.split } .flatten end |
.read(prompt) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/mmsh.rb', line 7 def self.read(prompt) cmd_lines = [] loop do cmd = Readline.readline("#{prompt} ", false).rstrip Readline::HISTORY.push(cmd) unless cmd.empty? cmd_lines << minimize(cmd) if cmd.end_with?('\\') next else break end end cmd_lines.join end |
.strip_continuation(cmd) ⇒ Object
Takes a command that may or may not contain line continuation, and removes it if it’s present.
51 52 53 |
# File 'lib/mmsh.rb', line 51 def self.strip_continuation(cmd) cmd.rstrip.end_with?('\\') ? cmd.rstrip[0..-2] : cmd.rstrip end |
.subcmds(multi_cmd_str) ⇒ Object
Takes a string captured from a CLI containing one or more commands, and returns an array of the commands within that string. Basically this splits on tokens that appear between commands.
Ex:
> Parser.subcmds('foo | bar; baz < fizz.txt')
=> ["foo", "|", "bar", ";", "baz < fizz.txt"]
90 91 92 93 94 |
# File 'lib/mmsh.rb', line 90 def self.subcmds(multi_cmd_str) multi_cmd_str .split(/(&&|\*|\||;)/) .map{|cmd| cmd.strip } end |