squared 0.4.41 → 0.5.0

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.
@@ -10,36 +10,16 @@ module Squared
10
10
  include Common::Shell
11
11
  extend Forwardable
12
12
 
13
- OPT_NAME = /\A(?:(--)|-)((?(1)[^=\s-][^=\s]*|[^=\s-]))\z/
14
- OPT_VALUE = /\A-{0,2}([^=\s-][^=\s]*)(?:=|\s+)(\S.*)\z/
15
- OPT_SINGLE = /\A-([^=\s-])(.+)\z/
16
- private_constant :OPT_NAME, :OPT_VALUE, :OPT_SINGLE
17
-
18
13
  class << self
19
14
  include Common::Format
20
15
  include Shell
21
16
  include Prompt
22
17
 
23
- def append(target, *args, delim: false, escape: false, quote: true, strip: nil, force: true, double: false,
24
- preserve: true, **)
18
+ def append(target, *args, delim: false, escape: false, quote: true, **)
25
19
  return if (ret = args.flatten).empty?
26
20
 
27
21
  target << '--' if delim && !target.include?('--')
28
- if strip
29
- pat, s = Array(strip)
30
- ret.map! { |val| val.is_a?(String) ? val.gsub(pat, s || '') : val }
31
- end
32
- ret.map! do |val|
33
- next val if opt?(val)
34
-
35
- if !(pa = val.is_a?(Pathname)) && escape
36
- shell_escape(val, quote: quote, double: double)
37
- elsif quote || pa
38
- shell_quote(val, force: force, double: double, preserve: preserve)
39
- else
40
- val
41
- end
42
- end
22
+ ret.map! { |val| escape ? shell_escape(val, quote: quote) : shell_quote(val) } if escape || quote
43
23
  if target.is_a?(Set)
44
24
  target.merge(ret)
45
25
  else
@@ -55,117 +35,35 @@ module Squared
55
35
  kwargs[:hint] ||= 'unrecognized'
56
36
  append(target, opts, delim: true) if kwargs.delete(:append)
57
37
  warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs)
58
- exit 1 unless pass || confirm("Run? [#{sub_style(target, styles: styles)}] [y/N] ", 'N')
59
- end
60
-
61
- def delete_key(target, *args, value: false, reverse: false, count: -1)
62
- ret = []
63
- args.each do |val|
64
- next if (opts = target.grep(matchopt(val, value))).empty?
38
+ return if pass || confirm("Run? [#{sub_style(target, styles: styles)}] [y/N] ", 'N')
65
39
 
66
- opts = opts.first(count) if count >= 0
67
- opts.send(reverse ? :reverse_each : :each) { |key| target.delete(key) }
68
- ret.concat(opts)
69
- end
70
- ret
40
+ raise_error 'user cancelled'
71
41
  end
72
42
 
73
43
  def strip(val)
74
44
  return [] unless val
75
45
 
76
- val = shell_split val if val.is_a?(String)
77
- ret = []
78
- pass = -1
79
- (args = Array(val)).each_with_index do |s, i|
80
- next if s.empty? || pass == i
81
-
82
- if s == '--'
83
- ret << s << args[i.succ..-1].join(' ')
84
- break
85
- end
86
- next ret << s unless s.start_with?('-')
87
-
88
- if !s.include?('=') && (j = args[i.succ]) && !j.start_with?('-')
89
- ret << "#{s.sub(/^-{1,2}/, '')}=#{j}"
90
- pass = i.succ
91
- else
92
- ret << s.sub(OPT_SINGLE, '\1=\2').sub(OPT_VALUE, '\1=\2').sub(OPT_NAME, '\2')
93
- end
94
- end
95
- ret
96
- end
97
-
98
- def select(list, bare: true, no: true, single: false, double: false)
99
- ret = bare ? list.grep_v(/=/) : list.grep(/=/).map! { |val| val.split('=', 2).first }
100
- ret.map! { |val| val.split('|', 2).last }
101
- ret = ret.grep_v(/\Ano-/) unless no
102
- return ret if single == double
103
-
104
- ret.select { |val| single ? val.size == 1 : val.size > 1 }
46
+ val = shell_split(val) if val.is_a?(String)
47
+ val.map { |s| s.sub(/\A-([a-z\d])(.+)\z/i, '\1=\2').sub(/\A--?/, '') }.reject(&:empty?)
105
48
  end
106
49
 
107
50
  def arg?(target, *args, value: false, **)
108
51
  r, s = args.partition { |val| val.is_a?(Regexp) }
109
- r << matchopts(s, value) unless s.empty?
110
- a = target.to_a.compact
111
- if (n = a.index('--'))
112
- a = a[0..n]
52
+ unless s.empty?
53
+ s.map! { |val| Regexp.escape(val.start_with?('-') ? val : shell_option(val)) }
54
+ r << /\A(?:#{s.join('|')})#{value ? '[ =].' : '(?: |=|\z)'}/
113
55
  end
114
- a.any? { |val| r.any? { |pat| pat.match?(val.to_s) } }
115
- end
116
-
117
- def opt?(val)
118
- return false unless val.is_a?(String)
119
-
120
- val.start_with?('-') && (OPT_NAME.match?(val) || OPT_VALUE.match?(val) || OPT_SINGLE.match?(val))
121
- end
122
-
123
- def pattern?(val)
124
- Regexp.new(val)
125
- val.start_with?('\A', '^') || val.end_with?('\z', '$') ||
126
- val.match?(/[.)][*+?]|\(\?[:=!><]|\\[dsw\d]|\[.+\]|\{\d+,?\d*\}/i)
127
- rescue RegexpError
128
- false
129
- end
130
-
131
- private
132
-
133
- def matchopt(val, value = false)
134
- /\A#{val.size == 1 ? shortopt(val) : longopt(val, value)}/
135
- end
136
-
137
- def matchopts(list, value = false)
138
- a, b = Array(list).partition { |val| val.size == 1 || val.match?(OPT_SINGLE) }
139
- return /\A#{shortopt(*a)}/ if b.empty?
140
- return /\A#{longopt(*b, value)}/ if a.empty?
141
-
142
- /\A(?:#{shortopt(*a)}|#{longopt(*b, value)})/
143
- end
144
-
145
- def shortopt(*group)
146
- group.map! { |s| Regexp.escape(s.sub(/\A-/, '')) }
147
- "-(?:#{Regexp.escape(group.join('|'))})(?:\\z|[^ =]| +[^ -])"
148
- end
149
-
150
- def longopt(*group, value)
151
- group.map! { |s| Regexp.escape(s.sub(/\A--/, '')) }
152
- "--(?:#{Regexp.escape(group.join('|'))})(?:#{value ? '=[^ ]| +[^ -]' : '[= ]|\z'})"
56
+ s = target.to_a.compact
57
+ r.any? { |pat| s.any?(pat) }
153
58
  end
154
59
  end
155
60
 
156
61
  attr_reader :target, :extras, :found, :errors, :values, :project, :path
157
62
 
158
63
  def_delegators :@target, :+, :-, :<<, :any?, :none?, :include?, :add, :add?, :find, :find_all, :find_index,
159
- :merge, :compact, :delete, :delete?, :delete_if, :grep, :grep_v, :inspect, :to_a, :to_s
160
- def_delegators :@extras, :empty?, :member?, :each, :each_with_index, :each_with_object, :partition, :dup,
161
- :first, :last, :shift, :unshift, :pop, :push, :concat, :index, :join, :map, :map!, :detect,
162
- :select, :select!, :reject, :size
163
-
164
- def_delegator :@extras, :delete, :remove
165
- def_delegator :@extras, :delete_at, :remove_at
166
- def_delegator :@extras, :delete_if, :remove_if
167
- def_delegator :@extras, :find_all, :detect_all
168
- def_delegator :@extras, :find_index, :detect_index
64
+ :merge, :delete, :delete?, :delete_if, :grep, :inspect, :to_a, :to_s
65
+ def_delegators :@extras, :empty?, :each, :each_with_index, :partition, :dup, :first, :last, :shift, :unshift,
66
+ :pop, :push, :join, :map, :map!, :select, :reject, :size
169
67
 
170
68
  def initialize(opts, list, target = Set.new, project: nil, path: nil, **kwargs, &blk)
171
69
  @target = target.is_a?(Set) ? target : target.to_set
@@ -176,7 +74,7 @@ module Squared
176
74
  parse(list, opts, **kwargs, &blk)
177
75
  end
178
76
 
179
- def parse(list, opts = extras, no: nil, single: nil, args: false, first: nil, underscore: nil, &blk)
77
+ def parse(list, opts = extras, no: nil, single: nil, args: false, first: nil, &blk)
180
78
  @extras = []
181
79
  @values = []
182
80
  bare = []
@@ -189,7 +87,6 @@ module Squared
189
87
  i = []
190
88
  f = []
191
89
  si = []
192
- bl = []
193
90
  list.flat_map do |val|
194
91
  x, y = val.split('|', 2)
195
92
  if y
@@ -224,12 +121,10 @@ module Squared
224
121
  si << flag
225
122
  when 'v'
226
123
  @values << Regexp.escape(flag)
227
- when '!'
228
- bl << flag
229
124
  else
230
125
  next
231
126
  end
232
- m << flag if flag.size == 1 && val[n + 2] == 'm'
127
+ m << flag if val[n + 2] == 'm'
233
128
  bare << flag if val.end_with?('?')
234
129
  else
235
130
  bare << val
@@ -237,66 +132,43 @@ module Squared
237
132
  end
238
133
  no = (no || []).map { |val| (n = val.index('=')) ? val[0, n] : val }
239
134
  bare.concat(no)
240
- if underscore
241
- tr = ->(list) { list.map { |val| val.tr('-', '_') } }
242
- @values.concat(tr.call(@values))
243
- bare.concat(tr.call(bare))
244
- e.concat(tr.call(e))
245
- b.concat(tr.call(b))
246
- m.concat(tr.call(m))
247
- p.concat(tr.call(p))
248
- q.concat(tr.call(q))
249
- qq.concat(tr.call(qq))
250
- i.concat(tr.call(i))
251
- f.concat(tr.call(f))
252
- si.concat(tr.call(si))
253
- bl.concat(tr.call(bl))
254
- no.concat(tr.call(no))
255
- end
256
135
  numtype = [
257
136
  [i, /\A\d+\z/],
258
- [f, /\A(\d+(\.\d*)?|\d*\.\d+)\z/],
137
+ [f, /\A\d*(?:\.\d+)?\z/],
259
138
  [si, /\A-?\d+\z/]
260
139
  ].freeze
261
140
  numcheck = ->(k, v) { numtype.any? { |flag, pat| flag.include?(k) && pat.match?(v) } }
262
141
  skip = false
263
142
  opts.each do |opt|
264
- next skip = true if opt == '--'
265
- next push opt if skip
143
+ next @extras << opt if skip
266
144
 
267
145
  if single&.match?(opt)
268
- add "-#{opt}"
146
+ target << "-#{opt}"
269
147
  elsif bare.include?(opt)
270
- add(opt.size == 1 ? "-#{opt}" : "--#{opt}")
271
- elsif opt.match?(/\Ano[-_]/) && no.include?(name = opt[3..-1])
272
- add "--no-#{name}"
148
+ target << (opt.size == 1 ? "-#{opt}" : "--#{opt}")
149
+ elsif opt.start_with?('no-') && no.include?(name = opt[3..-1])
150
+ target << "--no-#{name}"
273
151
  else
274
- if opt =~ OPT_VALUE
152
+ if opt =~ /\A([^=]+)=(.+)\z/
275
153
  key = $1
276
154
  val = $2
277
155
  merge = m.include?(key)
278
156
  if e.include?(key)
279
- add shell_option(key, val, merge: merge)
157
+ target << shell_option(key, val, merge: merge)
280
158
  elsif q.include?(key)
281
- add quote_option(key, val, double: qq.include?(key), merge: merge)
282
- elsif p.include?(key)
283
- if val =~ /\A(["']).+\1\z/
284
- add shell_option(key, val, double: $1 == '"', escape: false, merge: merge)
285
- elsif path
286
- add quote_option(key, path + val, merge: merge)
287
- else
288
- push opt
289
- end
290
- elsif b.include?(key) || (bl.include?(key) && %w[true false].include?(val)) || numcheck.call(key, val)
291
- add basic_option(key, val, merge: merge)
159
+ target << quote_option(key, val, double: qq.include?(key), merge: merge)
160
+ elsif p.include?(key) && path
161
+ target << quote_option(key, path + val, merge: merge)
162
+ elsif b.include?(key) || numcheck.call(key, val)
163
+ target << basic_option(key, val, merge: merge)
292
164
  elsif merge
293
- add basic_option(key, val, merge: true)
165
+ target << basic_option(key, val, merge: true)
294
166
  else
295
- push opt
167
+ @extras << opt
296
168
  end
297
169
  opt = key
298
170
  else
299
- push opt
171
+ @extras << opt
300
172
  skip = true if args
301
173
  end
302
174
  skip = true if first&.any? { |s| s.is_a?(Regexp) ? opt.match?(s) : !opt.include?(s) }
@@ -316,215 +188,100 @@ module Squared
316
188
  self
317
189
  end
318
190
 
319
- def append(*args, clear: false, preserve: '"', **kwargs)
320
- args = clear ? extras.dup.tap { extras.clear } : extras if args.empty?
321
- OptionPartition.append(target, *args, preserve: preserve, **kwargs)
191
+ def append(*args, **kwargs)
192
+ OptionPartition.append(target, *(args.empty? ? extras : args), **kwargs)
322
193
  self
323
194
  end
324
195
 
325
- def append_any(*args, escape: false, **kwargs)
326
- quote = kwargs.fetch(:quote, true)
327
- (args.empty? ? extras : args.flatten).each do |val|
328
- if exist?(val)
329
- add_path(val, **kwargs)
330
- elsif escape
331
- add shell_escape(val, **kwargs)
332
- elsif quote
333
- add_quote(val, **kwargs)
334
- else
335
- add val
336
- end
337
- found << val if args.empty?
338
- end
339
- self
340
- end
341
-
342
- def uniq(list)
343
- ignore = map { |val| nameonly(val) }
344
- list.reject do |val|
345
- next true if ignore.include?(s = nameonly(val))
346
-
347
- pat = OptionPartition.send(:matchopt, s)
348
- any? { |opt| opt.match?(pat) }
349
- end
350
- end
351
-
352
196
  def clear(opts = nil, errors: false, **kwargs)
353
197
  styles = project.theme[:inline] if project
354
- if errors
355
- OptionPartition.clear(target, self.errors, styles: styles, **kwargs)
356
- self.errors.clear
357
- return self unless opts
198
+ if !opts
199
+ opts = errors ? @errors : @extras
200
+ elsif errors
201
+ OptionPartition.clear(target, @errors, styles: styles, **kwargs)
202
+ @errors.clear
358
203
  end
359
- opts ||= extras
360
- OptionPartition.clear(target, if found.empty?
361
- opts
362
- else
363
- opts.reject { |val| found.include?(val) }
364
- end, styles: styles, **kwargs)
204
+ OptionPartition.clear(target, opts.reject { |val| found.include?(val) }, styles: styles, **kwargs)
365
205
  opts.clear
366
206
  self
367
207
  end
368
208
 
369
- def adjoin(*args, with: nil, start: false)
370
- i = -1
371
- temp = compact
372
- if with
373
- pat = case with
374
- when String, Symbol
375
- /\A#{Regexp.escape(with)}\z/
376
- when Array
377
- OptionPartition.send(:matchopts, with)
378
- else
379
- with
380
- end
381
- temp.each_with_index do |val, index|
382
- if val.to_s.match?(pat)
383
- i = index + (start.is_a?(Numeric) ? start : 1)
384
- break
385
- end
386
- end
387
- else
388
- temp.each_with_index do |val, index|
389
- if i == 0
390
- next unless val.is_a?(String) && val.start_with?('-')
391
-
392
- i = index
393
- break
394
- elsif index > 0 && !val.to_s.start_with?('-')
395
- if start
396
- i = index + (start.is_a?(Numeric) ? start : 1)
397
- break
398
- end
399
- i = 0
400
- end
401
- end
402
- end
403
- if i > 0
404
- if args.empty?
405
- args = dup
406
- reset
407
- else
408
- args.each { |val| remove val }
409
- end
410
- args = temp[0...i] + args + temp[i..-1]
411
- target.clear
412
- end
413
- merge args
414
- self
209
+ def arg?(*args, **kwargs)
210
+ OptionPartition.arg?(target, *args, **kwargs)
415
211
  end
212
+ end
416
213
 
417
- def add_path(*args, **kwargs)
418
- add shell_quote(path ? path.join(*args) : File.join(*args), option: false, **kwargs)
419
- self
214
+ class JoinSet < Set
215
+ def self.to_s
216
+ super[/[^:]+\z/, 0]
420
217
  end
421
218
 
422
- def add_quote(*args, **kwargs)
423
- kwargs.delete(:quote)
424
- args.compact!
425
- merge(args.map! { |val| val == '--' || OptionPartition.opt?(val) ? val : shell_quote(val, **kwargs) })
426
- self
219
+ attr_reader :delim
220
+
221
+ def initialize(data = [], delim: ' ')
222
+ super(data.compact)
223
+ @delim = delim
427
224
  end
428
225
 
429
- def delim
430
- add '--'
431
- self
226
+ def last(val, pat)
227
+ (@last ||= []).append([val, pat, $1]) if val =~ pat
228
+ self << val
432
229
  end
433
230
 
434
- def splice(*exclude, quote: true, delim: true, path: false, pattern: false, &blk)
435
- temp, other = if block_given?
436
- partition(&blk)
437
- elsif exclude.first.is_a?(Symbol)
438
- partition(&exclude.first)
439
- else
440
- exclude.map! { |pat| Regexp.new(pat) }
441
- partition do |val|
442
- val = val.to_s
443
- next if pattern && OptionPartition.pattern?(val)
444
-
445
- exclude.none? { |pat| val.match?(pat) }
446
- end
447
- end
448
- unless temp.empty?
449
- add '--' if delim
450
- extras.clear
451
- concat other
452
- if path
453
- temp.each { |val| add_path(val) }
454
- else
455
- temp.map! { |val| shell_quote(val) } if quote
456
- merge temp
231
+ def pass(&blk)
232
+ ret = to_a.map!(&:to_s).reject(&:empty?)
233
+ @last&.each do |val, pat, key|
234
+ i = []
235
+ j = nil
236
+ ret.each_with_index do |opt, index|
237
+ if opt == val
238
+ j = index
239
+ elsif j && opt[pat, 1] == key
240
+ i << index
241
+ end
457
242
  end
243
+ next unless j && !i.empty?
244
+
245
+ val = ret[j]
246
+ cur = j
247
+ i.each do |k|
248
+ ret[cur] = ret[k]
249
+ cur = k
250
+ end
251
+ ret[i.last] = val
458
252
  end
459
- self
253
+ block_given? ? ret.reject(&blk) : ret
460
254
  end
461
255
 
462
- def reset(errors: false)
463
- extras.clear
464
- found.clear
465
- clear(errors: true) if errors
466
- self
256
+ def and(*args)
257
+ self << '&&'
258
+ merge args
467
259
  end
468
260
 
469
- def append?(key, val = nil, type: nil, force: false, **kwargs)
470
- return false unless force || !arg?(key)
471
-
472
- val = yield self if block_given?
473
- return false unless val
474
-
475
- type ||= :quote if kwargs.empty?
476
- add case type
477
- when :quote
478
- quote_option(key, val)
479
- when :basic
480
- basic_option(key, val)
481
- else
482
- shell_option(key, val, **kwargs)
483
- end
484
- true
261
+ def or(*args)
262
+ self << '||'
263
+ merge args
485
264
  end
486
265
 
487
- def arg?(*args, **kwargs)
488
- OptionPartition.arg?(target, *args, **kwargs)
266
+ def with(*args, &blk)
267
+ temp('&&', *args, &blk)
489
268
  end
490
269
 
491
- def exist?(*args, add: false, first: false, last: false)
492
- return false unless path
493
- return path.join(*args).exist? unless args.empty?
494
-
495
- if first || last
496
- return false unless (val = first ? self.first : self.last).is_a?(String)
497
-
498
- path.join(val).exist?.tap do |ret|
499
- next unless add && ret
500
-
501
- add_path(first ? shift : pop)
502
- end
503
- else
504
- each_with_index do |val, index|
505
- next unless val.is_a?(String) && path.join(val).exist?
506
-
507
- if add
508
- remove_at index
509
- add_path val
510
- end
511
- return true
512
- end
513
- false
514
- end
270
+ def temp(*args, &blk)
271
+ args.compact!
272
+ ret = pass(&blk)
273
+ ret = Set.new(ret.concat(args)).to_a unless args.empty?
274
+ ret.join(@delim)
515
275
  end
516
276
 
517
- def uniq!(list)
518
- unless (list = uniq(list)).empty?
519
- concat list
520
- self
521
- end
277
+ def done
278
+ ret = to_s
279
+ clear
280
+ ret
522
281
  end
523
282
 
524
- private
525
-
526
- def nameonly(val)
527
- val[OPT_VALUE, 1] || val
283
+ def to_s
284
+ pass.join(@delim)
528
285
  end
529
286
  end
530
287
  end
@@ -3,16 +3,6 @@
3
3
  module Squared
4
4
  module Workspace
5
5
  module Project
6
- class << self
7
- attr_accessor :line_width
8
-
9
- def max_width(lines)
10
- n = [lines.empty? ? 0 : lines.max_by(&:size).size, 80].max
11
- [n, Rake.application.terminal_width].min
12
- end
13
- end
14
-
15
- @line_width = ENV.fetch('LOG_COLUMNS', 80).to_i
16
6
  end
17
7
  end
18
8
  end