mysh 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +93 -3
- data/bin/mysh +8 -0
- data/lib/mysh.rb +31 -9
- data/lib/mysh/auto_file.rb +77 -0
- data/lib/mysh/commands/cd.rb +29 -0
- data/lib/mysh/commands/exit.rb +1 -1
- data/lib/mysh/commands/help.rb +56 -0
- data/lib/mysh/commands/help_math.txt +38 -0
- data/lib/mysh/commands/history.rb +21 -0
- data/lib/mysh/expression.rb +58 -0
- data/lib/mysh/internal.rb +4 -2
- data/lib/mysh/internal/decorate.rb +31 -0
- data/lib/mysh/internal/klass.rb +13 -8
- data/lib/mysh/internal/parse.rb +82 -0
- data/lib/mysh/version.rb +1 -1
- data/mysh.gemspec +1 -1
- data/tests/my_shell_tests.rb +10 -0
- metadata +14 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83f9039c4f2cde3a39aa6866ce9c2ee97960e9a9
|
4
|
+
data.tar.gz: bb2f6c3978ddd5909c1d44de228a334685327d19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 109ac98304aa864f6e9d17b8de17c6b4c8cf37779025f373dd2ad91ca5a853dff7cdad1fbd824e8ecde8f6ee5efc78b03812265e7f28bfd6fb7a1d2b5c465021
|
7
|
+
data.tar.gz: 8af5305d816382e9d56babab655de0686010e643a23276e954c3a2f4b5de8c48081732ae08d5ede5f7d2f5dc6df560fe5e0176ebe3792e3bf30759541de961a1
|
data/README.md
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# Mysh
|
2
2
|
|
3
3
|
Inspired by the excellent article "Writing a Shell in 25 Lines of Ruby Code"
|
4
|
-
|
5
|
-
thought it would be fun to experiment with that concept and see if it could
|
4
|
+
I thought it would be fun to experiment with that concept and see if it could
|
6
5
|
be taken further.
|
7
6
|
|
8
7
|
Many years ago, a popular shell program was modeled after
|
@@ -18,6 +17,9 @@ shell program at this level of narcissism.
|
|
18
17
|
The mysh is available as both a stand-alone CLI program and for use as a
|
19
18
|
command shell within Ruby applications and Rails web sites.
|
20
19
|
|
20
|
+
See the original article at:
|
21
|
+
(http://www.blackbytes.info/2016/07/writing-a-shell-in-ruby/)
|
22
|
+
|
21
23
|
## Installation
|
22
24
|
|
23
25
|
Add this line to your application's Gemfile:
|
@@ -36,7 +38,95 @@ Or install it yourself as:
|
|
36
38
|
|
37
39
|
## Usage
|
38
40
|
|
39
|
-
|
41
|
+
The mysh gem includes a simple executable called mysh. When run, the user is
|
42
|
+
presented with a command prompt:
|
43
|
+
|
44
|
+
mysh>
|
45
|
+
|
46
|
+
This prompt can be used to execute three sorts of commands:
|
47
|
+
|
48
|
+
* Internal commands that are processed directly by mysh
|
49
|
+
* Ruby expressions, which are preceded by the equal (=) sign.
|
50
|
+
* External commands that are passed on to the standard command shell.
|
51
|
+
|
52
|
+
From the mysh help:
|
53
|
+
|
54
|
+
mysh> ?
|
55
|
+
mysh (MY SHell) version: 0.1.0
|
56
|
+
|
57
|
+
Internal mysh commands:
|
58
|
+
- executed by mysh directly.
|
59
|
+
- a leading space skips all internal commands.
|
60
|
+
|
61
|
+
! Display the mysh command history.
|
62
|
+
=an_expr Display the result of evaluating an expression in ruby.
|
63
|
+
=result Display the result of the previous evaluation.
|
64
|
+
=stuff \ This expression is continued on the next line.
|
65
|
+
? Display help information for mysh.
|
66
|
+
cd <dir> Change directory to <dir> and display the new working directory.
|
67
|
+
exit Exit mysh.
|
68
|
+
help Display help information for mysh.
|
69
|
+
history Display the mysh command history.
|
70
|
+
pwd Display the current working directory.
|
71
|
+
quit Exit mysh.
|
72
|
+
|
73
|
+
Math support:
|
74
|
+
- the execution environment includes the Math module.
|
75
|
+
- for more info use the help math command.
|
76
|
+
|
77
|
+
External commands:
|
78
|
+
- executed by the system using the standard shell.
|
79
|
+
- use help - for more info on external commands.
|
80
|
+
|
81
|
+
and
|
82
|
+
|
83
|
+
mysh> ? math
|
84
|
+
mysh (MY SHell) version: 0.1.0
|
85
|
+
|
86
|
+
mysh Math support summary
|
87
|
+
|
88
|
+
Method Returns Description
|
89
|
+
======= ======= ================================================
|
90
|
+
acos(x) Float Computes the arc cosine of x. Returns 0..PI.
|
91
|
+
acosh(x) Float Computes the inverse hyperbolic cosine of x.
|
92
|
+
asin(x) Float Computes the arc sine of x. Returns -PI/2..PI/2.
|
93
|
+
asinh(x) Float Computes the inverse hyperbolic sine of x.
|
94
|
+
atan(x) Float Computes the arc tangent of x. Returns -PI/2..PI/2.
|
95
|
+
atan2(y,x) Float Computes the arc tangent given y and x.
|
96
|
+
Returns a Float in the range -PI..PI.
|
97
|
+
atanh(x) Float Computes the inverse hyperbolic tangent of x.
|
98
|
+
cbrt(x) Float Returns the cube root of x.
|
99
|
+
cos(x) Float Computes the cosine of x (expressed in radians).
|
100
|
+
Returns a Float in the range -1.0..1.0.
|
101
|
+
cosh(x) Float Computes the hyperbolic cosine of x (expressed in radians).
|
102
|
+
erf(x) Float Calculates the error function of x.
|
103
|
+
erfc(x) Float Calculates the complementary error function of x.
|
104
|
+
exp(x) Float Returns e**x.
|
105
|
+
frexp(x) Array Returns a two-element array containing the normalized
|
106
|
+
fraction (a Float) and exponent (a Fixnum) of x.
|
107
|
+
gamma(x) Float Calculates the gamma function of x.
|
108
|
+
hypot(x,y) Float Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled
|
109
|
+
triangle with sides x and y.
|
110
|
+
ldexp(f,e) Float Returns the value of f*(2**e).
|
111
|
+
lgamma(x) Array Returns a two-element array containing the log of the
|
112
|
+
gamma of x and the sign of gamma of x.
|
113
|
+
log(x) Float Computes the natural log of c.
|
114
|
+
log(x,B) Float Computes the base B log of c.
|
115
|
+
log10(x) Float Returns the base 10 logarithm of x.
|
116
|
+
log2(x) Float Returns the base 2 logarithm of x.
|
117
|
+
sin(x) Float Computes the sine of x (expressed in radians).
|
118
|
+
Returns a Float in the range -1.0..1.0.
|
119
|
+
sinh(x) Float Computes the hyperbolic sine of x (expressed in radians).
|
120
|
+
sqrt(x) Float Returns the non-negative square root of x.
|
121
|
+
tan(x) Float Computes the tangent of x (expressed in radians).
|
122
|
+
tanh(x) Float Computes the hyperbolic tangent of x (expressed in radians).
|
123
|
+
|
124
|
+
|
125
|
+
The mysh can also be used from within a Ruby application:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
Mysh.run
|
129
|
+
```
|
40
130
|
|
41
131
|
## Contributing
|
42
132
|
|
data/bin/mysh
ADDED
data/lib/mysh.rb
CHANGED
@@ -2,13 +2,17 @@
|
|
2
2
|
|
3
3
|
# mysh -- MY SHell -- a Ruby/Rails inspired command shell.
|
4
4
|
|
5
|
+
require 'English'
|
6
|
+
|
5
7
|
#Use the mini_readline gem but make sure that it does
|
6
8
|
#not interfere with the standard readline library.
|
7
9
|
$no_alias_read_line_module = true
|
8
|
-
require
|
10
|
+
require 'mini_readline'
|
9
11
|
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
+
require_relative 'mysh/auto_file'
|
13
|
+
require_relative 'mysh/internal'
|
14
|
+
require_relative 'mysh/expression'
|
15
|
+
require_relative 'mysh/version'
|
12
16
|
|
13
17
|
#The MY SHell module. A container for its functionality.
|
14
18
|
module Mysh
|
@@ -19,20 +23,38 @@ module Mysh
|
|
19
23
|
end
|
20
24
|
|
21
25
|
#The actual shell method.
|
22
|
-
|
23
|
-
|
26
|
+
#<br>Endemic Code Smells
|
27
|
+
#* :reek:TooManyStatements
|
28
|
+
def self.run
|
29
|
+
reset
|
30
|
+
@input = MiniReadline::Readline.new(history: true,
|
31
|
+
eoi_detect: true,
|
32
|
+
auto_complete: true,
|
33
|
+
auto_source: AutoFile)
|
24
34
|
|
25
35
|
loop do
|
26
|
-
input = @input.readline
|
27
|
-
|
36
|
+
input = @input.readline(prompt: 'mysh> ')
|
37
|
+
|
38
|
+
begin
|
39
|
+
@exec_host.execute(input) ||
|
40
|
+
InternalCommand.execute(input) ||
|
41
|
+
system(input)
|
42
|
+
rescue Interrupt => err
|
43
|
+
puts err
|
44
|
+
end
|
28
45
|
end
|
29
46
|
|
30
|
-
rescue MiniReadlineEOI
|
47
|
+
rescue Interrupt, MiniReadlineEOI
|
48
|
+
end
|
49
|
+
|
50
|
+
#Reset the state of the execution hosting environment.
|
51
|
+
def self.reset
|
52
|
+
@exec_host = ExecHost.new
|
31
53
|
end
|
32
54
|
|
33
55
|
end
|
34
56
|
|
35
57
|
#Some test code to run a shell if this file is run directly.
|
36
58
|
if __FILE__ == $0
|
37
|
-
Mysh.
|
59
|
+
Mysh.run
|
38
60
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* auto_file.rb - The data source for mysh file name auto-complete.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* auto_file.rb - The data source for mysh file name auto-complete.
|
7
|
+
class AutoFile
|
8
|
+
|
9
|
+
#Create a new file/folder auto-data source. NOP
|
10
|
+
def initialize(_options); end
|
11
|
+
|
12
|
+
#Construct a new data list for auto-complete
|
13
|
+
def rebuild(str)
|
14
|
+
extract_root_pivot(str)
|
15
|
+
|
16
|
+
list = Dir.glob(dress_down(@pivot) + '*')
|
17
|
+
|
18
|
+
@cycler = list.empty? ? nil : list.cycle
|
19
|
+
end
|
20
|
+
|
21
|
+
#The regex for extraction of the root and pivot.
|
22
|
+
EXTRACT = /("[^"\s][^"]*"?$)|(\S+$)/
|
23
|
+
|
24
|
+
#Parse the string into the two basic components.
|
25
|
+
def extract_root_pivot(str)
|
26
|
+
@root, @pivot = EXTRACT =~ str ? [$PREMATCH, $MATCH] : [str, ""]
|
27
|
+
end
|
28
|
+
|
29
|
+
#Get the next string for auto-complete
|
30
|
+
def next
|
31
|
+
@root + dress_up(@cycler.next)
|
32
|
+
end
|
33
|
+
|
34
|
+
#Prepare the file name for internal use.
|
35
|
+
#<br>Endemic Code Smells
|
36
|
+
#* :reek:UtilityFunction
|
37
|
+
def dress_down(name)
|
38
|
+
name.gsub("\\", "/").gsub('"', '')
|
39
|
+
end
|
40
|
+
|
41
|
+
#Prepare the file name for external use.
|
42
|
+
#<br>Endemic Code Smells
|
43
|
+
#* :reek:UtilityFunction
|
44
|
+
def dress_up(name)
|
45
|
+
dress_up_quotes(dress_up_slashes(name))
|
46
|
+
end
|
47
|
+
|
48
|
+
#Dress up slashes and backslashes.
|
49
|
+
def dress_up_slashes(name)
|
50
|
+
backslash? ? name.gsub("/", "\\") : name
|
51
|
+
end
|
52
|
+
|
53
|
+
#Dress up in quotes if needed.
|
54
|
+
#<br>Endemic Code Smells
|
55
|
+
#* :reek:UtilityFunction
|
56
|
+
def dress_up_quotes(name)
|
57
|
+
name[' '] ? "\"#{name}\"" : name
|
58
|
+
end
|
59
|
+
|
60
|
+
#Does this file name use backslashes?
|
61
|
+
def backslash?
|
62
|
+
if @pivot.end_with?("\\")
|
63
|
+
true
|
64
|
+
elsif @pivot.end_with?("/")
|
65
|
+
false
|
66
|
+
elsif @pivot["\\"]
|
67
|
+
true
|
68
|
+
elsif @pivot["/"]
|
69
|
+
false
|
70
|
+
else
|
71
|
+
MiniReadline::PLATFORM == :windows
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* commands/cd.rb -- The mysh internal cd command.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* cd.rb -- The mysh internal cd command.
|
7
|
+
class InternalCommand
|
8
|
+
#Add the cd command to the library.
|
9
|
+
add(self.new('cd <dir>', 'Change directory to <dir> and display the new working directory.') do |args|
|
10
|
+
begin
|
11
|
+
Dir.chdir(args[0]) unless args.empty?
|
12
|
+
puts decorate(Dir.pwd)
|
13
|
+
rescue => err
|
14
|
+
puts "Error: #{err}"
|
15
|
+
end
|
16
|
+
end)
|
17
|
+
|
18
|
+
#Add the pwd command to the library.
|
19
|
+
add(self.new('pwd', 'Display the current working directory.') do |args|
|
20
|
+
begin
|
21
|
+
puts decorate(Dir.pwd)
|
22
|
+
rescue => err
|
23
|
+
puts "Error: #{err}"
|
24
|
+
end
|
25
|
+
end)
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
data/lib/mysh/commands/exit.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* commands/exit.rb -- The mysh internal exit command.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* exit.rb -- The mysh internal exit command.
|
7
|
+
class InternalCommand
|
8
|
+
#The tag used for default external help.
|
9
|
+
EXT_TAG = '-'
|
10
|
+
|
11
|
+
#Add the exit command to the library.
|
12
|
+
add(self.new('help', 'Display help information for mysh.') do |args|
|
13
|
+
puts "mysh (MY SHell) version: #{Mysh::VERSION}"
|
14
|
+
puts
|
15
|
+
|
16
|
+
if args.empty?
|
17
|
+
width = 0
|
18
|
+
puts "Internal mysh commands:"
|
19
|
+
puts " - executed by mysh directly."
|
20
|
+
puts " - a leading space skips all internal commands."
|
21
|
+
puts
|
22
|
+
|
23
|
+
InternalCommand
|
24
|
+
.info
|
25
|
+
.concat(ExecHost.info)
|
26
|
+
.sort do |first, second |
|
27
|
+
width = [width, first[0].length, second[0].length].max
|
28
|
+
first[0] <=> second[0]
|
29
|
+
end
|
30
|
+
.each do |info|
|
31
|
+
puts "#{info[0].ljust(width)} #{info[1]}"
|
32
|
+
end
|
33
|
+
|
34
|
+
puts
|
35
|
+
puts "Math support:"
|
36
|
+
puts " - the execution environment includes the Math module."
|
37
|
+
puts " - for more info use the help math command."
|
38
|
+
|
39
|
+
puts
|
40
|
+
puts "External commands:"
|
41
|
+
puts " - executed by the system using the standard shell."
|
42
|
+
puts " - use help #{EXT_TAG} for more info on external commands."
|
43
|
+
puts
|
44
|
+
elsif args[0] == 'math'
|
45
|
+
puts IO.read(File.dirname(__FILE__) + '/help_math.txt')
|
46
|
+
else
|
47
|
+
args[0] = "" if args[0] == EXT_TAG
|
48
|
+
system("help " + args.join)
|
49
|
+
end
|
50
|
+
|
51
|
+
end)
|
52
|
+
|
53
|
+
add_alias('?', 'help')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
mysh Math support summary
|
2
|
+
|
3
|
+
Method Returns Description
|
4
|
+
======= ======= ================================================
|
5
|
+
acos(x) Float Computes the arc cosine of x. Returns 0..PI.
|
6
|
+
acosh(x) Float Computes the inverse hyperbolic cosine of x.
|
7
|
+
asin(x) Float Computes the arc sine of x. Returns -PI/2..PI/2.
|
8
|
+
asinh(x) Float Computes the inverse hyperbolic sine of x.
|
9
|
+
atan(x) Float Computes the arc tangent of x. Returns -PI/2..PI/2.
|
10
|
+
atan2(y,x) Float Computes the arc tangent given y and x.
|
11
|
+
Returns a Float in the range -PI..PI.
|
12
|
+
atanh(x) Float Computes the inverse hyperbolic tangent of x.
|
13
|
+
cbrt(x) Float Returns the cube root of x.
|
14
|
+
cos(x) Float Computes the cosine of x (expressed in radians).
|
15
|
+
Returns a Float in the range -1.0..1.0.
|
16
|
+
cosh(x) Float Computes the hyperbolic cosine of x (expressed in radians).
|
17
|
+
erf(x) Float Calculates the error function of x.
|
18
|
+
erfc(x) Float Calculates the complementary error function of x.
|
19
|
+
exp(x) Float Returns e**x.
|
20
|
+
frexp(x) Array Returns a two-element array containing the normalized
|
21
|
+
fraction (a Float) and exponent (a Fixnum) of x.
|
22
|
+
gamma(x) Float Calculates the gamma function of x.
|
23
|
+
hypot(x,y) Float Returns sqrt(x**2 + y**2), the hypotenuse of a right-angled
|
24
|
+
triangle with sides x and y.
|
25
|
+
ldexp(f,e) Float Returns the value of f*(2**e).
|
26
|
+
lgamma(x) Array Returns a two-element array containing the log of the
|
27
|
+
gamma of x and the sign of gamma of x.
|
28
|
+
log(x) Float Computes the natural log of c.
|
29
|
+
log(x,B) Float Computes the base B log of c.
|
30
|
+
log10(x) Float Returns the base 10 logarithm of x.
|
31
|
+
log2(x) Float Returns the base 2 logarithm of x.
|
32
|
+
sin(x) Float Computes the sine of x (expressed in radians).
|
33
|
+
Returns a Float in the range -1.0..1.0.
|
34
|
+
sinh(x) Float Computes the hyperbolic sine of x (expressed in radians).
|
35
|
+
sqrt(x) Float Returns the non-negative square root of x.
|
36
|
+
tan(x) Float Computes the tangent of x (expressed in radians).
|
37
|
+
tanh(x) Float Computes the hyperbolic tangent of x (expressed in radians).
|
38
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* commands/exit.rb -- The mysh internal exit command.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* exit.rb -- The mysh internal history command.
|
7
|
+
class InternalCommand
|
8
|
+
#Add the exit command to the library.
|
9
|
+
add(self.new('history', 'Display the mysh command history.') do |args|
|
10
|
+
history = Mysh.input.history
|
11
|
+
|
12
|
+
#The history command should not be part of the history.
|
13
|
+
history.pop
|
14
|
+
|
15
|
+
puts history
|
16
|
+
end)
|
17
|
+
|
18
|
+
add_alias('!', 'history')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'mathn'
|
5
|
+
|
6
|
+
#* expression.rb -- mysh ruby expression processor.
|
7
|
+
module Mysh
|
8
|
+
|
9
|
+
#The mysh ruby expression processor.
|
10
|
+
class ExecHost
|
11
|
+
|
12
|
+
include Math
|
13
|
+
|
14
|
+
#Get help info on Ruby host exec.
|
15
|
+
def self.info
|
16
|
+
[["=an_expr", "Display the result of evaluating an expression in ruby."],
|
17
|
+
["=result", "Display the result of the previous evaluation."],
|
18
|
+
["=stuff \\","This expression is continued on the next line."]]
|
19
|
+
end
|
20
|
+
|
21
|
+
#The result of the previous expression.
|
22
|
+
attr_reader :result
|
23
|
+
|
24
|
+
#Process an expression.
|
25
|
+
def execute(str)
|
26
|
+
if str.start_with?('=')
|
27
|
+
do_execute(str)
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#Reset the state of the execution host.
|
34
|
+
#<br>Endemic Code Smells
|
35
|
+
#* :reek:UtilityFunction
|
36
|
+
def reset
|
37
|
+
Mysh.reset
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
#Do the actual work of executing an expression.
|
43
|
+
def do_execute(str)
|
44
|
+
if /\\\s*$/ =~ str
|
45
|
+
do_execute($PREMATCH + "\n" + Mysh.input.readline(prompt: 'mysh\\ '))
|
46
|
+
else
|
47
|
+
begin
|
48
|
+
pp eval("@result" + str)
|
49
|
+
rescue StandardError, ScriptError => err
|
50
|
+
puts "Error: #{err}"
|
51
|
+
end
|
52
|
+
|
53
|
+
:expression
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
data/lib/mysh/internal.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require_relative 'internal/klass
|
4
|
-
require_relative 'internal/
|
3
|
+
require_relative 'internal/klass'
|
4
|
+
require_relative 'internal/parse'
|
5
|
+
require_relative 'internal/instance'
|
6
|
+
require_relative 'internal/decorate'
|
5
7
|
|
6
8
|
#Load up the commands!
|
7
9
|
Dir[File.dirname(__FILE__) + '/commands/*.rb'].each {|file| require file }
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* decorate.rb -- mysh internal file name beauty treatments.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#The mysh internal file name beauty treatments.
|
7
|
+
class InternalCommand
|
8
|
+
|
9
|
+
#Make the file name fit the local system.
|
10
|
+
def self.decorate(name)
|
11
|
+
dress_up_quotes(dress_up_slashes(name))
|
12
|
+
end
|
13
|
+
|
14
|
+
#Dress up slashes and backslashes.
|
15
|
+
def self.dress_up_slashes(name)
|
16
|
+
backslash? ? name.gsub("/", "\\") : name
|
17
|
+
end
|
18
|
+
|
19
|
+
#Dress up in quotes if needed.
|
20
|
+
def self.dress_up_quotes(name)
|
21
|
+
name[' '] ? "\"#{name}\"" : name
|
22
|
+
end
|
23
|
+
|
24
|
+
#Does this file name use backslashes?
|
25
|
+
def self.backslash?
|
26
|
+
MiniReadline::PLATFORM == :windows
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/lib/mysh/internal/klass.rb
CHANGED
@@ -16,7 +16,7 @@ module Mysh
|
|
16
16
|
|
17
17
|
#Add a command to the command library.
|
18
18
|
def self.add(command)
|
19
|
-
@commands[command.name] = command
|
19
|
+
@commands[command.name.split[0]] = command
|
20
20
|
end
|
21
21
|
|
22
22
|
#Add an alias for an existing command.
|
@@ -25,23 +25,28 @@ module Mysh
|
|
25
25
|
fail "Error adding alias #{new_name} for #{old_name}"
|
26
26
|
end
|
27
27
|
|
28
|
-
@commands[new_name] = new(new_name,
|
28
|
+
@commands[new_name] = new(new_name.split[0],
|
29
29
|
command.description,
|
30
30
|
&command.action)
|
31
31
|
end
|
32
32
|
|
33
33
|
#Execute an internal command
|
34
34
|
def self.execute(str)
|
35
|
-
|
35
|
+
unless str[0] == ' '
|
36
|
+
command, args = parse(str.chomp)
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
false
|
38
|
+
if (command)
|
39
|
+
command.execute(args)
|
40
|
+
:internal
|
41
|
+
end
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
#Get information on all commands.
|
46
|
+
def self.info
|
47
|
+
@commands.values.map { |command| command.info }
|
48
|
+
end
|
49
|
+
|
45
50
|
end
|
46
51
|
end
|
47
52
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* parse.rb -- mysh internal command parser.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#The mysh internal command instance data and methods.
|
7
|
+
class InternalCommand
|
8
|
+
|
9
|
+
#Parse a command string for use by commands.
|
10
|
+
#<br>Endemic Code Smells
|
11
|
+
#* :reek:TooManyStatements
|
12
|
+
def self.parse(input)
|
13
|
+
result, read_point = [], input.chars.each
|
14
|
+
|
15
|
+
loop do
|
16
|
+
begin
|
17
|
+
next_parse_char = read_point.next
|
18
|
+
rescue StopIteration
|
19
|
+
break
|
20
|
+
end
|
21
|
+
|
22
|
+
if next_parse_char == '"'
|
23
|
+
result.concat(get_string(read_point))
|
24
|
+
elsif next_parse_char != ' '
|
25
|
+
result.concat(get_parameter(next_parse_char, read_point))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
[@commands[result.shift], result]
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
#Get a string parameter.
|
35
|
+
#<br>Endemic Code Smells
|
36
|
+
#* :reek:TooManyStatements
|
37
|
+
def self.get_string(read_point)
|
38
|
+
result = ""
|
39
|
+
|
40
|
+
loop do
|
41
|
+
begin
|
42
|
+
next_str_char = read_point.next
|
43
|
+
rescue StopIteration
|
44
|
+
break
|
45
|
+
end
|
46
|
+
|
47
|
+
break if next_str_char == '"'
|
48
|
+
|
49
|
+
result << next_str_char
|
50
|
+
end
|
51
|
+
|
52
|
+
[result]
|
53
|
+
end
|
54
|
+
|
55
|
+
#Get a parameter.
|
56
|
+
#<br>Endemic Code Smells
|
57
|
+
#* :reek:TooManyStatements
|
58
|
+
def self.get_parameter(first_char, read_point)
|
59
|
+
result = first_char
|
60
|
+
|
61
|
+
loop do
|
62
|
+
begin
|
63
|
+
next_parm_char = read_point.next
|
64
|
+
rescue StopIteration
|
65
|
+
break
|
66
|
+
end
|
67
|
+
|
68
|
+
if next_parm_char == '"'
|
69
|
+
return [result].concat(get_string(read_point))
|
70
|
+
elsif next_parm_char == ' '
|
71
|
+
break
|
72
|
+
else
|
73
|
+
result << next_parm_char
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
[result]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
data/lib/mysh/version.rb
CHANGED
data/mysh.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = Mysh::SUMMARY
|
13
13
|
spec.description = "mysh -- a Ruby inspired command shell " +
|
14
|
-
"for CLI and application use.
|
14
|
+
"for CLI and application use."
|
15
15
|
spec.homepage = "http://teuthida-technologies.com/"
|
16
16
|
|
17
17
|
spec.license = "MIT"
|
data/tests/my_shell_tests.rb
CHANGED
@@ -14,12 +14,22 @@ class MyShellTester < Minitest::Test
|
|
14
14
|
def test_that_module_entities_exists
|
15
15
|
assert_equal(Module, Mysh.class)
|
16
16
|
assert_equal(Class, Mysh::InternalCommand.class)
|
17
|
+
assert_equal(Class, Mysh::ExecHost.class)
|
17
18
|
end
|
18
19
|
|
19
20
|
def test_for_internal_commands
|
20
21
|
assert(Mysh::InternalCommand.commands['exit'], "The exit command is missing.")
|
21
22
|
assert(Mysh::InternalCommand.commands['quit'], "The quit command is missing.")
|
22
23
|
|
24
|
+
assert(Mysh::InternalCommand.commands['history'], "The history command is missing.")
|
25
|
+
assert(Mysh::InternalCommand.commands['!'], "The ! command is missing.")
|
26
|
+
|
27
|
+
assert(Mysh::InternalCommand.commands['help'], "The help command is missing.")
|
28
|
+
assert(Mysh::InternalCommand.commands['?'], "The ? command is missing.")
|
29
|
+
|
30
|
+
assert(Mysh::InternalCommand.commands['cd'], "The cd command is missing.")
|
31
|
+
assert(Mysh::InternalCommand.commands['pwd'], "The pwd command is missing.")
|
32
|
+
|
23
33
|
assert_raises { Mysh::InternalCommand.add_alias('blam', 'shazzam') }
|
24
34
|
end
|
25
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mysh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Camilleri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -108,10 +108,11 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 0.5.2
|
111
|
-
description: mysh -- a Ruby inspired command shell for CLI and application use.
|
111
|
+
description: mysh -- a Ruby inspired command shell for CLI and application use.
|
112
112
|
email:
|
113
113
|
- peter.c.camilleri@gmail.com
|
114
|
-
executables:
|
114
|
+
executables:
|
115
|
+
- mysh
|
115
116
|
extensions: []
|
116
117
|
extra_rdoc_files: []
|
117
118
|
files:
|
@@ -119,11 +120,20 @@ files:
|
|
119
120
|
- Gemfile
|
120
121
|
- LICENSE.txt
|
121
122
|
- README.md
|
123
|
+
- bin/mysh
|
122
124
|
- lib/mysh.rb
|
125
|
+
- lib/mysh/auto_file.rb
|
126
|
+
- lib/mysh/commands/cd.rb
|
123
127
|
- lib/mysh/commands/exit.rb
|
128
|
+
- lib/mysh/commands/help.rb
|
129
|
+
- lib/mysh/commands/help_math.txt
|
130
|
+
- lib/mysh/commands/history.rb
|
131
|
+
- lib/mysh/expression.rb
|
124
132
|
- lib/mysh/internal.rb
|
133
|
+
- lib/mysh/internal/decorate.rb
|
125
134
|
- lib/mysh/internal/instance.rb
|
126
135
|
- lib/mysh/internal/klass.rb
|
136
|
+
- lib/mysh/internal/parse.rb
|
127
137
|
- lib/mysh/version.rb
|
128
138
|
- mysh.gemspec
|
129
139
|
- rakefile.rb
|