mysh 0.2.7 → 0.3.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 +407 -87
- data/lib/mysh.rb +14 -4
- data/lib/mysh/expression.rb +10 -7
- data/lib/mysh/external_ruby.rb +1 -1
- data/lib/mysh/handlebars.rb +29 -0
- data/lib/mysh/handlebars/string.rb +22 -0
- data/lib/mysh/internal/action.rb +5 -5
- data/lib/mysh/internal/action_pool.rb +1 -1
- data/lib/mysh/internal/actions/cd.rb +2 -1
- data/lib/mysh/internal/actions/help/hbar.txt +13 -12
- data/lib/mysh/internal/actions/help/history.txt +1 -1
- data/lib/mysh/internal/actions/help/kbd.txt +1 -0
- data/lib/mysh/internal/actions/help/sub_help.rb +4 -3
- data/lib/mysh/internal/actions/help/vars.txt +34 -0
- data/lib/mysh/internal/actions/pwd.rb +1 -1
- data/lib/mysh/internal/actions/show/env.rb +3 -1
- data/lib/mysh/internal/actions/show/ruby.rb +1 -1
- data/lib/mysh/internal/actions/type.rb +1 -1
- data/lib/mysh/internal/actions/vars.rb +58 -0
- data/lib/mysh/internal/decorate.rb +13 -28
- data/lib/mysh/pre_processor.rb +11 -0
- data/lib/mysh/quick.rb +1 -0
- data/lib/mysh/shell_variables.rb +29 -0
- data/lib/mysh/shell_variables/evaluate.rb +23 -0
- data/lib/mysh/shell_variables/globalize.rb +9 -0
- data/lib/mysh/shell_variables/shell_variable_keeper.rb +36 -0
- data/lib/mysh/shell_variables/shell_variable_store.rb +76 -0
- data/lib/mysh/user_input.rb +10 -7
- data/lib/mysh/version.rb +1 -1
- data/mysh.gemspec +1 -1
- data/samples/show.txt +1 -1
- data/tests/my_shell_tests.rb +78 -5
- metadata +14 -5
- data/lib/mysh/user_input/handlebars.rb +0 -46
data/lib/mysh.rb
CHANGED
@@ -10,6 +10,9 @@ require_relative 'mysh/quick'
|
|
10
10
|
require_relative 'mysh/expression'
|
11
11
|
require_relative 'mysh/internal'
|
12
12
|
require_relative 'mysh/external_ruby'
|
13
|
+
require_relative 'mysh/handlebars'
|
14
|
+
require_relative 'mysh/shell_variables'
|
15
|
+
require_relative 'mysh/pre_processor'
|
13
16
|
require_relative 'mysh/version'
|
14
17
|
|
15
18
|
#The Mysh (MY SHell) module. A container for mysh and its functionality.
|
@@ -20,7 +23,7 @@ module Mysh
|
|
20
23
|
setup
|
21
24
|
|
22
25
|
while @mysh_running do
|
23
|
-
execute_a_command(
|
26
|
+
execute_a_command(get_command)
|
24
27
|
end
|
25
28
|
end
|
26
29
|
|
@@ -31,7 +34,7 @@ module Mysh
|
|
31
34
|
@mysh_running = true
|
32
35
|
end
|
33
36
|
|
34
|
-
#Execute a single line of input.
|
37
|
+
#Execute a single line of input and handle exceptions.
|
35
38
|
def self.execute_a_command(str)
|
36
39
|
try_execute_command(str)
|
37
40
|
|
@@ -39,11 +42,18 @@ module Mysh
|
|
39
42
|
@mysh_running = false
|
40
43
|
|
41
44
|
rescue Interrupt, StandardError, ScriptError => err
|
42
|
-
puts err
|
45
|
+
puts "Error #{err.class}: #{err}"
|
46
|
+
puts err.backtrace if MNV[:debug]
|
43
47
|
end
|
44
48
|
|
45
|
-
#Try to execute a single line of input.
|
49
|
+
#Try to execute a single line of input. Does not handle exceptions.
|
46
50
|
def self.try_execute_command(input)
|
51
|
+
unless input.start_with?("$")
|
52
|
+
input = input.preprocess
|
53
|
+
end
|
54
|
+
|
55
|
+
puts "=> #{input}" if MNV[:debug]
|
56
|
+
|
47
57
|
try_execute_quick_command(input) ||
|
48
58
|
try_execute_internal_command(input) ||
|
49
59
|
try_execute_external_ruby(input) ||
|
data/lib/mysh/expression.rb
CHANGED
@@ -2,12 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'pp'
|
4
4
|
require 'mathn'
|
5
|
-
|
6
5
|
require_relative 'expression/lineage'
|
7
6
|
|
8
7
|
#* mysh/expression.rb -- The mysh ruby expression processor.
|
9
8
|
#<br>Endemic Code Smells
|
10
|
-
#* :reek:ModuleInitialize
|
9
|
+
#* :reek:ModuleInitialize -- False positive
|
11
10
|
module Mysh
|
12
11
|
|
13
12
|
#Reset the state of the execution hosting environment.
|
@@ -29,13 +28,13 @@ module Mysh
|
|
29
28
|
#* The expression string always begins with an '=' character.
|
30
29
|
def execute(expression)
|
31
30
|
pp $mysh_exec_binding.eval("$mysh_exec_result" + expression)
|
32
|
-
|
33
|
-
puts "#{err.class.to_s}: #{err}"
|
34
|
-
ensure
|
35
|
-
return :expression
|
31
|
+
:expression
|
36
32
|
end
|
37
33
|
|
38
|
-
|
34
|
+
#Return a simple message for less convoluted error messages.
|
35
|
+
def inspect
|
36
|
+
"exec_host"
|
37
|
+
end
|
39
38
|
|
40
39
|
#Get the previous result
|
41
40
|
def result
|
@@ -48,6 +47,10 @@ module Mysh
|
|
48
47
|
nil
|
49
48
|
end
|
50
49
|
|
50
|
+
#Evaluate the string in the my shell context.
|
51
|
+
def mysh_eval(str)
|
52
|
+
$mysh_exec_binding.eval(str)
|
53
|
+
end
|
51
54
|
end
|
52
55
|
|
53
56
|
$mysh_exec_host = exec_class.new
|
data/lib/mysh/external_ruby.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require_relative 'handlebars/string'
|
4
|
+
|
5
|
+
#* user_input/handlebars.rb -- Handlebar embedded ruby support.
|
6
|
+
class Object
|
7
|
+
|
8
|
+
#Show a file with embedded ruby handlebars.
|
9
|
+
#<br>Note:
|
10
|
+
#The message receiver is the evaluation host for the handlebar code.
|
11
|
+
def show_handlebar_file(name, evaluator)
|
12
|
+
puts eval_handlebar_file(name, evaluator)
|
13
|
+
rescue Interrupt, StandardError, ScriptError => err
|
14
|
+
puts "Error in file: #{name}\n#{err.class}: #{err}"
|
15
|
+
puts err.backtrace if MNV[:debug]
|
16
|
+
end
|
17
|
+
|
18
|
+
#Expand a file with embedded ruby handlebars.
|
19
|
+
#<br>Note:
|
20
|
+
#The message receiver is the evaluation host for the handlebar code.
|
21
|
+
#<br>Endemic Code Smells
|
22
|
+
#* :reek:UtilityFunction
|
23
|
+
def eval_handlebar_file(name, evaluator)
|
24
|
+
IO.read(name).preprocess(evaluator)
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#Monkey patches for Mysh handlebars
|
4
|
+
class String
|
5
|
+
|
6
|
+
#Evaluate any variable substitutions in the input.
|
7
|
+
def eval_handlebars(evaluator=$mysh_exec_host)
|
8
|
+
gsub(/{{.*?}}/m) do |match|
|
9
|
+
code = match[2...-2]
|
10
|
+
silent = code.end_with?("#")
|
11
|
+
result = evaluator.mysh_eval(code)
|
12
|
+
|
13
|
+
(result unless silent).to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
#Process quoted brace characters
|
18
|
+
def eval_quoted_braces
|
19
|
+
gsub(/\\[\{\}]/) {|found| found[1]}
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/lib/mysh/internal/action.rb
CHANGED
@@ -28,6 +28,11 @@ module Mysh
|
|
28
28
|
[@name].concat(@description)
|
29
29
|
end
|
30
30
|
|
31
|
+
#Evaluate the string in the my shell context.
|
32
|
+
def mysh_eval(str)
|
33
|
+
@exec_binding.eval(str)
|
34
|
+
end
|
35
|
+
|
31
36
|
private
|
32
37
|
|
33
38
|
#Create a binding for mysh to execute expressions in.
|
@@ -35,11 +40,6 @@ module Mysh
|
|
35
40
|
binding
|
36
41
|
end
|
37
42
|
|
38
|
-
#Evaluate the string in the my shell context.
|
39
|
-
def mysh_eval(str)
|
40
|
-
@exec_binding.eval(str)
|
41
|
-
end
|
42
|
-
|
43
43
|
end
|
44
44
|
|
45
45
|
end
|
@@ -1,35 +1,36 @@
|
|
1
1
|
Help: About mysh handlebars:
|
2
2
|
|
3
|
-
In mysh, it is possible to embed snippets of ruby into text files
|
4
|
-
command line through the use of handlebars. Handlebars
|
3
|
+
In mysh, it is possible to embed snippets of ruby into text files, in shell
|
4
|
+
variables or on the command line through the use of handlebars. Handlebars
|
5
|
+
look like this:
|
5
6
|
|
6
7
|
\{\{ code goes here \}\}
|
7
8
|
|
8
9
|
Lets see a simple example of putting the result of a calculation into the
|
9
10
|
command line:
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
mysh>echo \{\{ (1..10).map {|i| i.to_s}.join(" ") \}\} > foo.txt
|
13
|
+
mysh>type foo.txt
|
14
|
+
1 2 3 4 5 6 7 8 9 10
|
14
15
|
|
15
16
|
Handlebars work by evaluating the ruby code within the \{\{ \}\} sequence in
|
16
17
|
the appropriate execution environment. For the command line, this is the same
|
17
18
|
environment used for the '=' quick execution command. For example:
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
mysh>=a="A very long string indeed!"
|
21
|
+
"A very long string indeed!"
|
22
|
+
mysh>echo \{\{ a \}\}
|
23
|
+
A very long string indeed!
|
23
24
|
|
24
25
|
The value returned by expression is coverted to a string (if needed) and then
|
25
26
|
inserted in place of the handlebar expression. There are, however, times when
|
26
27
|
it is not desired to insert anything in the place of the code snippet. For
|
27
28
|
those cases, simply end the expression with a '#' character. For example:
|
28
29
|
|
29
|
-
mysh>echo \{\{ "not embedded" #\}\} \{\{ "embedded" \}\}
|
30
|
-
|
30
|
+
mysh>echo \{\{ "not embedded" #\}\} \{\{ "embedded" \}\}
|
31
|
+
embedded
|
31
32
|
|
32
33
|
Finally, it may be that it is desired to embed braces into a text file or
|
33
|
-
the command line. In that case precede the brace with a
|
34
|
+
the command line. In that case precede the brace with a backslash character
|
34
35
|
like: \\{ or \\}
|
35
36
|
|
@@ -10,7 +10,7 @@ the quick form, ! is used, the space is optional.
|
|
10
10
|
Quick Long Command
|
11
11
|
Form Form Description
|
12
12
|
===== ======= ===========
|
13
|
-
! history Display the history buffer.
|
13
|
+
! history Display the entire history buffer.
|
14
14
|
|
15
15
|
!5 history 5 Retrieve history entry 5 and present this to the user
|
16
16
|
as the next command.
|
@@ -14,7 +14,7 @@ module Mysh
|
|
14
14
|
|
15
15
|
#Execute a help command.
|
16
16
|
def call(_args)
|
17
|
-
show_handlebar_file(ACTIONS_PATH + 'help/' + @file_name)
|
17
|
+
show_handlebar_file(ACTIONS_PATH + 'help/' + @file_name, self)
|
18
18
|
end
|
19
19
|
|
20
20
|
end
|
@@ -22,6 +22,7 @@ module Mysh
|
|
22
22
|
#Add help topics here. Don't sweat the order; they get sorted by name.
|
23
23
|
# Name Description Help File
|
24
24
|
help = [['', 'General help on mysh.', 'help.txt' ],
|
25
|
+
['$', 'Help on mysh variables.', 'vars.txt' ],
|
25
26
|
['show', 'Help on the show command.', 'show.txt' ],
|
26
27
|
['@', 'Help on the show command.', 'show.txt' ],
|
27
28
|
['env', 'Help on the show env command.', 'env.txt' ],
|
@@ -30,8 +31,8 @@ module Mysh
|
|
30
31
|
['=', 'Help on ruby expressions.', 'expr.txt' ],
|
31
32
|
['quick', 'Help on quick commands.', 'quick.txt' ],
|
32
33
|
['gls', 'Help on gls internal mysh command.', 'gls.txt' ],
|
33
|
-
['!', '
|
34
|
-
['history', '
|
34
|
+
['!', 'Help on the history command.', 'history.txt'],
|
35
|
+
['history', 'Help on the history command.', 'history.txt'],
|
35
36
|
['kbd', 'Help on mysh keyboard mapping.', 'kbd.txt' ],
|
36
37
|
['{{', 'Help on mysh handlebars.', 'hbar.txt' ],
|
37
38
|
['help', 'This help on the help command.', 'h_o_h.txt' ],
|
@@ -0,0 +1,34 @@
|
|
1
|
+
Help: mysh variables:
|
2
|
+
|
3
|
+
In mysh, variables are kept that control the behavior of the shell. This simple
|
4
|
+
command is used to set, delete, and display these variables. The basic method
|
5
|
+
for setting a variable is:
|
6
|
+
|
7
|
+
$name=value
|
8
|
+
|
9
|
+
Where:
|
10
|
+
* name is a word matching the regex: /[a-z][a-z0-9_]*/. Lower case only.
|
11
|
+
* value is a string, with embedded variables and handlebars.
|
12
|
+
|
13
|
+
To erase the value of a variable, use: $$name=
|
14
|
+
To display the name/value of a variable, use: $$name
|
15
|
+
To display all variable names/values use: $$
|
16
|
+
|
17
|
+
As an escapement, the string $$$$ maps to a single $$.
|
18
|
+
|
19
|
+
Some variables that are used in mysh are:
|
20
|
+
|
21
|
+
$$d The current date.
|
22
|
+
$$date_fmt The format for the date: "%Y-%m-%d"
|
23
|
+
$$debug Does the shell display additional debugging info (true/false)
|
24
|
+
$$h The home folder's path
|
25
|
+
$$post_prompt The prompt used when a line is continued with a trailing \\
|
26
|
+
character.
|
27
|
+
$$pre_prompt A prompt string displayed before the actual command prompt.
|
28
|
+
Delete the pre_prompt variable to disable pre-prompting.
|
29
|
+
$$prompt The user prompt.
|
30
|
+
$$t The current time.
|
31
|
+
$$time_fmt The format for the time: "%H:%M"
|
32
|
+
$$u The current user.
|
33
|
+
$$w The current working directory's path.
|
34
|
+
|
@@ -16,10 +16,12 @@ module Mysh
|
|
16
16
|
private
|
17
17
|
|
18
18
|
#Get the info
|
19
|
+
#<br>Endemic Code Smells
|
20
|
+
#* :reek:UtilityFunction
|
19
21
|
def info
|
20
22
|
[["user", ENV['USER']],
|
21
23
|
["home", ENV['HOME']],
|
22
|
-
["name",
|
24
|
+
["name", $PROGRAM_NAME.decorate],
|
23
25
|
["shell", ENV['SHELL'] || ENV['ComSpec']],
|
24
26
|
["host", ENV['HOSTNAME'] || ENV['COMPUTERNAME']],
|
25
27
|
["os", ENV['OS']],
|
@@ -19,7 +19,7 @@ module Mysh
|
|
19
19
|
#<br>Endemic Code Smells
|
20
20
|
#* :reek:UtilityFunction
|
21
21
|
def info
|
22
|
-
[["location",
|
22
|
+
[["location", RbConfig.ruby.decorate],
|
23
23
|
["description", RUBY_DESCRIPTION],
|
24
24
|
["version", RUBY_VERSION],
|
25
25
|
["jversion", (JRUBY_VERSION rescue nil)],
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* mysh/internal/actions/vars.rb -- The mysh internal variables commands.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* mysh/internal/actions/vars.rb -- The mysh internal variable commands.
|
7
|
+
class VarsCommand < Action
|
8
|
+
|
9
|
+
#The mysh variable parsing regex.
|
10
|
+
VAR_EXP = %r{(?<name> [a-z][a-z0-9_]*){0}
|
11
|
+
(?<equals> =){0}
|
12
|
+
(?<value> \S.*){0}
|
13
|
+
\$ (\g<name> \s* (\g<equals> \s* \g<value>?)?)?}x
|
14
|
+
|
15
|
+
#Setup an internal action.
|
16
|
+
def initialize(name, description)
|
17
|
+
@name = @equals = @value = nil
|
18
|
+
super(name, description)
|
19
|
+
end
|
20
|
+
|
21
|
+
#Execute a command against the internal mysh variables.
|
22
|
+
def call(str)
|
23
|
+
match = VAR_EXP.match(str.chomp)
|
24
|
+
@name, @equals, @value = match[:name], match[:equals], match[:value]
|
25
|
+
do_command
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
#Do the actual work here.
|
30
|
+
def do_command
|
31
|
+
sym = @name.to_sym if @name
|
32
|
+
|
33
|
+
if @value
|
34
|
+
MNV[sym] = @value
|
35
|
+
elsif @equals
|
36
|
+
MNV[sym] = ""
|
37
|
+
elsif @name
|
38
|
+
puts "#{@name} = #{MNV.get_source(sym)}"
|
39
|
+
else
|
40
|
+
show_all_values
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#Display all variables neatly.
|
45
|
+
def show_all_values
|
46
|
+
puts MNV.keys
|
47
|
+
.sort
|
48
|
+
.map {|sym| ["$" + sym.to_s, MNV.get_source(sym)]}
|
49
|
+
.format_mysh_bullets
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
#The show command action object.
|
55
|
+
desc = 'Set/query mysh variables. See ?$ for more.'
|
56
|
+
VARS_COMMAND = VarsCommand.new('$<name>=value', desc)
|
57
|
+
COMMANDS.add_action(VARS_COMMAND)
|
58
|
+
end
|
@@ -1,37 +1,22 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
#* mysh/internal/decorate.rb -- mysh internal file name beauty treatments.
|
4
|
-
|
4
|
+
class String
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
dress_up_quotes(dress_up_slashes(name))
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
#Dress up slashes and backslashes.
|
17
|
-
def dress_up_slashes(name)
|
18
|
-
backslash? ? name.gsub("/", "\\") : name
|
19
|
-
end
|
20
|
-
|
21
|
-
#Dress up in quotes if needed.
|
22
|
-
#<br>Endemic Code Smells
|
23
|
-
#* :reek:UtilityFunction
|
24
|
-
def dress_up_quotes(name)
|
25
|
-
name[' '] ? "\"#{name}\"" : name
|
26
|
-
end
|
6
|
+
#Make the file name fit the local system.
|
7
|
+
def decorate
|
8
|
+
self.dress_up_slashes
|
9
|
+
.dress_up_quotes
|
10
|
+
end
|
27
11
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
MiniReadline::PLATFORM == :windows
|
33
|
-
end
|
12
|
+
#Dress up slashes and backslashes.
|
13
|
+
def dress_up_slashes
|
14
|
+
MiniReadline::PLATFORM == :windows ? self.gsub("/", "\\") : self
|
15
|
+
end
|
34
16
|
|
17
|
+
#Dress up in quotes if needed.
|
18
|
+
def dress_up_quotes
|
19
|
+
self[' '] ? "\"#{self}\"" : self
|
35
20
|
end
|
36
21
|
|
37
22
|
end
|