mysh 0.1.16 → 0.1.17

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: 456fdf1833320032c9452e13eeb0c140d84f69e6
4
- data.tar.gz: 0590da7cd17f06fe1b428b47026b054f30fce371
3
+ metadata.gz: d3c002087bb9289b3a21c696dbec4cf5eb0c2aad
4
+ data.tar.gz: 89e63a29c1c26f4f84372cfa34995e820c3cf726
5
5
  SHA512:
6
- metadata.gz: d72558e9e315c03ba978cda6ef40cbbfe113bcc995933b2e76ad5744bc22aa5fa50dfa9958d82e65e333293c03f2ff0a1dba5100e5ed1c8edb047a3a0949ee14
7
- data.tar.gz: 18d160168fd6aec07cb6b6064f1a0adad97018214ab14dd24592e7c95bc629039a7460889f9c46217fc57c7eafa28b323832df9439c9fe20784356e4dd95b75e
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
- ! Display the mysh command history.
131
- ? Display help information for mysh.
132
- cd <dir> Change directory to the optional <dir> parameter
133
- and then display the current working directory.
134
- exit Exit mysh.
135
- help Display help information for mysh.
136
- history Display the mysh command history.
137
- pwd Display the current working directory.
138
- quit Exit mysh.
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
 
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- # mysh -- MY SHell -- a Ruby/Rails inspired command shell.
3
+ # mysh -- MY SHell -- a Ruby/Rails inspired command line shell.
4
4
 
5
5
  require 'English'
6
6
  require 'mini_readline'
@@ -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 do_execute(str)
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
- #A proxy for instance_eval.
77
- def instance_eval(str)
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 command.
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 command.
14
+ #Class monkey patch for the mysh lineage method.
15
15
  class Class
16
16
 
17
17
  #Get the lineage of this class.
@@ -7,5 +7,5 @@ require_relative 'internal/manage'
7
7
  require_relative 'internal/format'
8
8
  require_relative 'internal/decorate'
9
9
 
10
- #Load up the internal commands!
10
+ #Load up the internal actions!
11
11
  Dir[Mysh::Action::ACTIONS_PATH + '*.rb'].each {|file| require file }
@@ -5,30 +5,43 @@ module Mysh
5
5
 
6
6
  #The mysh internal action class.
7
7
  class Action
8
- #The name of the command.
8
+ #The name of the action.
9
9
  attr_reader :name
10
10
 
11
- #The description of the command.
11
+ #The description of the action.
12
12
  attr_reader :description
13
13
 
14
- #The action of the command.
14
+ #The action of the action.
15
15
  attr_reader :action
16
16
 
17
- #Setup an internal command
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 command.
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 command.
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 "Error adding alias #{new_name} for #{old_name}"
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
- split_name = new_name.split[0]
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 command folder.
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 command folder.
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 (MY ruby SHell) version: {{ Mysh::VERSION }}
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
- {{ format_items(Mysh::COMMANDS.actions_info).join("\n") }}
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
- =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 x.
22
- =vls "mask" List modules with version info. The optional mask string value is
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
 
@@ -5,5 +5,5 @@ or an optional specified topic.
5
5
 
6
6
  The available help topics are:
7
7
 
8
- {{ format_items(HELP.actions_info).join("\n") }}
8
+ {{ HELP.actions_info.mysh_bulletize.join("\n") }}
9
9
 
@@ -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
+
@@ -1,24 +1,19 @@
1
1
  # coding: utf-8
2
2
 
3
- require_relative 'format/bullets'
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
- #Display an array of items.
11
- def display_items(items)
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
- #Format an array of items.
17
- #<br>Endemic Code Smells
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 an item to this page.
18
- #<br>Endemic Code Smells
19
- #* :reek:FeatureEnvy :reek:TooManyStatements
20
- def add(raw_bullet = "*", *raw_item)
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 page as an array of strings.
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
- #How large is the largest bullet?
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, pass_one = [], true
59
- input = item.split(' ').each
60
- temp = key.ljust(len = @key_length)
44
+ result = []
61
45
 
62
- loop do
63
- word = ' ' + input.next
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 << temp
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
+
@@ -3,8 +3,8 @@
3
3
  #* internal/manage.rb -- Manage mysh internal commands.
4
4
  module Mysh
5
5
 
6
- #Set up the command library hash.
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
- command, args = parse_command(str.chomp)
19
+ action, args = parse_command(str.chomp)
20
20
 
21
- if (command)
22
- command.execute(args)
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 command.
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
@@ -35,7 +35,7 @@ class Object
35
35
  str.gsub(/{{.*?}}/m) do |match|
36
36
  code = match[2...-2]
37
37
  silent = code.end_with?("#")
38
- result = instance_eval(code)
38
+ result = mysh_eval(code)
39
39
 
40
40
  (result unless silent).to_s
41
41
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Mysh
4
4
  #The version string of MY SHell.
5
- VERSION = "0.1.16"
5
+ VERSION = "0.1.17"
6
6
 
7
7
  #A brief summary of this gem.
8
- SUMMARY = "mysh -- a Ruby inspired command shell."
8
+ SUMMARY = "mysh -- a Ruby inspired command line shell."
9
9
  end
@@ -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
+
File without changes
@@ -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.16
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-07 00:00:00.000000000 Z
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
- - test.rb
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: