cli-dispatcher 1.2.3 → 1.2.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f11805cc9ecff05fe987fe958cb4b6bf6a3a49d2a56596ff0eee761936b3ce3
4
- data.tar.gz: aac95196261ffb6835e1ca0220c5786f260f71bd8f9e904eaa7a824943cacd04
3
+ metadata.gz: b1b37219d472cc73b55f56047050b442e634de6b08c649dc617c12c0e812f220
4
+ data.tar.gz: 1cf08e0e3893984ef5d15c414d87b0889c3073dea6d7a6e8d7a6c6b12889d181
5
5
  SHA512:
6
- metadata.gz: d2a65276ba20ff7532ea71aff7219ade85ec908a317a8753740b42f1531283269e78df415ac6dbb607bfd009800e6e94cdd3692f01c2344b0c4653791455658b
7
- data.tar.gz: f2ec39cb1df8e03763a8b7b1a70fc01efa696d16df14f593abd8f80acdbd1c54359d05b99104837245be76d9b665896fa24665928ef025bc1bb149110b19c92a
6
+ metadata.gz: 593cce73a3bd60c69bcad822f1dcb20579f482eec9454ce86bd9164da88ff0f536cebdd67fbf55695c88622e3c391ece18bff6a12e8ad18f094d2cabee45308c
7
+ data.tar.gz: da5e84b8318b15d2510ac1a04086a66bd8a53689bb2afb59a9afa4d893f3380554702ecebdc55f88805002a8e81f15377767711cc16f17bb33d386624ea08724
@@ -1,5 +1,7 @@
1
1
  require 'optparse'
2
2
  require 'texttools'
3
+ require 'reline'
4
+ require 'shellwords'
3
5
 
4
6
  #
5
7
  # Constructs a program that can operate a number of user-provided commands. To
@@ -31,12 +33,12 @@ class Dispatcher
31
33
  # Reads ARGV and dispatches a command. If no arguments are given, an
32
34
  # appropriate warning is issued and the program terminates.
33
35
  #
34
- def dispatch_argv
36
+ def dispatch_argv(default_interactive = false)
35
37
  @option_parser ||= OptionParser.new
36
38
  add_options(@option_parser)
37
39
  @option_parser.banner = <<~EOF
38
- Usage: #$0 [options] command [arguments...]
39
- Run '#$0 help' for a list of commands.
40
+ Usage: #{File.basename($0)} [options] command [arguments...]
41
+ Run '#{File.basename($0)} help' for a list of commands.
40
42
 
41
43
  Options:
42
44
  EOF
@@ -48,35 +50,39 @@ class Dispatcher
48
50
  end
49
51
 
50
52
  @option_parser.parse!
51
- if ARGV.empty?
53
+ if !ARGV.empty?
54
+ exit dispatch(*ARGV) ? 0 : 1
55
+ elsif default_interactive
56
+ cmd_interactive
57
+ else
52
58
  STDERR.puts(@option_parser)
53
59
  exit 1
54
60
  end
55
- dispatch(*ARGV)
56
61
  end
57
62
 
58
63
  #
59
64
  # Dispatches a single command with given arguments. If the command is not
60
- # found, then issues a help warning.
65
+ # found, then issues a help warning. Returns true or false depending on
66
+ # whether the command executed successfully.
61
67
  #
62
68
  def dispatch(cmd, *args)
63
69
  cmd_sym = "cmd_#{cmd}".to_sym
64
70
  begin
65
71
  if respond_to?(cmd_sym)
66
72
  send(cmd_sym, *args)
73
+ return true
67
74
  else
68
- warn("Usage: #$0 [options] command [arguments...]")
69
- warn("Run '#$0 help' for a list of commands.")
70
- exit(1)
75
+ warn("Unknown command #{cmd_sym}. Run 'help' for a list of commands.")
76
+ return false
71
77
  end
72
78
  rescue ArgumentError
73
79
  if $!.backtrace_locations.first.base_label == cmd_sym.to_s
74
- warn("#{cmd}: wrong number of arguments")
80
+ warn("#{cmd}: wrong number of arguments.")
75
81
  warn("Usage: #{signature_string(cmd)}")
76
- exit(1)
77
82
  else
78
- raise $!
83
+ raise
79
84
  end
85
+ return false
80
86
  end
81
87
  end
82
88
 
@@ -143,12 +149,48 @@ class Dispatcher
143
149
  cmds.sort.each do |cmd|
144
150
  warn(TextTools.line_break(
145
151
  help_string(cmd, all: false),
146
- prefix: " " * 11,
147
- first_prefix: cmd.ljust(10) + ' ',
152
+ prefix: " " * 12,
153
+ first_prefix: cmd.ljust(11) + ' ',
148
154
  ))
149
155
  end
150
156
  end
151
157
 
158
+ def help_interactive
159
+ return "Start an interactive shell for entering commands."
160
+ end
161
+
162
+ #
163
+ # Runs the dispatcher in interactive mode, in which command lines are read
164
+ # from a prompt.
165
+ #
166
+ def cmd_interactive
167
+ stty_save = `stty -g`.chomp
168
+ loop do
169
+ begin
170
+ buf = Reline.readline(interactive_prompt, true)
171
+ exit unless buf
172
+ args = buf.shellsplit
173
+ next if args.empty?
174
+ exit if args.first == 'exit'
175
+ dispatch(*args)
176
+ rescue Interrupt
177
+ system("stty", stty_save)
178
+ exit
179
+ rescue
180
+ STDERR.puts $!.full_message
181
+ end
182
+ end
183
+ end
184
+
185
+ #
186
+ # Returns the string for the interactive prompt. Subclasses can override this
187
+ # method to offer more detailed prompts.
188
+ #
189
+ def interactive_prompt
190
+ return "#{File.basename($0)}> "
191
+ end
192
+
193
+
152
194
  #
153
195
  # Adds commands relevant when this dispatcher uses Structured data inputs.
154
196
  #
data/lib/structured.rb CHANGED
@@ -779,7 +779,7 @@ module Structured
779
779
  # @param indent The indent string before new lines.
780
780
  # @param sp Spacing after the colon, if any.
781
781
  def template_type(type, indent, sp = ' ')
782
- res = ''
782
+ res = String.new('')
783
783
  case type
784
784
  when :boolean
785
785
  res << " true/false\n"
data/lib/texttools.rb CHANGED
@@ -11,17 +11,41 @@ module TextTools
11
11
  def line_break(
12
12
  text, len: 80, prefix: '', first_prefix: nil, preserve_lines: false
13
13
  )
14
- res = ''
14
+ res = String.new('')
15
+
16
+ #
17
+ # Remove single paragraph breaks (unless preserve_lines is on). After this,
18
+ # every paragraph break should be preserved. Also remove trailing
19
+ # whitespace, which causes problems.
20
+ #
15
21
  text = text.split(/\s*\n\s*\n\s*/).map { |para|
16
22
  preserve_lines ? para : para.gsub(/\s*\n\s*/, " ")
17
- }.join("\n\n")
23
+ }.join("\n\n").rstrip
18
24
 
19
25
  cur_prefix = first_prefix || prefix
26
+
27
+ # Process each individual line separately.
28
+ while (line_match = /\s*\n\s*/.match(text))
29
+ res << one_line_break(line_match.pre_match, len, cur_prefix, prefix)
30
+ res << line_match[0].gsub(/[^\n]/, '')
31
+ cur_prefix = prefix
32
+ text = line_match.post_match
33
+ end
34
+ res << one_line_break(text, len, cur_prefix, prefix)
35
+ return res
36
+
37
+ end
38
+
39
+ #
40
+ # Line break a text that is guaranteed not to have any line breaks within it.
41
+ #
42
+ def one_line_break(text, len, first_prefix, prefix)
43
+ res = String.new('')
44
+ cur_prefix = first_prefix
20
45
  strlen = len - cur_prefix.length
21
46
  while text.length > strlen
22
- if (m = /\A([^\n]{0,#{strlen}})(\s+)/.match(text))
23
- res << cur_prefix + m[1]
24
- res << (m[2].include?("\n") ? m[2].gsub(/[^\n]/, '') : "\n")
47
+ if (m = /\A(.{0,#{strlen}})(\s+)/.match(text))
48
+ res << cur_prefix + m[1] + "\n"
25
49
  text = m.post_match
26
50
  else
27
51
  res << cur_prefix + text[0, strlen] + "\n"
@@ -31,8 +55,6 @@ module TextTools
31
55
  strlen = len - cur_prefix.length
32
56
  end
33
57
 
34
- # If there's no text left, then there were trailing spaces and the final \n
35
- # is superfluous.
36
58
  if text.length > 0
37
59
  res << cur_prefix + text
38
60
  else
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cli-dispatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charles Duan
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-01-14 00:00:00.000000000 Z
10
+ date: 2025-10-02 00:00:00.000000000 Z
12
11
  dependencies: []
13
12
  description: |
14
13
  Library for creating command-line programs that accept commands. Also
@@ -29,7 +28,6 @@ licenses:
29
28
  metadata:
30
29
  source_code_uri: https://github.com/charlesduan/cli-dispatcher
31
30
  documentation_uri: https://rubydoc.info/gems/cli-dispatcher/
32
- post_install_message:
33
31
  rdoc_options: []
34
32
  require_paths:
35
33
  - lib
@@ -44,8 +42,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
44
42
  - !ruby/object:Gem::Version
45
43
  version: '0'
46
44
  requirements: []
47
- rubygems_version: 3.5.11
48
- signing_key:
45
+ rubygems_version: 3.7.2
49
46
  specification_version: 4
50
47
  summary: Command-line command dispatcher
51
48
  test_files: []