shellopts 2.0.5 → 2.0.8

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: a3a8b18b0a610c14ac4a85f80cd70ff5f85ca7dc868b25615a67a3ad71f737b5
4
- data.tar.gz: 2b0442868d8ddf102a5f8ee1b3d3307ecbea17a95512f5164d4a64a9d3fa9ec7
3
+ metadata.gz: e6c52f313fee54283e1d5e704dd8b75a96239db6cff70584eefe747cf56270c1
4
+ data.tar.gz: 67b50b7b3a993bf77533246c9634ce7850d765891381244fedf2b1ecf3f6bc76
5
5
  SHA512:
6
- metadata.gz: c90ab9e0049ba64e21c2b0fd408b438df84c0265fced52b84d221bdb2b96f92e75624c00ab59526c9caa80f67e2e7d55c5bcf0cb8138b803722b424e08ea9202
7
- data.tar.gz: 372e29956c8f3e27f8f5617215cf610403d40a307257c0c63605e94bd39fffaa8bf9cb165e82fe61497fcc8f0519c4298c1bf4480fa26735f5bf5c01e12fe8e2
6
+ metadata.gz: 3cf5cd91d92bce24b1d04a3a526d6f43f8fe761f760319bf60191e2e638c3301fdbf9c63aa9f465aa8755cd18aa56293f0ae68e01870d6a877928bc1c0eebf5c
7
+ data.tar.gz: 0e1fa649cff6a072d676a33dab6a3cbb038cb6799b59088f7ebff1144e6983843fe16658c80fa75308f057caf24e5b232aea15c92f80290d0969d868e653159e
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
@@ -200,8 +200,8 @@ module ShellOpts
200
200
  # Number of characters between columns in brief output
201
201
  BRIEF_COL_SEP = 2
202
202
 
203
- # Maximum width of first column in brief option and command lists
204
- BRIEF_COL1_MIN_WIDTH = 6
203
+ # Minimum width of first column in brief option and command lists
204
+ BRIEF_COL1_MIN_WIDTH = 20
205
205
 
206
206
  # Maximum width of first column in brief option and command lists
207
207
  BRIEF_COL1_MAX_WIDTH = 40
@@ -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
@@ -122,6 +122,23 @@ module ShellOpts
122
122
  def self.parse(token)
123
123
  super(nil, token)
124
124
  end
125
+
126
+ def add_stdopts
127
+ option_token = Token.new(:option, 1, 1, "--version")
128
+ brief_token = Token.new(:brief, 1, 1, "Write version number and exit")
129
+ group = OptionGroup.new(self, option_token)
130
+ option = Option.parse(group, option_token)
131
+ brief = Brief.parse(group, brief_token)
132
+
133
+ option_token = Token.new(:option, 1, 1, "-h,help")
134
+ brief_token = Token.new(:brief, 1, 1, "Write help text and exit")
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")
137
+ group = OptionGroup.new(self, option_token)
138
+ option = Option.parse(group, option_token)
139
+ brief = Brief.parse(group, brief_token)
140
+ paragraph = Paragraph.parse(group, paragraph_token)
141
+ end
125
142
  end
126
143
 
127
144
  class ArgSpec
@@ -146,6 +163,14 @@ module ShellOpts
146
163
  @nodes = {}
147
164
  end
148
165
 
166
+ # def add_stdopts
167
+ # version_token = Token.new(:option, 1, 1, "--version")
168
+ # version_brief = Token.new(:brief, 1, 1, "Gryf gryf")
169
+ # group = Grammar::OptionGroup.new(@program, version_token)
170
+ # option = Grammar::Option.parse(group, version_token)
171
+ # brief = Grammr::Brief.parse(option, version_brief)
172
+ # end
173
+
149
174
  def parse()
150
175
  @program = Grammar::Program.parse(@tokens.shift)
151
176
  oneline = @tokens.first.lineno == @tokens.last.lineno
@@ -1,3 +1,3 @@
1
1
  module ShellOpts
2
- VERSION = "2.0.5"
2
+ VERSION = "2.0.8"
3
3
  end
data/lib/shellopts.rb CHANGED
@@ -127,16 +127,13 @@ module ShellOpts
127
127
  # Compile source and return grammar object. Also sets #spec and #grammar.
128
128
  # Returns the grammar
129
129
  def compile(spec)
130
- if stdopts
131
- spec += "\n--version\n Write version number and exit\n-h,help @ Write help text and exit\n Write help text. -h prints a brief text, --help prints a longer man-style description of the command"
132
- end
133
130
  handle_exceptions {
134
131
  @oneline = spec.index("\n").nil?
135
132
  @spec = spec.sub(/^\s*\n/, "")
136
133
  @file = find_caller_file
137
134
  @tokens = Lexer.lex(name, @spec, @oneline)
138
135
  ast = Parser.parse(tokens)
139
- # TODO: Add standard and message options and their handlers
136
+ ast.add_stdopts if stdopts
140
137
  @grammar = Analyzer.analyze(ast)
141
138
  }
142
139
  self
@@ -197,7 +194,7 @@ module ShellOpts
197
194
  saved = $stdout
198
195
  $stdout = $stderr
199
196
  $stderr.puts "#{name}: #{message}"
200
- Formatter.usage(program)
197
+ Formatter.usage(grammar)
201
198
  exit 1
202
199
  ensure
203
200
  $stdout = saved
data/main CHANGED
@@ -9,7 +9,9 @@ include ShellOpts
9
9
 
10
10
  VERSION = "1.2.3"
11
11
 
12
- SPEC = "-a"
12
+ SPEC = %(
13
+ -a @ An option
14
+ )
13
15
  opts, args = ShellOpts::process(SPEC, ARGV, version: VERSION)
14
16
  #ShellOpts::ShellOpts.help
15
17
 
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.5
4
+ version: 2.0.8
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