shellopts 2.0.6 → 2.0.9

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: 52971494b88f77b6b66a95e8409de7cbebcbf030588089c395424b7e86f5e372
4
- data.tar.gz: e00e482a0db690c2b7bd0861589a5179a67d7cec9b285ebcc1d2b5a7b6f73ff7
3
+ metadata.gz: a9d576d24bd0aec0dd43a2a3645ede04751d80ae22a4c88e8f66ed53bbe7e405
4
+ data.tar.gz: 9027ac55689a345099f6515e5280808528603dfafe385219e6cce77d1c166d96
5
5
  SHA512:
6
- metadata.gz: 2206c1e56c4239472bf5b697854fc4d7ba06bd9dedfe4eb2f86c2e115f4ddd52f66e9b4f47cbba41b1b4eafb08b8666b2115df7f70d769465dcb3e4a344d322a
7
- data.tar.gz: f9bc90bdba87159a2821afb3c719ba4c4fbc7077601266d9e61c5f83273924bc23e9fa2208bf727855fc99b6acac09a97ec3dc58be179f649c9ed6dbb4fcc259
6
+ metadata.gz: b44a4d95aa0585dd0ec31abccde4942c98ad712d9e3bdf9f0c0b6ead7333ff4c5b555ec5b45786a6f539388b2460c93d12f3755b2e80cbb81fd269c42a9b4955
7
+ data.tar.gz: 3c948a743d809df7d22bc142dcfa9aa4e943fed144004c4fbf5d1995c314f4aea3f91b032533222eed953e5344a45c55666339797e5ae2b1be262eea17071cd5
data/TODO CHANGED
@@ -1,4 +1,5 @@
1
1
 
2
+ o Add brackets to optional option arguments: '--all=FILE?' -> '--all[=FILE]'
2
3
  o Ignore all text after ' # ' (doesn't conflict with option flag)
3
4
  o Command aliases
4
5
  o Add user-defined setions
@@ -28,10 +28,13 @@ module ShellOpts
28
28
  @options = option_groups.map(&:options).flatten
29
29
  end
30
30
 
31
- # Move options before first command
31
+ # Move options before first command or before explicit COMMAND section
32
32
  def reorder_options
33
33
  if commands.any?
34
- if i = children.find_index { |child| child.is_a?(Command) }
34
+ i = children.find_index { |child|
35
+ child.is_a?(Command) || child.is_a?(Section) && child.name == "COMMAND"
36
+ }
37
+ if i
35
38
  options, rest = children[i+1..-1].partition { |child| child.is_a?(OptionGroup) }
36
39
  @children = children[0, i] + options + children[i..i] + rest
37
40
  end
@@ -2,21 +2,31 @@
2
2
  module ShellOpts
3
3
  # Specialization of Array for arguments lists. Args extends Array with a
4
4
  # #extract and an #expect method to extract elements from the array. The
5
- # methods raise a ShellOpts::UserError exception in case of errors
5
+ # methods raise a ShellOpts::Error exception in case of errors
6
6
  #
7
7
  class Args < Array
8
+ def initialize(*args, exception: false)
9
+ super(*args)
10
+ @exception = exception
11
+ end
12
+
13
+ # :call-seq:
14
+ # extract(count, message = nil)
15
+ # extract(range, message = nil)
16
+ #
8
17
  # Remove and return elements from beginning of the array
9
18
  #
10
19
  # If +count_or_range+ is a number, that number of elements will be
11
20
  # returned. If the count is one, a simple value is returned instead of an
12
21
  # array. If the count is negative, the elements will be removed from the
13
22
  # end of the array. If +count_or_range+ is a range, the number of elements
14
- # returned will be in that range. The range can't contain negative numbers
23
+ # returned will be in that range. Note that the range can't contain
24
+ # negative numbers
15
25
  #
16
- # #extract raise a ShellOpts::UserError exception if there's is not enough
26
+ # #extract raise a ShellOpts::Error exception if there's is not enough
17
27
  # elements in the array to satisfy the request
18
28
  #
19
- def extract(count_or_range, message = nil)
29
+ def extract(count_or_range, message = nil)
20
30
  case count_or_range
21
31
  when Range
22
32
  range = count_or_range
@@ -30,16 +40,16 @@ module ShellOpts
30
40
  count.abs <= self.size or inoa(message)
31
41
  start = count >= 0 ? 0 : size + count
32
42
  r = slice!(start, count.abs)
33
- r.size <= 0 ? nil : (r.size == 1 ? r.first : r)
43
+ r.size == 1 ? r.first : r
34
44
  else
35
45
  raise ArgumentError
36
46
  end
37
47
  end
38
48
 
39
49
  # As #extract except it doesn't allow negative counts and that the array is
40
- # expect to be emptied by the operation
50
+ # expected to be emptied by the operation
41
51
  #
42
- # #expect raise a ShellOpts::UserError exception if the array is not emptied
52
+ # #expect raise a ShellOpts::Error exception if the array is not emptied
43
53
  # by the operation
44
54
  #
45
55
  def expect(count_or_range, message = nil)
@@ -54,8 +64,10 @@ module ShellOpts
54
64
  end
55
65
 
56
66
  private
57
- def inoa(message = nil)
58
- raise ArgumentError, message || "Illegal number of arguments"
67
+ def inoa(message = nil)
68
+ message ||= "Illegal number of arguments"
69
+ raise Error, message if @exception
70
+ ::ShellOpts.error(message)
59
71
  end
60
72
  end
61
73
  end
@@ -112,36 +112,33 @@ module ShellOpts
112
112
 
113
113
  section = {
114
114
  Paragraph => "DESCRIPTION",
115
- OptionGroup => "OPTIONS",
116
- Command => "COMMANDS"
115
+ OptionGroup => "OPTION",
116
+ Command => "COMMAND"
117
117
  }
118
118
 
119
+ seen_sections = {}
119
120
  newline = false # True if a newline should be printed before child
120
121
  indent {
121
122
  children.each { |child|
122
- if child.is_a?(Section) # Explicit section
123
- # p :A
124
- puts
125
- indent(-1).puts Ansi.bold child.name
126
- section.delete_if { |_,v| v == child.name }
123
+ klass = child.is_a?(Section) ? section.key(child.name) : child.class
124
+ if s = section[klass] # Implicit section
125
+ section.delete(klass)
127
126
  section.delete(Paragraph)
128
- newline = false
129
- next
130
- elsif s = section[child.class] # Implicit section
131
- # p :B
132
- puts
127
+ if klass <= OptionGroup
128
+ s = s + "S" if options.size > 1
129
+ elsif klass <= Command
130
+ s = s + "S" if commands.size > 1 || commands.first&.commands&.size != 0
131
+ end
132
+ puts
133
133
  indent(-1).puts Ansi.bold s
134
- section.delete(child.class)
135
- section.delete(Paragraph)
136
134
  newline = false
137
- else # Any other node add a newline
138
- # p :C
135
+ next if child.is_a?(Section)
136
+ else # Any other node adds a newline
139
137
  puts if newline
140
138
  newline = true
141
139
  end
142
140
 
143
141
  if child.is_a?(Command)
144
- # prefix = child.parent != self ? nil : child.supercommand&.name
145
142
  prefix = child.supercommand == self ? nil : child.supercommand&.name
146
143
  child.puts_descr(prefix, brief: false, name: :path)
147
144
  newline = true
@@ -151,6 +151,10 @@ module ShellOpts
151
151
  class OptionGroup < Node
152
152
  alias_method :command, :parent
153
153
 
154
+ # Duck typing for compatibility with IdrNode (TODO: maybe just make
155
+ # OptionGroup an IdrNode and be over with it)
156
+ def name() options.first&.name end
157
+
154
158
  # Array of options in declaration order
155
159
  attr_reader :options
156
160
 
@@ -352,6 +356,10 @@ module ShellOpts
352
356
  end
353
357
 
354
358
  class Section < Node
359
+ def initialize(parent, token)
360
+ constrain token.source, *%w(DESCRIPTION OPTION COMMAND)
361
+ super
362
+ end
355
363
  def name() token.source end
356
364
  end
357
365
 
@@ -32,7 +32,7 @@ module ShellOpts
32
32
  end
33
33
  end
34
34
  end
35
- [@expr, Args.new(@args + @argv)]
35
+ [@expr, Args.new(@args + @argv, exception: @exception)]
36
36
  end
37
37
 
38
38
  def self.interpret(grammar, argv, **opts)
@@ -45,7 +45,7 @@ module ShellOpts
45
45
  # Match ArgDescr words (should be at least two characters long)
46
46
  DESCR_RE = /^[^a-z]{2,}$/
47
47
 
48
- SECTIONS = %w(DESCRIPTION OPTIONS COMMANDS)
48
+ SECTIONS = %w(DESCRIPTION OPTION OPTIONS COMMAND COMMANDS)
49
49
 
50
50
  using Ext::Array::ShiftWhile
51
51
 
@@ -109,7 +109,7 @@ module ShellOpts
109
109
 
110
110
  # Sections
111
111
  elsif SECTIONS.include?(line.text)
112
- @tokens << Token.new(:section, line.lineno, line.charno, line.text)
112
+ @tokens << Token.new(:section, line.lineno, line.charno, line.text.sub(/S$/, ""))
113
113
 
114
114
  # Options, commands, usage, arguments, and briefs
115
115
  elsif line =~ DECL_RE
@@ -132,7 +132,8 @@ module ShellOpts
132
132
 
133
133
  option_token = Token.new(:option, 1, 1, "-h,help")
134
134
  brief_token = Token.new(:brief, 1, 1, "Write help text and exit")
135
- paragraph_token = Token.new(:text, 1, 1, "-h prints a brief help text, --help prints a longer man-style description of the command")
135
+ paragraph_token = Token.new(:text, 1, 1,
136
+ "-h prints a brief help text, --help prints a longer man-style description of the command")
136
137
  group = OptionGroup.new(self, option_token)
137
138
  option = Option.parse(group, option_token)
138
139
  brief = Brief.parse(group, brief_token)
@@ -162,14 +163,6 @@ module ShellOpts
162
163
  @nodes = {}
163
164
  end
164
165
 
165
- # def add_stdopts
166
- # version_token = Token.new(:option, 1, 1, "--version")
167
- # version_brief = Token.new(:brief, 1, 1, "Gryf gryf")
168
- # group = Grammar::OptionGroup.new(@program, version_token)
169
- # option = Grammar::Option.parse(group, version_token)
170
- # brief = Grammr::Brief.parse(option, version_brief)
171
- # end
172
-
173
166
  def parse()
174
167
  @program = Grammar::Program.parse(@tokens.shift)
175
168
  oneline = @tokens.first.lineno == @tokens.last.lineno
@@ -1,3 +1,3 @@
1
1
  module ShellOpts
2
- VERSION = "2.0.6"
2
+ VERSION = "2.0.9"
3
3
  end
data/shellopts.gemspec CHANGED
@@ -1,7 +1,5 @@
1
1
 
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "shellopts/version"
2
+ require_relative "lib/shellopts/version"
5
3
 
6
4
  Gem::Specification.new do |spec|
7
5
  spec.name = "shellopts"
@@ -15,15 +13,18 @@ Gem::Specification.new do |spec|
15
13
  and has built-in help and error messages}
16
14
  spec.homepage = "http://github.com/clrgit/shellopts"
17
15
 
18
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
19
- f.match(%r{^(test|spec|features)/})
16
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
17
+ `git ls-files -z`.split("\x0").reject do |f|
18
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
19
+ end
20
20
  end
21
+
21
22
  spec.bindir = "exe"
22
23
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
24
  spec.require_paths = ["lib"]
24
25
 
25
26
  spec.add_dependency "forward_to"
26
- spec.add_dependency "constrain"
27
+ spec.add_dependency "constrain", "~> 0.5.1"
27
28
  spec.add_dependency "ruby-terminfo"
28
29
  spec.add_dependency "indented_io"
29
30
 
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.0.6
4
+ version: 2.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-03-01 00:00:00.000000000 Z
11
+ date: 2022-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: forward_to
@@ -28,16 +28,16 @@ dependencies:
28
28
  name: constrain
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.5.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 0.5.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: ruby-terminfo
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -132,10 +132,8 @@ executables: []
132
132
  extensions: []
133
133
  extra_rdoc_files: []
134
134
  files:
135
- - ".gitignore"
136
135
  - ".rspec"
137
136
  - ".ruby-version"
138
- - ".travis.yml"
139
137
  - Gemfile
140
138
  - README.md
141
139
  - Rakefile
data/.gitignore DELETED
@@ -1,30 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /rdoc/
5
- /pkg/
6
- /spec/reports/
7
- /tmp/
8
-
9
- # rspec failure tracking
10
- .rspec_status
11
-
12
- # simplecov
13
- /coverage/
14
-
15
- # Ignore Gemfile.lock. See https://stackoverflow.com/questions/4151495/should-gemfile-lock-be-included-in-gitignore
16
- /Gemfile.lock
17
-
18
- # Ignore vim files
19
- .*.swp
20
-
21
- # Ignore t.* files
22
- t
23
- t.*
24
- tt
25
- tt.*
26
- s
27
- s.*
28
-
29
- # Ignore temporary directory
30
- /spec/tmpdir/
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.5.1
5
- before_install: gem install bundler -v 1.16.1