gorails 0.1.1 → 0.1.4
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/CHANGELOG.md +18 -1
- data/Gemfile.lock +1 -6
- data/README.md +41 -12
- data/bin/update-deps +95 -0
- data/exe/gorails +2 -1
- data/gorails.gemspec +0 -2
- data/lib/gorails/commands/railsbytes.rb +45 -4
- data/lib/gorails/commands/version.rb +15 -0
- data/lib/gorails/commands.rb +2 -5
- data/lib/gorails/version.rb +1 -1
- data/lib/gorails.rb +11 -20
- data/vendor/deps/cli-kit/REVISION +1 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/definition.rb +301 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/evaluation.rb +237 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser/node.rb +131 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/parser.rb +128 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args/tokenizer.rb +132 -0
- data/vendor/deps/cli-kit/lib/cli/kit/args.rb +15 -0
- data/vendor/deps/cli-kit/lib/cli/kit/base_command.rb +29 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_help.rb +256 -0
- data/vendor/deps/cli-kit/lib/cli/kit/command_registry.rb +141 -0
- data/vendor/deps/cli-kit/lib/cli/kit/config.rb +137 -0
- data/vendor/deps/cli-kit/lib/cli/kit/core_ext.rb +30 -0
- data/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb +165 -0
- data/vendor/deps/cli-kit/lib/cli/kit/executor.rb +99 -0
- data/vendor/deps/cli-kit/lib/cli/kit/ini.rb +94 -0
- data/vendor/deps/cli-kit/lib/cli/kit/levenshtein.rb +89 -0
- data/vendor/deps/cli-kit/lib/cli/kit/logger.rb +95 -0
- data/vendor/deps/cli-kit/lib/cli/kit/opts.rb +284 -0
- data/vendor/deps/cli-kit/lib/cli/kit/resolver.rb +67 -0
- data/vendor/deps/cli-kit/lib/cli/kit/sorbet_runtime_stub.rb +142 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support/test_helper.rb +253 -0
- data/vendor/deps/cli-kit/lib/cli/kit/support.rb +10 -0
- data/vendor/deps/cli-kit/lib/cli/kit/system.rb +350 -0
- data/vendor/deps/cli-kit/lib/cli/kit/util.rb +133 -0
- data/vendor/deps/cli-kit/lib/cli/kit/version.rb +7 -0
- data/vendor/deps/cli-kit/lib/cli/kit.rb +151 -0
- data/vendor/deps/cli-ui/REVISION +1 -0
- data/vendor/deps/cli-ui/lib/cli/ui/ansi.rb +180 -0
- data/vendor/deps/cli-ui/lib/cli/ui/color.rb +98 -0
- data/vendor/deps/cli-ui/lib/cli/ui/formatter.rb +216 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_stack.rb +116 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/box.rb +176 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style/bracket.rb +149 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame/frame_style.rb +112 -0
- data/vendor/deps/cli-ui/lib/cli/ui/frame.rb +300 -0
- data/vendor/deps/cli-ui/lib/cli/ui/glyph.rb +92 -0
- data/vendor/deps/cli-ui/lib/cli/ui/os.rb +58 -0
- data/vendor/deps/cli-ui/lib/cli/ui/printer.rb +72 -0
- data/vendor/deps/cli-ui/lib/cli/ui/progress.rb +102 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/interactive_options.rb +534 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt/options_handler.rb +36 -0
- data/vendor/deps/cli-ui/lib/cli/ui/prompt.rb +354 -0
- data/vendor/deps/cli-ui/lib/cli/ui/sorbet_runtime_stub.rb +143 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/async.rb +46 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner/spin_group.rb +292 -0
- data/vendor/deps/cli-ui/lib/cli/ui/spinner.rb +82 -0
- data/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb +264 -0
- data/vendor/deps/cli-ui/lib/cli/ui/terminal.rb +53 -0
- data/vendor/deps/cli-ui/lib/cli/ui/truncater.rb +107 -0
- data/vendor/deps/cli-ui/lib/cli/ui/version.rb +6 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/base.rb +37 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets/status.rb +75 -0
- data/vendor/deps/cli-ui/lib/cli/ui/widgets.rb +91 -0
- data/vendor/deps/cli-ui/lib/cli/ui/wrap.rb +63 -0
- data/vendor/deps/cli-ui/lib/cli/ui.rb +356 -0
- metadata +59 -30
@@ -0,0 +1,301 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'cli/kit'
|
3
|
+
|
4
|
+
module CLI
|
5
|
+
module Kit
|
6
|
+
module Args
|
7
|
+
class Definition
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
Error = Class.new(Args::Error)
|
11
|
+
ConflictingFlag = Class.new(Error)
|
12
|
+
InvalidFlag = Class.new(Error)
|
13
|
+
InvalidLookup = Class.new(Error)
|
14
|
+
InvalidPosition = Class.new(Error)
|
15
|
+
|
16
|
+
sig { returns(T::Array[Flag]) }
|
17
|
+
attr_reader :flags
|
18
|
+
|
19
|
+
sig { returns(T::Array[Option]) }
|
20
|
+
attr_reader :options
|
21
|
+
|
22
|
+
sig { returns(T::Array[Position]) }
|
23
|
+
attr_reader :positions
|
24
|
+
|
25
|
+
sig { params(name: Symbol, short: T.nilable(String), long: T.nilable(String), desc: T.nilable(String)).void }
|
26
|
+
def add_flag(name, short: nil, long: nil, desc: nil)
|
27
|
+
short, long = strip_prefixes_and_validate(short, long)
|
28
|
+
flag = Flag.new(name: name, short: short, long: long, desc: desc)
|
29
|
+
add_resolution(flag)
|
30
|
+
@flags << flag
|
31
|
+
end
|
32
|
+
|
33
|
+
sig do
|
34
|
+
params(
|
35
|
+
name: Symbol, short: T.nilable(String), long: T.nilable(String),
|
36
|
+
desc: T.nilable(String), default: T.any(NilClass, String, T.proc.returns(String)),
|
37
|
+
required: T::Boolean, multi: T::Boolean,
|
38
|
+
).void
|
39
|
+
end
|
40
|
+
def add_option(name, short: nil, long: nil, desc: nil, default: nil, required: false, multi: false)
|
41
|
+
short, long = strip_prefixes_and_validate(short, long)
|
42
|
+
option = Option.new(
|
43
|
+
name: name, short: short, long: long, desc: desc, default: default,
|
44
|
+
required: required, multi: multi,
|
45
|
+
)
|
46
|
+
add_resolution(option)
|
47
|
+
@options << option
|
48
|
+
end
|
49
|
+
|
50
|
+
sig { params(name: Symbol, required: T::Boolean, multiple: T::Boolean, desc: T.nilable(String)).void }
|
51
|
+
def add_position(name, required:, multiple:, desc: nil)
|
52
|
+
index = @positions.size
|
53
|
+
position = Position.new(name: name, desc: desc, required: required, multiple: multiple, index: index)
|
54
|
+
validate_order(position)
|
55
|
+
add_name_resolution(position)
|
56
|
+
@positions << position
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { void }
|
60
|
+
def initialize
|
61
|
+
@flags = []
|
62
|
+
@options = []
|
63
|
+
@by_short = {}
|
64
|
+
@by_long = {}
|
65
|
+
@by_name = {}
|
66
|
+
@positions = []
|
67
|
+
end
|
68
|
+
|
69
|
+
class Flag
|
70
|
+
extend T::Sig
|
71
|
+
|
72
|
+
sig { returns(Symbol) }
|
73
|
+
attr_reader :name
|
74
|
+
|
75
|
+
sig { returns(T.nilable(String)) }
|
76
|
+
attr_reader :short
|
77
|
+
|
78
|
+
sig { returns(T.nilable(String)) }
|
79
|
+
attr_reader :long
|
80
|
+
|
81
|
+
sig { returns(T.nilable(String)) }
|
82
|
+
attr_reader :desc
|
83
|
+
|
84
|
+
sig { returns(String) }
|
85
|
+
def as_written_by_user
|
86
|
+
long ? "--#{long}" : "-#{short}"
|
87
|
+
end
|
88
|
+
|
89
|
+
sig { params(name: Symbol, short: T.nilable(String), long: T.nilable(String), desc: T.nilable(String)).void }
|
90
|
+
def initialize(name:, short: nil, long: nil, desc: nil)
|
91
|
+
if long&.start_with?('-') || short&.start_with?('-')
|
92
|
+
raise(ArgumentError, 'invalid - prefix')
|
93
|
+
end
|
94
|
+
|
95
|
+
@name = name
|
96
|
+
@short = short
|
97
|
+
@long = long
|
98
|
+
@desc = desc
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Position
|
103
|
+
extend T::Sig
|
104
|
+
|
105
|
+
sig { returns(Symbol) }
|
106
|
+
attr_reader :name
|
107
|
+
|
108
|
+
sig { returns(T.nilable(String)) }
|
109
|
+
attr_reader :desc
|
110
|
+
|
111
|
+
sig { returns(Integer) }
|
112
|
+
attr_reader :index
|
113
|
+
|
114
|
+
sig do
|
115
|
+
params(name: Symbol, desc: T.nilable(String), required: T::Boolean, multiple: T::Boolean, index: Integer)
|
116
|
+
.void
|
117
|
+
end
|
118
|
+
def initialize(name:, desc:, required:, multiple:, index:)
|
119
|
+
raise(ArgumentError, 'Cannot be required and multiple') if required && multiple
|
120
|
+
|
121
|
+
@name = name
|
122
|
+
@desc = desc
|
123
|
+
@required = required
|
124
|
+
@multiple = multiple
|
125
|
+
@index = index
|
126
|
+
end
|
127
|
+
|
128
|
+
sig { returns(T::Boolean) }
|
129
|
+
def required?
|
130
|
+
@required
|
131
|
+
end
|
132
|
+
|
133
|
+
sig { returns(T::Boolean) }
|
134
|
+
def multiple?
|
135
|
+
@multiple
|
136
|
+
end
|
137
|
+
|
138
|
+
sig { returns(T::Boolean) }
|
139
|
+
def optional?
|
140
|
+
!required?
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class Option < Flag
|
145
|
+
extend T::Sig
|
146
|
+
|
147
|
+
sig { returns(T.nilable(String)) }
|
148
|
+
def default
|
149
|
+
if @default.is_a?(Proc)
|
150
|
+
@default.call
|
151
|
+
else
|
152
|
+
@default
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
sig { returns(T::Boolean) }
|
157
|
+
def dynamic_default?
|
158
|
+
@default.is_a?(Proc)
|
159
|
+
end
|
160
|
+
|
161
|
+
sig { returns(T::Boolean) }
|
162
|
+
attr_reader :required
|
163
|
+
|
164
|
+
sig { returns(T::Boolean) }
|
165
|
+
attr_reader :multi
|
166
|
+
|
167
|
+
sig do
|
168
|
+
params(
|
169
|
+
name: Symbol, short: T.nilable(String), long: T.nilable(String),
|
170
|
+
desc: T.nilable(String), default: T.any(NilClass, String, T.proc.returns(String)),
|
171
|
+
required: T::Boolean, multi: T::Boolean,
|
172
|
+
).void
|
173
|
+
end
|
174
|
+
def initialize(name:, short: nil, long: nil, desc: nil, default: nil, required: false, multi: false)
|
175
|
+
if multi && (default || required)
|
176
|
+
raise(ArgumentError, 'multi-valued options cannot have a default or required value')
|
177
|
+
end
|
178
|
+
|
179
|
+
super(name: name, short: short, long: long, desc: desc)
|
180
|
+
@default = default
|
181
|
+
@required = required
|
182
|
+
@multi = multi
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
sig { params(name: Symbol).returns(T.nilable(Flag)) }
|
187
|
+
def lookup_flag(name)
|
188
|
+
flagopt = @by_name[name]
|
189
|
+
if flagopt.class == Flag
|
190
|
+
flagopt
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
sig { params(name: Symbol).returns(T.nilable(Option)) }
|
195
|
+
def lookup_option(name)
|
196
|
+
flagopt = @by_name[name]
|
197
|
+
if flagopt.class == Option
|
198
|
+
flagopt
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
sig { params(name: String).returns(T.any(Flag, Option, NilClass)) }
|
203
|
+
def lookup_short(name)
|
204
|
+
raise(InvalidLookup, "invalid '-' prefix") if name.start_with?('-')
|
205
|
+
|
206
|
+
@by_short[name]
|
207
|
+
end
|
208
|
+
|
209
|
+
sig { params(name: String).returns(T.any(Flag, Option, NilClass)) }
|
210
|
+
def lookup_long(name)
|
211
|
+
raise(InvalidLookup, "invalid '-' prefix") if name.start_with?('-')
|
212
|
+
|
213
|
+
@by_long[name]
|
214
|
+
end
|
215
|
+
|
216
|
+
sig { params(name: Symbol).returns(T.nilable(Position)) }
|
217
|
+
def lookup_position(name)
|
218
|
+
position = @by_name[name]
|
219
|
+
if position.class == Position
|
220
|
+
position
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
private
|
225
|
+
|
226
|
+
sig { params(position: Position).void }
|
227
|
+
def validate_order(position)
|
228
|
+
if @positions.last&.multiple?
|
229
|
+
raise(InvalidPosition, 'Cannot have any more positional arguments after multiple')
|
230
|
+
elsif @positions.last&.optional? && !position.optional?
|
231
|
+
raise(InvalidPosition, 'Cannot have any more required positional arguments after optional ones')
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
sig { params(short: String).returns(String) }
|
236
|
+
def strip_short_prefix(short)
|
237
|
+
unless short.match?(/^-[^-]/)
|
238
|
+
raise(InvalidFlag, "Short flag '#{short}' does not start with '-'")
|
239
|
+
end
|
240
|
+
if short.size != 2
|
241
|
+
raise(InvalidFlag, 'Short flag must be a single character')
|
242
|
+
end
|
243
|
+
|
244
|
+
short.sub(/^-/, '')
|
245
|
+
end
|
246
|
+
|
247
|
+
sig { params(long: String).returns(String) }
|
248
|
+
def strip_long_prefix(long)
|
249
|
+
unless long.match?(/^--[^-]/)
|
250
|
+
raise(InvalidFlag, "Long flag '#{long}' does not start with '--'")
|
251
|
+
end
|
252
|
+
|
253
|
+
long.sub(/^--/, '')
|
254
|
+
end
|
255
|
+
|
256
|
+
sig do
|
257
|
+
params(short: T.nilable(String), long: T.nilable(String))
|
258
|
+
.returns([T.nilable(String), T.nilable(String)])
|
259
|
+
end
|
260
|
+
def strip_prefixes_and_validate(short, long)
|
261
|
+
if short.nil? && long.nil?
|
262
|
+
raise(Error, 'One or more of short and long must be specified')
|
263
|
+
end
|
264
|
+
|
265
|
+
short = strip_short_prefix(short) if short
|
266
|
+
long = strip_long_prefix(long) if long
|
267
|
+
|
268
|
+
[short, long]
|
269
|
+
end
|
270
|
+
|
271
|
+
sig { params(flagopt: Flag).void }
|
272
|
+
def add_resolution(flagopt)
|
273
|
+
if flagopt.short
|
274
|
+
if (existing = @by_short[flagopt.short])
|
275
|
+
raise(ConflictingFlag, "Short flag '#{flagopt.short}' already defined by #{existing.name}")
|
276
|
+
end
|
277
|
+
|
278
|
+
@by_short[flagopt.short] = flagopt
|
279
|
+
end
|
280
|
+
if flagopt.long
|
281
|
+
if (existing = @by_long[flagopt.long])
|
282
|
+
raise(ConflictingFlag, "Long flag '#{flagopt.long}' already defined by #{existing.name}")
|
283
|
+
end
|
284
|
+
|
285
|
+
@by_long[flagopt.long] = flagopt
|
286
|
+
end
|
287
|
+
add_name_resolution(flagopt)
|
288
|
+
end
|
289
|
+
|
290
|
+
sig { params(arg: T.any(Flag, Position)).void }
|
291
|
+
def add_name_resolution(arg)
|
292
|
+
if (existing = @by_name[arg.name])
|
293
|
+
raise(ConflictingFlag, "Flag '#{arg.name}' already defined by #{existing.name}")
|
294
|
+
end
|
295
|
+
|
296
|
+
@by_name[arg.name] = arg
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'cli/kit'
|
3
|
+
|
4
|
+
module CLI
|
5
|
+
module Kit
|
6
|
+
module Args
|
7
|
+
class Evaluation
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
Error = Class.new(Args::Error)
|
11
|
+
|
12
|
+
class MissingRequiredOption < Error
|
13
|
+
extend T::Sig
|
14
|
+
sig { params(name: String).void }
|
15
|
+
def initialize(name)
|
16
|
+
super("missing required option `#{name}'")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class MissingRequiredPosition < Error
|
21
|
+
extend T::Sig
|
22
|
+
sig { void }
|
23
|
+
def initialize
|
24
|
+
super('more arguments required')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class TooManyPositions < Error
|
29
|
+
extend T::Sig
|
30
|
+
sig { void }
|
31
|
+
def initialize
|
32
|
+
super('too many arguments')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class FlagProxy
|
37
|
+
extend T::Sig
|
38
|
+
|
39
|
+
sig { params(sym: Symbol).returns(T::Boolean) }
|
40
|
+
def method_missing(sym)
|
41
|
+
flag = @evaluation.defn.lookup_flag(sym)
|
42
|
+
unless flag
|
43
|
+
raise NoMethodError, "undefined flag `#{sym}' for #{self}"
|
44
|
+
end
|
45
|
+
|
46
|
+
@evaluation.send(:lookup_flag, flag)
|
47
|
+
end
|
48
|
+
|
49
|
+
sig { params(sym: Symbol, include_private: T::Boolean).returns(T::Boolean) }
|
50
|
+
def respond_to_missing?(sym, include_private = false)
|
51
|
+
!!@evaluation.defn.lookup_flag(sym)
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { params(evaluation: Evaluation).void }
|
55
|
+
def initialize(evaluation)
|
56
|
+
@evaluation = evaluation
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class OptionProxy
|
61
|
+
extend T::Sig
|
62
|
+
|
63
|
+
sig { params(sym: Symbol).returns(T.any(NilClass, String, T::Array[String])) }
|
64
|
+
def method_missing(sym)
|
65
|
+
opt = @evaluation.defn.lookup_option(sym)
|
66
|
+
unless opt
|
67
|
+
raise NoMethodError, "undefined option `#{sym}' for #{self}"
|
68
|
+
end
|
69
|
+
|
70
|
+
@evaluation.send(:lookup_option, opt)
|
71
|
+
end
|
72
|
+
|
73
|
+
sig { params(sym: Symbol, include_private: T::Boolean).returns(T::Boolean) }
|
74
|
+
def respond_to_missing?(sym, include_private = false)
|
75
|
+
!!@evaluation.defn.lookup_option(sym)
|
76
|
+
end
|
77
|
+
|
78
|
+
sig { params(evaluation: Evaluation).void }
|
79
|
+
def initialize(evaluation)
|
80
|
+
@evaluation = evaluation
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class PositionProxy
|
85
|
+
extend T::Sig
|
86
|
+
|
87
|
+
sig { params(sym: Symbol).returns(T.any(NilClass, String, T::Array[String])) }
|
88
|
+
def method_missing(sym)
|
89
|
+
position = @evaluation.defn.lookup_position(sym)
|
90
|
+
unless position
|
91
|
+
raise NoMethodError, "undefined position `#{sym}' for #{self}"
|
92
|
+
end
|
93
|
+
|
94
|
+
@evaluation.send(:lookup_position, position)
|
95
|
+
end
|
96
|
+
|
97
|
+
sig { params(sym: Symbol, include_private: T::Boolean).returns(T::Boolean) }
|
98
|
+
def respond_to_missing?(sym, include_private = false)
|
99
|
+
!!@evaluation.defn.lookup_position(sym)
|
100
|
+
end
|
101
|
+
|
102
|
+
sig { params(evaluation: Evaluation).void }
|
103
|
+
def initialize(evaluation)
|
104
|
+
@evaluation = evaluation
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
sig { returns(FlagProxy) }
|
109
|
+
def flag
|
110
|
+
@flag_proxy ||= FlagProxy.new(self)
|
111
|
+
end
|
112
|
+
|
113
|
+
sig { returns(OptionProxy) }
|
114
|
+
def opt
|
115
|
+
@option_proxy ||= OptionProxy.new(self)
|
116
|
+
end
|
117
|
+
|
118
|
+
sig { returns(PositionProxy) }
|
119
|
+
def position
|
120
|
+
@position_proxy ||= PositionProxy.new(self)
|
121
|
+
end
|
122
|
+
|
123
|
+
sig { returns(Definition) }
|
124
|
+
attr_reader :defn
|
125
|
+
|
126
|
+
sig { returns(T::Array[Parser::Node]) }
|
127
|
+
attr_reader :parse
|
128
|
+
|
129
|
+
sig { returns(T::Array[String]) }
|
130
|
+
def unparsed
|
131
|
+
@unparsed ||= begin
|
132
|
+
nodes = T.cast(
|
133
|
+
parse.select { |node| node.is_a?(Parser::Node::Unparsed) },
|
134
|
+
T::Array[Parser::Node::Unparsed],
|
135
|
+
)
|
136
|
+
nodes.flat_map(&:value)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
sig { params(defn: Definition, parse: T::Array[Parser::Node]).void }
|
141
|
+
def initialize(defn, parse)
|
142
|
+
@defn = defn
|
143
|
+
@parse = parse
|
144
|
+
check_required!
|
145
|
+
end
|
146
|
+
|
147
|
+
sig { void }
|
148
|
+
def check_required!
|
149
|
+
@defn.options.each do |opt|
|
150
|
+
next unless opt.required
|
151
|
+
|
152
|
+
node = @parse.detect do |node|
|
153
|
+
node.is_a?(Parser::Node::Option) && node.name == opt.name
|
154
|
+
end
|
155
|
+
if !node || T.cast(node, Parser::Node::Option).value.nil?
|
156
|
+
raise(MissingRequiredOption, opt.as_written_by_user)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
min_positions = @defn.positions.count(&:required?)
|
160
|
+
max_positions = if @defn.positions.last&.multiple?
|
161
|
+
Float::INFINITY
|
162
|
+
else
|
163
|
+
min_positions + @defn.positions.count(&:optional?)
|
164
|
+
end
|
165
|
+
raise(MissingRequiredPosition) if args.size < min_positions
|
166
|
+
raise(TooManyPositions) if args.size > max_positions
|
167
|
+
end
|
168
|
+
|
169
|
+
sig { params(flag: Definition::Flag).returns(T::Boolean) }
|
170
|
+
def lookup_flag(flag)
|
171
|
+
if flag.short
|
172
|
+
flags = T.cast(
|
173
|
+
parse.select { |node| node.is_a?(Parser::Node::ShortFlag) },
|
174
|
+
T::Array[Parser::Node::ShortFlag],
|
175
|
+
)
|
176
|
+
return true if flags.any? { |node| node.value == flag.short }
|
177
|
+
end
|
178
|
+
if flag.long
|
179
|
+
flags = T.cast(
|
180
|
+
parse.select { |node| node.is_a?(Parser::Node::LongFlag) },
|
181
|
+
T::Array[Parser::Node::LongFlag],
|
182
|
+
)
|
183
|
+
return true if flags.any? { |node| node.value == flag.long }
|
184
|
+
end
|
185
|
+
false
|
186
|
+
end
|
187
|
+
|
188
|
+
sig { params(opt: Definition::Option).returns(T.any(NilClass, String, T::Array[String])) }
|
189
|
+
def lookup_option(opt)
|
190
|
+
if opt.short
|
191
|
+
opts = T.cast(
|
192
|
+
parse.select { |node| node.is_a?(Parser::Node::ShortOption) },
|
193
|
+
T::Array[Parser::Node::ShortOption],
|
194
|
+
)
|
195
|
+
matches = opts.reverse.select { |node| node.name == opt.short }
|
196
|
+
if (first = matches.first)
|
197
|
+
return(opt.multi ? matches.map(&:value) : first.value)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
if opt.long
|
201
|
+
opts = T.cast(
|
202
|
+
parse.select { |node| node.is_a?(Parser::Node::LongOption) },
|
203
|
+
T::Array[Parser::Node::LongOption],
|
204
|
+
)
|
205
|
+
matches = opts.reverse.select { |node| node.name == opt.long }
|
206
|
+
if (first = matches.first)
|
207
|
+
return(opt.multi ? matches.map(&:value) : first.value)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
opt.multi ? [] : opt.default
|
211
|
+
end
|
212
|
+
|
213
|
+
sig { params(position: Definition::Position).returns(T.any(NilClass, String, T::Array[String])) }
|
214
|
+
def lookup_position(position)
|
215
|
+
if position.multiple?
|
216
|
+
args[position.index..]
|
217
|
+
else
|
218
|
+
args[position.index]
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
sig { returns(T::Array[String]) }
|
225
|
+
def args
|
226
|
+
@args ||= begin
|
227
|
+
nodes = T.cast(
|
228
|
+
parse.select { |node| node.is_a?(Parser::Node::Argument) },
|
229
|
+
T::Array[Parser::Node::Argument],
|
230
|
+
)
|
231
|
+
nodes.map(&:value)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# typed: true
|
2
|
+
require 'cli/kit'
|
3
|
+
|
4
|
+
module CLI
|
5
|
+
module Kit
|
6
|
+
module Args
|
7
|
+
class Parser
|
8
|
+
class Node
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig { void }
|
12
|
+
def initialize
|
13
|
+
end
|
14
|
+
|
15
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
16
|
+
def ==(other)
|
17
|
+
self.class == other.class
|
18
|
+
end
|
19
|
+
|
20
|
+
class Option < Node
|
21
|
+
extend T::Sig
|
22
|
+
|
23
|
+
sig { returns(String) }
|
24
|
+
attr_reader :name
|
25
|
+
|
26
|
+
sig { returns(String) }
|
27
|
+
attr_reader :value
|
28
|
+
|
29
|
+
sig { params(name: String, value: String).void }
|
30
|
+
def initialize(name, value)
|
31
|
+
@name = name
|
32
|
+
@value = value
|
33
|
+
super()
|
34
|
+
end
|
35
|
+
private_class_method(:new) # don't instantiate this class directly
|
36
|
+
|
37
|
+
sig { returns(String) }
|
38
|
+
def inspect
|
39
|
+
"#<#{self.class.name} #{@name}=#{@value}>"
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
43
|
+
def ==(other)
|
44
|
+
!!(super(other) && @value == other.value && @name == other.name)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class LongOption < Option
|
49
|
+
public_class_method(:new)
|
50
|
+
end
|
51
|
+
|
52
|
+
class ShortOption < Option
|
53
|
+
public_class_method(:new)
|
54
|
+
end
|
55
|
+
|
56
|
+
class Flag < Node
|
57
|
+
sig { returns(String) }
|
58
|
+
attr_reader :value
|
59
|
+
|
60
|
+
sig { params(value: String).void }
|
61
|
+
def initialize(value)
|
62
|
+
@value = value
|
63
|
+
super()
|
64
|
+
end
|
65
|
+
private_class_method(:new) # don't instantiate this class directly
|
66
|
+
|
67
|
+
sig { returns(String) }
|
68
|
+
def inspect
|
69
|
+
"#<#{self.class.name} #{@value}>"
|
70
|
+
end
|
71
|
+
|
72
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
73
|
+
def ==(other)
|
74
|
+
!!(super(other) && @value == other.value)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class LongFlag < Flag
|
79
|
+
public_class_method(:new)
|
80
|
+
end
|
81
|
+
|
82
|
+
class ShortFlag < Flag
|
83
|
+
public_class_method(:new)
|
84
|
+
end
|
85
|
+
|
86
|
+
class Argument < Node
|
87
|
+
sig { returns(String) }
|
88
|
+
attr_reader :value
|
89
|
+
|
90
|
+
sig { params(value: String).void }
|
91
|
+
def initialize(value)
|
92
|
+
@value = value
|
93
|
+
super()
|
94
|
+
end
|
95
|
+
|
96
|
+
sig { returns(String) }
|
97
|
+
def inspect
|
98
|
+
"#<#{self.class.name} #{@value}>"
|
99
|
+
end
|
100
|
+
|
101
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
102
|
+
def ==(other)
|
103
|
+
!!(super(other) && @value == other.value)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
class Unparsed < Node
|
108
|
+
sig { returns(T::Array[String]) }
|
109
|
+
attr_reader :value
|
110
|
+
|
111
|
+
sig { params(value: T::Array[String]).void }
|
112
|
+
def initialize(value)
|
113
|
+
@value = value
|
114
|
+
super()
|
115
|
+
end
|
116
|
+
|
117
|
+
sig { returns(String) }
|
118
|
+
def inspect
|
119
|
+
"#<#{self.class.name} #{@value.join(" ")}>"
|
120
|
+
end
|
121
|
+
|
122
|
+
sig { params(other: T.untyped).returns(T::Boolean) }
|
123
|
+
def ==(other)
|
124
|
+
!!(super(other) && @value == other.value)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|