squared 0.5.27 → 0.6.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,9 +10,9 @@ 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/
13
+ OPT_NAME = /\A(?:(--)|-)((?(1)[A-Za-z\d]+|[A-Za-z\d]))\z/
14
+ OPT_VALUE = /\A-{0,2}([^= ]+)(?: *= *| +)(.+)\z/
15
+ OPT_SINGLE = /\A-([A-Za-z\d])(.+)\z/
16
16
  private_constant :OPT_NAME, :OPT_VALUE, :OPT_SINGLE
17
17
 
18
18
  class << self
@@ -21,23 +21,37 @@ module Squared
21
21
  include Prompt
22
22
 
23
23
  def append(target, *args, delim: false, escape: false, quote: true, strip: nil, force: true, double: false,
24
- preserve: true, **)
24
+ filter: nil, **)
25
25
  return if (ret = args.flatten).empty?
26
26
 
27
27
  target << '--' if delim && !target.include?('--')
28
28
  if strip
29
29
  pat, s = Array(strip)
30
- ret.map! { |val| val.is_a?(String) ? val.gsub(pat, s || '') : val }
30
+ ret.map! { |val| val.gsub(pat, s || '') }
31
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
32
+ ret, err = ret.partition { |val| filter.match?(val) } if filter
33
+ if block_given?
34
+ out = []
35
+ err ||= []
36
+ ret.each do |val|
37
+ case (s = yield val)
38
+ when String
39
+ out << s
40
+ when NilClass, FalseClass
41
+ err << val
42
+ else
43
+ out << val
44
+ end
45
+ end
46
+ ret = out
47
+ end
48
+ if escape || quote
49
+ ret.map! do |val|
50
+ if escape
51
+ shell_escape(val, quote: quote, double: double)
52
+ else
53
+ shell_quote(val, force: force, double: double)
54
+ end
41
55
  end
42
56
  end
43
57
  if target.is_a?(Set)
@@ -45,13 +59,13 @@ module Squared
45
59
  else
46
60
  target.concat(ret)
47
61
  end
48
- ret
62
+ err || ret
49
63
  end
50
64
 
51
65
  def clear(target, opts, pass: true, styles: nil, **kwargs)
52
66
  return if opts.empty?
53
67
 
54
- kwargs[:subject] ||= stripext target.first
68
+ kwargs[:subject] ||= target.first.stripext
55
69
  kwargs[:hint] ||= 'unrecognized'
56
70
  append(target, opts, delim: true) if kwargs.delete(:append)
57
71
  warn log_message(Logger::WARN, opts.join(', '), pass: true, **kwargs)
@@ -74,25 +88,7 @@ module Squared
74
88
  return [] unless val
75
89
 
76
90
  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
91
+ val.map { |s| s.sub(OPT_SINGLE, '\1=\2').sub(OPT_VALUE, '\1=\2').sub(OPT_NAME, '\2') }.reject(&:empty?)
96
92
  end
97
93
 
98
94
  def select(list, bare: true, no: true, single: false, double: false)
@@ -104,28 +100,29 @@ module Squared
104
100
  ret.select { |val| single ? val.size == 1 : val.size > 1 }
105
101
  end
106
102
 
107
- def arg?(target, *args, value: false, **)
108
- r, s = args.partition { |val| val.is_a?(Regexp) }
109
- r << matchopts(s, value) unless s.empty?
110
- a = target.to_a
111
- if (n = a.index('--'))
112
- a = a[0..n]
103
+ def uniq!(list, pass = [])
104
+ keys = {}
105
+ list.each_with_index do |val, i|
106
+ j = val =~ OPT_VALUE ? $1 : val
107
+ (keys[j] ||= []) << i unless pass.include?(j)
113
108
  end
114
- r.any? { |pat| a.any?(pat) }
115
- end
109
+ data = keys.map { |item| item[1].size > 1 ? item[1][0..-2] : [] }.reject(&:empty?)
110
+ return if data.empty?
116
111
 
117
- def opt?(val)
118
- return false unless val.is_a?(String)
112
+ data.each { |key| key.each { |i| list[i] = nil } }
113
+ list.compact!
114
+ list
115
+ end
119
116
 
120
- val.start_with?('-') && (OPT_NAME.match?(val) || OPT_VALUE.match?(val) || OPT_SINGLE.match?(val))
117
+ def arg?(target, *args, value: false, **)
118
+ r, s = args.partition { |val| val.is_a?(Regexp) }
119
+ r << matchopts(s, value) unless s.empty?
120
+ s = target.to_a.compact
121
+ r.any? { |pat| s.any?(pat) }
121
122
  end
122
123
 
123
124
  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
125
+ val.match?(/(?:\A\^|\$\z)/) || val.match?(/(?:\.[*+]|\(\?:|\\[dsw]|\[.+\]|\{\d+,?\d*\})/)
129
126
  end
130
127
 
131
128
  private
@@ -136,30 +133,29 @@ module Squared
136
133
 
137
134
  def matchopts(list, value = false)
138
135
  a, b = Array(list).partition { |val| val.size == 1 || val.match?(OPT_SINGLE) }
139
- return /\A#{shortopt(*a)}/ if b.empty?
136
+ return /\A#{shortopt(*a)}}/ if b.empty?
140
137
  return /\A#{longopt(*b, value)}/ if a.empty?
141
138
 
142
139
  /\A(?:#{shortopt(*a)}|#{longopt(*b, value)})/
143
140
  end
144
141
 
145
142
  def shortopt(*group)
146
- group.map! { |s| Regexp.escape(s.delete_prefix('-')) }
147
- "-(?:#{group.join('|')})(?:\\z|[^ =]| +[^ -])"
143
+ group.map! { |s| s.delete_prefix('-') }
144
+ "-(?:#{Regexp.escape(group.join('|'))})(?:\\z|[^ =]| +[^ -])"
148
145
  end
149
146
 
150
147
  def longopt(*group, value)
151
- group.map! { |s| Regexp.escape(s.delete_prefix('--')) }
152
- "--(?:#{group.join('|')})(?:#{value ? '=[^ ]| +[^ -]' : '[= ]|\z'})"
148
+ group.map! { |s| s.delete_prefix('--') }
149
+ "--(?:#{Regexp.escape(group.join('|'))})(?:#{value ? '=[^ ]| +[^ -]' : '[= ]|\z'})"
153
150
  end
154
151
  end
155
152
 
156
- attr_reader :target, :extras, :found, :errors, :values, :project, :path
153
+ attr_reader :target, :extras, :found, :errors, :values, :project, :path, :sep
157
154
 
158
155
  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, :shift, :unshift, :pop, :push, :concat, :index, :join, :map, :map!, :detect, :select,
162
- :select!, :reject, :size
156
+ :merge, :delete, :delete?, :delete_if, :grep, :grep_v, :inspect, :to_a, :to_s
157
+ def_delegators :@extras, :empty?, :each, :each_with_index, :partition, :dup, :first, :shift, :unshift,
158
+ :pop, :push, :concat, :index, :join, :map, :map!, :detect, :select, :select!, :reject, :size
163
159
 
164
160
  def_delegator :@extras, :delete, :remove
165
161
  def_delegator :@extras, :delete_at, :remove_at
@@ -167,10 +163,11 @@ module Squared
167
163
  def_delegator :@extras, :find_all, :detect_all
168
164
  def_delegator :@extras, :find_index, :detect_index
169
165
 
170
- def initialize(opts, list, target = Set.new, project: nil, path: nil, **kwargs, &blk)
166
+ def initialize(opts, list, target = Set.new, project: nil, path: nil, sep: '=', **kwargs, &blk)
171
167
  @target = target.is_a?(Set) ? target : target.to_set
172
168
  @project = project
173
169
  @path = path || project&.path
170
+ @sep = sep
174
171
  @errors = []
175
172
  @found = []
176
173
  parse(list, opts, **kwargs, &blk)
@@ -204,7 +201,7 @@ module Squared
204
201
  .each do |val|
205
202
  if (n = val.index('='))
206
203
  flag = val[0, n]
207
- case val[n + 1]
204
+ case val[n.succ]
208
205
  when 'e'
209
206
  e << flag
210
207
  when 'b'
@@ -229,7 +226,7 @@ module Squared
229
226
  else
230
227
  next
231
228
  end
232
- m << flag if flag.size == 1 && val[n + 2] == 'm'
229
+ m << flag if val[n + 2] == 'm'
233
230
  bare << flag if val.end_with?('?')
234
231
  else
235
232
  bare << val
@@ -238,7 +235,7 @@ module Squared
238
235
  no = (no || []).map { |val| (n = val.index('=')) ? val[0, n] : val }
239
236
  bare.concat(no)
240
237
  if underscore
241
- tr = ->(list) { list.map { |val| val.tr('-', '_') } }
238
+ tr = ->(a) { a.map { |val| val.tr('-', '_') } }
242
239
  @values.concat(tr.call(@values))
243
240
  bare.concat(tr.call(bare))
244
241
  e.concat(tr.call(e))
@@ -255,10 +252,10 @@ module Squared
255
252
  end
256
253
  numtype = [
257
254
  [i, /\A\d+\z/],
258
- [f, /\A(\d+(\.\d*)?|\d*\.\d+)\z/],
255
+ [f, /\A\d*(?:\.\d+)?\z/],
259
256
  [si, /\A-?\d+\z/]
260
257
  ].freeze
261
- numcheck = ->(k, v) { numtype.any? { |flag, pat| flag.include?(k) && pat.match?(v) } }
258
+ numcheck = ->(k, v) { numtype.any? { |flag, pat| flag.include?(k) && v.match?(pat) } }
262
259
  skip = false
263
260
  opts.each do |opt|
264
261
  next skip = true if opt == '--'
@@ -274,27 +271,23 @@ module Squared
274
271
  if opt =~ OPT_VALUE
275
272
  key = $1
276
273
  val = $2
277
- if val =~ /\A(["'])(.+)\1\z/
278
- val = $2
279
- double = $1 == '"'
280
- end
281
274
  merge = m.include?(key)
282
275
  if e.include?(key)
283
- add shell_option(key, val, double: double, merge: merge)
276
+ add shell_option(key, val, merge: merge, sep: sep)
284
277
  elsif q.include?(key)
285
- add quote_option(key, val, double: double || qq.include?(key), merge: merge)
278
+ add quote_option(key, val, double: qq.include?(key), merge: merge, sep: sep)
286
279
  elsif p.include?(key)
287
- if !double.nil?
288
- add shell_option(key, val, double: double, merge: merge, escape: false)
280
+ if val.match?(/\A(["']).+\1\z/)
281
+ add shell_option(key, val, escape: false, merge: merge, sep: sep)
289
282
  elsif path
290
- add quote_option(key, path + val, merge: merge)
283
+ add quote_option(key, path + val, merge: merge, sep: sep)
291
284
  else
292
285
  push opt
293
286
  end
294
287
  elsif b.include?(key) || (bl.include?(key) && %w[true false].include?(val)) || numcheck.call(key, val)
295
- add basic_option(key, val, double: double, merge: merge)
288
+ add basic_option(key, val, merge: merge, sep: sep)
296
289
  elsif merge
297
- add basic_option(key, val, double: double, merge: true)
290
+ add basic_option(key, val, merge: true, sep: sep)
298
291
  else
299
292
  push opt
300
293
  end
@@ -306,39 +299,40 @@ module Squared
306
299
  skip = true if first&.any? { |s| s.is_a?(Regexp) ? opt.match?(s) : !opt.include?(s) }
307
300
  end
308
301
  end
309
- @values = @values.empty? ? /\A\s+\z/ : /\A(#{@values.join('|')})=(.+)\z/m
302
+ @values = @values.empty? ? /\A\s+\z/ : /\A(#{@values.join('|')})#{sep}(.+)\z/m
310
303
  @extras.each_with_index(&blk) if block_given?
311
304
  self
312
305
  end
313
306
 
314
- def swap(opts = nil)
307
+ def swap(opts = nil, &blk)
315
308
  unless opts
316
309
  opts = found
317
310
  @found = []
318
311
  end
312
+ opts.sort!(&blk) if block_given?
319
313
  @extras = opts
320
314
  self
321
315
  end
322
316
 
323
- def append(*args, clear: false, preserve: '"', **kwargs)
324
- args = clear ? extras.dup.tap { extras.clear } : extras if args.empty?
325
- OptionPartition.append(target, *args, preserve: preserve, **kwargs)
317
+ def append(*args, **kwargs, &blk)
318
+ args = extras if args.empty?
319
+ out = OptionPartition.append(target, *args, **kwargs, &blk)
320
+ errors.concat(out) if out && (block_given? || kwargs[:filter])
326
321
  self
327
322
  end
328
323
 
329
- def append_any(*args, escape: false, **kwargs)
330
- quote = kwargs.fetch(:quote, true)
324
+ def append_any(*args, quote: true, **kwargs)
331
325
  (args.empty? ? extras : args.flatten).each do |val|
326
+ val = yield val if block_given?
327
+ next unless val.is_a?(String)
328
+
332
329
  if exist?(val)
333
330
  add_path(val, **kwargs)
334
- elsif escape
335
- add shell_escape(val, **kwargs)
336
331
  elsif quote
337
332
  add_quote(val, **kwargs)
338
333
  else
339
334
  add val
340
335
  end
341
- found << val if args.empty?
342
336
  end
343
337
  self
344
338
  end
@@ -349,7 +343,7 @@ module Squared
349
343
  end
350
344
 
351
345
  def values_of(*args, strict: true, first: false, last: false)
352
- eq, s = strict ? ['=', '[^ ]+'] : ['(?:=| +)', '[^-][^ ]*']
346
+ eq, s = strict ? [sep, '[^ ]+'] : ['(?:=| +)', '[^-][^ ]*']
353
347
  g = ["\"((?:[^\"]|(?<=\\\\)\"(?!$#{windows? ? '| ' : ''}))*)\""]
354
348
  g << "'((?:[^']|'\\\\'')*)'" unless windows?
355
349
  g << "(#{s})"
@@ -388,23 +382,19 @@ module Squared
388
382
  def clear(opts = nil, errors: false, **kwargs)
389
383
  styles = project.theme[:inline] if project
390
384
  if errors
391
- OptionPartition.clear(target, self.errors, styles: styles, **kwargs)
392
- self.errors.clear
385
+ OptionPartition.clear(target, @errors, styles: styles, **kwargs)
386
+ @errors.clear
393
387
  return self unless opts
394
388
  end
395
389
  opts ||= extras
396
- OptionPartition.clear(target, if found.empty?
397
- opts
398
- else
399
- opts.reject { |val| found.include?(val) }
400
- end, styles: styles, **kwargs)
390
+ OptionPartition.clear(target, opts - found, styles: styles, **kwargs)
401
391
  opts.clear
402
392
  self
403
393
  end
404
394
 
405
395
  def adjoin(*args, with: nil, start: false)
406
- i = -1
407
- temp = compact
396
+ index = -1
397
+ temp = to_a
408
398
  if with
409
399
  pat = case with
410
400
  when String, Symbol
@@ -414,82 +404,135 @@ module Squared
414
404
  else
415
405
  with
416
406
  end
417
- temp.each_with_index do |val, index|
407
+ temp.each_with_index do |val, i|
418
408
  if val.to_s.match?(pat)
419
- i = index + (start.is_a?(Numeric) ? start : 1)
409
+ index = i + (start.is_a?(Numeric) ? start : 1)
420
410
  break
421
411
  end
422
412
  end
423
413
  else
424
- temp.each_with_index do |val, index|
425
- if i == 0
426
- next unless val.is_a?(String) && val.start_with?('-')
414
+ temp.each_with_index do |val, i|
415
+ if index == 0
416
+ next unless val.start_with?('-')
427
417
 
428
- i = index
418
+ index = i
429
419
  break
430
- elsif index > 0 && !val.to_s.start_with?('-')
420
+ elsif i > 0 && !val.start_with?('-')
431
421
  if start
432
- i = index + (start.is_a?(Numeric) ? start : 1)
422
+ index = i + (start.is_a?(Numeric) ? start : 1)
433
423
  break
434
424
  end
435
- i = 0
425
+ index = 0
436
426
  end
437
427
  end
438
428
  end
439
- if i > 0
429
+ if index > 0
440
430
  if args.empty?
441
431
  args = dup
442
432
  reset
443
433
  else
444
434
  args.each { |val| remove val }
445
435
  end
446
- args = temp[0...i] + args + temp[i..-1]
436
+ args = temp[0...index] + args + temp[index..-1]
447
437
  target.clear
448
438
  end
449
439
  merge args
450
440
  self
451
441
  end
452
442
 
453
- def add_path(*args, **kwargs)
454
- add shell_quote(path ? path.join(*args) : File.join(*args), option: false, **kwargs)
443
+ def add_path(*args, force: true, double: false, **kwargs)
444
+ if args.empty?
445
+ args = select { |s| s.is_a?(String) }
446
+ args.map! { |val| path + val } if path
447
+ append(args, force: force, **kwargs)
448
+ else
449
+ add shell_quote(path ? path.join(*args) : File.join(*args), option: false, force: force, double: double)
450
+ end
455
451
  self
456
452
  end
457
453
 
458
454
  def add_quote(*args, **kwargs)
459
- kwargs.delete(:quote)
460
- args.compact!
461
- merge(args.map! { |val| val == '--' || OptionPartition.opt?(val) ? val : shell_quote(val, **kwargs) })
455
+ merge(args.compact.map! { |val| val == '--' ? val : shell_quote(val, **kwargs) })
462
456
  self
463
457
  end
464
458
 
465
- def delim
466
- add '--'
459
+ def add_option(flag, val = nil, **kwargs)
460
+ add shell_option(flag, val, **kwargs)
467
461
  self
468
462
  end
469
463
 
464
+ def add_first(fallback = nil, prefix: nil, path: false, quote: false, reverse: false, expect: false, **kwargs)
465
+ val = (reverse ? pop : shift) || fallback
466
+ if val
467
+ val.delete_prefix!(prefix) if prefix
468
+ return self if block_given? && !(val = yield val).is_a?(String)
469
+
470
+ if path
471
+ add_path(val, **kwargs)
472
+ elsif quote
473
+ add_quote(val, **kwargs)
474
+ else
475
+ add val
476
+ end
477
+ elsif expect
478
+ raise(expect.is_a?(String) ? expect : 'no value provided')
479
+ end
480
+ self
481
+ end
482
+
483
+ def last(val = nil, &blk)
484
+ unless block_given?
485
+ case val
486
+ when NilClass
487
+ return extras.last
488
+ when Numeric
489
+ return extras.last(val)
490
+ when String, Array, Regexp
491
+ val = OptionPartition.send(:matchopts, val) unless val.is_a?(Regexp)
492
+ blk = proc { |s| s&.match?(val) }
493
+ else
494
+ raise TypeError, "unknown: #{val}"
495
+ end
496
+ end
497
+ ret = find_all(&blk)
498
+ unless ret.empty?
499
+ ret = case val
500
+ when NilClass
501
+ ret.first(1)
502
+ when Numeric
503
+ ret.first(val)
504
+ else
505
+ ret
506
+ end
507
+ ret.each do |opt|
508
+ delete opt
509
+ add opt
510
+ end
511
+ end
512
+ val.nil? ? ret.first : ret
513
+ end
514
+
470
515
  def splice(*exclude, quote: true, delim: true, path: false, pattern: false, &blk)
471
- temp, other = if block_given?
472
- partition(&blk)
473
- elsif exclude.first.is_a?(Symbol)
474
- partition(&exclude.first)
475
- else
476
- exclude.map! { |pat| Regexp.new(pat) }
477
- partition do |val|
478
- val = val.to_s
479
- next if pattern && OptionPartition.pattern?(val)
480
-
481
- exclude.none? { |pat| val.match?(pat) }
482
- end
483
- end
484
- unless temp.empty?
516
+ found, other = if block_given?
517
+ partition(&blk)
518
+ elsif exclude.first.is_a?(Symbol)
519
+ partition(&exclude.first)
520
+ else
521
+ partition do |val|
522
+ next false if pattern && OptionPartition.pattern?(val)
523
+
524
+ exclude.none? { |pat| val.match?(Regexp.new(pat)) }
525
+ end
526
+ end
527
+ unless found.empty?
485
528
  add '--' if delim
486
529
  extras.clear
487
530
  concat other
488
531
  if path
489
- temp.each { |val| add_path(val) }
532
+ found.each { |val| add_path(val) }
490
533
  else
491
- temp.map! { |val| shell_quote(val) } if quote
492
- merge temp
534
+ found.map! { |val| shell_quote(val) } if quote
535
+ merge found
493
536
  end
494
537
  end
495
538
  self
@@ -502,7 +545,7 @@ module Squared
502
545
  self
503
546
  end
504
547
 
505
- def append?(key, val = nil, type: nil, force: false, **kwargs)
548
+ def append?(key, val = nil, type: nil, force: false, sep: '=', **kwargs)
506
549
  return false unless force || !arg?(key)
507
550
 
508
551
  val = yield self if block_given?
@@ -511,11 +554,11 @@ module Squared
511
554
  type ||= :quote if kwargs.empty?
512
555
  add case type
513
556
  when :quote
514
- quote_option(key, val)
557
+ quote_option(key, val, sep: sep)
515
558
  when :basic
516
- basic_option(key, val)
559
+ basic_option(key, val, sep: sep)
517
560
  else
518
- shell_option(key, val, **kwargs)
561
+ shell_option(key, val, sep: sep, **kwargs)
519
562
  end
520
563
  true
521
564
  end
@@ -524,24 +567,23 @@ module Squared
524
567
  OptionPartition.arg?(target, *args, **kwargs)
525
568
  end
526
569
 
527
- def exist?(*args, add: false, first: false, last: false)
528
- return false unless path
529
- return path.join(*args).exist? unless args.empty?
570
+ def exist?(*args, add: false, first: false, last: false, glob: false)
571
+ return with_glob?(File.join(*args), glob) unless args.empty?
530
572
 
531
573
  if first || last
532
- return false unless (val = first ? self.first : self.last).is_a?(String)
574
+ return false unless (val = first ? self.first : self.last)
533
575
 
534
- path.join(val).exist?.tap do |ret|
576
+ with_glob?(val, glob).tap do |ret|
535
577
  next unless add && ret
536
578
 
537
- add_path(first ? shift : pop)
579
+ add_first(path: true, reverse: !first)
538
580
  end
539
581
  else
540
- each_with_index do |val, index|
541
- next unless val.is_a?(String) && path.join(val).exist?
582
+ each_with_index do |val, i|
583
+ next unless with_glob?(val, glob)
542
584
 
543
585
  if add
544
- remove_at index
586
+ remove_at i
545
587
  add_path val
546
588
  end
547
589
  return true
@@ -563,8 +605,13 @@ module Squared
563
605
  val[OPT_VALUE, 1] || val
564
606
  end
565
607
 
608
+ def with_glob?(val, glob = true)
609
+ return false unless path && val.is_a?(String) && !val.empty?
610
+
611
+ path.join(val).exist? || (glob && !path.glob(val).empty?)
612
+ end
613
+
566
614
  def windows?
567
- require 'rake'
568
615
  Rake::Win32.windows?
569
616
  end
570
617
  end
@@ -574,20 +621,11 @@ module Squared
574
621
  super[/[^:]+\z/, 0]
575
622
  end
576
623
 
577
- alias to_ary to_a
578
-
579
- attr_reader :delim, :extras
624
+ attr_reader :delim
580
625
 
581
- def initialize(data = [], delim: ' ', partition: '--', uniq: /\A--?[^=\s-][^=\s]*(?:=|\s+)\S/)
582
- @delim = delim
583
- @partition = partition
584
- @uniq = uniq
585
- @extras = []
626
+ def initialize(data = [], delim: ' ')
586
627
  super(data.compact)
587
- end
588
-
589
- def compact
590
- to_ary.map!(&:to_s).reject(&:empty?)
628
+ @delim = delim
591
629
  end
592
630
 
593
631
  def last(val, pat)
@@ -596,28 +634,27 @@ module Squared
596
634
  end
597
635
 
598
636
  def pass(&blk)
599
- ret = compact
637
+ ret = to_a.map!(&:to_s).reject(&:empty?)
600
638
  @last&.each do |val, pat, key|
601
- i = []
602
- j = nil
603
- ret.each_with_index do |opt, index|
639
+ items = []
640
+ index = nil
641
+ ret.each_with_index do |opt, i|
604
642
  if opt == val
605
- j = index
606
- elsif j && opt[pat, 1] == key
607
- i << index
643
+ index = i
644
+ elsif index && opt[pat, 1] == key
645
+ items << i
608
646
  end
609
647
  end
610
- next unless j && !i.empty?
648
+ next unless index && !items.empty?
611
649
 
612
- val = ret[j]
613
- cur = j
614
- i.each do |k|
650
+ val = ret[index]
651
+ cur = index
652
+ items.each do |k|
615
653
  ret[cur] = ret[k]
616
654
  cur = k
617
655
  end
618
- ret[i.last] = val
656
+ ret[items.last] = val
619
657
  end
620
- ret.concat(extras.map(&:to_s).reject(&:empty?)) unless extras.empty?
621
658
  return ret unless block_given?
622
659
 
623
660
  ret.reject(&blk)
@@ -639,83 +676,17 @@ module Squared
639
676
 
640
677
  def temp(*args, &blk)
641
678
  args.compact!
642
- pass(&blk)
643
- .concat(args)
644
- .join(@delim)
679
+ ret = pass(&blk)
680
+ ret = Set.new(ret.concat(args)).to_a unless args.empty?
681
+ ret.join(@delim)
645
682
  end
646
683
 
647
684
  def done
648
685
  to_s.tap { clear }
649
686
  end
650
687
 
651
- def merge(enum)
652
- if !extras.empty?
653
- extras.concat(enum.to_a)
654
- self
655
- elsif (n = enum.find_index { |val| extras?(val) })
656
- data = enum.to_a
657
- @extras = if n == 0
658
- data
659
- else
660
- super(data[0...n])
661
- data[n..-1]
662
- end
663
- self
664
- else
665
- super
666
- end
667
- end
668
-
669
- def <<(obj)
670
- extras!(obj) || super
671
- end
672
-
673
- def size
674
- super + extras.size
675
- end
676
-
677
- def include?(obj)
678
- return true if super
679
- return extras.include?(obj) unless (n = extras.index(@partition))
680
-
681
- extras[0..n].include?(obj)
682
- end
683
-
684
- def to_a
685
- pass
686
- end
687
-
688
688
  def to_s
689
- to_a.join(@delim)
690
- end
691
-
692
- def to_enum(*args)
693
- to_a.to_enum(*args)
694
- end
695
-
696
- def to_json(*args)
697
- to_a.to_json(*args)
698
- end
699
-
700
- def to_yaml(*args)
701
- to_a.to_yaml(*args)
702
- end
703
-
704
- alias add :<<
705
- alias add? :<<
706
- alias member? include?
707
-
708
- private
709
-
710
- def extras!(obj)
711
- return if extras.empty? && !extras?(obj)
712
-
713
- extras << obj unless !extras.include?(@partition) && include?(obj) && @uniq.match?(obj.to_s)
714
- self
715
- end
716
-
717
- def extras?(obj)
718
- obj == @partition || (include?(obj) && !@uniq.match?(obj.to_s))
689
+ pass.join(@delim)
719
690
  end
720
691
  end
721
692
  end