squared 0.5.11 → 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.
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'date'
5
4
  require 'logger'
6
5
 
7
6
  module Squared
@@ -15,15 +14,17 @@ module Squared
15
14
  include Prompt
16
15
  include Utils
17
16
  include Support
17
+ include Workspace::Support::Variables
18
18
  include Rake::DSL
19
19
 
20
- VAR_SET = %i[parent global script index envname desc dependfile dependindex theme archive env dev prod graph
21
- pass only exclude asdf].freeze
20
+ OPTIONS = Workspace::Support.hashobj
21
+ VAR_SET = %i[parent global script index envname desc dependfile dependname dependindex theme archive env graph
22
+ dev prod pass only exclude asdf].freeze
22
23
  BLK_SET = %i[run depend doc lint test copy clean].freeze
23
24
  SEM_VER = /\b(\d+)(?:(\.)(\d+))?(?:(\.)(\d+))?[-.]?(\S+)?\b/.freeze
24
25
  URI_SCHEME = %r{\A([a-z][a-z\d+-.]*)://[^@:\[\]\\^<>|\s]}i.freeze
25
26
  TASK_METADATA = Rake::TaskManager.record_task_metadata
26
- private_constant :VAR_SET, :BLK_SET, :SEM_VER, :URI_SCHEME, :TASK_METADATA
27
+ private_constant :OPTIONS, :VAR_SET, :BLK_SET, :SEM_VER, :URI_SCHEME, :TASK_METADATA
27
28
 
28
29
  class << self
29
30
  def populate(*); end
@@ -35,13 +36,33 @@ module Squared
35
36
  (%i[build archive graph prereqs] + BLK_SET).freeze
36
37
  end
37
38
 
38
- def as_path(val)
39
- case val
40
- when Pathname
41
- val
42
- when String
43
- Pathname.new(val)
39
+ def options(*args, **kwargs)
40
+ name = nil
41
+ with = []
42
+ proj = []
43
+ opts = []
44
+ args.each do |val|
45
+ case val
46
+ when String
47
+ if name
48
+ opts << val
49
+ else
50
+ name = val
51
+ end
52
+ when Symbol
53
+ if name
54
+ proj << val
55
+ else
56
+ with << val
57
+ end
58
+ end
44
59
  end
60
+ return if !name || (opts.empty? && kwargs.empty? && with.empty?)
61
+
62
+ base = OPTIONS[ref]
63
+ data = [opts.freeze, kwargs.freeze, with.freeze].freeze
64
+ proj << :_ if proj.empty?
65
+ proj.each { |val| (base[val] ||= {})[name.to_s] = data }
45
66
  end
46
67
 
47
68
  def ref
@@ -61,27 +82,39 @@ module Squared
61
82
  def to_s
62
83
  super[/[^:]+\z/, 0]
63
84
  end
85
+
86
+ private
87
+
88
+ def as_path(val)
89
+ case val
90
+ when Pathname
91
+ val
92
+ when String
93
+ Pathname.new(val)
94
+ end
95
+ end
64
96
  end
65
97
 
66
98
  @@tasks = {}
67
99
  @@graph = { _: [] }
68
100
  @@asdf = Pathname.new("#{Dir.home}/.asdf").yield_self do |path|
69
- if path.join('asdf.sh').exist?
70
- [path, 15]
71
- elsif ENV['ASDF_DATA_DIR']
72
- [Pathname.new(ENV['ASDF_DATA_DIR']), 16]
73
- end
101
+ version = if path.join('asdf.sh').exist?
102
+ 15
103
+ elsif ENV['ASDF_DATA_DIR'] && (path = Pathname.new(ENV['ASDF_DATA_DIR'])).exist?
104
+ 16
105
+ end
106
+ Struct.new(:path, :version).new(path, version) if version
74
107
  end
75
108
  @@print_order = 0
76
109
 
77
110
  subtasks({
78
111
  'graph' => %i[run print].freeze,
79
- 'unpack' => %i[zip tar gem ext].freeze,
80
- 'asdf' => %i[set exec current]
112
+ 'unpack' => %i[zip gz tar ext].freeze,
113
+ 'asdf' => %i[set exec current update latest where reshim]
81
114
  })
82
115
 
83
116
  attr_reader :name, :project, :workspace, :path, :theme, :group, :parent, :dependfile,
84
- :exception, :pipe, :verbose
117
+ :exception, :pipe, :verbose, :global
85
118
 
86
119
  def initialize(workspace, path, name, *, group: nil, first: {}, last: {}, error: {}, common: ARG[:COMMON],
87
120
  **kwargs)
@@ -99,23 +132,28 @@ module Squared
99
132
  @clean = kwargs[:clean]
100
133
  @release = kwargs[:release]
101
134
  self.version = kwargs[:version]
102
- self.exception = kwargs[:exception]
103
- self.pipe = kwargs[:pipe]
104
- self.verbose = kwargs[:verbose]
135
+ self.exception = env_bool(kwargs[:exception], workspace.exception, strict: true)
136
+ self.pipe = env_pipe(kwargs[:pipe], workspace.pipe, strict: true)
137
+ self.verbose = case (val = env('VERBOSE', kwargs[:verbose]))
138
+ when String
139
+ env_bool(val, workspace.verbose, strict: true, index: true)
140
+ else
141
+ val.nil? ? workspace.verbose : val
142
+ end
143
+ self.global = false
105
144
  @output = []
106
145
  @ref = []
107
146
  @children = []
108
147
  @events = hashobj.update({ first: first, last: last, error: error })
109
148
  @as = hashobj
110
149
  @desc = (@name.include?(':') ? @name.split(':').join(ARG[:SPACE]) : @name).freeze
111
- @parent = nil
112
- @global = false
113
150
  @log = nil
114
151
  @dev = nil
115
152
  @prod = nil
116
153
  @withargs = nil
117
154
  @session = nil
118
155
  @index = -1
156
+ parent_set kwargs[:parent]
119
157
  run_set(kwargs[:run], kwargs[:env], opts: kwargs.fetch(:opts, true))
120
158
  graph_set kwargs[:graph]
121
159
  pass_set kwargs[:pass]
@@ -151,32 +189,25 @@ module Squared
151
189
 
152
190
  data = @workspace.script_find(*@ref, @group)
153
191
  if @output[0].nil?
154
- if (scr = data[:script])
155
- @global = true
156
- script_set(scr, args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod])
157
- elsif (run = data[:run])
158
- @global = true
159
- run_set run
192
+ if data[:script]
193
+ unless kwargs[:script] == false
194
+ script_set(data[:script], args: data.fetch(:args, kwargs[:args]), prod: kwargs[:prod], global: true)
195
+ end
196
+ elsif data[:run]
197
+ run_set(data[:run], global: true)
160
198
  end
161
- unless data[:env]
162
- if (scr = kwargs[:script])
163
- @global = false
164
- script_set(scr, args: kwargs[:args])
165
- elsif @script && !data[:global]
166
- if (scr = @script[:script])
167
- @global = false
168
- script_set(scr, args: @script.fetch(:args, kwargs[:args]))
169
- elsif (run = @script[:run])
170
- @global = false
171
- run_set run
172
- end
199
+ if kwargs[:script]
200
+ script_set(kwargs[:script], args: kwargs[:args]) unless data[:env][:script]
201
+ elsif @script
202
+ if @script[:script]
203
+ script_set(@script[:script], args: @script.fetch(:args, kwargs[:args])) unless data[:global][:script]
204
+ elsif @script[:run] && !data[:global][:run]
205
+ run_set @script[:run]
173
206
  end
174
207
  end
175
- elsif data[:env] && data[:run]
176
- @global = true
177
- run_set data[:run]
208
+ elsif data[:run] && data[:env][:run]
209
+ run_set(data[:run], global: true)
178
210
  end
179
- @global = true
180
211
  end
181
212
 
182
213
  def initialize_events(ref, **)
@@ -189,10 +220,11 @@ module Squared
189
220
  return if @log
190
221
 
191
222
  log = log.is_a?(Hash) ? log.dup : { file: log }
192
- if (file = env('LOG_FILE'))
193
- file = Time.now.strftime(file)
194
- elsif (val = env('LOG_AUTO'))
195
- file = "#{@name}-%s.log" % [case val
223
+ file = if (val = env('LOG_FILE'))
224
+ Time.now.strftime(val)
225
+ elsif (val = env('LOG_AUTO'))
226
+ require 'date'
227
+ "#{@name}-%s.log" % [case val
196
228
  when 'y', 'year'
197
229
  Date.today.year
198
230
  when 'm', 'month'
@@ -202,19 +234,21 @@ module Squared
202
234
  else
203
235
  val.include?('%') ? Time.now.strftime(val) : Time.now.strftime('%FT%T%:z')
204
236
  end]
205
- elsif (val = log[:file])
206
- file = val.is_a?(String) ? Time.now.strftime(val) : "#{@name}-#{Date.today}.log"
207
- end
208
- begin
209
- file &&= @workspace.home.join(env('LOG_DIR', ''), file).realdirpath
210
- rescue StandardError => e
211
- file = nil
212
- print_error e
213
- end
237
+ elsif (val = log[:file])
238
+ if val.is_a?(String)
239
+ Time.now.strftime(val)
240
+ else
241
+ require 'date'
242
+ "#{@name}-#{Date.today}.log"
243
+ end
244
+ end
245
+ .yield_self do |dir|
246
+ @workspace.home.join(env('LOG_DIR', ''), dir).realdirpath if dir
247
+ rescue StandardError => e
248
+ print_error e
249
+ end
214
250
  log[:progname] ||= @name
215
- if (val = env('LOG_LEVEL', ignore: false))
216
- log[:level] = val.match?(/\d/) ? log_sym(val.to_i) : val
217
- end
251
+ log[:level] = val.match?(/\d/) ? log_sym(val.to_i) : val if (val = env('LOG_LEVEL', ignore: false))
218
252
  log.delete(:file)
219
253
  @log = [file, log]
220
254
  end
@@ -222,7 +256,7 @@ module Squared
222
256
  def initialize_env(dev: nil, prod: nil, **)
223
257
  @dev = env_match('BUILD', dev, suffix: 'DEV', strict: true)
224
258
  @prod = env_match('BUILD', prod, suffix: 'PROD', strict: true)
225
- if (val = env('BUILD', suffix: 'ENV')) && @output[2] != false
259
+ if @output[2] != false && (val = env('BUILD', suffix: 'ENV'))
226
260
  @output[2] = parse_json(val, hint: "BUILD_#{@envname}_ENV") || @output[2]
227
261
  end
228
262
  unless @output[0] == false || @output[0].is_a?(Array)
@@ -237,7 +271,6 @@ module Squared
237
271
  @version = val if (val = env('BUILD', suffix: 'VERSION'))
238
272
  return unless (val = env('BUILD', strict: true))
239
273
 
240
- @global = false
241
274
  if val == '0'
242
275
  @output = [false]
243
276
  elsif script?
@@ -293,24 +326,36 @@ module Squared
293
326
  end
294
327
 
295
328
  def exception=(val)
296
- @exception = env_bool(val, workspace.exception, strict: true)
329
+ @exception = case val
330
+ when Numeric, TrueClass, FalseClass
331
+ val
332
+ else
333
+ workspace.exception
334
+ end
297
335
  end
298
336
 
299
337
  def pipe=(val)
300
- @pipe = env_pipe(val, workspace.pipe, strict: true)
338
+ @pipe = case val
339
+ when Numeric, Pathname
340
+ val
341
+ else
342
+ workspace.pipe
343
+ end
301
344
  end
302
345
 
303
346
  def verbose=(val)
304
- @verbose = case (val = env('VERBOSE', val))
305
- when NilClass
306
- workspace.verbose
307
- when String
308
- env_bool(val, workspace.verbose, strict: true, index: true)
309
- else
347
+ @verbose = case val
348
+ when Numeric, TrueClass, FalseClass
310
349
  val
350
+ else
351
+ workspace.verbose
311
352
  end
312
353
  end
313
354
 
355
+ def global=(val)
356
+ @global = val unless val.nil?
357
+ end
358
+
314
359
  def ref
315
360
  Base.ref
316
361
  end
@@ -337,45 +382,40 @@ module Squared
337
382
  else
338
383
  out, done = graph(args, out: [])
339
384
  out.map! do |val|
340
- done.each_with_index do |proj, i|
341
- next unless val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/)
342
-
343
- val += " (#{i.succ})"
344
- break
345
- end
346
- val
385
+ n = done.index { |proj| val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/) }
386
+ n ? val.subhint(n.succ) : val
347
387
  end
348
388
  emphasize(out, title: path, right: true, border: borderstyle, sub: [
349
- { pat: /\A(#{Regexp.escape(path.to_s)})(.*)\z/, styles: theme[:header] },
350
- { pat: /\A(#{Regexp.escape(name)})(.*)\z/, styles: theme[:active] },
351
- { pat: /\A((?~ \() \()(\d+)(\).*)\z/, styles: theme[:inline], index: 2 }
389
+ opt_style(theme[:header], /\A(#{Regexp.escape(path.to_s)})(.*)\z/),
390
+ opt_style(theme[:active], /\A(#{Regexp.escape(name)})(.*)\z/),
391
+ opt_style(theme[:inline], /\A((?~ \() \()(\d+)(\).*)\z/, 2)
352
392
  ])
353
393
  end
354
394
  end
355
395
  when 'unpack'
356
- format_desc(action, flag, 'tag/url,dir,digest?,f|force?', before: flag == :ext ? 'ext' : nil)
396
+ format_desc(action, flag, 'tag/url,dir,digest?,f/orce?', before: ('ext' if flag == :ext))
357
397
  params = %i[tag dir digest force]
358
- params.prepend(:ext) if flag == :ext
398
+ params.unshift(:ext) if flag == :ext
359
399
  task flag, params do |_, args|
360
400
  ext = flag == :ext ? param_guard(action, flag, args: args, key: :ext) : flag.to_s
361
401
  tag = param_guard(action, flag, args: args, key: :tag)
362
402
  dir = param_guard(action, flag, args: args, key: :dir)
363
403
  unless tag.match?(URI_SCHEME)
364
- if flag == :gem
365
- tag = "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
366
- elsif @release
367
- tag = "%s.#{ext}" % [@release.include?('??') ? @release.sub('??', tag) : @release + tag]
368
- else
369
- raise_error("no base uri: #{tag}", hint: ext)
370
- end
371
- end
372
- case (digest = args.digest)
373
- when 'f', 'force'
374
- digest = nil
375
- force = true
376
- else
377
- force = args.fetch(:force, false)
404
+ tag = if ext == 'gem'
405
+ "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
406
+ elsif @release
407
+ "%s.#{ext}" % [@release.include?('??') ? @release.sub('??', tag) : @release + tag]
408
+ else
409
+ raise_error ArgumentError, "no base uri: #{tag}", hint: ext
410
+ end
378
411
  end
412
+ force = case (digest = args.digest)
413
+ when 'f', 'force'
414
+ digest = nil
415
+ true
416
+ else
417
+ args.fetch(:force, false)
418
+ end
379
419
  unpack(basepath(dir), uri: tag, digest: digest, ext: ext, force: force)
380
420
  end
381
421
  when 'asdf'
@@ -383,7 +423,7 @@ module Squared
383
423
 
384
424
  case flag
385
425
  when :set
386
- format_desc action, flag, 'version,opts*=u|home,p|parent'
426
+ format_desc action, flag, 'version,dir?=u/home|p/arent'
387
427
  task flag, [:version] do |_, args|
388
428
  args = if (version = args.version)
389
429
  args.extras
@@ -392,15 +432,15 @@ module Squared
392
432
  @asdf[1].children
393
433
  .map(&:basename)
394
434
  .sort { |a, b| b <=> a }
395
- .append('latest', 'system'),
396
- force: true, accept: [['Confirm?', false, true]],
397
- values: ['Options'])
435
+ .push('latest', 'system'),
436
+ accept: [accept_y('Confirm?')],
437
+ values: 'Options', force: true)
398
438
  OptionPartition.strip(opts)
399
439
  end
400
440
  asdf(flag, args, version: version)
401
441
  end
402
442
  else
403
- format_desc(action, flag, flag == :exec ? 'command' : nil)
443
+ format_desc(action, flag, ('command' if flag == :exec))
404
444
  task flag do |_, args|
405
445
  args = args.to_a
406
446
  args << readline('Enter command', force: true) if args.empty? && flag == :exec
@@ -419,7 +459,7 @@ module Squared
419
459
  end
420
460
 
421
461
  def with(**kwargs, &blk)
422
- @withargs = kwargs.empty? ? nil : kwargs
462
+ @withargs = (kwargs unless kwargs.empty?)
423
463
  if block_given?
424
464
  instance_eval(&blk)
425
465
  @withargs = nil
@@ -428,35 +468,31 @@ module Squared
428
468
  end
429
469
 
430
470
  def add(path, name = nil, **kwargs, &blk)
431
- if path.is_a?(String) && (seg = path[%r{\A(.+)[\\/]\*+\z}, 1])
432
- return self unless checkdir?(path = basepath(seg))
471
+ if path.is_a?(String) && path =~ %r{\A(.+)[\\/]\*+\z}
472
+ return self unless checkdir?(path = basepath($1))
433
473
 
434
474
  path = path.children.select { |val| checkdir?(val) }
435
475
  end
436
476
  if path.is_a?(Array)
437
- name = @name if name == true
477
+ name = self.name if name == true
438
478
  path.each { |val| add(val, name && task_join(name, File.basename(val)), **kwargs, &blk) }
439
- return self
440
- end
441
- return self unless projectpath?(path = basepath(path)) && checkdir?(path)
442
-
443
- kwargs = hashdup(@withargs).update(kwargs) if @withargs
444
- kwargs[:group] = group if group && !kwargs.key?(:group)
445
- kwargs[:ref] = ref unless kwargs.key?(:ref)
446
- parent = self
447
- proj = nil
448
- name = case name
449
- when String, Symbol
450
- name.to_s
451
- else
452
- path.basename
453
- end
454
- workspace.add(path, name, **kwargs) do
455
- __send__ :parent_set, parent
456
- proj = self
457
- instance_eval(&blk) if block_given?
479
+ elsif projectpath?(path = basepath(path)) && checkdir?(path)
480
+ kwargs = hashdup(@withargs).update(kwargs) if @withargs
481
+ kwargs[:group] = group if group && !kwargs.key?(:group)
482
+ kwargs[:ref] = ref unless kwargs.key?(:ref)
483
+ proj = nil
484
+ name = case name
485
+ when String, Symbol
486
+ name.to_s
487
+ else
488
+ path.basename
489
+ end
490
+ workspace.add(path, name, parent: self, **kwargs) do
491
+ proj = self
492
+ instance_eval(&blk) if block_given?
493
+ end
494
+ @children << proj
458
495
  end
459
- @children << proj
460
496
  self
461
497
  end
462
498
 
@@ -466,15 +502,15 @@ module Squared
466
502
  end
467
503
 
468
504
  def inject(obj, *args, **kwargs, &blk)
469
- return self unless enabled?
505
+ if enabled?
506
+ raise 'link not compatible' unless obj.respond_to?(:link) && (out = obj.link(self, *args, **kwargs, &blk))
470
507
 
471
- out = obj.link(self, *args, **kwargs, &blk) if obj.respond_to?(:link)
472
- if !out
473
- print_error('link not compatible', subject: obj, hint: name)
474
- elsif out.respond_to?(:build)
475
- out.build
508
+ out.build if out.respond_to?(:build)
476
509
  end
477
510
  self
511
+ rescue StandardError => e
512
+ print_error(e, subject: obj, hint: name)
513
+ self
478
514
  end
479
515
 
480
516
  def build(*args, sync: invoked_sync?('build'), from: :run, **)
@@ -482,8 +518,8 @@ module Squared
482
518
  if args.empty?
483
519
  return unless from == :run
484
520
 
485
- banner = verbosetype > 1 if from_base?('build')
486
- run_b(@run, sync: sync, from: from, banner: banner) if series?(@run)
521
+ banner = verbose? if from_base?('build')
522
+ run_b(@run, sync: sync, banner: banner, from: from) if series?(@run)
487
523
  args = @output
488
524
  end
489
525
  if args.first.is_a?(Struct)
@@ -521,12 +557,12 @@ module Squared
521
557
  if cmd
522
558
  return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
523
559
 
524
- cmd = as_get(cmd, from)
560
+ cmd = as_get cmd, from
525
561
  opts = compose(opts, script: false) if opts && respond_to?(:compose)
526
562
  flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
527
563
  case opts
528
564
  when Hash
529
- cmd = Array(cmd).append(flags)
565
+ cmd = Array(cmd).push(flags)
530
566
  .concat(append_hash(opts, target: [], build: true))
531
567
  .compact
532
568
  .join(' ')
@@ -543,7 +579,7 @@ module Squared
543
579
  cmd = compose(as_get(opts, from), flags, script: true, args: extra, from: from)
544
580
  from = :script if from == :run && script?
545
581
  end
546
- run(cmd, var, sync: sync, from: from, banner: banner)
582
+ run(cmd, var, sync: sync, banner: banner, from: from)
547
583
  end
548
584
 
549
585
  def depend(*, sync: invoked_sync?('depend'), **)
@@ -556,7 +592,7 @@ module Squared
556
592
  next if @@graph[:_].include?(proj)
557
593
 
558
594
  if (val = ENV["PREREQS_#{proj.instance_variable_get(:@envname)}"] || ENV["PREREQS_#{proj.ref.upcase}"])
559
- val.split(/\s*,\s*/).each do |meth|
595
+ split_escape(val) do |meth|
560
596
  if proj.respond_to?(meth.to_sym)
561
597
  begin
562
598
  proj.__send__(meth, sync: sync)
@@ -615,7 +651,7 @@ module Squared
615
651
  begin
616
652
  @clean.each { |cmd, opts| build(cmd.to_s, opts, sync: sync) }
617
653
  rescue StandardError => e
618
- on_error e, from
654
+ on_error e, :clean
619
655
  end
620
656
  else
621
657
  if @clean.is_a?(Enumerable) && !series?(@clean)
@@ -643,9 +679,9 @@ module Squared
643
679
  end
644
680
 
645
681
  def graph(start = [], tasks = nil, *, sync: invoked_sync?('graph'), pass: [], out: nil, **)
646
- if (val = env('GRAPH', strict: true))
682
+ env('GRAPH', strict: true) do |val|
647
683
  tasks ||= []
648
- split_escape(val).each do |task|
684
+ split_escape(val) do |task|
649
685
  if ref?(task.to_sym) && (script = workspace.script_get(:graph, ref: task.to_sym))
650
686
  tasks.concat(script[:graph])
651
687
  else
@@ -653,7 +689,7 @@ module Squared
653
689
  end
654
690
  end
655
691
  end
656
- pass.concat(split_escape(val)) if (val = env('GRAPH', suffix: 'PASS'))
692
+ env('GRAPH', suffix: 'PASS') { |val| pass.concat(split_escape(val)) }
657
693
  start, neg = start.partition { |name| !name.start_with?('-') }
658
694
  data = graph_collect(self, start, pass: neg.map! { |name| name[1..-1] })
659
695
  unless out
@@ -676,9 +712,9 @@ module Squared
676
712
  if !target.exist?
677
713
  target.mkpath
678
714
  elsif !target.directory?
679
- raise_error('invalid location', hint: target)
715
+ raise_error Errno::EEXIST, target, hint: uri
680
716
  elsif !file && !target.empty?
681
- raise_error('directory not empty', hint: target) unless force || env('UNPACK_FORCE')
717
+ raise_error Errno::EEXIST, target, hint: uri unless force || env('UNPACK_FORCE')
682
718
  create = true
683
719
  end
684
720
  if digest
@@ -698,25 +734,27 @@ module Squared
698
734
  when 128, 'sha512'
699
735
  Digest::SHA512
700
736
  else
701
- raise_error "invalid checksum: #{digest}"
737
+ raise_error "invalid checksum: #{digest}", hint: uri
702
738
  end
703
739
  end
704
- if (val = env('HEADERS')) && (val = parse_json(val, hint: "HEADERS_#{@envname}"))
705
- headers = headers.is_a?(Hash) ? headers.merge(val) : val
740
+ env('HEADERS') do |val|
741
+ if (data = parse_json(val, hint: "HEADERS_#{@envname}"))
742
+ headers = headers.is_a?(Hash) ? headers.merge(data) : data
743
+ end
706
744
  end
707
745
  if file
708
746
  ext ||= File.extname(file)[1..-1]
709
747
  else
710
748
  require 'open-uri'
711
749
  data = nil
712
- (uri = Array(uri)).each_with_index do |url, index|
750
+ (uri = Array(uri)).each_with_index do |url, i|
713
751
  URI.open(url, headers) do |f|
714
752
  data = f.read
715
753
  if algo && algo.hexdigest(data) != digest
716
754
  data = nil
717
- raise_error("checksum failed: #{digest}", hint: url) if index == uri.size - 1
755
+ raise_error "invalid checksum: #{digest}", hint: url if i == uri.size.pred
718
756
  end
719
- next if ext && index == 0
757
+ next if ext && i == 0
720
758
 
721
759
  case f.content_type
722
760
  when 'application/zip'
@@ -725,12 +763,14 @@ module Squared
725
763
  ext = 'tgz'
726
764
  when 'application/x-xz'
727
765
  ext = 'txz'
766
+ when 'application/x-7z-compressed'
767
+ ext = '7z'
728
768
  end
729
769
  end
730
770
  break uri = url if data
731
771
  end
732
772
  unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
733
- raise_error("no content#{data ? ' type' : ''}", hint: uri)
773
+ raise_error(data ? TypeError : RuntimeError, "no content#{data ? ' type' : ''}", hint: uri)
734
774
  end
735
775
  end
736
776
  ext = ext.downcase
@@ -739,13 +779,13 @@ module Squared
739
779
  end
740
780
  begin
741
781
  unless file
742
- if ext == 'gem'
743
- dir = Dir.mktmpdir
744
- file = File.new(File.join(dir, File.basename(uri)), 'w')
745
- else
746
- require 'tempfile'
747
- file = Tempfile.new("#{name}-")
748
- end
782
+ file = if ext == 'gem'
783
+ dir = Dir.mktmpdir
784
+ File.new(File.join(dir, File.basename(uri)), 'w')
785
+ else
786
+ require 'tempfile'
787
+ Tempfile.new("#{name}-")
788
+ end
749
789
  file.write(data)
750
790
  file.close
751
791
  file = Pathname.new(file)
@@ -759,7 +799,7 @@ module Squared
759
799
  case ext
760
800
  when 'zip', 'aar'
761
801
  session 'unzip', shell_quote(file), quote_option('d', target)
762
- when 'tar', 'tgz', 'tar.gz', 'tar.xz', 'gz', 'xz'
802
+ when 'tar', /\A(?:t|tar\.)?[gx]z\z/
763
803
  flags = +(verbose ? 'v' : '')
764
804
  if ext.end_with?('gz')
765
805
  flags += 'z'
@@ -802,16 +842,17 @@ module Squared
802
842
  def asdf(flag, opts = [], version: nil)
803
843
  return unless @asdf
804
844
 
805
- cmd = session 'asdf', flag
845
+ cmd = flag == :update ? session('asdf', 'plugin update') : session('asdf', flag)
806
846
  name = @asdf.first
807
- legacy = @@asdf[1] == 15
847
+ legacy = @@asdf.version == 15
848
+ banner = true
808
849
  case flag
809
850
  when :set
810
- u = has_value?(opts, %w[u home])
851
+ u = has_value?(opts, 'u', 'home')
811
852
  cmd << if legacy
812
853
  cmd.delete(flag)
813
854
  u ? 'global' : 'local'
814
- elsif has_value?(opts, %w[p parent])
855
+ elsif has_value?(opts, 'p', 'parent')
815
856
  '--parent'
816
857
  elsif u
817
858
  '--home'
@@ -822,8 +863,11 @@ module Squared
822
863
  when :current
823
864
  cmd << '--no-header' unless legacy
824
865
  cmd << name
866
+ else
867
+ cmd << name
868
+ banner = flag == :update || flag == :reshim
825
869
  end
826
- print_success if success?(run(from: :"asdf:#{flag}"), flag == :set)
870
+ success?(run(banner: banner, from: :"asdf:#{flag}"), flag == :set || flag == :reshim)
827
871
  end
828
872
 
829
873
  def first(key, *args, **kwargs, &blk)
@@ -863,28 +907,27 @@ module Squared
863
907
  instance_variable_set :"@#{key}", [blk]
864
908
  end
865
909
  else
866
- log&.warn "series: @#{key} (invalid)"
910
+ log&.warn "series: @#{key}".subhint('invalid')
867
911
  end
868
912
  self
869
913
  end
870
914
 
871
- def run(cmd = @session, var = nil, exception: self.exception, sync: true, from: nil, banner: true, chdir: path,
872
- interactive: nil, hint: nil, **)
873
- unless cmd
874
- print_error('no command session started', subject: project, hint: from, pass: true)
875
- return
876
- end
915
+ def run(cmd = @session, var = nil, exception: self.exception, sync: true, banner: true, from: nil, chdir: path,
916
+ interactive: nil, hint: nil, series: true, **)
917
+ return print_error('no command session started', subject: project, hint: from, pass: true) unless cmd
918
+
877
919
  cmd = cmd.target if cmd.is_a?(OptionPartition)
878
- if interactive && (!@session || !option('y'))
879
- title, y = case interactive
880
- when Array
881
- interactive
882
- when String
883
- [interactive, 'N']
884
- else
885
- ['Run', 'Y']
886
- end
887
- exit 1 unless confirm("#{title}? [#{sub_style(cmd.to_s, styles: theme[:inline])}]", y)
920
+ if interactive && sync && (!@session || !option('y'))
921
+ title, y, hint = case interactive
922
+ when Array
923
+ interactive
924
+ when String
925
+ [interactive, 'N']
926
+ else
927
+ ['Run', 'Y']
928
+ end
929
+ title = "#{title} #{sub_style(hint, styles: theme[:active])}" if hint
930
+ exit 1 unless confirm_basic("#{title}?", cmd, y)
888
931
  end
889
932
  cmd = session_done cmd
890
933
  log&.info cmd
@@ -894,7 +937,7 @@ module Squared
894
937
  log&.warn "ENV discarded: #{var}" if var
895
938
  task_invoke(cmd, exception: exception, warning: warning?)
896
939
  else
897
- print_item format_banner(hint ? "#{cmd} (#{hint})" : cmd, banner: banner) if sync
940
+ print_item(format_banner(cmd, banner: banner, hint: hint), series: series) if sync
898
941
  if var != false && (pre = runenv)
899
942
  case pre
900
943
  when Hash
@@ -926,14 +969,7 @@ module Squared
926
969
  args = block_args args, &blk
927
970
  end
928
971
  if variables.include?(key) || blocks.include?(key)
929
- val = case args.size
930
- when 0
931
- nil
932
- when 1
933
- args.first
934
- else
935
- args
936
- end
972
+ val = args.size > 1 ? args : args.first
937
973
  case key
938
974
  when :index
939
975
  index_set val
@@ -963,7 +999,7 @@ module Squared
963
999
  instance_variable_set(:"@#{key}", val)
964
1000
  end
965
1001
  else
966
- log&.warn "variable_set: @#{key} (private)"
1002
+ log&.warn "variable_set: @#{key}".subhint('private')
967
1003
  end
968
1004
  self
969
1005
  end
@@ -986,6 +1022,10 @@ module Squared
986
1022
  @ref.include?(val)
987
1023
  end
988
1024
 
1025
+ def exist?(*args)
1026
+ basepath(*args).exist?
1027
+ end
1028
+
989
1029
  def build?
990
1030
  !!@output[0] || script? || series?(@run)
991
1031
  end
@@ -1059,10 +1099,14 @@ module Squared
1059
1099
  @dependindex ? @dependindex.succ : 0
1060
1100
  end
1061
1101
 
1102
+ def dependname
1103
+ @dependname ||= dependfile&.basename.to_s
1104
+ end
1105
+
1062
1106
  def log
1063
1107
  return @log unless @log.is_a?(Array)
1064
1108
 
1065
- @log = Logger.new(enabled? ? @log.first : nil, **@log.last)
1109
+ @log = Logger.new((@log.first if enabled?), **@log.last)
1066
1110
  end
1067
1111
 
1068
1112
  def allref
@@ -1089,6 +1133,12 @@ module Squared
1089
1133
  workspace.task_localname(name)
1090
1134
  end
1091
1135
 
1136
+ def scriptname(from: :run)
1137
+ return unless (name = @output[1]) && respond_to?(:compose)
1138
+
1139
+ as_get name, from
1140
+ end
1141
+
1092
1142
  def inspect
1093
1143
  "#<#{self.class}: #{name} => #{self}>"
1094
1144
  end
@@ -1107,10 +1157,18 @@ module Squared
1107
1157
  log_console(*args, pipe: kwargs[:pipe] || pipe)
1108
1158
  end
1109
1159
 
1110
- def run_s(*cmd, env: nil, sync: true, from: nil, banner: verbose != false, **kwargs)
1160
+ def run_s(*cmd, sync: true, banner: verbosetype > 0, from: nil, **kwargs)
1161
+ cmd.flatten!
1162
+ case cmd.last
1163
+ when Hash, TrueClass, FalseClass
1164
+ var = cmd.pop
1165
+ end
1111
1166
  on :first, from
1112
1167
  begin
1113
- cmd.flatten.each { |val| run(val, env, sync: sync, banner: banner, **kwargs) }
1168
+ cmd.each do |val|
1169
+ print_run val, banner
1170
+ run(val, var, sync: sync, banner: banner, **kwargs)
1171
+ end
1114
1172
  rescue StandardError => e
1115
1173
  ret = on :error, from, e
1116
1174
  raise unless ret == true
@@ -1127,7 +1185,12 @@ module Squared
1127
1185
  when Proc
1128
1186
  instance_eval(&obj)
1129
1187
  when Method
1130
- obj.call
1188
+ args = if (n = obj.arity.abs) > 0
1189
+ Array.new(n).tap { |data| data[0] = self }
1190
+ else
1191
+ []
1192
+ end
1193
+ obj.call(*args)
1131
1194
  else
1132
1195
  if series?(obj)
1133
1196
  obj.each(&:call)
@@ -1142,7 +1205,7 @@ module Squared
1142
1205
  def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], depth: 0,
1143
1206
  single: false, last: false, context: nil)
1144
1207
  tag = ->(proj) { "#{proj.name}#{SEM_VER.match?(proj.version) ? "@#{proj.version}" : ''}" }
1145
- check = ->(deps) { deps.reject { |val| done.include?(val) } }
1208
+ script = ->(proj) { workspace.script_get(:graph, group: proj.group, ref: proj.allref)&.fetch(:graph, nil) }
1146
1209
  dedupe = lambda do |name|
1147
1210
  next [] unless (ret = data[name])
1148
1211
 
@@ -1153,12 +1216,11 @@ module Squared
1153
1216
  end
1154
1217
  ret
1155
1218
  end
1156
- start = target.name
1157
1219
  if depth == 0
1158
- items = check.call(dedupe.call(start))
1220
+ items = dedupe.call(target.name) - done
1159
1221
  single = items.size == 1
1160
1222
  else
1161
- items = check.call(data[start])
1223
+ items = data[target.name] - done
1162
1224
  end
1163
1225
  if out
1164
1226
  a, b, c, d, e = ARG[:GRAPH]
@@ -1173,53 +1235,50 @@ module Squared
1173
1235
  "#{last ? d : c}#{b * 3}#{e} #{f}"
1174
1236
  end
1175
1237
  else
1176
- "#{single ? ' ' : a}#{' ' * (depth - 1)}#{last ? d : c}#{b * 3}#{items.empty? ? b : e} #{f}"
1238
+ "#{single ? ' ' : a}#{' ' * depth.pred}#{last ? d : c}#{b * 3}#{items.empty? ? b : e} #{f}"
1177
1239
  end
1178
1240
  end
1179
1241
  items.each_with_index do |proj, i|
1180
1242
  next if done.include?(proj)
1181
1243
 
1182
- t = dedupe.call(proj.name)
1244
+ t = dedupe.call(name = proj.name)
1183
1245
  j = if out
1184
- if i == items.size - 1 || check.call(post = items[(i + 1)..-1]).empty?
1246
+ if i == items.size.pred || (post = items[i.succ..-1] - done).empty?
1185
1247
  true
1186
1248
  elsif !t.empty? && depth > 0
1187
- post.reject { |pr| t.include?(pr) }.empty?
1249
+ (post - t).empty?
1188
1250
  end
1189
1251
  end
1190
- unless start == proj.name || (none = check.call(t).empty?)
1252
+ unless target.name == name || (none = (t - done).empty?)
1191
1253
  graph_branch(proj, data, tasks, out, sync: sync, pass: pass, done: done, depth: depth.succ,
1192
1254
  single: single, last: j == true, context: target)
1193
1255
  end
1194
1256
  if !out
1195
- if !tasks && (script = workspace.script_get(:graph, group: proj.group, ref: proj.allref))
1196
- tasks = script[:graph]
1197
- end
1198
- (tasks || (dev? ? ['build', 'copy'] : ['depend', 'build'])).each do |meth|
1257
+ (tasks || (subtasks = script.call(proj)) || (dev? ? %w[build copy] : %w[depend build])).each do |meth|
1199
1258
  next if pass.include?(meth)
1200
1259
 
1201
- if workspace.task_defined?(cmd = task_join(proj.name, meth))
1202
- if ENV.key?(key = "BANNER_#{proj.name.upcase}")
1260
+ if workspace.task_defined?(cmd = task_join(name, meth))
1261
+ if ENV.key?(key = "BANNER_#{name.upcase}")
1203
1262
  key = nil
1204
1263
  else
1205
1264
  ENV[key] = '0'
1206
1265
  end
1207
1266
  run(cmd, sync: false, banner: false)
1208
1267
  ENV.delete(key) if key
1209
- elsif proj.has?(meth, tasks ? nil : workspace.baseref)
1268
+ elsif proj.has?(meth, (workspace.baseref unless tasks || subtasks))
1210
1269
  proj.__send__(meth.to_sym, sync: sync)
1211
1270
  end
1212
1271
  end
1213
1272
  elsif none
1214
1273
  a, b, c, d = ARG[:GRAPH]
1215
1274
  out << if depth == 0
1216
- "#{i == items.size - 1 ? d : c}#{b * 4} #{tag.call(proj)}"
1275
+ "#{i == items.size.pred ? d : c}#{b * 4} #{tag.call(proj)}"
1217
1276
  else
1218
1277
  s = ''.dup
1219
1278
  k = 0
1220
1279
  final = data.keys.last
1221
1280
  while k < depth
1222
- indent = k > 0 ? ((last && !j) || (j && k == depth - 1) || single) : j && last && depth == 1
1281
+ indent = k > 0 ? ((last && !j) || (j && k == depth.pred) || single) : j && last && depth == 1
1223
1282
  s += "#{indent || (last && data[final].last == context) ? ' ' : a} "
1224
1283
  k += 1
1225
1284
  end
@@ -1237,22 +1296,19 @@ module Squared
1237
1296
  next if pass.include?(val)
1238
1297
 
1239
1298
  if (obj = workspace.find(name: val))
1240
- next unless obj.enabled?
1241
-
1242
- items = [obj]
1299
+ obj.enabled? ? [obj] : []
1243
1300
  else
1244
- items = workspace.find(group: val, ref: val.to_sym)
1245
- end
1246
- items.each do |proj|
1301
+ workspace.find(group: val, ref: val.to_sym)
1302
+ end.each do |proj|
1247
1303
  next if pass.include?(name = proj.name)
1248
1304
 
1249
1305
  if proj.graph? && !data.key?(name) && !root.include?(name)
1250
1306
  graph_collect(proj, data: data, pass: pass, root: root + [name, target.name])
1251
1307
  end
1252
- next if (objs = data.fetch(name, [])).include?(target)
1253
-
1254
- deps << proj
1255
- deps.concat(objs)
1308
+ unless (objs = data.fetch(name, [])).include?(target)
1309
+ deps << proj
1310
+ deps.concat(objs)
1311
+ end
1256
1312
  end
1257
1313
  end
1258
1314
  deps.uniq!
@@ -1278,44 +1334,96 @@ module Squared
1278
1334
  end
1279
1335
 
1280
1336
  def env(key, default = nil, suffix: nil, equals: nil, ignore: nil, strict: false)
1281
- a = "#{key}_#{@envname}"
1337
+ name = "#{key}_#{@envname}"
1282
1338
  ret = if suffix
1283
- ENV.fetch("#{a}_#{suffix}", '')
1339
+ ENV.fetch("#{name}_#{suffix}", '')
1284
1340
  elsif strict
1285
- ENV[a].to_s
1341
+ ENV[name].to_s
1286
1342
  else
1287
1343
  ignore = ['0'].freeze if ignore.nil?
1288
- ENV[a] || ENV.fetch(key, '')
1344
+ ENV[name] || ENV.fetch(key, '')
1289
1345
  end
1290
- return ret == equals.to_s unless equals.nil?
1291
-
1292
- ret.empty? || (ignore && Array(ignore).any? { |val| ret == val.to_s }) ? default : ret
1346
+ if !equals.nil?
1347
+ ret = ret == equals.to_s
1348
+ elsif ret.empty? || (ignore && Array(ignore).any? { |val| ret == val.to_s })
1349
+ ret = default
1350
+ end
1351
+ block_given? && !ret.nil? ? yield(ret) : ret
1293
1352
  end
1294
1353
 
1295
1354
  def session(*cmd, prefix: cmd.first, main: true, path: true, options: true)
1296
- prefix = stripext prefix.to_s
1355
+ prefix = prefix.to_s.stripext
1297
1356
  if path && (val = shell_bin(prefix))
1298
1357
  cmd[0] = shell_quote(val, force: false)
1299
1358
  end
1300
1359
  ret = JoinSet.new(cmd.flatten(1))
1301
- if options && (val = env("#{prefix.upcase}_OPTIONS"))
1302
- split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^ =]+)[ =].+\z/m) }
1360
+ if options
1361
+ env("#{prefix.upcase}_OPTIONS") do |val|
1362
+ if val.start_with('-')
1363
+ ret.concat(shell_parse(val))
1364
+ else
1365
+ split_escape(val) { |opt| ret.last(fill_option(opt), /\A(--?[^= ]+)[= ].+\z/m) }
1366
+ end
1367
+ end
1303
1368
  end
1304
1369
  main ? @session = ret : ret
1305
1370
  end
1306
1371
 
1307
- def session_delete(*args, target: @session)
1308
- OptionPartition.delete(target, *args)
1309
- end
1310
-
1311
1372
  def session_output(*cmd, **kwargs)
1312
1373
  session(*cmd, main: false, options: false, **kwargs)
1313
1374
  end
1314
1375
 
1376
+ def session_get(val, pass: nil)
1377
+ base = OPTIONS[ref]
1378
+ args = []
1379
+ kwargs = {}
1380
+ with = []
1381
+ [:_, name.to_sym].each do |key|
1382
+ next unless base.key?(key) && (a, b, c = base[key][val])
1383
+
1384
+ args.concat(a)
1385
+ append_keys(kwargs, b, :opts)
1386
+ with.concat(c)
1387
+ end
1388
+ OptionPartition.uniq!(args, pass) if pass
1389
+ [args, kwargs, with]
1390
+ end
1391
+
1392
+ def session_apply(val, args: nil, kwargs: nil, pass: [], keys: [:opts], exclude: [])
1393
+ a = []
1394
+ b = {}
1395
+ Array(val).each do |c|
1396
+ d, e, f = session_get c
1397
+ unless (f -= exclude).empty?
1398
+ h = []
1399
+ i = {}
1400
+ session_apply(f.map!(&:to_s), args: h, kwargs: i, pass: pass, keys: keys, exclude: exclude.concat(f))
1401
+ a.concat(h)
1402
+ append_keys(b, i, *keys)
1403
+ end
1404
+ a.concat(d)
1405
+ append_keys(b, e, *keys)
1406
+ end
1407
+ if args
1408
+ args.unshift(*a)
1409
+ OptionPartition.uniq!(args, pass) if pass
1410
+ end
1411
+ kwargs&.update(b) { |_, val| val }
1412
+ nil
1413
+ end
1414
+
1415
+ def session_opts(val, args: nil, kwargs: nil, pass: nil, keys: [:opts])
1416
+ opts = kwargs.delete(:opts) || []
1417
+ return opts unless val
1418
+
1419
+ session_apply(val, args: args, kwargs: kwargs, pass: pass, keys: keys)
1420
+ kwargs.fetch(:opts, []).concat(opts)
1421
+ end
1422
+
1315
1423
  def session_done(cmd)
1316
- return cmd unless cmd.respond_to?(:done)
1424
+ return cmd.to_s unless cmd.respond_to?(:done)
1317
1425
 
1318
- raise_error('no args added', hint: cmd.first) unless cmd.size > 1
1426
+ raise_error 'no command added', hint: cmd.first unless cmd.size > 1
1319
1427
  @session = nil if cmd == @session
1320
1428
  cmd.done
1321
1429
  end
@@ -1330,20 +1438,22 @@ module Squared
1330
1438
  return unless prefix
1331
1439
 
1332
1440
  args.each do |val|
1333
- next unless (ret = env(env_key(stripext(prefix), val), **kwargs))
1441
+ next unless (ret = env(env_key(prefix.to_s.stripext, val), **kwargs))
1334
1442
 
1335
1443
  return block_given? ? yield(ret) : ret
1336
1444
  end
1337
1445
  nil
1338
1446
  end
1339
1447
 
1340
- def option_clear(opts, target: @session, **kwargs)
1448
+ def option_clear(opts, empty = true, target: @session, **kwargs)
1341
1449
  return unless target
1342
1450
 
1343
1451
  OptionPartition.clear(target, opts, styles: theme[:inline], **kwargs)
1452
+ opts.clear if empty
1453
+ nil
1344
1454
  end
1345
1455
 
1346
- def print_success(*)
1456
+ def print_success
1347
1457
  puts 'Success'
1348
1458
  end
1349
1459
 
@@ -1351,10 +1461,17 @@ module Squared
1351
1461
  warn log_message(loglevel, *args, **kwargs) if warning?
1352
1462
  end
1353
1463
 
1354
- def print_item(*val)
1355
- puts unless printfirst?
1464
+ def print_run(cmd, banner = true, verbose: nil, **)
1465
+ return if banner || !stdout? || verbose == false
1466
+
1467
+ puts "\n> #{cmd}"
1356
1468
  printsucc
1357
- puts val unless val.empty? || (val.size == 1 && val.first.nil?)
1469
+ end
1470
+
1471
+ def print_item(*val, series: true)
1472
+ puts unless printfirst?
1473
+ printsucc if series
1474
+ puts val unless val.empty? || (val.size == 1 && !val.first)
1358
1475
  end
1359
1476
 
1360
1477
  def print_banner(*lines, client: false, styles: theme[:banner], border: borderstyle, **)
@@ -1383,14 +1500,15 @@ module Squared
1383
1500
 
1384
1501
  def print_footer(*lines, sub: nil, reverse: false, right: false, border: borderstyle, **)
1385
1502
  n = line_width lines
1503
+ sub = as_a sub
1386
1504
  lines.map! do |val|
1387
1505
  s = right ? val.rjust(n) : val.ljust(n)
1388
- sub&.each { |h| s = sub_style(s, **h) }
1506
+ sub.each { |h| s = sub_style(s, **h) }
1389
1507
  s
1390
1508
  end
1391
- ret = [sub_style(ARG[:BORDER][1] * n, styles: border), *lines]
1392
- ret.reverse! if reverse
1393
- ret.join("\n")
1509
+ [sub_style(ARG[:BORDER][1] * n, styles: border)].concat(lines)
1510
+ .tap { |ret| ret.reverse! if reverse }
1511
+ .join("\n")
1394
1512
  end
1395
1513
 
1396
1514
  def print_status(*args, from: nil, **kwargs)
@@ -1399,15 +1517,15 @@ module Squared
1399
1517
  case from
1400
1518
  when :outdated
1401
1519
  out = print_footer("major #{args[0]} / minor #{args[1]} / patch #{args[2]}", right: true).split("\n")
1402
- out[1] = sub_style(out[1], pat: /^( +major )(\d+)(.+)$/, styles: theme[:major], index: 2)
1403
- out[1] = sub_style(out[1], pat: /^(.+)(minor )(\d+)(.+)$/, styles: theme[:active], index: 3)
1520
+ out[1] = sub_style(out[1], **opt_style(theme[:major], /^( +major )(\d+)(.+)$/, 2))
1521
+ out[1] = sub_style(out[1], **opt_style(theme[:active], /^(.+)(minor )(\d+)(.+)$/, 3))
1522
+ out[1] = sub_style(out[1], **opt_style(theme[:current], /^(.+)(patch )(\d+)(.+)$/, 3)) if theme[:current]
1404
1523
  puts out
1405
1524
  when :completed
1406
- if verbose && kwargs[:start]
1407
- msg = sub_style('completed', styles: theme[:active])
1408
- puts log_message(Logger::INFO, *args, msg, subject: kwargs[:subject],
1409
- hint: time_format(time_epoch - kwargs[:start]))
1410
- end
1525
+ return unless verbose && kwargs[:start]
1526
+
1527
+ puts log_message(Logger::INFO, *args, sub_style('completed', styles: theme[:active]),
1528
+ subject: kwargs[:subject], hint: time_format(time_epoch - kwargs[:start]))
1411
1529
  end
1412
1530
  end
1413
1531
 
@@ -1417,7 +1535,7 @@ module Squared
1417
1535
  workspace.format_desc([@desc, action, flag].compact, opts, **kwargs)
1418
1536
  end
1419
1537
 
1420
- def format_banner(cmd, banner: true)
1538
+ def format_banner(cmd, banner: true, hint: nil, strip: nil)
1421
1539
  return unless banner && banner?
1422
1540
 
1423
1541
  if (data = workspace.banner_get(*@ref, group: group))
@@ -1431,11 +1549,14 @@ module Squared
1431
1549
  out = []
1432
1550
  if data.command
1433
1551
  if cmd =~ /\A(?:"((?:[^"]|(?<=\\)")+)"|'((?:[^']|(?<=\\)')+)'|(\S+))( |\z)/
1434
- path = $3 || $2 || $1
1435
- name = stripext path
1436
- cmd = cmd.sub(path, data.command == 0 ? name : name.upcase)
1552
+ arg = $3 || $2 || $1
1553
+ cmd = cmd.sub(arg, data.command == 0 ? arg.stripext : arg.stripext.upcase)
1554
+ end
1555
+ if strip || (strip.nil? && data.order.include?(:path))
1556
+ cmd = cmd.gsub(/(?:#{s = Regexp.escape(File.join(path, ''))}?(?=["'])|#{s})/, '')
1557
+ .gsub(/(?: -[^ ])? (?:""|'')/, '')
1437
1558
  end
1438
- out << cmd
1559
+ out << cmd.subhint(hint)
1439
1560
  end
1440
1561
  data.order.each do |val|
1441
1562
  if val.is_a?(Array)
@@ -1463,7 +1584,7 @@ module Squared
1463
1584
  end
1464
1585
  end
1465
1586
 
1466
- def format_list(items, cmd, type, grep: [], from: nil, each: nil)
1587
+ def format_list(items, cmd, type, grep: [], from: nil)
1467
1588
  reg = grep.map { |val| Regexp.new(val) }
1468
1589
  out = []
1469
1590
  unless items.empty?
@@ -1471,29 +1592,29 @@ module Squared
1471
1592
  items.each_with_index do |val, i|
1472
1593
  next unless matchany?(val.first, reg)
1473
1594
 
1474
- out << ('%*d. %s' % [pad, i.succ, each ? each.call(val) : val.first])
1595
+ out << ('%*d. %s' % [pad, i.succ, block_given? ? yield(val) : val.first])
1475
1596
  end
1476
1597
  end
1477
1598
  sub = [headerstyle]
1478
- if out.empty?
1479
- out = ["No #{type} were found:", '']
1480
- unless grep.empty?
1481
- i = 0
1482
- out.concat(grep.map { |s| "#{i += 1}. #{s}" })
1483
- out << ''
1484
- end
1485
- if from
1486
- out << (from = from.to_s)
1487
- pat = /\A(#{Regexp.escape(from)})(.*)\z/
1488
- end
1489
- else
1490
- pat = /\A(\s*\d+\.)(.+)\z/
1491
- unless grep.empty?
1492
- footer = "#{out.size} found"
1493
- sub << { pat: /\A(\d+)( .+)\z/, styles: theme[:inline] }
1494
- end
1495
- end
1496
- sub << { pat: pat, styles: theme[:active] } if pat
1599
+ pat = if out.empty?
1600
+ out = ["No #{type} were found:", '']
1601
+ unless grep.empty?
1602
+ i = 0
1603
+ out.concat(grep.map { |s| "#{i += 1}. #{s}" })
1604
+ out << ''
1605
+ end
1606
+ if from
1607
+ out << (from = from.to_s)
1608
+ /\A(#{Regexp.escape(from)})(.*)\z/
1609
+ end
1610
+ else
1611
+ unless grep.empty?
1612
+ footer = "#{out.size} found "
1613
+ sub << opt_style(theme[:inline], /\A(\d+)( .+)\z/)
1614
+ end
1615
+ /\A(\s*\d+\.)(.+)\z/
1616
+ end
1617
+ sub << opt_style(theme[:active], pat) if pat
1497
1618
  emphasize(out, title: task_join(name, cmd), border: borderstyle, sub: sub, footer: footer, right: true)
1498
1619
  end
1499
1620
 
@@ -1507,8 +1628,7 @@ module Squared
1507
1628
 
1508
1629
  def append_hash(data, target: @session || [], build: false)
1509
1630
  if build && (type = env('BUILD', suffix: 'TYPE') || ENV['BUILD_TYPE'])
1510
- type = "__#{type}__"
1511
- if (extra = data[type] || data[type.to_sym]).is_a?(Hash)
1631
+ if (extra = data[type = "__#{type}__"] || data[type.to_sym]).is_a?(Hash)
1512
1632
  data = data.merge(extra)
1513
1633
  else
1514
1634
  extra = nil
@@ -1529,30 +1649,24 @@ module Squared
1529
1649
  when FalseClass
1530
1650
  target << shell_option(key).sub(/^--(?!no-)/, '--no-')
1531
1651
  else
1532
- target << shell_option(key, val.is_a?(String) ? val : nil)
1652
+ target << shell_option(key, (val if val.is_a?(String)))
1533
1653
  end
1534
1654
  end
1535
1655
  target
1536
1656
  end
1537
1657
 
1538
1658
  def append_any(val, target: @session, build: false, delim: false)
1539
- return unless val
1540
-
1541
1659
  if delim && !target.include?('--')
1542
1660
  target << '--'
1543
1661
  else
1544
1662
  delim = false
1545
1663
  end
1546
- val = shell_split(val) if val.is_a?(String)
1664
+ val = shell_split val if val.is_a?(String)
1547
1665
  case val
1548
1666
  when Hash
1549
1667
  append_hash(val, target: target, build: build)
1550
1668
  when Enumerable
1551
- if target.is_a?(Array)
1552
- target.concat(val.to_a)
1553
- else
1554
- target.merge(val.to_a)
1555
- end
1669
+ merge_list target, val
1556
1670
  else
1557
1671
  target.delete('--') if delim
1558
1672
  nil
@@ -1573,7 +1687,7 @@ module Squared
1573
1687
  next unless (val = option(opt, **kwargs))
1574
1688
 
1575
1689
  return target << if flag
1576
- shell_option(opt, equals ? val : nil, quote: quote, escape: escape, force: force)
1690
+ shell_option(opt, (val if equals), quote: quote, escape: escape, force: force)
1577
1691
  else
1578
1692
  shell_quote val
1579
1693
  end
@@ -1593,9 +1707,11 @@ module Squared
1593
1707
  flag = "no-#{flag}"
1594
1708
  val = nil
1595
1709
  end
1596
- ret << shell_option(flag, equals ? val : nil, escape: escape, quote: quote, force: force)
1710
+ ret << shell_option(flag, (val if equals), escape: escape, quote: quote, force: force)
1597
1711
  end
1598
- ret.each { |val| target << val } unless ret.empty?
1712
+ next if ret.empty?
1713
+
1714
+ merge_list target, ret
1599
1715
  end
1600
1716
  end
1601
1717
 
@@ -1603,6 +1719,24 @@ module Squared
1603
1719
  target << '--no-color' if !ARG[:COLOR] || stdin? || option('color', target: target, equals: '0')
1604
1720
  end
1605
1721
 
1722
+ def append_keys(base, data, *keys)
1723
+ out = {}
1724
+ keys.each do |key|
1725
+ next unless data.key?(key)
1726
+
1727
+ out[key] = case (val = data[key])
1728
+ when Array
1729
+ base.fetch(key, []) + val
1730
+ when Hash
1731
+ base.fetch(key, {}).update(val)
1732
+ else
1733
+ val
1734
+ end
1735
+ end
1736
+ base.update(data)
1737
+ .update(out)
1738
+ end
1739
+
1606
1740
  def merge_opts(base, data)
1607
1741
  case data
1608
1742
  when String
@@ -1643,20 +1777,31 @@ module Squared
1643
1777
  end
1644
1778
  end
1645
1779
 
1646
- def collect_hash(data, pass: [])
1647
- [].tap do |ret|
1648
- data.each { |key, val| ret.concat(val) unless pass.include?(key) }
1780
+ def merge_list(base, data)
1781
+ data = Array(data)
1782
+ case base
1783
+ when Array
1784
+ base.concat(data)
1785
+ when Set
1786
+ base.merge(data)
1787
+ else
1788
+ Array(base).concat(data)
1649
1789
  end
1650
1790
  end
1651
1791
 
1792
+ def collect_hash(data, pass: [])
1793
+ ret = []
1794
+ data.each { |key, val| ret.concat(val) unless pass.include?(key) }
1795
+ ret
1796
+ end
1797
+
1652
1798
  def parse_json(val, kind: Hash, hint: nil)
1653
1799
  ret = JSON.parse(val)
1654
- raise_error("invalid JSON #{kind.name}", val, hint: hint) if kind && !ret.is_a?(kind)
1800
+ raise_error 'invalid JSON'.subhint(kind.name), val, hint: hint if kind && !ret.is_a?(kind)
1801
+ ret
1655
1802
  rescue StandardError => e
1656
1803
  log&.warn e
1657
1804
  print_error(e, subject: name)
1658
- else
1659
- ret
1660
1805
  end
1661
1806
 
1662
1807
  def param_guard(action, flag, args:, key: nil, pat: nil, values: nil)
@@ -1668,12 +1813,16 @@ module Squared
1668
1813
  raise_error(action, "#{flag}[#{key}]", hint: val.nil? ? 'missing' : 'invalid')
1669
1814
  elsif args.is_a?(Array) && args.empty?
1670
1815
  @session = nil
1671
- raise_error(action, "#{flag}+", hint: 'empty')
1816
+ raise_error action, "#{flag}+", hint: 'empty'
1672
1817
  end
1673
1818
  args
1674
1819
  end
1675
1820
 
1676
- def confirm_outdated(pkg, ver, rev, cur = nil, lock: false, col1: 0)
1821
+ def confirm_basic(msg, target, default = 'Y', style: :inline, **kwargs)
1822
+ confirm("#{msg} [#{sub_style(target.to_s, styles: theme[style])}]", default, **kwargs)
1823
+ end
1824
+
1825
+ def confirm_outdated(pkg, ver, rev, cur = nil, lock: false, col1: 0, **kwargs)
1677
1826
  a = sub_style(case rev
1678
1827
  when 1
1679
1828
  'MAJOR'
@@ -1685,16 +1834,17 @@ module Squared
1685
1834
  b = sub_style(pkg.ljust(col1), styles: theme[:inline])
1686
1835
  c = lock ? sub_style((cur || 'locked').rjust(7), styles: color(:red)) : cur&.rjust(7)
1687
1836
  d = rev == 1 || lock ? 'N' : 'Y'
1688
- confirm "#{a}: #{b}#{c} #{sub_style(ver.rjust(col1 > 0 ? 10 : 0), styles: theme[:inline])} ", d
1837
+ confirm("#{a}: #{b}#{c} #{sub_style(ver.rjust(col1 > 0 ? 10 : 0), styles: theme[:inline])} ", d, **kwargs)
1689
1838
  end
1690
1839
 
1691
1840
  def choice_index(msg, list, values: nil, accept: nil, series: false, trim: nil, column: nil, multiple: false,
1692
1841
  force: true, **kwargs)
1693
- puts if !series && !printfirst?
1694
- msg = "#{msg} (optional)" unless force
1695
- unless (ret = choice(msg, list, multiple: multiple, force: force, **kwargs)) && !ret.empty?
1842
+ puts unless series || printfirst?
1843
+ ret = choice(msg, list, multiple: multiple, force: force, **kwargs).tap do |val|
1844
+ next unless val.to_s.empty?
1845
+
1696
1846
  exit 1 if force
1697
- return
1847
+ return nil
1698
1848
  end
1699
1849
  ret = multiple ? ret.map! { |val| val.sub(trim, '') } : ret.sub(trim, '') if trim
1700
1850
  if column
@@ -1708,7 +1858,7 @@ module Squared
1708
1858
  ret = Array(ret) if accept.any? { |val| val[1] == true }
1709
1859
  loop do
1710
1860
  item = accept.first
1711
- c = confirm("#{item[0]}#{hint ? " [#{hint}]" : ''}", item[2] ? 'Y' : 'N', timeout: 60)
1861
+ c = confirm("#{item[0]}#{hint ? " [#{hint}]" : ''}", item[2] ? 'Y' : 'N')
1712
1862
  if item[1] == true
1713
1863
  ret << c
1714
1864
  elsif !c
@@ -1729,25 +1879,29 @@ module Squared
1729
1879
  force = false
1730
1880
  end
1731
1881
  val = readline(val, force: force)
1732
- ret << (val.empty? ? nil : val)
1882
+ ret << (val unless val.empty?)
1733
1883
  end
1734
1884
  end
1735
1885
  printsucc unless series
1736
1886
  ret
1737
1887
  end
1738
1888
 
1889
+ def accept_b(val, yes = false)
1890
+ [val, true, yes]
1891
+ end
1892
+
1893
+ def accept_y(val, bool = false)
1894
+ [val, bool, true]
1895
+ end
1896
+
1739
1897
  def command_args(args, min: 0, force: false, **kwargs)
1740
1898
  return if args.size > min || option('i', 'interactive', **kwargs, equals: '0')
1741
1899
 
1742
1900
  readline('Enter arguments', force: force)
1743
1901
  end
1744
1902
 
1745
- def block_args(val = nil, &blk)
1746
- if (ret = instance_eval(&blk)).nil?
1747
- val
1748
- else
1749
- Array(ret)
1750
- end
1903
+ def block_args(fallback = nil, &blk)
1904
+ (ret = instance_eval(&blk)).nil? ? fallback : Array(ret)
1751
1905
  end
1752
1906
 
1753
1907
  def runenv
@@ -1780,12 +1934,10 @@ module Squared
1780
1934
 
1781
1935
  def matchmap(list, prefix = nil)
1782
1936
  list.map do |val|
1783
- if val.is_a?(Regexp)
1784
- val
1785
- else
1786
- val = ".*#{val}" if prefix && !val.sub!(/\A(\^|\\A)/, '')
1787
- Regexp.new("#{prefix}#{val == '*' ? '.+' : val}")
1788
- end
1937
+ next val if val.is_a?(Regexp)
1938
+
1939
+ val = ".*#{val}" if prefix && !val.sub!(/\A(\^|\\A)/, '')
1940
+ Regexp.new("#{prefix}#{val == '*' ? '.+' : val}")
1789
1941
  end
1790
1942
  end
1791
1943
 
@@ -1802,15 +1954,14 @@ module Squared
1802
1954
  end
1803
1955
 
1804
1956
  def semscan(val, fill: true)
1805
- val.scan(SEM_VER).first.yield_self { |data| fill ? semver(data) : data }
1957
+ ret = val.scan(SEM_VER).first
1958
+ fill ? semver(ret) : ret
1806
1959
  end
1807
1960
 
1808
1961
  def semcmp(val, other)
1809
1962
  return 0 if val == other
1810
-
1811
- a, b = [val, other].map! { |ver| ver.scan(SEM_VER) }
1812
- return -1 if b.empty?
1813
- return 1 if a.empty?
1963
+ return -1 if (b = other.scan(SEM_VER)).empty?
1964
+ return 1 if (a = val.scan(SEM_VER)).empty?
1814
1965
 
1815
1966
  a, b = [a.first, b.first].map! do |c|
1816
1967
  d = begin
@@ -1820,14 +1971,38 @@ module Squared
1820
1971
  end
1821
1972
  [c[0], c[2], c[4] || '0', d]
1822
1973
  end
1823
- a.each_with_index do |c, index|
1824
- next if c == (d = b[index])
1974
+ a.each_with_index do |c, i|
1975
+ next if c == (d = b[i])
1825
1976
 
1826
1977
  return c.to_i < d.to_i ? 1 : -1
1827
1978
  end
1828
1979
  0
1829
1980
  end
1830
1981
 
1982
+ def sembump(val, flag = :patch, join: true)
1983
+ ret = semscan(val, fill: false)
1984
+ case flag
1985
+ when :major
1986
+ ret[2] = if ret[0] != '0' || ret[2].nil?
1987
+ ret[0] = ret[0].succ
1988
+ '0'
1989
+ else
1990
+ ret[2].succ
1991
+ end
1992
+ ret[4] = '0'
1993
+ when :minor
1994
+ if ret[0] == '0'
1995
+ ret[4] &&= ret[4].succ
1996
+ else
1997
+ ret[2] = ret[2].succ
1998
+ ret[4] &&= '0'
1999
+ end
2000
+ when :patch
2001
+ ret[4] &&= ret[4].succ
2002
+ end
2003
+ join ? ret.join : ret
2004
+ end
2005
+
1831
2006
  def semgte?(val, other)
1832
2007
  semcmp(val, other) != 1
1833
2008
  end
@@ -1837,7 +2012,7 @@ module Squared
1837
2012
  end
1838
2013
 
1839
2014
  def indexerror(val, list = nil)
1840
- raise_error("requested index #{val}", hint: list && "of #{list.size}")
2015
+ raise_error IndexError, "requested index #{val}", hint: list && "of #{list.size}"
1841
2016
  end
1842
2017
 
1843
2018
  def indexchar
@@ -1856,10 +2031,6 @@ module Squared
1856
2031
  val.compact.flat_map { |s| color(s) }
1857
2032
  end
1858
2033
 
1859
- def epochtime
1860
- Time.now.strftime('%s%L').to_i
1861
- end
1862
-
1863
2034
  def verbosetype
1864
2035
  case verbose
1865
2036
  when TrueClass
@@ -1891,7 +2062,7 @@ module Squared
1891
2062
  end
1892
2063
  end
1893
2064
 
1894
- def on_error(err, from, exception: self.exception, pass: false, dryrun: false)
2065
+ def on_error(err, from, pass: false, exception: self.exception, dryrun: false)
1895
2066
  log&.error err
1896
2067
  unless dryrun
1897
2068
  ret = on :error, from, err
@@ -1900,20 +2071,17 @@ module Squared
1900
2071
  print_error(err, pass: pass) unless ret
1901
2072
  end
1902
2073
 
1903
- def pwd_set(pass: false, dryrun: false, from: nil)
2074
+ def pwd_set(pass: false, exception: self.exception, dryrun: false, from: nil)
1904
2075
  pwd = Dir.pwd
1905
2076
  return yield if (path.to_s == pwd || pass == true) && (workspace.mri? || !workspace.windows?)
1906
2077
 
1907
2078
  Dir.chdir path
1908
- ret = yield
1909
- Dir.chdir pwd
2079
+ yield.tap { Dir.chdir pwd }
1910
2080
  rescue StandardError => e
1911
- on_error(e, from, dryrun: dryrun)
1912
- else
1913
- ret
2081
+ on_error(e, from, exception: exception, dryrun: dryrun)
1914
2082
  end
1915
2083
 
1916
- def run_set(cmd, val = nil, opts: nil, **)
2084
+ def run_set(cmd, val = nil, opts: nil, global: false, **)
1917
2085
  noopt = @output[1] == false && !@output[0].nil?
1918
2086
  noenv = @output[2] == false
1919
2087
  parse = lambda do |data|
@@ -1932,6 +2100,7 @@ module Squared
1932
2100
  ret[2] = data[:env] unless dise
1933
2101
  ret
1934
2102
  end
2103
+ self.global = global
1935
2104
  case cmd
1936
2105
  when Array
1937
2106
  @output = if cmd.all? { |data| data.is_a?(Hash) }
@@ -1963,11 +2132,12 @@ module Squared
1963
2132
  end
1964
2133
  end
1965
2134
 
1966
- def script_set(cmd, prod: nil, args: nil, **)
2135
+ def script_set(cmd, prod: nil, args: nil, global: false, **)
1967
2136
  return if @output[1] == false && @output[0].nil?
1968
2137
 
2138
+ self.global = global
1969
2139
  @output[0] = nil
1970
- @output[1] = if @global && cmd.is_a?(Array)
2140
+ @output[1] = if self.global && cmd.is_a?(Array)
1971
2141
  cmd[prod == true ? 1 : 0]
1972
2142
  else
1973
2143
  cmd
@@ -2012,7 +2182,7 @@ module Squared
2012
2182
 
2013
2183
  def asdf_set(val)
2014
2184
  @asdf = if @@asdf && val
2015
- dir = @@asdf[0].join('installs', val)
2185
+ dir = @@asdf.path.join('installs', val)
2016
2186
  [val, dir] if dir.exist? && !dir.empty?
2017
2187
  end
2018
2188
  end
@@ -2028,9 +2198,12 @@ module Squared
2028
2198
  end
2029
2199
 
2030
2200
  def dependfile_set(list)
2031
- @dependindex = list.index { |file| basepath(file).exist? }.tap do |index|
2032
- @dependfile = basepath(list[index || 0])
2033
- end
2201
+ @dependindex = if @dependname
2202
+ @dependfile = basepath @dependname
2203
+ list.index(@dependname)
2204
+ else
2205
+ list.index { |file| exist?(file) }.tap { |i: 0| @dependfile = basepath(list[i]) }
2206
+ end
2034
2207
  end
2035
2208
 
2036
2209
  def as_get(val, from)
@@ -2072,12 +2245,10 @@ module Squared
2072
2245
  end
2073
2246
 
2074
2247
  def checkdir?(val)
2075
- if val.directory? && !val.empty?
2076
- true
2077
- else
2078
- log&.warn "directory \"#{val}\" (#{val.empty? ? 'empty' : 'not found'})"
2079
- false
2080
- end
2248
+ return true if val.directory? && !val.empty?
2249
+
2250
+ log&.warn "directory \"#{val}\"".subhint(val.directory? ? 'empty' : 'missing')
2251
+ false
2081
2252
  end
2082
2253
 
2083
2254
  def semmajor?(cur, want)
@@ -2117,14 +2288,24 @@ module Squared
2117
2288
  return true if val || from_sync?(ac = workspace.task_name(action))
2118
2289
  return val if group && !(val = from_sync?(ac, group)).nil?
2119
2290
  return val if (base = workspace.find_base(self)) && !(val = from_sync?(ac, base.ref)).nil?
2120
- return false if workspace.series.chain?(val = task_join(name, action))
2121
- return true if task_invoked?(val) && (!task_invoked?(ac) || !workspace.task_defined?(ac, 'sync'))
2291
+ return false if workspace.series.chain?(key = task_join(name, action))
2292
+ return true if task_invoked?(key) && (!task_invoked?(ac) || !workspace.task_defined?(ac, 'sync'))
2122
2293
 
2123
- workspace.series.name_get(action).yield_self { |name| name != action && invoked_sync?(name) }
2294
+ ret = workspace.series.name_get(action)
2295
+ ret != action && invoked_sync?(ret)
2124
2296
  end
2125
2297
 
2126
- def success?(ret, display = true)
2127
- ret == true && display && stdout? && banner?
2298
+ def success?(run, *cond)
2299
+ case run
2300
+ when TrueClass
2301
+ true
2302
+ when FalseClass
2303
+ false
2304
+ else
2305
+ $?.success?
2306
+ end.tap do |ret|
2307
+ print_success if ret && stdout? && banner? && cond.none? { |val| val == false }
2308
+ end
2128
2309
  end
2129
2310
 
2130
2311
  def banner?
@@ -2151,12 +2332,13 @@ module Squared
2151
2332
  workspace.warning
2152
2333
  end
2153
2334
 
2154
- def has_value?(data, other)
2155
- case data
2335
+ def has_value?(target, *args)
2336
+ args = args.first if args.size == 1 && args.first.is_a?(Enumerable)
2337
+ case target
2156
2338
  when Hash
2157
- other.is_a?(Enumerable) ? other.any? { |obj| data.value?(obj) } : data.value?(other)
2339
+ args.is_a?(Enumerable) ? args.any? { |obj| target.value?(obj) } : target.value?(args)
2158
2340
  when Enumerable
2159
- other.is_a?(Enumerable) ? other.any? { |obj| data.include?(obj) } : data.include?(other)
2341
+ args.is_a?(Enumerable) ? args.any? { |obj| target.include?(obj) } : target.include?(args)
2160
2342
  else
2161
2343
  false
2162
2344
  end
@@ -2170,28 +2352,16 @@ module Squared
2170
2352
  BLK_SET
2171
2353
  end
2172
2354
 
2173
- def hashobj
2174
- Workspace::Support.hashobj
2175
- end
2176
-
2177
- def hashlist
2178
- Workspace::Support.hashlist
2179
- end
2180
-
2181
- def hashdup
2182
- Workspace::Support.hashdup
2183
- end
2184
-
2185
2355
  def borderstyle
2186
2356
  workspace.banner_get(*@ref, group: group)&.border || theme[:border]
2187
2357
  end
2188
2358
 
2189
2359
  def headerstyle
2190
- { pat: /^(\S+)(\s+)$/, styles: theme[:header] }
2360
+ opt_style theme[:header], /^(\S+)(\s+)$/
2191
2361
  end
2192
2362
 
2193
2363
  def scriptargs
2194
- { target: script? ? @output[1] : @output[0], ref: ref, group: group, global: @global }
2364
+ { target: script? ? @output[1] : @output[0], script: script?, ref: ref, group: group, global: @global }
2195
2365
  end
2196
2366
  end
2197
2367