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