shellopts 2.4.0 → 2.4.2

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
  SHA256:
3
- metadata.gz: 68428ade0dd8ec48fa85a8d43362743d6dc5595d9f4af3347d0fa402eaf0e7bb
4
- data.tar.gz: 51404fbc53ddbacb0b7a4552777e3de7c8abce1d508782f6c901da4b2cd332ba
3
+ metadata.gz: 93dc09edd7bd318c85134a93f7c45352f4b2e550663c1a80a029d4fcb1d8ab16
4
+ data.tar.gz: c9e0b523c15f372d5dd988d2fd804c01539e90f0ee02ef68d284b4a1340e7c9c
5
5
  SHA512:
6
- metadata.gz: ca5499680c53cc74388102b130eb9a7dfc7dc53ba7556615991d93d882ddc4993e1854891d78bbd97ccb4d37e8d493fb1c4e199cc4361f96ddb2e55c536f4cc7
7
- data.tar.gz: d75bef2e9b154a0332ed55a272341072654db8c615c5e4c9a27a94823efd6bae354fe32ca14679c92553af3e0e4f69f50ca3aeb675c5149d8394195f1f5a9f4a
6
+ metadata.gz: 520132f149801fb6d2bb8e325e38cdb6bf81a01c9d881f88165b02550dfae4a0f95706bcbd558e34b2232015b327c87f779cbf2cdef6d0355640db6e87acaaea
7
+ data.tar.gz: 7a26fe6f1a8501f9a52103224ea4cdfa2d95441e6253af6ecfcb71f09f8f57c84bae7734079fa5ab1c47756f859ac0eaddbac3c350ce1d8a6b845be011ecedc3
data/README.md CHANGED
@@ -193,7 +193,6 @@ indicate that the option can be repeated
193
193
  --gamma=ARG? @ --gamma, takes an optional argument
194
194
  ```
195
195
 
196
-
197
196
  An option argument has a name and a type. The type can be specified as '#'
198
197
  (integer), '$' (float), or as a comma-separated list of allowed values. It can
199
198
  also be defined by a keyword that expects a file or directory argument:
@@ -202,15 +201,17 @@ also be defined by a keyword that expects a file or directory argument:
202
201
  | --------- | ---- |
203
202
  | FILE | A file if present or in an existing directory if not |
204
203
  | DIR | A directory if present or in an existing directory if not |
205
- | PATH | Either a FILE or DIR |
204
+ | PATH | FILE or DIR |
206
205
  | EFILE | An existing file |
207
206
  | EDIR | An existing directory |
208
- | EPATH | Either an EFILE or EDIR |
207
+ | EPATH | EFILE or EDIR |
209
208
  | NFILE | A new file |
210
209
  | NDIR | A new directory |
211
- | NPATH | A new file or directory |
210
+ | NPATH | NFILE or NDIR |
211
+
212
212
 
213
- By default the option name is inferred from the type but it can be specified explicitly by separating it from the type with a ':'. Examples:
213
+ By default the option name is inferred from the type but it can be specified
214
+ explicitly by separating it from the type with a ':'. Examples:
214
215
 
215
216
  ```
216
217
  -a=# @ -a takes an integer argument
@@ -244,7 +245,7 @@ In single-line format, subcommands are specified by prefixing the supercommand's
244
245
 
245
246
  ## Example
246
247
 
247
- The rm(1) command could be specified like this:
248
+ The standard rm(1) command could be specified like this:
248
249
 
249
250
  ```ruby
250
251
 
data/TODO CHANGED
@@ -1,4 +1,14 @@
1
1
 
2
+ o Remove IFILE and OFILE. Alternatively document them
3
+ o Document special-case file argument '-'
4
+ o Accept both strings and symbols for commands (maybe... ruins the global namespace in #[])
5
+ o ShellOpts#command -> Full path. Eg. ':command.subcommand!'
6
+ ShellOpts#commands -> Array of commands. Eg. [:command!, :subcommand!]
7
+ o Exclude -h, -v, and -q from short description and only include them in the
8
+ detailed option description
9
+ o Output handling: mesg, verb, ... should record eols. error and failure should
10
+ use that to end the current line with a newline if necessary
11
+ o Strings from ShellOpts are frozen. Is that what we want?
2
12
  o Assigner methods for options
3
13
  o Make opts[] point at the main object
4
14
  opts[].subcommand is the direct subcommand of main
@@ -26,7 +26,7 @@ module ShellOpts
26
26
  def to_s() name end
27
27
 
28
28
  protected
29
- # it is important that #set_message return false
29
+ # Note that it is important that #set_message return false
30
30
  def set_message(msg)
31
31
  @message = msg
32
32
  false
@@ -60,6 +60,18 @@ module ShellOpts
60
60
  class FileArgument < ArgumentType
61
61
  attr_reader :kind
62
62
 
63
+ def subject # Used in error messages
64
+ @subject ||=
65
+ case kind
66
+ when :file, :efile; "regular file"
67
+ when :nfile, :ifile, :ofile; "file"
68
+ when :dir, :edir, :ndir; "directory"
69
+ when :path, :epath, :npath; "path"
70
+ else
71
+ raise ArgumentError
72
+ end
73
+ end
74
+
63
75
  def initialize(kind)
64
76
  constrain kind, :file, :dir, :path, :efile, :edir, :epath, :nfile, :ndir, :npath, :ifile, :ofile
65
77
  @kind = kind
@@ -70,19 +82,18 @@ module ShellOpts
70
82
  if literal == '-' && [:ifile, :ofile].include?(kind)
71
83
  true
72
84
 
73
- # Special-case standard I/O files
85
+ # Special-case standard I/O files. These files have read-write (rw)
86
+ # filesystem permissions so they need to be handled individually
74
87
  elsif %w(/dev/stdin /dev/stdout /dev/stderr /dev/null).include?(literal)
75
88
  case kind
76
89
  when :file, :path, :efile, :epath, :nfile, :npath
77
90
  true
78
91
  when :ifile
79
- %w(/dev/stdin /dev/null).include? literal or
80
- set_message "Can't read #{literal}"
92
+ %w(/dev/stdin /dev/null).include? literal or set_message "Can't read #{literal}"
81
93
  when :ofile
82
- %w(/dev/stdout /dev/stderr /dev/null).include?(literal) or
83
- set_message "Can't write to #{literal}"
94
+ %w(/dev/stdout /dev/stderr /dev/null).include?(literal) or set_message "Can't write to #{literal}"
84
95
  when :dir, :edir, :ndir
85
- set_message "Expected file, got directory #{literal}"
96
+ set_message "#{literal} is not a directory"
86
97
  else
87
98
  raise ArgumentError, "Unhandled kind: #{kind.inspect}"
88
99
  end
@@ -128,50 +139,44 @@ module ShellOpts
128
139
 
129
140
  protected
130
141
  def match_path(name, literal, kind, method, mode)
131
- subject =
132
- case kind
133
- when :file, :efile, :nfile, :ifile, :ofile; "file"
134
- when :dir, :edir, :ndir; "directory"
135
- when :path, :epath, :npath; "path"
136
- else
137
- raise ArgumentError
138
- end
139
-
140
- # file exists and is the rigth type?
142
+ # file exists and the method returned true
141
143
  if File.send(method, literal)
142
144
  if mode == :new
143
- set_message "#{subject.capitalize} already exists in #{name}: #{literal}"
145
+ set_message "Won't overwrite #{literal}"
144
146
  elsif kind == :path || kind == :epath
145
147
  if File.file?(literal) || File.directory?(literal)
146
148
  true
147
149
  else
148
- set_message "Expected file or directory as #{name} argument: #{literal}"
150
+ set_message "#{literal} is not a file or a directory"
149
151
  end
150
152
  elsif (kind == :ifile || kind == :ofile) && File.directory?(literal)
151
- set_message "File expected, got directory: #{literal}"
153
+ set_message "#{literal} is not a device file"
152
154
  else
153
155
  true
154
156
  end
155
157
 
156
- # file exists but not the right type?
158
+ # file exists but the method returned false
157
159
  elsif File.exist?(literal)
158
160
  if kind == :ifile
159
161
  set_message "Can't read #{literal}"
160
162
  elsif kind == :ofile
161
163
  set_message "Can't write to #{literal}"
162
164
  elsif mode == :new
163
- set_message "#{subject.capitalize} already exists - #{literal}"
165
+ set_message "Won't overwrite #{literal}"
164
166
  else
165
- set_message "Expected #{subject} as #{name} argument: #{literal}"
167
+ set_message "#{literal} is not a #{subject}"
166
168
  end
167
169
 
168
170
  # file does not exist
169
171
  else
170
172
  if [:default, :new].include? mode
171
- if File.exist?(File.dirname(literal)) || kind == :ofile
172
- true
173
+ dir = File.dirname(literal)
174
+ if !File.directory?(dir)
175
+ set_message "Illegal path - #{literal}"
176
+ elsif !File.writable?(dir)
177
+ set_message "Can't create #{subject} #{literal}"
173
178
  else
174
- set_message "Illegal path in #{name}: #{literal}"
179
+ true
175
180
  end
176
181
  else
177
182
  set_message "Can't find #{literal}"
@@ -183,7 +188,7 @@ module ShellOpts
183
188
  class EnumArgument < ArgumentType
184
189
  attr_reader :values
185
190
  def initialize(values) @values = values.dup end
186
- def match?(name, literal) value?(literal) or set_message "Illegal value in #{name}: '#{literal}'" end
191
+ def match?(name, literal) value?(literal) or set_message "Illegal value - #{literal}" end
187
192
  def value?(value) @values.include?(value) end
188
193
  end
189
194
  end
@@ -1,3 +1,3 @@
1
1
  module ShellOpts
2
- VERSION = "2.4.0"
2
+ VERSION = "2.4.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shellopts
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 2.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-31 00:00:00.000000000 Z
11
+ date: 2024-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: forward_to