mysh 0.1.16 → 0.1.17
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 +19 -12
- data/lib/mysh.rb +1 -1
- data/lib/mysh/expression.rb +5 -13
- data/lib/mysh/expression/lineage.rb +2 -2
- data/lib/mysh/internal.rb +1 -1
- data/lib/mysh/internal/action.rb +19 -6
- data/lib/mysh/internal/action_pool.rb +14 -10
- data/lib/mysh/internal/actions/actions_path.rb +2 -2
- data/lib/mysh/internal/actions/gls.rb +19 -0
- data/lib/mysh/internal/actions/help.rb +8 -5
- data/lib/mysh/internal/actions/{help.txt → help/help.txt} +2 -2
- data/lib/mysh/internal/actions/{help_expr.txt → help/help_expr.txt} +4 -5
- data/lib/mysh/internal/actions/{help_help.txt → help/help_help.txt} +1 -1
- data/lib/mysh/internal/actions/{help_math.txt → help/help_math.txt} +0 -0
- data/lib/mysh/internal/actions/show.rb +27 -0
- data/lib/mysh/internal/actions/vls.rb +22 -0
- data/lib/mysh/internal/format.rb +12 -17
- data/lib/mysh/internal/format/array.rb +56 -0
- data/lib/mysh/internal/format/bullets.rb +15 -71
- data/lib/mysh/internal/format/columns.rb +122 -0
- data/lib/mysh/internal/format/object.rb +13 -0
- data/lib/mysh/internal/format/string.rb +46 -0
- data/lib/mysh/internal/manage.rb +7 -7
- data/lib/mysh/user_input/handlebars.rb +1 -1
- data/lib/mysh/version.rb +2 -2
- data/samples/show.txt +11 -0
- data/{test.rb → samples/test.rb} +0 -0
- data/tests/my_shell_tests.rb +66 -0
- metadata +16 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3c002087bb9289b3a21c696dbec4cf5eb0c2aad
|
4
|
+
data.tar.gz: 89e63a29c1c26f4f84372cfa34995e820c3cf726
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eab8e85ede1899c6d87a457141a7664421fb9171e5175b5b3c82ac9181d4ce6838db03fe3c9f4334bbf61c9ca190524cfeddf859edefdd70c8171d65d296822a
|
7
|
+
data.tar.gz: 0a8e2f49879875648bf8435e9011c4188f4f05802b95a20a6045e95b6f5583b33b9cf1f526579f91c90d33871c387ff6796eccf154635710d3a3ad26a04b5130
|
data/README.md
CHANGED
@@ -19,7 +19,7 @@ Since that name was available, it would seem that no one had yet written a
|
|
19
19
|
shell program at this level of narcissism.
|
20
20
|
|
21
21
|
The mysh is available as both a stand-alone CLI program and for use as a
|
22
|
-
command shell within Ruby applications and Rails web sites.
|
22
|
+
command shell within Ruby applications and (eventually) Rails web sites.
|
23
23
|
|
24
24
|
See the original article at:
|
25
25
|
(http://www.blackbytes.info/2016/07/writing-a-shell-in-ruby/)
|
@@ -75,8 +75,6 @@ A few noteworthy methods exist that facilitate use of Ruby expressions:
|
|
75
75
|
reset Reset the execution environment to the default state.
|
76
76
|
result Returns the result of the previous expression.
|
77
77
|
x.lineage Get the class lineage of the object x.
|
78
|
-
vls "mask" List modules with version info. The optional mask string value is
|
79
|
-
used to filter for modules containing that string.
|
80
78
|
```
|
81
79
|
|
82
80
|
The Ruby expression execution environment has direct access to many advanced
|
@@ -127,15 +125,18 @@ Internal commands are recognized by name and are executed by mysh directly.
|
|
127
125
|
The following set of commands are supported:
|
128
126
|
|
129
127
|
```
|
130
|
-
!
|
131
|
-
?
|
132
|
-
cd <dir>
|
133
|
-
|
134
|
-
exit
|
135
|
-
help
|
136
|
-
history
|
137
|
-
pwd
|
138
|
-
quit
|
128
|
+
! Display the mysh command history.
|
129
|
+
? <topic> Display help information for mysh with an optional topic.
|
130
|
+
cd <dir> Change directory to the optional <dir> parameter and then display
|
131
|
+
the current working directory.
|
132
|
+
exit Exit mysh.
|
133
|
+
help <topic> Display help information for mysh with an optional topic.
|
134
|
+
history Display the mysh command history.
|
135
|
+
pwd Display the current working directory.
|
136
|
+
quit Exit mysh.
|
137
|
+
show <file> Display a text file with optional embedded handlebars.
|
138
|
+
vls <mask> Display the loaded modules, matching the optional mask, that have
|
139
|
+
version info.
|
139
140
|
```
|
140
141
|
Of note is the command "help help" which provides a list of available topics.
|
141
142
|
|
@@ -238,7 +239,13 @@ module Mysh
|
|
238
239
|
end
|
239
240
|
end
|
240
241
|
```
|
242
|
+
#### Add Method Return Values
|
243
|
+
Both the add and add_alias methods return the newly created action instance.
|
244
|
+
This may be useful, for example, if it is desired to add singleton methods to
|
245
|
+
the action in order to extend functionality.
|
241
246
|
|
247
|
+
Note that when an action is aliased, none of the singleton methods are copied
|
248
|
+
across and these will have to be regenerated in the new action object.
|
242
249
|
|
243
250
|
## Contributing
|
244
251
|
|
data/lib/mysh.rb
CHANGED
data/lib/mysh/expression.rb
CHANGED
@@ -34,24 +34,16 @@ module Mysh
|
|
34
34
|
ExecHost.exec_binding = binding
|
35
35
|
end
|
36
36
|
|
37
|
-
#Process an expression.
|
38
|
-
def execute(str)
|
39
|
-
if str.start_with?('=')
|
40
|
-
do_execute(str)
|
41
|
-
:expression
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
37
|
#Do the actual work of executing an expression.
|
48
|
-
def
|
38
|
+
def execute(str)
|
49
39
|
self.result = exec_binding.eval(str[1..-1])
|
50
40
|
send(result ? :pp : :puts, result)
|
51
41
|
rescue Interrupt, StandardError, ScriptError => err
|
52
42
|
puts "#{err.class.to_s}: #{err}"
|
53
43
|
end
|
54
44
|
|
45
|
+
private
|
46
|
+
|
55
47
|
#Get the execute binding.
|
56
48
|
def exec_binding
|
57
49
|
self.class.exec_binding
|
@@ -73,8 +65,8 @@ module Mysh
|
|
73
65
|
nil
|
74
66
|
end
|
75
67
|
|
76
|
-
#
|
77
|
-
def
|
68
|
+
#Evaluate the string in the my shell context.
|
69
|
+
def mysh_eval(str)
|
78
70
|
exec_binding.eval(str)
|
79
71
|
end
|
80
72
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
#Object monkey patch for the mysh lineage
|
3
|
+
#Object monkey patch for the mysh lineage method.
|
4
4
|
class Object
|
5
5
|
|
6
6
|
#Get the lineage of this object.
|
@@ -11,7 +11,7 @@ class Object
|
|
11
11
|
|
12
12
|
end
|
13
13
|
|
14
|
-
#Class monkey patch for the mysh lineage
|
14
|
+
#Class monkey patch for the mysh lineage method.
|
15
15
|
class Class
|
16
16
|
|
17
17
|
#Get the lineage of this class.
|
data/lib/mysh/internal.rb
CHANGED
data/lib/mysh/internal/action.rb
CHANGED
@@ -5,30 +5,43 @@ module Mysh
|
|
5
5
|
|
6
6
|
#The mysh internal action class.
|
7
7
|
class Action
|
8
|
-
#The name of the
|
8
|
+
#The name of the action.
|
9
9
|
attr_reader :name
|
10
10
|
|
11
|
-
#The description of the
|
11
|
+
#The description of the action.
|
12
12
|
attr_reader :description
|
13
13
|
|
14
|
-
#The action of the
|
14
|
+
#The action of the action.
|
15
15
|
attr_reader :action
|
16
16
|
|
17
|
-
#Setup an internal
|
17
|
+
#Setup an internal action.
|
18
18
|
def initialize(name, description, &action)
|
19
19
|
@name, @description, @action = name, description.in_array, action
|
20
|
+
@exec_binding = mysh_binding
|
20
21
|
end
|
21
22
|
|
22
|
-
#Execute the
|
23
|
+
#Execute the action.
|
23
24
|
def execute(args)
|
24
25
|
instance_exec(args, &@action)
|
25
26
|
end
|
26
27
|
|
27
|
-
#Get information about the
|
28
|
+
#Get information about the action.
|
28
29
|
def action_info
|
29
30
|
[@name].concat(@description)
|
30
31
|
end
|
31
32
|
|
33
|
+
private
|
34
|
+
|
35
|
+
#Create a binding for mysh to execute expressions in.
|
36
|
+
def mysh_binding
|
37
|
+
binding
|
38
|
+
end
|
39
|
+
|
40
|
+
#Evaluate the string in the my shell context.
|
41
|
+
def mysh_eval(str)
|
42
|
+
@exec_binding.eval(str)
|
43
|
+
end
|
44
|
+
|
32
45
|
end
|
33
46
|
|
34
47
|
end
|
@@ -6,9 +6,12 @@ module Mysh
|
|
6
6
|
#* A managed hash of mysh actions.
|
7
7
|
class ActionPool
|
8
8
|
|
9
|
+
#The name of this action pool.
|
10
|
+
attr_reader :pool_name
|
11
|
+
|
9
12
|
#Create a new action pool
|
10
|
-
def initialize(&default_action)
|
11
|
-
@pool = {}
|
13
|
+
def initialize(pool_name, &default_action)
|
14
|
+
@pool_name, @pool = pool_name, {}
|
12
15
|
|
13
16
|
if default_action
|
14
17
|
@pool.default = Action.new("", "", &default_action)
|
@@ -24,27 +27,28 @@ module Mysh
|
|
24
27
|
def add(name, description, &action)
|
25
28
|
split_name = name.split[0] || ""
|
26
29
|
|
30
|
+
if @pool.has_key?(split_name)
|
31
|
+
fail "Add error: Action #{split_name.inspect} already exists in #{pool_name}."
|
32
|
+
end
|
33
|
+
|
27
34
|
@pool[split_name] = Action.new(name, description, &action)
|
28
35
|
end
|
29
36
|
|
30
37
|
#Add an alias for an existing action.
|
31
38
|
def add_alias(new_name, old_name)
|
32
|
-
unless (action = @pool[old_name])
|
33
|
-
fail "
|
39
|
+
unless (action = @pool[old_name.split[0]])
|
40
|
+
fail "Alias error: Action #{old_name.inspect} not found in #{pool_name}"
|
34
41
|
end
|
35
42
|
|
36
|
-
|
37
|
-
|
38
|
-
@pool[split_name] =
|
39
|
-
Action.new(new_name, action.description, &action.action)
|
43
|
+
add(new_name, action.description, &action.action)
|
40
44
|
end
|
41
45
|
|
42
46
|
#Get information on all actions.
|
43
47
|
def actions_info
|
44
48
|
@pool
|
45
49
|
.values
|
46
|
-
.map {|action| action.action_info
|
47
|
-
.sort {|first, second| first[0] <=> second[0]
|
50
|
+
.map {|action| action.action_info}
|
51
|
+
.sort {|first, second| first[0] <=> second[0]}
|
48
52
|
end
|
49
53
|
|
50
54
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
#* internal/actions/actions_path.rb -- A convenient hook to the
|
3
|
+
#* internal/actions/actions_path.rb -- A convenient hook to the actions folder.
|
4
4
|
module Mysh
|
5
5
|
|
6
|
-
#* internal/actions/actions_path.rb -- A convenient hook to the
|
6
|
+
#* internal/actions/actions_path.rb -- A convenient hook to the actions folder.
|
7
7
|
class Action
|
8
8
|
|
9
9
|
#Capture this folder's name.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* internal/actions/gls.rb -- The mysh gem ls command.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* internal/actions/gls.rb -- The mysh gem ls command.
|
7
|
+
class Action
|
8
|
+
|
9
|
+
desc = 'Display the loaded ruby gems.'
|
10
|
+
|
11
|
+
COMMANDS.add('gls <mask>', desc) do |args|
|
12
|
+
puts Gem.loaded_specs.keys.sort.join(" ")
|
13
|
+
puts
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
@@ -7,24 +7,24 @@ module Mysh
|
|
7
7
|
class Action
|
8
8
|
|
9
9
|
# Help topics
|
10
|
-
HELP = ActionPool.new do |args|
|
10
|
+
HELP = ActionPool.new("HELP") do |args|
|
11
11
|
puts "No help found for #{args[0].inspect}."
|
12
12
|
end
|
13
13
|
|
14
14
|
HELP.add("", "General help on mysh.") do |args|
|
15
|
-
show_handlebar_file(ACTIONS_PATH + 'help.txt')
|
15
|
+
show_handlebar_file(ACTIONS_PATH + 'help/help.txt')
|
16
16
|
end
|
17
17
|
|
18
18
|
HELP.add("math", "Help on mysh math functions.") do |args|
|
19
|
-
show_handlebar_file(ACTIONS_PATH + 'help_math.txt')
|
19
|
+
show_handlebar_file(ACTIONS_PATH + 'help/help_math.txt')
|
20
20
|
end
|
21
21
|
|
22
22
|
HELP.add("=", "Help on mysh ruby expressions.") do |args|
|
23
|
-
show_handlebar_file(ACTIONS_PATH + 'help_expr.txt')
|
23
|
+
show_handlebar_file(ACTIONS_PATH + 'help/help_expr.txt')
|
24
24
|
end
|
25
25
|
|
26
26
|
HELP.add("help", "Help on mysh help.") do |args|
|
27
|
-
show_handlebar_file(ACTIONS_PATH + 'help_help.txt')
|
27
|
+
show_handlebar_file(ACTIONS_PATH + 'help/help_help.txt')
|
28
28
|
end
|
29
29
|
|
30
30
|
HELP.add_alias('?', 'help')
|
@@ -42,3 +42,6 @@ module Mysh
|
|
42
42
|
|
43
43
|
end
|
44
44
|
|
45
|
+
#Load up the extra help actions!
|
46
|
+
Dir[Mysh::Action::ACTIONS_PATH + 'help/*.rb'].each {|file| require file }
|
47
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
mysh
|
1
|
+
mysh version: {{ Mysh::VERSION }}
|
2
2
|
|
3
3
|
The mysh is a shell program inspired by the Ruby programming language in the
|
4
4
|
same way the csh was inspired by the "C" programming language.
|
@@ -11,7 +11,7 @@ In mysh, commands fall into one of three broad categories. There are:
|
|
11
11
|
2) Internal mysh commands are processed within mysh itself. The following set
|
12
12
|
of commands are supported:
|
13
13
|
|
14
|
-
{{
|
14
|
+
{{ Mysh::COMMANDS.actions_info.mysh_bulletize.join("\n") }}
|
15
15
|
|
16
16
|
3) All other commands are executed by the system using the standard shell or
|
17
17
|
the appropriate ruby interpreter. If the command has a '.rb' extension, it
|
@@ -16,11 +16,10 @@ string parameters.
|
|
16
16
|
|
17
17
|
A few special methods exist:
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
used to filter for modules containing that string.
|
19
|
+
reset Reset the execution environment to the default state.
|
20
|
+
result Returns the result of the previous expression.
|
21
|
+
x.lineage Get the class lineage of the object or class x.
|
22
|
+
|
24
23
|
|
25
24
|
Also included are a number of math methods. See '? math' for more on these.
|
26
25
|
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* internal/actions/show.rb -- The mysh show command.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* internal/actions/show.rb -- The mysh show command.
|
7
|
+
class Action
|
8
|
+
|
9
|
+
# The base help command.
|
10
|
+
desc = 'Display a text file with optional embedded handlebars.'
|
11
|
+
|
12
|
+
COMMANDS.add('show <file>', desc) do |args|
|
13
|
+
file_name = args.shift
|
14
|
+
|
15
|
+
@exec_binding = binding
|
16
|
+
|
17
|
+
if file_name
|
18
|
+
show_handlebar_file(file_name)
|
19
|
+
else
|
20
|
+
puts "Error: A text file must be specified."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* internal/actions/vls.rb -- The mysh module version ls command.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#* internal/actions/vls.rb -- The mysh module version ls command.
|
7
|
+
class Action
|
8
|
+
|
9
|
+
desc = 'Display the loaded modules, matching the optional mask, ' +
|
10
|
+
'that have version info.'
|
11
|
+
|
12
|
+
COMMANDS.add('vls <mask>', desc) do |args|
|
13
|
+
mask = args.shift || /./
|
14
|
+
|
15
|
+
puts VersionLS.vls(mask).mysh_bulletize.join("\n")
|
16
|
+
puts
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
data/lib/mysh/internal/format.rb
CHANGED
@@ -1,24 +1,19 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
#The mysh internal command class level report formatting.
|
6
|
-
class Object
|
7
|
-
|
8
|
-
private
|
3
|
+
#* internal/format.rb - Some formatting facilities for mysh.
|
4
|
+
module Mysh
|
9
5
|
|
10
|
-
#
|
11
|
-
|
12
|
-
items.puts_mysh_bullets
|
13
|
-
puts
|
14
|
-
end
|
6
|
+
#Assume an 80 column working area for formatting.
|
7
|
+
PAGE_WIDTH = 80
|
15
8
|
|
16
|
-
#
|
17
|
-
|
18
|
-
#* :reek:FeatureEnvy :reek:UtilityFunction
|
19
|
-
def format_items(items)
|
20
|
-
items.mysh_bulletize
|
21
|
-
end
|
9
|
+
#Assume an in infinite page length for formatting.
|
10
|
+
PAGE_LENGTH = false
|
22
11
|
|
23
12
|
end
|
24
13
|
|
14
|
+
require_relative 'format/bullets'
|
15
|
+
require_relative 'format/columns'
|
16
|
+
require_relative 'format/array'
|
17
|
+
require_relative 'format/string'
|
18
|
+
require_relative 'format/object'
|
19
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* internal/format/array.rb - Support for displaying an array formatted neatly.
|
4
|
+
class Array
|
5
|
+
|
6
|
+
# Columns ========================================================
|
7
|
+
|
8
|
+
#Print out the array with efficient columns.
|
9
|
+
def puts_mysh_columns(page_width = Mysh::PAGE_WIDTH)
|
10
|
+
|
11
|
+
puts format_mysh_columns(page_width)
|
12
|
+
end
|
13
|
+
|
14
|
+
#Convert the array to strings with efficient columns.
|
15
|
+
#<br>Returns
|
16
|
+
#* An array of pages, that is, arrays of strings.
|
17
|
+
def format_mysh_columns(page_width = Mysh::PAGE_WIDTH)
|
18
|
+
builder = Mysh::ColumnizedPage.new(Mysh::PAGE_LENGTH, page_width)
|
19
|
+
|
20
|
+
self.each {|item| builder.add(item)}
|
21
|
+
|
22
|
+
builder.render
|
23
|
+
end
|
24
|
+
|
25
|
+
alias :format_description :format_mysh_columns
|
26
|
+
|
27
|
+
#Get the widest element of an array.
|
28
|
+
#<br>Returns
|
29
|
+
#* The width of the widest string in the array.
|
30
|
+
def mysh_column_width
|
31
|
+
(self.max_by {|item| item.length}).length
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# Bullets ========================================================
|
36
|
+
|
37
|
+
#Print out the array as bullet points.
|
38
|
+
def puts_mysh_bullets
|
39
|
+
puts mysh_bulletize
|
40
|
+
end
|
41
|
+
|
42
|
+
#Convert the array to strings with bullet points.
|
43
|
+
#<br>
|
44
|
+
#* An array of strings
|
45
|
+
def mysh_bulletize(page_width = Mysh::PAGE_WIDTH)
|
46
|
+
builder = Mysh::BulletPoints.new(page_width)
|
47
|
+
|
48
|
+
self.each do |pair|
|
49
|
+
builder.add(*pair)
|
50
|
+
end
|
51
|
+
|
52
|
+
builder.render
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
@@ -6,33 +6,21 @@ module Mysh
|
|
6
6
|
#A class to display data in bullet points.
|
7
7
|
class BulletPoints
|
8
8
|
|
9
|
-
#Assume an 80 column working area.
|
10
|
-
PAGE_WIDTH = 80
|
11
|
-
|
12
9
|
#Prepare a blank slate.
|
13
|
-
def initialize
|
10
|
+
def initialize(page_width)
|
11
|
+
@page_width = page_width
|
14
12
|
@bullet_data = []
|
15
13
|
end
|
16
14
|
|
17
|
-
#Add
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
if raw_item.empty?
|
23
|
-
bullet = ["*"]
|
24
|
-
items = raw_bullet.in_array
|
25
|
-
else
|
26
|
-
bullet = [raw_bullet]
|
27
|
-
items = raw_item.in_array
|
28
|
-
end
|
29
|
-
|
30
|
-
items.each_index do |index|
|
31
|
-
@bullet_data << [(bullet[index] || "").to_s, items[index].to_s]
|
15
|
+
#Add items to these bullet points.
|
16
|
+
def add(bullet, *items)
|
17
|
+
items.each do |item|
|
18
|
+
@bullet_data << [bullet.to_s, item]
|
19
|
+
bullet = ""
|
32
20
|
end
|
33
21
|
end
|
34
22
|
|
35
|
-
#Render the
|
23
|
+
#Render the bullet points as an array of strings.
|
36
24
|
def render
|
37
25
|
@key_length, results = get_key_length, []
|
38
26
|
|
@@ -46,68 +34,24 @@ module Mysh
|
|
46
34
|
|
47
35
|
private
|
48
36
|
|
49
|
-
#
|
37
|
+
#Allowing for a trailing space, how large is the largest bullet?
|
50
38
|
def get_key_length
|
51
|
-
(@bullet_data.max_by {|line| line[0].length})[0].length
|
39
|
+
(@bullet_data.max_by {|line| line[0].length})[0].length + 1
|
52
40
|
end
|
53
41
|
|
54
42
|
#Render one bullet point.
|
55
|
-
#<br>Endemic Code Smells
|
56
|
-
#* :reek:DuplicateMethodCall :reek:TooManyStatements
|
57
43
|
def render_bullet(key, item)
|
58
|
-
result
|
59
|
-
input = item.split(' ').each
|
60
|
-
temp = key.ljust(len = @key_length)
|
44
|
+
result = []
|
61
45
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
while len >= PAGE_WIDTH
|
66
|
-
result << temp.slice!(0, PAGE_WIDTH - 1)
|
67
|
-
temp = blank_key + ' ' + temp
|
68
|
-
len = temp.length
|
69
|
-
end
|
70
|
-
|
71
|
-
if ((len += word.length) >= PAGE_WIDTH) && !pass_one
|
72
|
-
result << temp
|
73
|
-
temp = blank_key + word
|
74
|
-
len = temp.length
|
75
|
-
else
|
76
|
-
temp << word
|
77
|
-
pass_one = false
|
78
|
-
end
|
46
|
+
item.format_description(@page_width - @key_length - 1).each do |desc_line|
|
47
|
+
result << key.ljust(@key_length) + desc_line
|
48
|
+
key = ""
|
79
49
|
end
|
80
50
|
|
81
|
-
result
|
82
|
-
end
|
83
|
-
|
84
|
-
#Generate a blank bullet key
|
85
|
-
def blank_key
|
86
|
-
' ' * @key_length
|
51
|
+
result
|
87
52
|
end
|
88
53
|
|
89
54
|
end
|
90
55
|
|
91
56
|
end
|
92
57
|
|
93
|
-
#Bullet point support in the Array class.
|
94
|
-
class Array
|
95
|
-
#Print out the array as bullet points.
|
96
|
-
def puts_mysh_bullets
|
97
|
-
puts mysh_bulletize
|
98
|
-
end
|
99
|
-
|
100
|
-
#Convert the array to strings with bullet points.
|
101
|
-
#<br>
|
102
|
-
#* An array of arrays of strings
|
103
|
-
def mysh_bulletize
|
104
|
-
builder = Mysh::BulletPoints.new
|
105
|
-
|
106
|
-
self.each do |pair|
|
107
|
-
builder.add(*pair)
|
108
|
-
end
|
109
|
-
|
110
|
-
builder.render
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* internal/format/bullets.rb - Print out data in neat columns.
|
4
|
+
module Mysh
|
5
|
+
|
6
|
+
#A class to display data in columns.
|
7
|
+
class ColumnizedPage
|
8
|
+
#Prepare a blank page.
|
9
|
+
def initialize(page_length, page_width)
|
10
|
+
@page_length, @page_width = page_length, page_width
|
11
|
+
@page_data = []
|
12
|
+
end
|
13
|
+
|
14
|
+
#Add an item to this page.
|
15
|
+
#<br>Returns
|
16
|
+
#* The number if items that did not fit in the page.
|
17
|
+
def add(raw_item)
|
18
|
+
item = raw_item.to_s
|
19
|
+
fail "Item too large to fit." unless item.length < @page_width
|
20
|
+
|
21
|
+
if (column = find_next_column)
|
22
|
+
@page_data[column] << item
|
23
|
+
else
|
24
|
+
@page_data << [item]
|
25
|
+
end
|
26
|
+
|
27
|
+
adjust_configuration
|
28
|
+
end
|
29
|
+
|
30
|
+
#Render the page as an array of strings.
|
31
|
+
def render
|
32
|
+
results, column_widths = [], get_column_widths
|
33
|
+
|
34
|
+
rows.times { |row_index| results << render_row(row_index, column_widths)}
|
35
|
+
|
36
|
+
@page_data.clear
|
37
|
+
results
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
#Get the widths of all columns
|
43
|
+
def get_column_widths
|
44
|
+
@page_data.map {|column| column.mysh_column_width}
|
45
|
+
end
|
46
|
+
|
47
|
+
#Render a single row of data.
|
48
|
+
def render_row(row_index, widths)
|
49
|
+
@page_data.each_with_index.map do |column, index|
|
50
|
+
column[row_index].to_s.ljust(widths[index])
|
51
|
+
end.join(" ")
|
52
|
+
end
|
53
|
+
|
54
|
+
#Make sure the page fits within its boundaries.
|
55
|
+
#<br>Returns
|
56
|
+
#* The number if items that did not fit in the page.
|
57
|
+
def adjust_configuration
|
58
|
+
while total_width >= @page_width
|
59
|
+
return @page_data.pop.length if rows == @page_length
|
60
|
+
add_a_row
|
61
|
+
end
|
62
|
+
|
63
|
+
0
|
64
|
+
end
|
65
|
+
|
66
|
+
#Add a row to the page, moving items as needed.
|
67
|
+
def add_a_row
|
68
|
+
target = rows + 1
|
69
|
+
pool, @page_data = @page_data.flatten, []
|
70
|
+
|
71
|
+
until pool.empty?
|
72
|
+
@page_data << pool.shift(target)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
#Compute the total width of all of the columns.
|
77
|
+
#<br>Returns
|
78
|
+
#* The sum of the widths of the widest items of each column plus a space
|
79
|
+
# between each of those columns.
|
80
|
+
def total_width
|
81
|
+
if empty?
|
82
|
+
0
|
83
|
+
else
|
84
|
+
#The starting point, @page_data.length-1, represents the spaces needed
|
85
|
+
#between the columns. So N columns means N-1 spaces.
|
86
|
+
@page_data.inject(@page_data.length-1) do |sum, column|
|
87
|
+
sum + column.mysh_column_width
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#Does the data fit on the page?
|
93
|
+
def fits?
|
94
|
+
total_width < @page_width
|
95
|
+
end
|
96
|
+
|
97
|
+
#How many rows are currently in this page?
|
98
|
+
def rows
|
99
|
+
empty? ? 0 : @page_data[0].length
|
100
|
+
end
|
101
|
+
|
102
|
+
#Is this page empty?
|
103
|
+
def empty?
|
104
|
+
@page_data.empty?
|
105
|
+
end
|
106
|
+
|
107
|
+
#Which column will receive the next item?
|
108
|
+
#<br>Returns
|
109
|
+
#* The index of the first non-filled column or nil if none found.
|
110
|
+
def find_next_column
|
111
|
+
(1...(@page_data.length)).each do |index|
|
112
|
+
if @page_data[index].length < @page_data[index-1].length
|
113
|
+
return index
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* internal/format/object.rb - Support for displaying data formatted neatly.
|
4
|
+
class Object
|
5
|
+
|
6
|
+
#Create a bullet point description from this object.
|
7
|
+
def format_description(max_width)
|
8
|
+
self.to_s.format_description(max_width)
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
#* internal/format/string.rb - Support for displaying data formatted neatly.
|
4
|
+
class String
|
5
|
+
|
6
|
+
#Create a bullet point description from this string.
|
7
|
+
def format_description(max_width)
|
8
|
+
do_format_description(split(' ').each, max_width)
|
9
|
+
end
|
10
|
+
|
11
|
+
#Do the formatting legwork.
|
12
|
+
def do_format_description(input, max_width)
|
13
|
+
result, build = [], ""
|
14
|
+
|
15
|
+
loop do
|
16
|
+
build = build.split_if_over(input.next, max_width, result)
|
17
|
+
.split_if_huge(max_width, result)
|
18
|
+
end
|
19
|
+
|
20
|
+
result << build
|
21
|
+
end
|
22
|
+
|
23
|
+
#Split if adding a word goes over a little.
|
24
|
+
def split_if_over(word, max_width, buffer)
|
25
|
+
word.prepend(" ") unless self.empty?
|
26
|
+
word_len = word.length
|
27
|
+
|
28
|
+
if (length + word_len) >= max_width && word_len < max_width
|
29
|
+
buffer << self
|
30
|
+
word.lstrip
|
31
|
+
else
|
32
|
+
self + word
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
#Split up a overlong blob of text.
|
38
|
+
def split_if_huge(max_width, buffer)
|
39
|
+
while length >= max_width
|
40
|
+
buffer << slice!(0, max_width)
|
41
|
+
end
|
42
|
+
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
data/lib/mysh/internal/manage.rb
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
#* internal/manage.rb -- Manage mysh internal commands.
|
4
4
|
module Mysh
|
5
5
|
|
6
|
-
#Set up the command
|
7
|
-
COMMANDS = ActionPool.new
|
6
|
+
#Set up the command action pool.
|
7
|
+
COMMANDS = ActionPool.new("COMMANDS")
|
8
8
|
|
9
9
|
#Parse a command string for use by commands.
|
10
10
|
def self.parse_command(str)
|
@@ -13,19 +13,19 @@ module Mysh
|
|
13
13
|
[COMMANDS[result.shift], result]
|
14
14
|
end
|
15
15
|
|
16
|
-
#Execute an internal command
|
16
|
+
#Execute the action of an internal command.
|
17
17
|
def self.execute(str)
|
18
18
|
unless str[0] == ' '
|
19
|
-
|
19
|
+
action, args = parse_command(str.chomp)
|
20
20
|
|
21
|
-
if (
|
22
|
-
|
21
|
+
if (action)
|
22
|
+
action.execute(args)
|
23
23
|
:internal
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
#Try to execute the string as an internal
|
28
|
+
#Try to execute the string as an internal action.
|
29
29
|
def self.try_execute_internal_command(str)
|
30
30
|
execute(str)
|
31
31
|
end
|
data/lib/mysh/version.rb
CHANGED
data/samples/show.txt
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
This is a sample show file.
|
2
|
+
|
3
|
+
{{ a = 5 #}}a = {{ a.to_s }}
|
4
|
+
Args = {{ args.inspect }}
|
5
|
+
|
6
|
+
{{ count = 100 #}}
|
7
|
+
|
8
|
+
{{ [["Numbers", Array.new(count){|i| (i+1)} ],
|
9
|
+
["Squares", Array.new(count){|i| (i+1)*(i+1)} ],
|
10
|
+
["Cubes", Array.new(count){|i| (i+1)*(i+1)*(i+1)} ]].mysh_bulletize.join("\n") }}
|
11
|
+
|
data/{test.rb → samples/test.rb}
RENAMED
File without changes
|
data/tests/my_shell_tests.rb
CHANGED
@@ -11,10 +11,23 @@ class MyShellTester < Minitest::Test
|
|
11
11
|
#Track mini-test progress.
|
12
12
|
include MinitestVisible
|
13
13
|
|
14
|
+
#Evaluate the string in a mysh context.
|
15
|
+
def mysh_eval(str)
|
16
|
+
@mysh_binding ||= binding
|
17
|
+
|
18
|
+
@mysh_binding.eval(str)
|
19
|
+
end
|
20
|
+
|
14
21
|
def test_that_module_entities_exists
|
22
|
+
assert_equal(String, Mysh::VERSION.class)
|
23
|
+
|
15
24
|
assert_equal(Module, Mysh.class)
|
16
25
|
assert_equal(Class, Mysh::Action.class)
|
26
|
+
assert_equal(Class, Mysh::ActionPool.class)
|
17
27
|
assert_equal(Class, Mysh::ExecHost.class)
|
28
|
+
|
29
|
+
assert_equal(Mysh::ActionPool, Mysh::COMMANDS.class)
|
30
|
+
assert_equal(Mysh::ActionPool, Mysh::Action::HELP.class)
|
18
31
|
end
|
19
32
|
|
20
33
|
def test_for_internal_commands
|
@@ -44,4 +57,57 @@ class MyShellTester < Minitest::Test
|
|
44
57
|
assert_equal("{{A}}", eval_handlebars("{{ '{'+'{A}'+'}' }}"))
|
45
58
|
end
|
46
59
|
|
60
|
+
def test_command_parsing
|
61
|
+
assert_equal([], Mysh.parse_args(""))
|
62
|
+
|
63
|
+
assert_equal(["1", "2", "3"], Mysh.parse_args("1 2 3"))
|
64
|
+
|
65
|
+
assert_equal(["1", "Trump", "loses", "election", "3"],
|
66
|
+
Mysh.parse_args("1 Trump loses election 3"))
|
67
|
+
|
68
|
+
assert_equal(["1", "Trump loses election", "3"],
|
69
|
+
Mysh.parse_args('1 "Trump loses election" 3'))
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_the_lineage_method
|
74
|
+
assert_equal("String instance < String < Object < BasicObject",
|
75
|
+
"Hello".lineage)
|
76
|
+
|
77
|
+
assert_equal("Fixnum instance < Fixnum < Integer < Numeric < Object < BasicObject",
|
78
|
+
(4).lineage)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_some_formatting
|
82
|
+
result =
|
83
|
+
["1 5 9 13 17 21 25 29 33 37 41 45 49 53 57 61 65 69 73 77 81 85 89 93 97 ",
|
84
|
+
"2 6 10 14 18 22 26 30 34 38 42 46 50 54 58 62 66 70 74 78 82 86 90 94 98 ",
|
85
|
+
"3 7 11 15 19 23 27 31 35 39 43 47 51 55 59 63 67 71 75 79 83 87 91 95 99 ",
|
86
|
+
"4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100"]
|
87
|
+
|
88
|
+
assert_equal(result, (1..100).to_a.format_mysh_columns)
|
89
|
+
|
90
|
+
data =
|
91
|
+
[["key_largo", "/long_folder_name_one/long_folder_name_two/long_folder_name_three/fine_descriptive_name"],
|
92
|
+
["key_west", "Semper ubi sub ubi. Semper ubi sub ubi. Semper ubi sub ubi. Semper ubi sub ubi. "],
|
93
|
+
["counting", Array.new(100) {|i| i} ],
|
94
|
+
["pie", Math::PI]
|
95
|
+
]
|
96
|
+
|
97
|
+
result =
|
98
|
+
["key_largo /long_folder_name_one/long_folder_name_two/long_folder_name_three/fin",
|
99
|
+
" e_descriptive_name",
|
100
|
+
"key_west Semper ubi sub ubi. Semper ubi sub ubi. Semper ubi sub ubi. Semper",
|
101
|
+
" ubi sub ubi.",
|
102
|
+
"counting 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95",
|
103
|
+
" 1 6 11 16 21 26 31 36 41 46 51 56 61 66 71 76 81 86 91 96",
|
104
|
+
" 2 7 12 17 22 27 32 37 42 47 52 57 62 67 72 77 82 87 92 97",
|
105
|
+
" 3 8 13 18 23 28 33 38 43 48 53 58 63 68 73 78 83 88 93 98",
|
106
|
+
" 4 9 14 19 24 29 34 39 44 49 54 59 64 69 74 79 84 89 94 99",
|
107
|
+
"pie 3.141592653589793"
|
108
|
+
]
|
109
|
+
|
110
|
+
assert_equal(result, data.mysh_bulletize)
|
111
|
+
end
|
112
|
+
|
47
113
|
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.1.
|
4
|
+
version: 0.1.17
|
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-10-
|
11
|
+
date: 2016-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -160,15 +160,22 @@ files:
|
|
160
160
|
- lib/mysh/internal/actions/actions_path.rb
|
161
161
|
- lib/mysh/internal/actions/cd.rb
|
162
162
|
- lib/mysh/internal/actions/exit.rb
|
163
|
+
- lib/mysh/internal/actions/gls.rb
|
163
164
|
- lib/mysh/internal/actions/help.rb
|
164
|
-
- lib/mysh/internal/actions/help.txt
|
165
|
-
- lib/mysh/internal/actions/help_expr.txt
|
166
|
-
- lib/mysh/internal/actions/help_help.txt
|
167
|
-
- lib/mysh/internal/actions/help_math.txt
|
165
|
+
- lib/mysh/internal/actions/help/help.txt
|
166
|
+
- lib/mysh/internal/actions/help/help_expr.txt
|
167
|
+
- lib/mysh/internal/actions/help/help_help.txt
|
168
|
+
- lib/mysh/internal/actions/help/help_math.txt
|
168
169
|
- lib/mysh/internal/actions/history.rb
|
170
|
+
- lib/mysh/internal/actions/show.rb
|
171
|
+
- lib/mysh/internal/actions/vls.rb
|
169
172
|
- lib/mysh/internal/decorate.rb
|
170
173
|
- lib/mysh/internal/format.rb
|
174
|
+
- lib/mysh/internal/format/array.rb
|
171
175
|
- lib/mysh/internal/format/bullets.rb
|
176
|
+
- lib/mysh/internal/format/columns.rb
|
177
|
+
- lib/mysh/internal/format/object.rb
|
178
|
+
- lib/mysh/internal/format/string.rb
|
172
179
|
- lib/mysh/internal/manage.rb
|
173
180
|
- lib/mysh/user_input.rb
|
174
181
|
- lib/mysh/user_input/handlebars.rb
|
@@ -179,7 +186,8 @@ files:
|
|
179
186
|
- mysh.reek
|
180
187
|
- rakefile.rb
|
181
188
|
- reek.txt
|
182
|
-
-
|
189
|
+
- samples/show.txt
|
190
|
+
- samples/test.rb
|
183
191
|
- tests/my_shell_tests.rb
|
184
192
|
homepage: http://teuthida-technologies.com/
|
185
193
|
licenses:
|
@@ -204,6 +212,6 @@ rubyforge_project:
|
|
204
212
|
rubygems_version: 2.2.3
|
205
213
|
signing_key:
|
206
214
|
specification_version: 4
|
207
|
-
summary: mysh -- a Ruby inspired command shell.
|
215
|
+
summary: mysh -- a Ruby inspired command line shell.
|
208
216
|
test_files: []
|
209
217
|
has_rdoc:
|