mysh 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7927b9f18a9a450e85b27f329ef62a9cc4dc212b
4
- data.tar.gz: d058babe1aadabcb1b63bb5eaa9af689f2674ab5
3
+ metadata.gz: d3adff2eeba99442ae70d9eea972c624906238a1
4
+ data.tar.gz: 828447d5721f3a973e20ef96d6ad7aa6a82dcbc3
5
5
  SHA512:
6
- metadata.gz: 40c991266f6c8b9185d2c635ba496cd3c6ba593744efa299cd088767f03f3be63400b05fafc1a6db31567e447a7fa21fddc9144476b564b85b0eaea7a6902398
7
- data.tar.gz: 96f671dec8eaba3798c5bd807c54ae681c588f69c9b530cda545af70e3c9fff8f0f5481018d3d065cefa7ec9ef26ce89be26c0de9702ea94525baba8dd91fa37
6
+ metadata.gz: ea9d214229c39f0185346032bdcd06b27df9cd241df796b8b427543f593995c4e76706af3f3012625ce335cbf6bb794e9b142aed11f353558505fe19f2822d2c
7
+ data.tar.gz: 5c30d99b23cb66088fa77a2e71ddf24304d03f118a67f7f1e58a2ec33a0e8b36cd9e2bdb1aeb840d5237a2e7e1a7c05d9f8179bb4c8ceb58ed13fea349a433ba
data/README.md CHANGED
@@ -25,6 +25,10 @@ web sites.
25
25
  See the original article at:
26
26
  (http://www.blackbytes.info/2016/07/writing-a-shell-in-ruby/)
27
27
 
28
+ Oh, and one other little thing. A survey of the mysh reveals that it currently
29
+ contains 2291 lines of code. It seems that there has been some growth beyond
30
+ the 25 lines in the original article.
31
+
28
32
  ## Installation
29
33
 
30
34
  Add this line to your application's Gemfile:
@@ -52,21 +56,21 @@ mysh <options>
52
56
 
53
57
  Where the available options are:
54
58
 
55
- Option | Short Form | Description
56
- ---------------------|-------------|---------------------------
57
- --debug | -d | Turn on mysh debugging.
58
- --no-debug | -nd | Turn off mysh debugging.
59
- --help | -? -h | Display mysh usage info and exit.
60
- --init filename | -i filename | Initialize mysh by loading the specified file.
61
- --no-init | -ni | Do not load a file to initialize mysh.
62
- --load filename | -l filename | Load the specified file into the mysh.
63
- --post-prompt "str" | -pp "str" | Set the mysh line continuation prompt to "str".
64
- --no-post-prompt | -npp | Turn off mysh line continuation prompting.
65
- --pre-prompt "str" | -pr "str" | Set the mysh pre prompt to "str".
66
- --no-pre-prompt | -npr | Turn off mysh pre prompting.
67
- --prompt "str" | -p "str" | Set the mysh prompt to "str".
68
- --no-prompt | -np | Turn off mysh prompting.
69
- --quit | | Quit out of the mysh program.
59
+ Option | Short Form(s)| Description | Default
60
+ ---------------------|--------------|-------------------------|-----------
61
+ --debug | -d | Turn on mysh debugging. | false
62
+ --no-debug | -nd | Turn off mysh debugging.
63
+ --help | -? -h | Display mysh usage info and exit.
64
+ --init filename | -i filename | Initialize mysh by loading the specified file. | ~/mysh_init.mysh
65
+ --no-init | -ni | Do not load a file to initialize mysh.
66
+ --load filename | -l filename | Load the specified file into the mysh.
67
+ --post-prompt "str" | -pp "str" | Set the mysh line continuation prompt to "str". | $prompt
68
+ --no-post-prompt | -npp | Turn off mysh line continuation prompting.
69
+ --pre-prompt "str" | -pr "str" | Set the mysh pre prompt to "str". | $w
70
+ --no-pre-prompt | -npr | Turn off mysh pre prompting.
71
+ --prompt "str" | -p "str" | Set the mysh prompt to "str". | mysh
72
+ --no-prompt | -np | Turn off mysh prompting.
73
+ --quit | | Quit out of the mysh program.
70
74
 
71
75
  <br>When mysh is run, the user is presented with a command prompt:
72
76
 
@@ -90,17 +94,26 @@ and acclimated to its environment. The boot/initialization process of mysh is
90
94
  somewhat modeled after (well if I'm honest, more like inspired by) that of the
91
95
  famous bash shell. On startup:
92
96
 
93
- 1. Process pre-boot options. Some command line options are processed early.
94
- These are --help, -h, -?, --init, -i, --no-init, -ni, and --quit. See above
95
- for details on these.
96
- 2. Try to load and execute the mysh init file. There are two possible files
97
- for this role. They are the ~/mysh_init.mysh and ~/mysh_init.rb files. If
98
- both files should be present, the .mysh file is processed and the .rb is
99
- ignored. NOTE: If an init file should be specified with the --init (-i)
100
- option, or disabled with the --no-init (-ni) option, this step is skipped.
101
- 3. The rest of the command line options are processed at this time. Again,
102
- see above for details.
103
-
97
+ 1. Option values are initialized to their initial, default values.
98
+ 2. Process pre-boot command line options: Some command line options are
99
+ processed early. These are --help, -h, -?, --init, -i, --no-init, and -ni.
100
+ See Usage above for details on these.
101
+ 3. Try to load and execute the mysh_init file. There are three possible files
102
+ for this role. They are ~/mysh_init.mysh, ~/mysh_init.rb, and ~/mysh_init.txt.
103
+ In priority, ".mysh" > ".rb" > ".txt". <br>NOTE: If an init file should be
104
+ specified with the --init option, or disabled with the --no-init option, this
105
+ step is skipped.
106
+ 4. The rest of the command line options are processed at this time. Again,
107
+ see Usage above for details.
108
+
109
+ It should be noted that in the event of a conflict in settings during the boot
110
+ process, the last command/option encountered shall prevail. For example if the
111
+ ~/mysh_init.mysh contains the line:
112
+ ```
113
+ $debug = on
114
+ ```
115
+ and the command line has the -nd option, then debug mode will be disabled
116
+ because the -nd command line option is processed after the mysh_init file.
104
117
 
105
118
  ###REPL
106
119
 
@@ -110,6 +123,10 @@ Print and Loop and is used in may utilities like irb, pry and the rails
110
123
  console. To better use mysh, it is good to understand each of these four
111
124
  operating steps.
112
125
 
126
+ For more information on REPLs please see:
127
+ (https://en.wikipedia.org/wiki/Read-eval-print_loop) and
128
+ (https://repl.it/languages/ruby)
129
+
113
130
  ####READ
114
131
 
115
132
  The first step is just to get input from the user. For interactive sessions
@@ -175,7 +192,6 @@ character in the input. These signature characters are:
175
192
  below.
176
193
  * @ to get information about the system, its environment, and the ruby
177
194
  installation. For more information see Shell Info below.
178
-
179
195
  2. Internal Commands - These commands are recognized by having the first word
180
196
  in the input match a word stored in an internal hash of command actions. For
181
197
  more information see Internal Commands below.
@@ -333,8 +349,8 @@ for setting a variable is:
333
349
  $name=value
334
350
 
335
351
  Where:
336
- * name is a word matching the regex: /[a-z][a-z0-9_]*/. Lower case only.
337
- * value is a string, with embedded variables and handlebars.
352
+ * name is a word matching the regex: /[a-z][a-z0-9_]*/. Note: lower case only.
353
+ * value is some text, with optional embedded variables and handlebars.
338
354
 
339
355
  To erase the value of a variable, use:
340
356
 
@@ -490,6 +506,8 @@ environment.
490
506
 
491
507
  Topic | Description
492
508
  ---------|----------------------------------------------------
509
+ version | The version of mysh in use.
510
+ init file| The init file in use or &#60;none found&#62; or &#60;none&#62;.
493
511
  user | The current user name.
494
512
  home | The current home directory.
495
513
  name | The path/name of the mysh program currently executing.
@@ -546,9 +564,11 @@ say <stuff> | Display the text in the command arguments.
546
564
  type file | Display a text file with support for optional embedded handlebars and mysh variables.
547
565
  vls {mask} | Display the loaded modules, matching the optional mask, that have version info.
548
566
 
549
- Note that the load command applied to a mysh script file acts exactly the same
550
- as if the script file were executed directly from the command line. As a
551
- result of this:
567
+ Notes:
568
+ 1. The notation {x} means that x is optional.
569
+ 2. The load command applied to a mysh script file acts exactly the same
570
+ as if the script file were executed directly from the command line. As a
571
+ result of this:
552
572
 
553
573
  ```
554
574
  myfile.mysh
@@ -622,28 +642,51 @@ located at:
622
642
  A survey of the contents of that folder will reveal the nature of these files.
623
643
 
624
644
  New internal commands may also be added in code via the the add_action method
625
- of the InternalCommand class of the Mysh module. The code to do this would look
626
- something like this:
645
+ of the Action class of the Mysh module. There are two ways to do this:
646
+
647
+ * The command may be created as an instance of the Action class with a command
648
+ name, description and a block that contains the action to be performed by this
649
+ command. This block takes one parameter, an input wrapper (see About Command
650
+ Arguments below for details). This approach is best when the command is simple
651
+ enough to fit into a single lambda block of code. Like this template:
627
652
 
628
653
  ```ruby
629
654
  module Mysh
630
- class NewCommand < Action
655
+ command_name = 'new <item>'
656
+ desc = "A succinct description of what this command does."
657
+ action = lambda do |input|
658
+ #Action packed stuff goes here!
659
+ end
660
+
661
+ COMMANDS.add_action(Action.new(command_name, desc, &action))
662
+ end
663
+ ```
631
664
 
665
+
666
+ * The command may be created as an instance of a sub-class of the Action class.
667
+ In this case, only a name and description are needed as the sub-class should
668
+ contain all the needed code. The action method is the process_command and this
669
+ takes one parameter, an input wrapper (see About Command Arguments below for
670
+ details). This approach is required when the command action needs to be spread
671
+ across multiple methods. Like this template:
672
+
673
+ ```ruby
674
+ module Mysh
675
+ class NewCommand < Action
632
676
  #This method is called when the command is executed.
633
- def call(args)
677
+ def process_command(input)
678
+ #Even more action packed stuff goes here!
634
679
  end
635
-
636
680
  end
637
681
 
638
682
  desc = "A succinct description of what this command does."
639
683
  command_name = 'new <item>'
640
684
  COMMANDS.add_action(NewCommand.new(command_name, desc))
641
-
642
685
  end
643
686
  ```
644
687
 
645
- Where:
646
- * command_name is the name of the command with optional argument descriptions
688
+ ##### Command names:
689
+ The name of the command is a string with optional argument descriptions
647
690
  separated with spaces. The command is the first word of this string. For
648
691
  example a command_name of:
649
692
 
@@ -653,22 +696,90 @@ example a command_name of:
653
696
 
654
697
  will create a command called "new" with a title of "new &#60;item&#62;"
655
698
 
656
- * command_description is a string or an array of strings that describe the
657
- command. This serves as the descriptive help for the command. The help display
658
- code handles matters like word wrap automatically.
699
+ ##### Command descriptions:
700
+ A string or an array of strings that describe the command. This serves as the
701
+ descriptive help for the command. The help display code handles matters like
702
+ word wrap automatically.
703
+
704
+ ##### About Command Arguments
705
+
706
+ The process_command method take one parameter that is an instance of the
707
+ InputWrapper class. This class provides several ways to access the parts of the
708
+ command line. These are:
709
+
710
+ Method | Description
711
+ --------------|----------------
712
+ raw | The raw, unprocessed command line text.
713
+ cooked | The command line with variables and handlebars expanded.
714
+ raw_command | The command portion of the raw text.
715
+ quick_command | The quick command of the raw text.
716
+ raw_body | The raw text after the command.
717
+ quick_body | The raw text after the quick command.
718
+ cooked_body | The cooked text after the command.
719
+ parsed | The command and parameters parsed into an array of strings.
720
+ args | The parameters parsed into an array of strings.
721
+
722
+ Note: commands are not normally "cooked". Should this be required
723
+ use the following code snippet:
724
+
725
+ ```ruby
726
+ input.raw.preprocess
727
+ ```
728
+
729
+ ##### Some Useful Helper Methods
730
+
731
+ Within the mysh environment, there exists a number of methods designed to make
732
+ life easier in adding new commands or in load ruby files or embedded into
733
+ handlebars. Some of these more noteworthy methods are listed below:
734
+
735
+ ###### MNV[:name]
736
+ Retrieve the mysh variable "$name"
659
737
 
660
- #### About command args
738
+ ###### MNV[:name]="value"
739
+ Set/Update the mysh variable "$name". Note that the value is always a string,
740
+ even for things like "true" and "false". If the value is an empty string, the
741
+ variable is deleted.
661
742
 
662
- The call method take one parameter called args. The args parameter is an array
663
- of zero or more arguments that were entered with the command.
743
+ ###### mysh "string"
744
+ Execute the string as a mysh command.
664
745
 
665
- So if a command is given
746
+ ###### Mysh.parse_args("string")
747
+ Parse the string into an array of arguments.
666
748
 
667
- command abc "this is a string" 23 --launch --all
749
+ ###### Mysh.input.readline(parms)
750
+ Get a line of input from the console. See the mini_readline gem for info
751
+ on the optional parms.
668
752
 
669
- the args array will contain:
753
+ ###### "string".preprocess(context=mysh_default_context)
754
+ Process the string for embedded variables and handlebars. By default,
755
+ any embedded ruby is evaluated in the mysh global expression binding. However,
756
+ another BindingWrapper instance may be passed to access an alternative binding.
670
757
 
671
- ["abc", "this is a string", "23", "--launch", "--all"]
758
+ ###### "string".decorate
759
+ Given a string with a file spec, decorate that string so that it is more
760
+ pleasing to the local environment. This is a great boon to writing effortless
761
+ portable code.
762
+
763
+ #### Adding Help Topics
764
+
765
+ In mysh, help topics are generally implemented as text files often augmented
766
+ with embedded mysh variables and ruby code. It it noteworthy however that they
767
+ can also be mysh script or ruby code files. The management of these help files
768
+ is located in the file:
769
+ ```
770
+ mysh/lib/mysh/internal/actions/help/sub_help.rb
771
+ ```
772
+ In this file, you can locate a variable called "help". This is an array of
773
+ arrays where each line describes a help topic. Within each line is a further
774
+ array of three strings. Respectively these are:
775
+ 1. The name of the help item.
776
+ 2. A brief description of the help topic. This line is used in the help on help
777
+ (??) topic.
778
+ 3. The name of the file, **with its extension**, that contains the actual help
779
+ information.
780
+
781
+ To add a new help topic, simply add the new help file to the help folder and
782
+ and a corresponding line entry to to the help variable.
672
783
 
673
784
  ## Contributing
674
785
 
@@ -676,7 +787,7 @@ All participation is welcomed. There are two fabulous plans to choose from:
676
787
 
677
788
  #### Plan A
678
789
 
679
- 1. Fork it ( https://github.com/PeterCamilleri/mysh/fork )
790
+ 1. Fork it (https://github.com/PeterCamilleri/mysh/fork)
680
791
  2. Switch to the development branch ('git branch development')
681
792
  3. Create your feature branch ('git checkout -b my-new-feature')
682
793
  4. Commit your changes ('git commit -am "Add some feature"')
@@ -7,11 +7,13 @@ require 'in_array'
7
7
 
8
8
  require_relative 'mysh/exceptions'
9
9
  require_relative 'mysh/binding_wrapper'
10
+ require_relative 'mysh/input_wrapper'
10
11
  require_relative 'mysh/user_input'
11
- require_relative 'mysh/quick'
12
12
  require_relative 'mysh/expression'
13
13
  require_relative 'mysh/internal'
14
- require_relative 'mysh/external_ruby'
14
+ require_relative 'mysh/quick'
15
+ require_relative 'mysh/external'
16
+ require_relative 'mysh/system'
15
17
  require_relative 'mysh/handlebars'
16
18
  require_relative 'mysh/shell_variables'
17
19
  require_relative 'mysh/pre_processor'
@@ -1,20 +1,20 @@
1
1
  # coding: utf-8
2
2
 
3
- #* mysh/external_ruby.rb -- Support for executing Ruby files with the ruby interpreter.
3
+ #* mysh/external.rb -- Support for executing external files.
4
4
  module Mysh
5
5
 
6
- #Try to execute as a Ruby program.
6
+ #Try to execute an external file.
7
7
  #<br>Endemic Code Smells
8
8
  #* :reek:TooManyStatements
9
- def self.try_execute_external_ruby(str)
10
- args = parse_args(str.chomp)
9
+ def self.try_execute_external(input)
10
+ args = input.parsed
11
11
  file_name = args.shift
12
12
 
13
13
  if (file_name)
14
14
  ext = File.extname(file_name)
15
15
 
16
16
  if ext == '.rb'
17
- new_command = "#{RbConfig.ruby} #{str}"
17
+ new_command = "#{RbConfig.ruby} #{input.cooked}"
18
18
  puts "=> #{new_command}" if MNV[:debug]
19
19
  system(new_command)
20
20
  :ruby_exec
@@ -22,8 +22,7 @@ module Mysh
22
22
  Mysh.process_file(file_name)
23
23
  :mysh_script
24
24
  elsif ext == '.txt'
25
- exec_host = BindingWrapper.new(binding)
26
- show_handlebar_file(file_name, exec_host)
25
+ show_handlebar_file(file_name, BindingWrapper.new(binding))
27
26
  :internal
28
27
  end
29
28
  end
@@ -8,7 +8,7 @@ class Object
8
8
  #Show a file with embedded ruby handlebars.
9
9
  #<br>Note:
10
10
  #The message receiver is the evaluation host for the handlebar code.
11
- def show_handlebar_file(name, evaluator)
11
+ def show_handlebar_file(name, evaluator = $mysh_exec_host)
12
12
  puts eval_handlebar_file(name, evaluator)
13
13
  end
14
14
 
@@ -9,18 +9,23 @@ module Mysh
9
9
  #Perform init phase processing.
10
10
  def self.mysh_load_init
11
11
 
12
- unless $mysh_init_file || !(home = ENV['HOME'])
13
- name_mysh = home + '/mysh_init.mysh'
14
- name_rb = home + '/mysh_init.rb'
15
-
16
- if File.file?(name_mysh)
17
- process_file($mysh_init_file = name_mysh)
18
- elsif File.file?(name_rb)
19
- load ($mysh_init_file = name_rb)
12
+ unless $mysh_init_file
13
+
14
+ if (home = ENV['HOME'])
15
+ names = [home + '/mysh_init.mysh',
16
+ home + '/mysh_init.rb',
17
+ home + '/mysh_init.txt']
18
+
19
+ $mysh_init_file = names.detect {|name| File.file?(name)}
20
+ end
21
+
22
+ if $mysh_init_file
23
+ mysh "load #{$mysh_init_file.decorate}"
24
+ else
25
+ $mysh_init_file = '<none found>'
20
26
  end
21
27
  end
22
28
 
23
- $mysh_init_file = '<none found>' unless $mysh_init_file
24
29
  end
25
30
 
26
31
  end
@@ -0,0 +1,67 @@
1
+ # coding: utf-8
2
+
3
+ #* mysh/internal/input_wrapper.rb -- An action compatible wrapper for a input.
4
+ module Mysh
5
+
6
+ #* mysh/internal/input_wrapper.rb -- An action compatible wrapper for a input.
7
+ class InputWrapper
8
+
9
+ #Build an input wrapper.
10
+ def initialize(raw)
11
+ @raw = raw.chomp
12
+ @raw_command = @raw_body = nil
13
+ end
14
+
15
+ #Access the raw text.
16
+ attr_reader :raw
17
+
18
+ #Get the first raw character.
19
+ def quick_command
20
+ @raw[0] || ""
21
+ end
22
+
23
+ #Get the balance of the raw string.
24
+ def quick_body
25
+ @raw[1..-1] || ""
26
+ end
27
+
28
+ #Get the command word if it exists.
29
+ def raw_command
30
+ @raw_command ||= @raw.split[0] || ""
31
+ end
32
+
33
+ #Get the parameter text.
34
+ def raw_body
35
+ @raw_body ||= @raw[(raw_command.length)..-1]
36
+ end
37
+
38
+ #Get the preprocessed argument text.
39
+ def cooked_body
40
+ raw_body.preprocess
41
+ end
42
+
43
+ #Access the massaged text.
44
+ def cooked
45
+ raw_command + cooked_body
46
+ end
47
+
48
+ #Get the parsed arguments
49
+ def args
50
+ Mysh.parse_args(cooked_body)
51
+ end
52
+
53
+ #Get the parsed command line.
54
+ def parsed
55
+ [raw_command] + args
56
+ end
57
+
58
+ #Set up input for a quick style command.
59
+ def quick
60
+ @raw_command = quick_command
61
+ @raw_body = quick_body
62
+ self
63
+ end
64
+
65
+ end
66
+
67
+ end