squared 0.4.42 → 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,70 +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
- if val =~ /\A(["'])(.+)\1\z/
278
- val = $2
279
- double = $1 == '"'
280
- end
281
155
  merge = m.include?(key)
282
156
  if e.include?(key)
283
- add shell_option(key, val, double: double, merge: merge)
157
+ target << shell_option(key, val, merge: merge)
284
158
  elsif q.include?(key)
285
- add quote_option(key, val, double: double || qq.include?(key), merge: merge)
286
- elsif p.include?(key)
287
- if !double.nil?
288
- add shell_option(key, val, double: double, merge: merge, escape: false)
289
- elsif path
290
- add quote_option(key, path + val, merge: merge)
291
- else
292
- push opt
293
- end
294
- 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)
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)
296
164
  elsif merge
297
- add basic_option(key, val, double: double, merge: true)
165
+ target << basic_option(key, val, merge: true)
298
166
  else
299
- push opt
167
+ @extras << opt
300
168
  end
301
169
  opt = key
302
170
  else
303
- push opt
171
+ @extras << opt
304
172
  skip = true if args
305
173
  end
306
174
  skip = true if first&.any? { |s| s.is_a?(Regexp) ? opt.match?(s) : !opt.include?(s) }
@@ -320,215 +188,100 @@ module Squared
320
188
  self
321
189
  end
322
190
 
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)
191
+ def append(*args, **kwargs)
192
+ OptionPartition.append(target, *(args.empty? ? extras : args), **kwargs)
326
193
  self
327
194
  end
328
195
 
329
- def append_any(*args, escape: false, **kwargs)
330
- quote = kwargs.fetch(:quote, true)
331
- (args.empty? ? extras : args.flatten).each do |val|
332
- if exist?(val)
333
- add_path(val, **kwargs)
334
- elsif escape
335
- add shell_escape(val, **kwargs)
336
- elsif quote
337
- add_quote(val, **kwargs)
338
- else
339
- add val
340
- end
341
- found << val if args.empty?
342
- end
343
- self
344
- end
345
-
346
- def uniq(list)
347
- ignore = map { |val| nameonly(val) }
348
- list.reject do |val|
349
- next true if ignore.include?(s = nameonly(val))
350
-
351
- pat = OptionPartition.send(:matchopt, s)
352
- any? { |opt| opt.match?(pat) }
353
- end
354
- end
355
-
356
196
  def clear(opts = nil, errors: false, **kwargs)
357
197
  styles = project.theme[:inline] if project
358
- if errors
359
- OptionPartition.clear(target, self.errors, styles: styles, **kwargs)
360
- self.errors.clear
361
- 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
362
203
  end
363
- opts ||= extras
364
- OptionPartition.clear(target, if found.empty?
365
- opts
366
- else
367
- opts.reject { |val| found.include?(val) }
368
- end, styles: styles, **kwargs)
204
+ OptionPartition.clear(target, opts.reject { |val| found.include?(val) }, styles: styles, **kwargs)
369
205
  opts.clear
370
206
  self
371
207
  end
372
208
 
373
- def adjoin(*args, with: nil, start: false)
374
- i = -1
375
- temp = compact
376
- if with
377
- pat = case with
378
- when String, Symbol
379
- /\A#{Regexp.escape(with)}\z/
380
- when Array
381
- OptionPartition.send(:matchopts, with)
382
- else
383
- with
384
- end
385
- temp.each_with_index do |val, index|
386
- if val.to_s.match?(pat)
387
- i = index + (start.is_a?(Numeric) ? start : 1)
388
- break
389
- end
390
- end
391
- else
392
- temp.each_with_index do |val, index|
393
- if i == 0
394
- next unless val.is_a?(String) && val.start_with?('-')
395
-
396
- i = index
397
- break
398
- elsif index > 0 && !val.to_s.start_with?('-')
399
- if start
400
- i = index + (start.is_a?(Numeric) ? start : 1)
401
- break
402
- end
403
- i = 0
404
- end
405
- end
406
- end
407
- if i > 0
408
- if args.empty?
409
- args = dup
410
- reset
411
- else
412
- args.each { |val| remove val }
413
- end
414
- args = temp[0...i] + args + temp[i..-1]
415
- target.clear
416
- end
417
- merge args
418
- self
209
+ def arg?(*args, **kwargs)
210
+ OptionPartition.arg?(target, *args, **kwargs)
419
211
  end
212
+ end
420
213
 
421
- def add_path(*args, **kwargs)
422
- add shell_quote(path ? path.join(*args) : File.join(*args), option: false, **kwargs)
423
- self
214
+ class JoinSet < Set
215
+ def self.to_s
216
+ super[/[^:]+\z/, 0]
424
217
  end
425
218
 
426
- def add_quote(*args, **kwargs)
427
- kwargs.delete(:quote)
428
- args.compact!
429
- merge(args.map! { |val| val == '--' || OptionPartition.opt?(val) ? val : shell_quote(val, **kwargs) })
430
- self
219
+ attr_reader :delim
220
+
221
+ def initialize(data = [], delim: ' ')
222
+ super(data.compact)
223
+ @delim = delim
431
224
  end
432
225
 
433
- def delim
434
- add '--'
435
- self
226
+ def last(val, pat)
227
+ (@last ||= []).append([val, pat, $1]) if val =~ pat
228
+ self << val
436
229
  end
437
230
 
438
- def splice(*exclude, quote: true, delim: true, path: false, pattern: false, &blk)
439
- temp, other = if block_given?
440
- partition(&blk)
441
- elsif exclude.first.is_a?(Symbol)
442
- partition(&exclude.first)
443
- else
444
- exclude.map! { |pat| Regexp.new(pat) }
445
- partition do |val|
446
- val = val.to_s
447
- next if pattern && OptionPartition.pattern?(val)
448
-
449
- exclude.none? { |pat| val.match?(pat) }
450
- end
451
- end
452
- unless temp.empty?
453
- add '--' if delim
454
- extras.clear
455
- concat other
456
- if path
457
- temp.each { |val| add_path(val) }
458
- else
459
- temp.map! { |val| shell_quote(val) } if quote
460
- 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
461
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
462
252
  end
463
- self
253
+ block_given? ? ret.reject(&blk) : ret
464
254
  end
465
255
 
466
- def reset(errors: false)
467
- extras.clear
468
- found.clear
469
- clear(errors: true) if errors
470
- self
256
+ def and(*args)
257
+ self << '&&'
258
+ merge args
471
259
  end
472
260
 
473
- def append?(key, val = nil, type: nil, force: false, **kwargs)
474
- return false unless force || !arg?(key)
475
-
476
- val = yield self if block_given?
477
- return false unless val
478
-
479
- type ||= :quote if kwargs.empty?
480
- add case type
481
- when :quote
482
- quote_option(key, val)
483
- when :basic
484
- basic_option(key, val)
485
- else
486
- shell_option(key, val, **kwargs)
487
- end
488
- true
261
+ def or(*args)
262
+ self << '||'
263
+ merge args
489
264
  end
490
265
 
491
- def arg?(*args, **kwargs)
492
- OptionPartition.arg?(target, *args, **kwargs)
266
+ def with(*args, &blk)
267
+ temp('&&', *args, &blk)
493
268
  end
494
269
 
495
- def exist?(*args, add: false, first: false, last: false)
496
- return false unless path
497
- return path.join(*args).exist? unless args.empty?
498
-
499
- if first || last
500
- return false unless (val = first ? self.first : self.last).is_a?(String)
501
-
502
- path.join(val).exist?.tap do |ret|
503
- next unless add && ret
504
-
505
- add_path(first ? shift : pop)
506
- end
507
- else
508
- each_with_index do |val, index|
509
- next unless val.is_a?(String) && path.join(val).exist?
510
-
511
- if add
512
- remove_at index
513
- add_path val
514
- end
515
- return true
516
- end
517
- false
518
- 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)
519
275
  end
520
276
 
521
- def uniq!(list)
522
- unless (list = uniq(list)).empty?
523
- concat list
524
- self
525
- end
277
+ def done
278
+ ret = to_s
279
+ clear
280
+ ret
526
281
  end
527
282
 
528
- private
529
-
530
- def nameonly(val)
531
- val[OPT_VALUE, 1] || val
283
+ def to_s
284
+ pass.join(@delim)
532
285
  end
533
286
  end
534
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