mysh 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|