mysh 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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($mysh_exec_host.eval_handlebars(get_command("mysh")))
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, err.backtrace
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) ||
@@ -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
- rescue Interrupt, StandardError, ScriptError => err
33
- puts "#{err.class.to_s}: #{err}"
34
- ensure
35
- return :expression
31
+ :expression
36
32
  end
37
33
 
38
- private
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
@@ -9,7 +9,7 @@ module Mysh
9
9
 
10
10
  if cmd && File.extname(cmd) == '.rb'
11
11
  new_command = "#{RbConfig.ruby} #{str}"
12
- puts "=> #{new_command}"
12
+ puts "=> #{new_command}" if MNV[:debug]
13
13
  system(new_command)
14
14
  :ruby_exec
15
15
  end
@@ -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
@@ -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
@@ -24,7 +24,7 @@ module Mysh
24
24
  def add_action(action)
25
25
  split_name = action.name.split[0] || ""
26
26
 
27
- if @pool.has_key?(split_name)
27
+ if @pool.key?(split_name)
28
28
  fail "Add error: Action #{split_name.inspect} already exists in #{pool_name}."
29
29
  end
30
30
 
@@ -9,9 +9,10 @@ module Mysh
9
9
  #Execute the cd command.
10
10
  def call(args)
11
11
  Dir.chdir(args[0]) unless args.empty?
12
- puts decorate(Dir.pwd)
12
+ puts Dir.pwd.decorate
13
13
  rescue => err
14
14
  puts "Error: #{err}"
15
+ puts err.backtrace if MNV[:debug]
15
16
  end
16
17
 
17
18
  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 or on the
4
- command line through the use of handlebars. Handlebars look like this:
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
- mysh>echo \{\{ (1..10).map {|i| i.to_s}.join(" ") \}\} > foo.txt
12
- mysh>type foo.txt
13
- 1 2 3 4 5 6 7 8 9 10
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
- mysh>=a="A very long string indeed!"
20
- "A very long string indeed!"
21
- mysh>echo \{\{ a \}\}
22
- A very long string indeed!
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
- embedded
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 baclslash character
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.
@@ -28,4 +28,5 @@ Quick exit mysh | Ctrl-z | Alt-z
28
28
  Notes:
29
29
  Windows keys are aliased through the numeric key pad unless NumLock is on.
30
30
  Mac/Linux mappings may use Escape letter if Alt-letter is unavailable.
31
+ Cygwin systems use the Mac/Linux mappings.
31
32
 
@@ -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
- ['!', 'This help on the history command.', 'history.txt'],
34
- ['history', 'This help on the history command.', 'history.txt'],
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
+
@@ -8,7 +8,7 @@ module Mysh
8
8
 
9
9
  #Execute the cd command.
10
10
  def call(_args)
11
- puts decorate(Dir.pwd)
11
+ puts Dir.pwd.decorate
12
12
  end
13
13
 
14
14
  end
@@ -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", decorate($PROGRAM_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", decorate(RbConfig.ruby)],
22
+ [["location", RbConfig.ruby.decorate],
23
23
  ["description", RUBY_DESCRIPTION],
24
24
  ["version", RUBY_VERSION],
25
25
  ["jversion", (JRUBY_VERSION rescue nil)],
@@ -13,7 +13,7 @@ module Mysh
13
13
  @exec_binding = binding
14
14
 
15
15
  if file_name
16
- show_handlebar_file(file_name)
16
+ show_handlebar_file(file_name, self)
17
17
  else
18
18
  puts "Error: A text file must be specified."
19
19
  end
@@ -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
- module Mysh
4
+ class String
5
5
 
6
- #* mysh/internal/decorate.rb -- The mysh internal file name beauty treatments.
7
- class Action
8
-
9
- #Make the file name fit the local system.
10
- def decorate(name)
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
- #Does this file name use backslashes?
29
- #<br>Endemic Code Smells
30
- #* :reek:UtilityFunction
31
- def backslash?
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