shellopts 2.0.0.pre.13 → 2.0.1
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 +4 -4
- data/.gitignore +2 -1
- data/.ruby-version +1 -1
- data/README.md +201 -267
- data/TODO +46 -134
- data/doc/format.rb +95 -0
- data/doc/grammar.txt +27 -0
- data/doc/syntax.rb +110 -0
- data/doc/syntax.txt +10 -0
- data/lib/ext/array.rb +58 -5
- data/lib/ext/forward_to.rb +15 -0
- data/lib/ext/lcs.rb +34 -0
- data/lib/shellopts/analyzer.rb +130 -0
- data/lib/shellopts/ansi.rb +8 -0
- data/lib/shellopts/args.rb +29 -21
- data/lib/shellopts/argument_type.rb +139 -0
- data/lib/shellopts/dump.rb +158 -0
- data/lib/shellopts/formatter.rb +325 -0
- data/lib/shellopts/grammar.rb +375 -0
- data/lib/shellopts/interpreter.rb +103 -0
- data/lib/shellopts/lexer.rb +175 -0
- data/lib/shellopts/parser.rb +269 -82
- data/lib/shellopts/program.rb +279 -0
- data/lib/shellopts/renderer.rb +227 -0
- data/lib/shellopts/stack.rb +7 -0
- data/lib/shellopts/token.rb +44 -0
- data/lib/shellopts/version.rb +2 -2
- data/lib/shellopts.rb +439 -220
- data/main +1180 -0
- data/shellopts.gemspec +9 -15
- metadata +85 -42
- data/lib/main.rb +0 -1
- data/lib/shellopts/ast/command.rb +0 -41
- data/lib/shellopts/ast/node.rb +0 -37
- data/lib/shellopts/ast/option.rb +0 -21
- data/lib/shellopts/ast/program.rb +0 -14
- data/lib/shellopts/compiler.rb +0 -128
- data/lib/shellopts/generator.rb +0 -15
- data/lib/shellopts/grammar/command.rb +0 -80
- data/lib/shellopts/grammar/node.rb +0 -33
- data/lib/shellopts/grammar/option.rb +0 -66
- data/lib/shellopts/grammar/program.rb +0 -65
- data/lib/shellopts/idr.rb +0 -236
- data/lib/shellopts/main.rb +0 -10
- data/lib/shellopts/option_struct.rb +0 -148
- data/lib/shellopts/shellopts.rb +0 -123
data/shellopts.gemspec
CHANGED
@@ -5,26 +5,16 @@ require "shellopts/version"
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "shellopts"
|
8
|
-
spec.version =
|
8
|
+
spec.version = ShellOpts::VERSION
|
9
9
|
spec.authors = ["Claus Rasmussen"]
|
10
10
|
spec.email = ["claus.l.rasmussen@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{Parse command line options and arguments}
|
13
13
|
spec.description = %q{ShellOpts is a simple command line parsing libray
|
14
|
-
that
|
15
|
-
|
16
|
-
getopt(1)-like string that is interpreted by the
|
17
|
-
library to process the command line}
|
14
|
+
that supports short and long options and subcommands,
|
15
|
+
and has built-in help and error messages}
|
18
16
|
spec.homepage = "http://github.com/clrgit/shellopts"
|
19
17
|
|
20
|
-
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
21
|
-
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
22
|
-
if spec.respond_to?(:metadata)
|
23
|
-
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
24
|
-
else
|
25
|
-
raise "RubyGems 2.0+ is required to protect against public gem pushes"
|
26
|
-
end
|
27
|
-
|
28
18
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
29
19
|
f.match(%r{^(test|spec|features)/})
|
30
20
|
end
|
@@ -32,9 +22,13 @@ Gem::Specification.new do |spec|
|
|
32
22
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
23
|
spec.require_paths = ["lib"]
|
34
24
|
|
35
|
-
spec.
|
25
|
+
spec.add_dependency "forward_to"
|
26
|
+
spec.add_dependency "constrain"
|
27
|
+
spec.add_dependency "ruby-terminfo"
|
28
|
+
spec.add_dependency "indented_io"
|
29
|
+
|
30
|
+
spec.add_development_dependency "bundler", "~> 2.2.10"
|
36
31
|
spec.add_development_dependency "rake", ">= 12.3.3"
|
37
32
|
spec.add_development_dependency "rspec", "~> 3.0"
|
38
|
-
spec.add_development_dependency "indented_io"
|
39
33
|
spec.add_development_dependency "simplecov"
|
40
34
|
end
|
metadata
CHANGED
@@ -1,71 +1,113 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shellopts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Claus Rasmussen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: forward_to
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
type: :
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: constrain
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
34
|
-
type: :
|
33
|
+
version: '0'
|
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:
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: ruby-terminfo
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: indented_io
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: bundler
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
44
72
|
requirements:
|
45
73
|
- - "~>"
|
46
74
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
75
|
+
version: 2.2.10
|
48
76
|
type: :development
|
49
77
|
prerelease: false
|
50
78
|
version_requirements: !ruby/object:Gem::Requirement
|
51
79
|
requirements:
|
52
80
|
- - "~>"
|
53
81
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
82
|
+
version: 2.2.10
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
84
|
+
name: rake
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
58
86
|
requirements:
|
59
87
|
- - ">="
|
60
88
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
89
|
+
version: 12.3.3
|
62
90
|
type: :development
|
63
91
|
prerelease: false
|
64
92
|
version_requirements: !ruby/object:Gem::Requirement
|
65
93
|
requirements:
|
66
94
|
- - ">="
|
67
95
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
96
|
+
version: 12.3.3
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.0'
|
69
111
|
- !ruby/object:Gem::Dependency
|
70
112
|
name: simplecov
|
71
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,10 +124,8 @@ dependencies:
|
|
82
124
|
version: '0'
|
83
125
|
description: |-
|
84
126
|
ShellOpts is a simple command line parsing libray
|
85
|
-
that
|
86
|
-
|
87
|
-
getopt(1)-like string that is interpreted by the
|
88
|
-
library to process the command line
|
127
|
+
that supports short and long options and subcommands,
|
128
|
+
and has built-in help and error messages
|
89
129
|
email:
|
90
130
|
- claus.l.rasmussen@gmail.com
|
91
131
|
executables: []
|
@@ -103,32 +143,35 @@ files:
|
|
103
143
|
- bin/console
|
104
144
|
- bin/mkdoc
|
105
145
|
- bin/setup
|
146
|
+
- doc/format.rb
|
147
|
+
- doc/grammar.txt
|
106
148
|
- doc/stylesheet.css
|
149
|
+
- doc/syntax.rb
|
150
|
+
- doc/syntax.txt
|
107
151
|
- lib/ext/array.rb
|
108
|
-
- lib/
|
152
|
+
- lib/ext/forward_to.rb
|
153
|
+
- lib/ext/lcs.rb
|
109
154
|
- lib/shellopts.rb
|
155
|
+
- lib/shellopts/analyzer.rb
|
156
|
+
- lib/shellopts/ansi.rb
|
110
157
|
- lib/shellopts/args.rb
|
111
|
-
- lib/shellopts/
|
112
|
-
- lib/shellopts/
|
113
|
-
- lib/shellopts/
|
114
|
-
- lib/shellopts/
|
115
|
-
- lib/shellopts/
|
116
|
-
- lib/shellopts/
|
117
|
-
- lib/shellopts/grammar/command.rb
|
118
|
-
- lib/shellopts/grammar/node.rb
|
119
|
-
- lib/shellopts/grammar/option.rb
|
120
|
-
- lib/shellopts/grammar/program.rb
|
121
|
-
- lib/shellopts/idr.rb
|
122
|
-
- lib/shellopts/main.rb
|
123
|
-
- lib/shellopts/option_struct.rb
|
158
|
+
- lib/shellopts/argument_type.rb
|
159
|
+
- lib/shellopts/dump.rb
|
160
|
+
- lib/shellopts/formatter.rb
|
161
|
+
- lib/shellopts/grammar.rb
|
162
|
+
- lib/shellopts/interpreter.rb
|
163
|
+
- lib/shellopts/lexer.rb
|
124
164
|
- lib/shellopts/parser.rb
|
125
|
-
- lib/shellopts/
|
165
|
+
- lib/shellopts/program.rb
|
166
|
+
- lib/shellopts/renderer.rb
|
167
|
+
- lib/shellopts/stack.rb
|
168
|
+
- lib/shellopts/token.rb
|
126
169
|
- lib/shellopts/version.rb
|
170
|
+
- main
|
127
171
|
- shellopts.gemspec
|
128
172
|
homepage: http://github.com/clrgit/shellopts
|
129
173
|
licenses: []
|
130
|
-
metadata:
|
131
|
-
allowed_push_host: https://rubygems.org
|
174
|
+
metadata: {}
|
132
175
|
post_install_message:
|
133
176
|
rdoc_options: []
|
134
177
|
require_paths:
|
@@ -140,11 +183,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
140
183
|
version: '0'
|
141
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
185
|
requirements:
|
143
|
-
- - "
|
186
|
+
- - ">="
|
144
187
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
188
|
+
version: '0'
|
146
189
|
requirements: []
|
147
|
-
rubygems_version: 3.
|
190
|
+
rubygems_version: 3.2.26
|
148
191
|
signing_key:
|
149
192
|
specification_version: 4
|
150
193
|
summary: Parse command line options and arguments
|
data/lib/main.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
hej
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module ShellOpts
|
2
|
-
module Ast
|
3
|
-
class Command < Node
|
4
|
-
# Array of options (Ast::Option). Initially empty but filled out by the
|
5
|
-
# parser
|
6
|
-
attr_reader :options
|
7
|
-
|
8
|
-
# Optional sub-command (Ast::Command). Initially nil but assigned by the
|
9
|
-
# parser
|
10
|
-
attr_accessor :subcommand
|
11
|
-
|
12
|
-
def initialize(grammar, name)
|
13
|
-
super(grammar, name)
|
14
|
-
@options = []
|
15
|
-
@subcommand = nil
|
16
|
-
end
|
17
|
-
|
18
|
-
# Array of option or command tuples
|
19
|
-
def values
|
20
|
-
(options + (Array(subcommand || []))).map { |node| node.to_tuple }
|
21
|
-
end
|
22
|
-
|
23
|
-
# :nocov:
|
24
|
-
def dump(&block)
|
25
|
-
super {
|
26
|
-
yield if block_given?
|
27
|
-
puts "options:"
|
28
|
-
indent { options.each { |opt| opt.dump } }
|
29
|
-
print "subcommand:"
|
30
|
-
if subcommand
|
31
|
-
puts
|
32
|
-
indent { subcommand.dump }
|
33
|
-
else
|
34
|
-
puts "nil"
|
35
|
-
end
|
36
|
-
}
|
37
|
-
end
|
38
|
-
# :nocov:
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/lib/shellopts/ast/node.rb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
module ShellOpts
|
2
|
-
module Ast
|
3
|
-
class Node
|
4
|
-
# The associated Grammar::Node object
|
5
|
-
attr_reader :grammar
|
6
|
-
|
7
|
-
# Key of node. Shorthand for grammar.key
|
8
|
-
def key() @grammar.key end
|
9
|
-
|
10
|
-
# Name of node (either program, command, or option name)
|
11
|
-
attr_reader :name
|
12
|
-
|
13
|
-
# Initialize an +Ast::Node+ object. +grammar+ is the corresponding
|
14
|
-
# grammar object (+Grammar::Node+) and +name+ is the name of the option
|
15
|
-
# or sub-command
|
16
|
-
def initialize(grammar, name)
|
17
|
-
@grammar, @name = grammar, name
|
18
|
-
end
|
19
|
-
|
20
|
-
# Return a name/value pair
|
21
|
-
def to_tuple
|
22
|
-
[name, values]
|
23
|
-
end
|
24
|
-
|
25
|
-
# Return either a value (option value), an array of values (command), or
|
26
|
-
# nil (option without a value). It must be defined in sub-classes of Ast::Node
|
27
|
-
def values() raise end
|
28
|
-
|
29
|
-
# :nocov:
|
30
|
-
def dump(&block)
|
31
|
-
puts key.inspect
|
32
|
-
indent { yield } if block_given?
|
33
|
-
end
|
34
|
-
# :nocov:
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
data/lib/shellopts/ast/option.rb
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
module ShellOpts
|
2
|
-
module Ast
|
3
|
-
class Option < Node
|
4
|
-
# Optional value. Can be a String, Integer, or Float
|
5
|
-
attr_reader :value
|
6
|
-
|
7
|
-
def initialize(grammar, name, value)
|
8
|
-
super(grammar, name)
|
9
|
-
@value = value
|
10
|
-
end
|
11
|
-
|
12
|
-
def values() value end
|
13
|
-
|
14
|
-
# :nocov:
|
15
|
-
def dump
|
16
|
-
super { puts "values: #{values.inspect}" }
|
17
|
-
end
|
18
|
-
# :nocov:
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module ShellOpts
|
2
|
-
module Ast
|
3
|
-
class Program < Command
|
4
|
-
# Command line arguments. Initially nil but assigned by the parser. This array
|
5
|
-
# is the same as the argument array returned by Ast.parse
|
6
|
-
attr_accessor :arguments
|
7
|
-
|
8
|
-
def initialize(grammar)
|
9
|
-
super(grammar, grammar.name)
|
10
|
-
@arguments = nil
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/lib/shellopts/compiler.rb
DELETED
@@ -1,128 +0,0 @@
|
|
1
|
-
require "ext/array.rb"
|
2
|
-
|
3
|
-
require 'shellopts/grammar/node.rb'
|
4
|
-
require 'shellopts/grammar/option.rb'
|
5
|
-
require 'shellopts/grammar/command.rb'
|
6
|
-
require 'shellopts/grammar/program.rb'
|
7
|
-
|
8
|
-
module ShellOpts
|
9
|
-
module Grammar
|
10
|
-
# Compiles an option definition string and returns a Grammar::Program
|
11
|
-
# object. name is the name of the program and source is the
|
12
|
-
# option definition string
|
13
|
-
def self.compile(name, source)
|
14
|
-
name.is_a?(String) or raise Compiler::Error, "Expected String argument, got #{name.class}"
|
15
|
-
source.is_a?(String) or raise Compiler::Error, "Expected String argument, got #{source.class}"
|
16
|
-
Compiler.new(name, source).call
|
17
|
-
end
|
18
|
-
|
19
|
-
# Service object for compiling an option definition string. Returns a
|
20
|
-
# Grammar::Program object
|
21
|
-
#
|
22
|
-
# Compiler implements a recursive descend algorithm to compile the option
|
23
|
-
# string. The algorithm uses state variables and is embedded in a
|
24
|
-
# Grammar::Compiler service object
|
25
|
-
class Compiler
|
26
|
-
class Error < RuntimeError; end
|
27
|
-
|
28
|
-
# Initialize a Compiler object. source is the option definition string
|
29
|
-
def initialize(name, source)
|
30
|
-
@name, @tokens = name, source.split(/\s+/).reject(&:empty?)
|
31
|
-
|
32
|
-
# @subcommands_by_path is an hash from subcommand-path to Command or Program
|
33
|
-
# object. The top level Program object has nil as its path.
|
34
|
-
# @subcommands_by_path is used to check for uniqueness of subcommands and to
|
35
|
-
# link sub-subcommands to their parents
|
36
|
-
@subcommands_by_path = {}
|
37
|
-
end
|
38
|
-
|
39
|
-
def call
|
40
|
-
compile_program
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
using XArray # For Array#find_dup
|
45
|
-
|
46
|
-
# Returns the current token
|
47
|
-
def curr_token() @tokens.first end
|
48
|
-
|
49
|
-
# Returns the current token and advance to the next token
|
50
|
-
def next_token() @tokens.shift end
|
51
|
-
|
52
|
-
def compile_program
|
53
|
-
program = @subcommands_by_path[nil] = Grammar::Program.new(@name, compile_options)
|
54
|
-
while curr_token && curr_token != "--"
|
55
|
-
compile_subcommand
|
56
|
-
end
|
57
|
-
program.args.concat(@tokens[1..-1]) if curr_token
|
58
|
-
program
|
59
|
-
end
|
60
|
-
|
61
|
-
def compile_subcommand
|
62
|
-
path = curr_token[0..-2]
|
63
|
-
ident_list = compile_ident_list(path, ".")
|
64
|
-
parent_path = ident_list.size > 1 ? ident_list[0..-2].join(".") : nil
|
65
|
-
name = ident_list[-1]
|
66
|
-
|
67
|
-
parent = @subcommands_by_path[parent_path] or
|
68
|
-
raise Compiler::Error, "No such subcommand: #{parent_path.inspect}"
|
69
|
-
!@subcommands_by_path.key?(path) or raise Compiler::Error, "Duplicate subcommand: #{path.inspect}"
|
70
|
-
next_token
|
71
|
-
@subcommands_by_path[path] = Grammar::Command.new(parent, name, compile_options)
|
72
|
-
end
|
73
|
-
|
74
|
-
def compile_options
|
75
|
-
option_list = []
|
76
|
-
while curr_token && curr_token != "--" && !curr_token.end_with?("!")
|
77
|
-
option_list << compile_option
|
78
|
-
end
|
79
|
-
dup = option_list.map(&:names).flatten.find_dup and
|
80
|
-
raise Compiler::Error, "Duplicate option name: #{dup.inspect}"
|
81
|
-
option_list
|
82
|
-
end
|
83
|
-
|
84
|
-
def compile_option
|
85
|
-
# Match string and build flags
|
86
|
-
flags = []
|
87
|
-
curr_token =~ /^(\+)?(.+?)(?:(=)(\$|\#)?(.*?)(\?)?)?$/
|
88
|
-
flags << :repeated if $1 == "+"
|
89
|
-
names = $2
|
90
|
-
flags << :argument if $3 == "="
|
91
|
-
flags << :integer if $4 == "#"
|
92
|
-
flags << :float if $4 == "$"
|
93
|
-
label = $5 == "" ? nil : $5
|
94
|
-
flags << :optional if $6 == "?"
|
95
|
-
|
96
|
-
# Build names
|
97
|
-
short_names = []
|
98
|
-
long_names = []
|
99
|
-
ident_list = compile_ident_list(names, ",")
|
100
|
-
(dup = ident_list.find_dup).nil? or
|
101
|
-
raise Compiler::Error, "Duplicate identifier #{dup.inspect} in #{curr_token.inspect}"
|
102
|
-
ident_list.each { |ident|
|
103
|
-
if ident.size == 1
|
104
|
-
short_names << "-#{ident}"
|
105
|
-
else
|
106
|
-
long_names << "--#{ident}"
|
107
|
-
end
|
108
|
-
}
|
109
|
-
|
110
|
-
next_token
|
111
|
-
Grammar::Option.new(short_names, long_names, flags, label)
|
112
|
-
end
|
113
|
-
|
114
|
-
# Compile list of option names or a subcommand path
|
115
|
-
def compile_ident_list(ident_list_str, sep)
|
116
|
-
ident_list_str.split(sep, -1).map { |str|
|
117
|
-
!str.empty? or
|
118
|
-
raise Compiler::Error, "Empty identifier in #{curr_token.inspect}"
|
119
|
-
!str.start_with?("-") or
|
120
|
-
raise Compiler::Error, "Identifier can't start with '-' in #{curr_token.inspect}"
|
121
|
-
str !~ /([^\w\d#{sep}-])/ or
|
122
|
-
raise Compiler::Error, "Illegal character #{$1.inspect} in #{curr_token.inspect}"
|
123
|
-
str
|
124
|
-
}
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
data/lib/shellopts/generator.rb
DELETED
@@ -1,80 +0,0 @@
|
|
1
|
-
module ShellOpts
|
2
|
-
module Grammar
|
3
|
-
# A command. Commands are organized hierarchically with a Program object as
|
4
|
-
# the root node
|
5
|
-
#
|
6
|
-
# Sets Node#key to the name of the command incl. the exclamation point
|
7
|
-
class Command < Node
|
8
|
-
# Parent command. Nil if this is the top level command (the program)
|
9
|
-
attr_reader :parent
|
10
|
-
|
11
|
-
# Name of command (String). Name doesn't include the exclamation point ('!')
|
12
|
-
attr_reader :name
|
13
|
-
|
14
|
-
# Same as #name. TODO Define in Grammar::Node instead
|
15
|
-
alias :key_name :name
|
16
|
-
|
17
|
-
# List of options in declaration order
|
18
|
-
attr_reader :option_list
|
19
|
-
|
20
|
-
# List of commands in declaration order
|
21
|
-
attr_reader :subcommand_list
|
22
|
-
|
23
|
-
# Multihash from option key or names (both short and long names) to option. This
|
24
|
-
# means an option can occur more than once as the hash value
|
25
|
-
def options()
|
26
|
-
@option_multihash ||= @option_list.flat_map { |option|
|
27
|
-
option.identifiers.map { |ident| [ident, option] }
|
28
|
-
}.to_h
|
29
|
-
end
|
30
|
-
|
31
|
-
# Sub-commands of this command. Is a multihash from sub-command key or
|
32
|
-
# name to command object. Lazily constructed because subcommands are added
|
33
|
-
# after initialization
|
34
|
-
def subcommands()
|
35
|
-
@subcommand_multihash ||= @subcommand_list.flat_map { |subcommand|
|
36
|
-
subcommand.identifiers.map { |name| [name, subcommand] }
|
37
|
-
}.to_h
|
38
|
-
end
|
39
|
-
|
40
|
-
# Initialize a Command object. parent is the parent Command object or nil
|
41
|
-
# if this is the root object. name is the name of the command (without
|
42
|
-
# the exclamation mark), and option_list a list of Option objects
|
43
|
-
def initialize(parent, name, option_list)
|
44
|
-
super("#{name}!".to_sym, name)
|
45
|
-
parent.attach(self) if parent
|
46
|
-
@option_list = option_list
|
47
|
-
@subcommand_list = []
|
48
|
-
end
|
49
|
-
|
50
|
-
# Return key for the identifier
|
51
|
-
def identifier2key(ident)
|
52
|
-
options[ident]&.key || subcommands[ident]&.key
|
53
|
-
end
|
54
|
-
|
55
|
-
# Return list of identifiers for the command
|
56
|
-
def identifiers() [key, name] end
|
57
|
-
|
58
|
-
# :nocov:
|
59
|
-
def dump(&block)
|
60
|
-
puts "#{key.inspect}"
|
61
|
-
indent {
|
62
|
-
puts "parent: #{parent&.key.inspect}"
|
63
|
-
puts "name: #{name.inspect}"
|
64
|
-
yield if block_given?
|
65
|
-
puts "options:"
|
66
|
-
indent { option_list.each { |opt| opt.dump } }
|
67
|
-
puts "subcommands: "
|
68
|
-
indent { subcommand_list.each { |cmd| cmd.dump } }
|
69
|
-
}
|
70
|
-
end
|
71
|
-
# :nocov:
|
72
|
-
|
73
|
-
protected
|
74
|
-
def attach(subcommand)
|
75
|
-
subcommand.instance_variable_set(:@parent, self)
|
76
|
-
@subcommand_list << subcommand
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module ShellOpts
|
2
|
-
module Grammar
|
3
|
-
# Root class for Grammar objects
|
4
|
-
#
|
5
|
-
# Node objects are created by ShellOpts::Grammar.compile that returns a
|
6
|
-
# Program object that in turn contains other node objects in a hierarchical
|
7
|
-
# structure that reflects the grammar of the program. Only
|
8
|
-
# ShellOpts::Grammar.compile should create node objects
|
9
|
-
class Node
|
10
|
-
# Key (Symbol) of node. Unique within the enclosing command
|
11
|
-
attr_reader :key
|
12
|
-
|
13
|
-
# Name of node. The name of an option is without the prefixed '-' or
|
14
|
-
# '--', the name of a command is without the suffixed '!'. Note that name
|
15
|
-
# collisions can happen between options and commands names
|
16
|
-
attr_reader :name
|
17
|
-
|
18
|
-
def initialize(key, name)
|
19
|
-
@key, @name = key, name
|
20
|
-
end
|
21
|
-
|
22
|
-
# :nocov:
|
23
|
-
def dump(&block)
|
24
|
-
puts key.inspect
|
25
|
-
indent {
|
26
|
-
puts "name: #{name.inspect}"
|
27
|
-
yield if block_given?
|
28
|
-
}
|
29
|
-
end
|
30
|
-
# :nocov:
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|