shellopts 2.0.0.pre.4 → 2.0.0.pre.7

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.
@@ -16,7 +16,7 @@ module ShellOpts
16
16
  end
17
17
 
18
18
  private
19
- # Parse a command line
19
+ # Parse a subcommand line
20
20
  class Parser
21
21
  class Error < RuntimeError; end
22
22
 
@@ -27,24 +27,24 @@ module ShellOpts
27
27
 
28
28
  def call
29
29
  program = Ast::Program.new(@grammar)
30
- parse_command(program)
30
+ parse_subcommand(program)
31
31
  program.arguments = @argv
32
32
  program
33
33
  end
34
34
 
35
35
  private
36
- def parse_command(command)
37
- @seen_options = {} # Every new command resets the seen options
36
+ def parse_subcommand(subcommand)
37
+ @seen_options = {} # Every new subcommand resets the seen options
38
38
  while arg = @argv.first
39
39
  if arg == "--"
40
40
  @argv.shift
41
41
  break
42
42
  elsif arg.start_with?("-")
43
- parse_option(command)
44
- elsif cmd = command.grammar.commands[arg]
43
+ parse_option(subcommand)
44
+ elsif cmd = subcommand.grammar.subcommands[arg]
45
45
  @argv.shift
46
- command.command = Ast::Command.new(cmd, arg)
47
- parse_command(command.command)
46
+ subcommand.subcommand = Ast::Command.new(cmd, arg)
47
+ parse_subcommand(subcommand.subcommand)
48
48
  break
49
49
  else
50
50
  break
@@ -52,7 +52,7 @@ module ShellOpts
52
52
  end
53
53
  end
54
54
 
55
- def parse_option(command)
55
+ def parse_option(subcommand)
56
56
  # Split into name and argument
57
57
  case @argv.first
58
58
  when /^(--.+?)(?:=(.*))?$/
@@ -62,7 +62,7 @@ module ShellOpts
62
62
  end
63
63
  @argv.shift
64
64
 
65
- option = command.grammar.options[name] or raise Error, "Unknown option '#{name}'"
65
+ option = subcommand.grammar.options[name] or raise Error, "Unknown option '#{name}'"
66
66
  !@seen_options.key?(option.key) || option.repeated? or raise Error, "Duplicate option '#{name}'"
67
67
  @seen_options[option.key] = true
68
68
 
@@ -83,7 +83,7 @@ module ShellOpts
83
83
  raise Error, "No argument allowed for option '#{name}'"
84
84
  end
85
85
 
86
- command.options << Ast::Option.new(option, name, arg)
86
+ subcommand.options << Ast::Option.new(option, name, arg)
87
87
  end
88
88
 
89
89
  def parse_arg(option, name, arg)
@@ -6,7 +6,7 @@ require "shellopts/args.rb"
6
6
  # TODO
7
7
  #
8
8
  # PROCESSING
9
- # 1. Compile usage string and yield a grammar
9
+ # 1. Compile spec string and yield a grammar
10
10
  # 2. Parse the options using the grammar and yield an AST
11
11
  # 3. Construct the Program model from the AST
12
12
  # 4. Apply defaults to the model
@@ -17,19 +17,20 @@ require "shellopts/args.rb"
17
17
  module ShellOpts
18
18
  # The command line processing object
19
19
  class ShellOpts
20
- # One of :key, :name, :option
21
- #
22
- # Option Command
23
- # :key key #command! (no collision)
24
- # :name name #command (possible collision)
25
- # :option --option #command (multihash, no collision) (TODO)
26
- #
27
- DEFAULT_USE = :key
28
-
29
20
  # Name of program
30
- attr_reader :name
21
+ attr_accessor :name
22
+
23
+ # Usage string. If #usage is nil, the auto-generated default is used
24
+ def usage() @usage || @grammar.usage end
25
+ def usage=(usage) @usage = usage end
31
26
 
32
- # The grammar compiled from the usage string
27
+ # Specification of the command
28
+ attr_reader :spec
29
+
30
+ # Original argv argument
31
+ attr_reader :argv
32
+
33
+ # The grammar compiled from the spec string
33
34
  attr_reader :grammar
34
35
 
35
36
  # The AST parsed from the command line arguments
@@ -38,32 +39,33 @@ module ShellOpts
38
39
  # The IDR generated from the Ast
39
40
  attr_reader :idr
40
41
 
41
- # Object for error & fail messages. Default is to write a message on
42
- # standard error and exit with status 1
43
- attr_accessor :messenger
44
-
45
- # Compile a usage string into a grammar and use that to parse command line
42
+ # Compile a spec string into a grammar and use that to parse command line
46
43
  # arguments
47
44
  #
48
- # +usage+ is the usage string, and +argv+ the command line (typically the
45
+ # +spec+ is the spec string, and +argv+ the command line (typically the
49
46
  # global ARGV array). +name+ is the name of the program and defaults to the
50
47
  # basename of the program
51
48
  #
52
- # Syntax errors in the usage string are caused by the developer and raise a
53
- # +ShellOpts::CompilerError+ exception. Errors in the +argv+ arguments are
49
+ # Syntax errors in the spec string are caused by the developer and raise a
50
+ # +ShellOpts::CompilerError+ exception. Errors in the +argv+ arguments are
54
51
  # caused by the user and terminates the program with an error message and a
55
- # short description of its usage
56
- def initialize(usage, argv, name: PROGRAM, messenger: nil)
52
+ # short description of its spec
53
+ #
54
+ # TODO: Change to (name, spec, argv, usage: nil) because
55
+ # ShellOpts::ShellOpts isn't a magician like the ShellOpts module
56
+ def initialize(spec, argv, name: ::ShellOpts.default_name, usage: ::ShellOpts.default_usage)
57
57
  @name = name
58
+ @spec = spec
59
+ @usage = usage
60
+ @argv = argv
58
61
  begin
59
- @grammar = Grammar.compile(name, usage)
60
- @messenger = messenger || Messenger.new(name, @grammar.usage)
61
- @ast = Ast.parse(@grammar, argv)
62
- @idr = Idr.generate(@ast, @messenger)
62
+ @grammar = Grammar.compile(@name, @spec)
63
+ @ast = Ast.parse(@grammar, @argv)
64
+ @idr = Idr.generate(self)
63
65
  rescue Grammar::Compiler::Error => ex
64
66
  raise CompilerError.new(5, ex.message)
65
67
  rescue Ast::Parser::Error => ex
66
- error(ex.message)
68
+ raise UserError.new(ex.message)
67
69
  end
68
70
  end
69
71
 
@@ -75,10 +77,18 @@ module ShellOpts
75
77
  def to_a() idr.to_a end
76
78
 
77
79
  # Return a hash representation of the options. See {ShellOpts::OptionsHash}
78
- def to_h(use: :key, aliases: {}) @idr.to_h(use: use, aliases: aliases) end
80
+ def to_h(key_type: ::ShellOpts.default_key_type, aliases: {})
81
+ @idr.to_h(key_type: :key_type, aliases: aliases)
82
+ end
83
+
84
+ # TODO
85
+ # Return OptionHash object
86
+ # def to_hash(...)
79
87
 
80
88
  # Return a struct representation of the options. See {ShellOpts::OptionStruct}
81
- def to_struct(use: :key, aliases: {}) @idr.to_struct(use: use, aliases: aliases) end
89
+ def to_struct(key_type: ::ShellOpts.default_key_type, aliases: {})
90
+ @idr.to_struct(key_type: key_type, aliases: aliases)
91
+ end
82
92
 
83
93
  # List of remaining non-option command line arguments. Returns a Argv object
84
94
  def args() Args.new(self, ast&.arguments) end
@@ -86,15 +96,21 @@ module ShellOpts
86
96
  # Iterate options and commands as name/value pairs. Same as +to_a.each+
87
97
  def each(&block) to_a.each(&block) end
88
98
 
89
- # Print error messages and usage string and exit with status 1. This method
99
+ # Print error messages and spec string and exit with status 1. This method
90
100
  # should be called in response to user-errors (eg. specifying an illegal
91
101
  # option)
92
- def error(*msgs) @messenger.error(*msgs) end
102
+ def error(*msgs, exit: true)
103
+ msg = "#{name}: #{msgs.join}\n" + (@usage ? usage : "Usage: #{name} #{usage}")
104
+ $stderr.puts msg.rstrip
105
+ exit(1) if exit
106
+ end
93
107
 
94
108
  # Print error message and exit with status 1. This method should called in
95
109
  # response to system errors (like disk full)
96
- def fail(*msgs) @messenger.fail(*msgs) end
110
+ def fail(*msgs, exit: true)
111
+ $stderr.puts "#{name}: #{msgs.join}"
112
+ exit(1) if exit
113
+ end
97
114
  end
98
115
  end
99
116
 
100
-
@@ -1,3 +1,3 @@
1
1
  module Shellopts
2
- VERSION = "2.0.0-4"
2
+ VERSION = "2.0.0.pre.7"
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.0.0.pre.4
4
+ version: 2.0.0.pre.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claus Rasmussen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-28 00:00:00.000000000 Z
11
+ date: 2020-10-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -118,13 +118,10 @@ files:
118
118
  - lib/shellopts/grammar/option.rb
119
119
  - lib/shellopts/grammar/program.rb
120
120
  - lib/shellopts/idr.rb
121
- - lib/shellopts/messenger.rb
122
121
  - lib/shellopts/option_struct.rb
123
122
  - lib/shellopts/parser.rb
124
123
  - lib/shellopts/shellopts.rb
125
- - lib/shellopts/utils.rb
126
124
  - lib/shellopts/version.rb
127
- - rs
128
125
  - shellopts.gemspec
129
126
  homepage: http://github.com/clrgit/shellopts
130
127
  licenses: []
@@ -1,71 +0,0 @@
1
-
2
- module ShellOpts
3
- # Service object for output of messages
4
- #
5
- # Messages are using the common command line formats
6
- #
7
- class Messenger
8
- # Name of the program. When assigning to +name+ prefixed and suffixed
9
- # whitespaces are removed
10
- attr_accessor :name
11
-
12
- # :nodoc:
13
- def name=(name) @name = name.strip end
14
- # :nodoc:
15
-
16
- # Usage string. If not nil the usage string is printed by #error. When
17
- # assigning to +usage+ suffixed whitespaces are removed and the format
18
- # automatically set to +:custom+
19
- attr_accessor :usage
20
-
21
- # :nodoc:
22
- def usage=(usage)
23
- @format = :custom
24
- @usage = usage&.rstrip
25
- end
26
- # :nodoc:
27
-
28
- # Format of the usage string: +:default+ prefixes the +usage+ with 'Usage:
29
- # #{name} ' before printing. +:custom+ prints +usage+ as is
30
- attr_accessor :format
31
-
32
- # Initialize a Messenger object. +name+ is the name of the name and +usage+
33
- # is a short description of the options (eg. '-a -b') or a longer multiline
34
- # explanation. The +:format+ option selects bewtween the two: +short+ (the
35
- # default) or :long. Note that
36
- #
37
- def initialize(name, usage, format: :default)
38
- @name = name
39
- @usage = usage
40
- @format = format
41
- end
42
-
43
- # Print error message and usage string and exit with status 1. Output is
44
- # using the following format
45
- #
46
- # <name name>: <message>
47
- # Usage: <name name> <options and arguments>
48
- #
49
- def error(*msgs)
50
- $stderr.print "#{name}: #{msgs.join}\n"
51
- if usage
52
- $stderr.print "Usage: #{name} " if format == :default
53
- $stderr.print "#{usage}\n"
54
- end
55
- exit 1
56
- end
57
-
58
- # Print error message and exit with status 1. It use the current ShellOpts
59
- # object if defined. This method should not be called in response to
60
- # user-errors but system errors (like disk full). Output is using the
61
- # following format:
62
- #
63
- # <name name>: <message>
64
- #
65
- def fail(*msgs)
66
- $stderr.puts "#{name}: #{msgs.join}"
67
- exit 1
68
- end
69
- end
70
- end
71
-
@@ -1,16 +0,0 @@
1
-
2
- module ShellOpts
3
- # Use `include ShellOpts::Utils` to include ShellOpts utility methods in the
4
- # global namespace
5
- module Utils
6
- # Forwards to `ShellOpts.error`
7
- def error(*msgs)
8
- ::ShellOpts.error(*msgs)
9
- end
10
-
11
- # Forwards to `ShellOpts.fail`
12
- def fail(*msgs)
13
- ::ShellOpts.fail(*msgs)
14
- end
15
- end
16
- end
data/rs DELETED
@@ -1,40 +0,0 @@
1
- #!/usr/bin/bash
2
-
3
- PROGRAM=$(basename $0)
4
- USAGE="SOURCE-FILE"
5
-
6
- function error() {
7
- echo "$PROGRAM: $@"
8
- echo "Usage: $PROGRAM $USAGE"
9
- exit 1
10
- } >&2
11
-
12
- [ $# = 1 ] || error "Illegal number of arguments"
13
- SOURCE_NAME=${1%.rb}.rb
14
-
15
- GEM_FILE=$(ls *.gemspec 2>/dev/null)
16
- [ -n "$GEM_FILE" ] || error "Can't find gemspec file"
17
- GEM_NAME=${GEM_FILE%.gemspec}
18
-
19
- if [ -f lib/$SOURCE_NAME ]; then
20
- SOURCE_FILE=lib/$SOURCE_NAME
21
- elif [ -f lib/$GEM_NAME/$SOURCE_NAME ]; then
22
- SOURCE_FILE=lib/$GEM_NAME/$SOURCE_NAME
23
- else
24
- SOURCE_FILE=$(find lib/$GEM_NAME -type f -path $SOURCE_NAME | head -1)
25
- if [ -z "$SOURCE_FILE" ]; then
26
- SOURCE_FILE=lib/$GEM_NAME/$SOURCE_NAME
27
- fi
28
- fi
29
-
30
- SPEC_FILE=spec/${SOURCE_NAME%.rb}_spec.rb
31
- [ -f $SPEC_FILE ] || error "Can't find spec file '$SPEC_FILE'"
32
-
33
- rspec --fail-fast $SPEC_FILE || {
34
- # rcov forgets a newline when rspec fails
35
- status=$?; echo; exit $status;
36
- }
37
-
38
-
39
-
40
-