squared 0.4.5 → 0.4.7

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d23d69be4457a4dfa43c961b405d27f834b915aa7c370b2733d2438dc5792b55
4
- data.tar.gz: d070c6ee2417ce81709a5fe6ea881e152d7839b6ef4030f8ab7539b2d7552f8f
3
+ metadata.gz: 0cf1642a52eeb080a0aa4dadb9c7fb5a3060612904bd06a8161ab18b4e333a9a
4
+ data.tar.gz: 7bad82be155782b37036cc2d447395a37585ed33b4d37c5281e3ccd3f902ea33
5
5
  SHA512:
6
- metadata.gz: 5c4f6c187e2b5dd2f230e972919f48ed4badd124c7b73df86f28ec77c87027898480c3bf02044a5e3c986334214c82ec1eaeb15b52d8424eeafc720086652ee3
7
- data.tar.gz: 1ec9ca0ff06a048e13743759b82c3e070be6a23efcc2fce8b7d5cad82e49a65597538e78780b8fe88937a07cd055f26f7c54c4a2554926d04183707c0b0e79fe
6
+ metadata.gz: 77fda3077ec4c929fad3003d7255d5aeb7b0f7fa2d14a717678772572a3a972214247aabc6911d8e717103b855ae1109c81c118ca5564f46fd4e79ecfc62cf6a
7
+ data.tar.gz: 29e84ae67dc2aad4ac61c99407443d65210f96af60649784c9264a75c686473b919328a9ea6d97b6bda6e4fd61aeaa97df4e196bdf87f6e32819dfea1306c76a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,81 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.7] - 2025-04-17
4
+
5
+ ### Added
6
+
7
+ - Project support class OptionPartition was created.
8
+ - Git command tag action sign was implemented.
9
+ - Gem command uninstall was implemented.
10
+
11
+ ### Changed
12
+
13
+ - DateTime instances was replaced with Time.
14
+ - Utils method time_offset was renamed time_since.
15
+ - Ruby gem command build will search project for gemspec.
16
+
17
+ ### Fixed
18
+
19
+ - Project task archive was not enabled.
20
+
21
+ ## [0.3.9] - 2025-04-17
22
+
23
+ ### Fixed
24
+
25
+ - Project option parser did not separate custom values.
26
+
27
+ ## [0.2.9] - 2025-04-17
28
+
29
+ ### Changed
30
+
31
+ - Project log file naming supports more date formats.
32
+
33
+ ### Fixed
34
+
35
+ - Environment options did not always pass session object.
36
+ - Git command pull actions used unknown flags.
37
+ - Workspace describe did not merge multiple invocations.
38
+
39
+ ## [0.1.6] - 2025-04-17
40
+
41
+ ### Fixed
42
+
43
+ - User-defined program paths were not reduced to bare name.
44
+ - Project path validation did not include separator.
45
+
46
+ ## [0.4.6] - 2025-04-12
47
+
48
+ ### Added
49
+
50
+ - Python command venv action run was implemented.
51
+ - Program paths can be defined per session using ENV.
52
+ - Python style verbose is supported.
53
+
54
+ ### Changed
55
+
56
+ - Python dependtype lists setup.cfg before pyproject.toml.
57
+ - Pip install is editable by default.
58
+
59
+ ### Fixed
60
+
61
+ - Node copy task did not reset revbuild target flags.
62
+ - Python venv init did not locate user-defined program paths.
63
+ - Node update task did not reset revbuild target flags.
64
+
65
+ ## [0.3.8] - 2025-04-12
66
+
67
+ ### Fixed
68
+
69
+ - Project class did not parse verbose string values.
70
+
71
+ ## [0.2.8] - 2025-04-12
72
+
73
+ ### Fixed
74
+
75
+ - User-defined program paths were not sanitized for ENV.
76
+ - Project clean task used incompatible rmtree flag.
77
+ - Git branch unset-upstream used undefined variable.
78
+
3
79
  ## [0.4.5] - 2025-04-09
4
80
 
5
81
  ### Fixed
@@ -457,12 +533,16 @@
457
533
 
458
534
  - Changelog was created.
459
535
 
536
+ [0.4.7]: https://github.com/anpham6/squared/releases/tag/v0.4.7-ruby
537
+ [0.4.6]: https://github.com/anpham6/squared/releases/tag/v0.4.6-ruby
460
538
  [0.4.5]: https://github.com/anpham6/squared/releases/tag/v0.4.5-ruby
461
539
  [0.4.4]: https://github.com/anpham6/squared/releases/tag/v0.4.4-ruby
462
540
  [0.4.3]: https://github.com/anpham6/squared/releases/tag/v0.4.3-ruby
463
541
  [0.4.2]: https://github.com/anpham6/squared/releases/tag/v0.4.2-ruby
464
542
  [0.4.1]: https://github.com/anpham6/squared/releases/tag/v0.4.1-ruby
465
543
  [0.4.0]: https://github.com/anpham6/squared/releases/tag/v0.4.0-ruby
544
+ [0.3.9]: https://github.com/anpham6/squared/releases/tag/v0.3.9-ruby
545
+ [0.3.8]: https://github.com/anpham6/squared/releases/tag/v0.3.8-ruby
466
546
  [0.3.7]: https://github.com/anpham6/squared/releases/tag/v0.3.7-ruby
467
547
  [0.3.6]: https://github.com/anpham6/squared/releases/tag/v0.3.6-ruby
468
548
  [0.3.5]: https://github.com/anpham6/squared/releases/tag/v0.3.5-ruby
@@ -471,6 +551,8 @@
471
551
  [0.3.2]: https://github.com/anpham6/squared/releases/tag/v0.3.2-ruby
472
552
  [0.3.1]: https://github.com/anpham6/squared/releases/tag/v0.3.1-ruby
473
553
  [0.3.0]: https://github.com/anpham6/squared/releases/tag/v0.3.0-ruby
554
+ [0.2.9]: https://github.com/anpham6/squared/releases/tag/v0.2.9-ruby
555
+ [0.2.8]: https://github.com/anpham6/squared/releases/tag/v0.2.8-ruby
474
556
  [0.2.7]: https://github.com/anpham6/squared/releases/tag/v0.2.7-ruby
475
557
  [0.2.6]: https://github.com/anpham6/squared/releases/tag/v0.2.6-ruby
476
558
  [0.2.5]: https://github.com/anpham6/squared/releases/tag/v0.2.5-ruby
@@ -479,6 +561,7 @@
479
561
  [0.2.2]: https://github.com/anpham6/squared/releases/tag/v0.2.2-ruby
480
562
  [0.2.1]: https://github.com/anpham6/squared/releases/tag/v0.2.1-ruby
481
563
  [0.2.0]: https://github.com/anpham6/squared/releases/tag/v0.2.0-ruby
564
+ [0.1.6]: https://github.com/anpham6/squared/releases/tag/v0.1.6-ruby
482
565
  [0.1.5]: https://github.com/anpham6/squared/releases/tag/v0.1.5-ruby
483
566
  [0.1.4]: https://github.com/anpham6/squared/releases/tag/v0.1.4-ruby
484
567
  [0.1.3]: https://github.com/anpham6/squared/releases/tag/v0.1.3-ruby
data/README.ruby.md CHANGED
@@ -99,8 +99,8 @@ Workspace::Application
99
99
  # OR
100
100
  add(["publish/sqd-cli", "publish/sqd-serve"], true, exclude: [:base]) # rake squared:sqd-serve:build
101
101
  end
102
- .add("squared/sqd", exclude: :git, pass: [:node, "checkout", "bump"]) do # Skip initialize(:node) + squared:checkout:* + squared:bump:*
103
- variable_set :script, "build:sqd" # Override detection
102
+ .add("squared/sqd", exclude: :git, pass: [:node, "checkout", "bump"]) do # Skip initialize(:node) + squared:checkout:* + squared:bump:*
103
+ variable_set :script, "build:sqd" # Override detection
104
104
  variable_set :depend, false
105
105
  variable_set :clean, ["build/sqd/"]
106
106
  end
@@ -141,7 +141,7 @@ Workspace::Application
141
141
  run: "rake compile" # rake rb:pathname:build
142
142
  }
143
143
  })
144
- .with(:python) do # ref=Symbol | group=String
144
+ .with(:python, editable: false) do # ref=Symbol | group=String
145
145
  banner([:name, ": ", :version], "path") # chrome-docs: 0.1.0 | /workspaces/chrome-docs
146
146
  doc("make html") # rake rb:doc:python
147
147
  run(false) # rake rb:build:python (disabled)
@@ -443,7 +443,7 @@ Most project classes will inherit from `Git` which enables these tasks:
443
443
  | rev | rev | commit branch output parseopt |
444
444
  | show | show | format oneline |
445
445
  | stash | stash | push pop apply drop list |
446
- | tag | tag | add delete list |
446
+ | tag | tag | add sign delete list |
447
447
 
448
448
  You can disable all of them at once using the `exclude` property.
449
449
 
@@ -466,12 +466,12 @@ Workspace::Application
466
466
 
467
467
  ### Path
468
468
 
469
- All project executable programs can have their binary path set to a non-global alias.
469
+ All project binary programs can have their executable path set to a non-global alias.
470
470
 
471
471
  ```ruby
472
472
  Common::PATH.merge!({
473
- GIT: "/usr/bin/git",
474
- TAR: "/opt/archivers/tar",
473
+ GIT: "/usr/bin/git", # PATH_GIT=/usr/bin/git
474
+ TAR: "/opt/archivers/tar", # PATH_TAR=/opt/archivers/tar
475
475
  UNZIP: "/opt/archivers/unzip",
476
476
  GEM: "~/.rvm/gems/ruby-3.4.0/bin/gem",
477
477
  BUNDLE: "~/.rvm/gems/ruby-3.4.0/bin/bundle",
@@ -483,41 +483,47 @@ Common::PATH.merge!({
483
483
 
484
484
  ### Build
485
485
 
486
- ```sh
486
+ ```ruby
487
487
  Workspace::Application
488
488
  .new
489
489
  .add("squared", run: "gcc a.c -o a.o", opts: { __debug__: { g: true, O2: true, c: nil }, c: true, j: 4 }) # gcc a.c -o a.o -c -j4
490
+ ```
490
491
 
491
- BUILD_TYPE # global
492
+ ```sh
493
+ BUILD_TYPE # global
494
+ ${PROG}_COLOR=0 # --no-color (e.g. GIT_COLOR)
492
495
 
493
496
  # :env :run :args :opts :type
494
497
  # LD_LIBRARY_PATH="path/to/lib" CFLAGS="-Wall" gcc a.c -o a.o -g -O2
495
- BUILD_${NAME} # gcc a.c -o a.o
496
- BUILD_${NAME}_OPTS # -g
497
- BUILD_${NAME}_ENV # {"LD_LIBRARY_PATH":"path/to/lib","CFLAGS":"-Wall"} (hash/json)
498
- BUILD_${NAME}_TYPE # debug
498
+ BUILD_${NAME} # gcc a.c -o a.o
499
+ BUILD_${NAME}_OPTS # -g
500
+ BUILD_${NAME}_ENV # {"LD_LIBRARY_PATH":"path/to/lib","CFLAGS":"-Wall"} (hash/json)
501
+ BUILD_${NAME}_TYPE # debug
499
502
 
500
503
  # :env :script :opts :args
501
504
  # NODE_ENV="production" NO_COLOR="1" npm run build:dev --loglevel=error --workspaces=false -- --quiet
502
- BUILD_${NAME} # build:dev
503
- BUILD_${NAME}_OPTS # --loglevel=error --workspaces=false
504
- BUILD_${NAME}_ENV # {"NODE_ENV":"production","NO_COLOR":"1"} (hash/json)
505
- BUILD_${NAME}_DEV # pattern,0,1 (:dev)
506
- BUILD_${NAME}_PROD # pattern,0,1 (:prod)
507
- ${REF}_${NAME}_OPTS # --quiet (e.g. NODE_SQUARED_OPTS)
508
-
509
- BUILD_${NAME}=0 # skip project
510
- BUILD_${NAME}_VERSION=0.1.0 # publish + detection
511
-
512
- BANNER=0 # hide banner
513
- BANNER_${NAME}=0 #
505
+ BUILD_${NAME} # build:dev
506
+ BUILD_${NAME}_OPTS # --loglevel=error --workspaces=false
507
+ BUILD_${NAME}_ENV # {"NODE_ENV":"production","NO_COLOR":"1"} (hash/json)
508
+ BUILD_${NAME}_DEV # pattern,0,1 (:dev)
509
+ BUILD_${NAME}_PROD # pattern,0,1 (:prod)
510
+ ${REF}_${NAME}_OPTS # --quiet (e.g. NODE_SQUARED_OPTS)
511
+
512
+ BUILD_${NAME}=0 # skip project
513
+ BUILD_${NAME}_VERSION=0.1.0 # publish + detection
514
+
515
+ BANNER=0 # hide banner
516
+ BANNER_${NAME}=0 #
517
+
518
+ REVBUILD_FORCE=1 # Rebuild all targets
519
+ REVBUILD_FORCE_${NAME}=1 # Rebuild project
514
520
  ```
515
521
 
516
522
  ### Graph
517
523
 
518
524
  ```sh
519
- GRAPH_${NAME} # depend,build => squared:depend + squared:build
520
- GRAPH_${NAME}_PASS # -emc,pir,express => pir + express
525
+ GRAPH_${NAME} # depend,build => squared:depend + squared:build
526
+ GRAPH_${NAME}_PASS # -emc,pir,express => pir + express
521
527
  ```
522
528
 
523
529
  ### Logger
@@ -525,22 +531,22 @@ GRAPH_${NAME}_PASS # -emc,pir,express => pir + express
525
531
  These global options also can target the project suffix `${NAME}`. (e.g. LOG_FILE_EMC)
526
532
 
527
533
  ```sh
528
- LOG_FILE # %Y-%m-%d.log
534
+ LOG_FILE # %Y-%m-%d.log
529
535
  # OR
530
- LOG_AUTO # year,y,month,m,day,d,1
536
+ LOG_AUTO # year,y,month,m,day,d,1
531
537
  # Optional
532
- LOG_DIR # exist?
533
- LOG_LEVEL # See gem "logger"
534
- LOG_COLUMNS # terminal width (default: 80)
538
+ LOG_DIR # exist?
539
+ LOG_LEVEL # See gem "logger"
540
+ LOG_COLUMNS # terminal width (default: 80)
535
541
  ```
536
542
 
537
543
  ### Git
538
544
 
539
545
  ```sh
540
- GIT_OPTIONS=q,strategy=ort # all
541
- GIT_OPTIONS_${NAME}=v,ff-only # project only
542
- GIT_AUTOSTASH=1 # rebase (all)
543
- GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
546
+ GIT_OPTIONS=q,strategy=ort # all
547
+ GIT_OPTIONS_${NAME}=v,ff # project only
548
+ GIT_AUTOSTASH=1 # rebase (all)
549
+ GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
544
550
  ```
545
551
 
546
552
  | Command | Flag | ENV |
@@ -564,7 +570,8 @@ GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
564
570
  | checkout | branch | DETACH TRACK=s |
565
571
  | checkout | global path | HEAD=s PATHSPEC=s |
566
572
  | checkout | * | FORCE MERGE |
567
- | tag | add | SIGN HEAD=s |
573
+ | tag | add | SIGN FORCE HEAD=s |
574
+ | tag | sign | FORCE HEAD=s |
568
575
  | log | * | PATHSPEC=s |
569
576
  | diff | -between -contain | MERGE_BASE |
570
577
  | diff | head branch | INDEX=n |
@@ -12,7 +12,7 @@ module Squared
12
12
  super[/[^:]+\z/, 0]
13
13
  end
14
14
 
15
- def_delegators :@data, :+, :each, :each_with_index, :entries, :to_a, :include?
15
+ def_delegators :@data, :+, :each, :each_with_index, :entries, :merge, :to_a, :include?
16
16
 
17
17
  def initialize(data = [])
18
18
  @data = Set.new(data)
@@ -74,10 +74,7 @@ module Squared
74
74
  def temp(*args, &blk)
75
75
  args.compact!
76
76
  ret = pass(&blk)
77
- unless args.empty?
78
- ret += args
79
- ret = Set.new(ret).to_a
80
- end
77
+ ret = Set.new(ret.concat(args)).to_a unless args.empty?
81
78
  ret.join(@delim)
82
79
  end
83
80
 
@@ -255,7 +255,7 @@ module Squared
255
255
  end
256
256
  out << draw.(b2, b3)
257
257
  if title
258
- out += title.map { |t| pr.(t) }
258
+ out.concat(title.map { |t| pr.(t) })
259
259
  out << draw.(b6, b7)
260
260
  end
261
261
  lines.each { |line| out << pr.(line) }
@@ -268,7 +268,7 @@ module Squared
268
268
  s
269
269
  end
270
270
  end
271
- out += footer
271
+ out.concat(footer)
272
272
  end
273
273
  if block_given?
274
274
  yield out
@@ -291,6 +291,10 @@ module Squared
291
291
  val.gsub(/\x1B\[(\d+;?)+m/, '')
292
292
  end
293
293
 
294
+ def stripext(val)
295
+ File.basename(val, File.extname(val))
296
+ end
297
+
294
298
  def raise_error(*args, hint: nil, kind: ArgumentError)
295
299
  raise kind, message(*args, hint: hint, empty: true), caller_locations(1).map(&:to_s)
296
300
  end
@@ -13,7 +13,7 @@ module Squared
13
13
  return val if !r[3] || (!r[5] && r[6].match?(/\s/))
14
14
 
15
15
  combine = lambda do |opt|
16
- if r[2] =~ /^(["'])(.+)\1$/
16
+ if r[2] =~ /\A(["'])(.+)\1\z/
17
17
  double = $1 == '"'
18
18
  r[2] = $2
19
19
  override = true
@@ -36,7 +36,7 @@ module Squared
36
36
  def shell_quote(val, option: true, force: true, double: false, override: false)
37
37
  val = val.to_s
38
38
  return val if !force && !val.include?(' ')
39
- return val if option && val.match?(/(?:^|\S=|[^=]\s+|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/m)
39
+ return val if option && val.match?(/(?:\A|\S=|[^=]\s+|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/m)
40
40
 
41
41
  if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
42
42
  "\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
@@ -48,7 +48,7 @@ module Squared
48
48
  def shell_option(flag, val = nil, escape: true, quote: true, force: true, double: false, override: false,
49
49
  merge: false)
50
50
  flag = flag.to_s
51
- if flag =~ /^(["'])(.+)\1$/
51
+ if flag =~ /\A(["'])(.+)\1\z/
52
52
  double = $1 == '"'
53
53
  flag = $2
54
54
  escape = false
@@ -76,7 +76,7 @@ module Squared
76
76
  ret = Shellwords.split(val)
77
77
  return ret if join == false
78
78
 
79
- ret = ret.map { |opt| shell_escape(opt, quote: quote) } if escape
79
+ ret.map! { |opt| shell_escape(opt, quote: quote) } if escape
80
80
  return ret unless join
81
81
 
82
82
  ret.join(join.is_a?(::String) ? join : ' ')
@@ -23,14 +23,14 @@ module Squared
23
23
  def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil, verbose: true)
24
24
  src = Pathname.new(src)
25
25
  dest = Pathname.new(dest)
26
- raise "#{dest} (not found)" if !create && !dest.parent.exist?
26
+ raise "#{dest.cleanpath} (not found)" if !create && !dest.parent.exist?
27
27
 
28
28
  subdir = {}
29
29
  dest.mkpath if create
30
30
  if pass
31
31
  exclude = []
32
32
  pass = [pass] unless pass.is_a?(::Array)
33
- pass.each { |val| exclude += Dir.glob(src.join(val)) }
33
+ pass.each { |val| exclude.concat(Dir.glob(src.join(val))) }
34
34
  end
35
35
  (glob.is_a?(::Array) ? glob : [glob]).each do |val|
36
36
  Dir.glob(src.join(val)) do |path|
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'pathname'
4
4
  require 'rake'
5
+ require 'time'
5
6
 
6
7
  module Squared
7
8
  module Common
@@ -18,7 +19,7 @@ module Squared
18
19
 
19
20
  last = val[i + 1..-1].strip
20
21
  quote = ''
21
- if last =~ /^(["'])(.+)\1$/
22
+ if last =~ /\A(["'])(.+)\1\z/
22
23
  last = $2
23
24
  quote = $1
24
25
  end
@@ -101,6 +102,11 @@ module Squared
101
102
  (cur.strftime('%Q').to_i + time_offset) - (val.strftime('%Q').to_i + ret)
102
103
  end
103
104
 
105
+ def time_since(val, ms: true)
106
+ s = ms ? '%s%L' : '%s'
107
+ Time.now.utc.strftime(s).to_i - Time.parse(val).utc.strftime(s).to_i
108
+ end
109
+
104
110
  def env(key, default = nil, suffix: nil, strict: false, equals: nil, ignore: nil)
105
111
  ret = env_value(key, suffix: suffix, strict: strict)
106
112
  return ret == equals.to_s unless equals.nil?
@@ -144,7 +150,7 @@ module Squared
144
150
  def env_pipe(key, default = 1, suffix: nil, strict: false, root: nil)
145
151
  if default.is_a?(::String)
146
152
  begin
147
- default = (root ? root.join(default) : Pathname.new(default)).realdirpath
153
+ default = (root ? Pathname.new(root).join(default) : Pathname.new(default)).realdirpath
148
154
  rescue StandardError => e
149
155
  default = 1
150
156
  warn e
@@ -188,7 +188,7 @@ module Squared
188
188
  def to_s
189
189
  realpath if target?
190
190
 
191
- @mime.keys.map { |ext| "#{main}.#{ext}" }.join(',')
191
+ @mime.keys.map! { |ext| "#{main}.#{ext}" }.join(',')
192
192
  end
193
193
 
194
194
  def inspect
@@ -291,9 +291,9 @@ module Squared
291
291
  pad = [pad, key.size].max
292
292
  end
293
293
  if stdin?
294
- puts out.map(&:last).join("\n")
294
+ puts out.map!(&:last).join("\n")
295
295
  else
296
- out.map { |item| "#{item[0].ljust(pad)} : #{item[1]}" }
296
+ out.map! { |item| "#{item[0].ljust(pad)} : #{item[1]}" }
297
297
  end
298
298
  end
299
299
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.4.5'
4
+ VERSION = '0.4.7'
5
5
  end
@@ -38,7 +38,7 @@ module Squared
38
38
  impl_series.alias(*args)
39
39
  end
40
40
  if (args = obj.bannerargs)
41
- @attr_banner += args
41
+ @attr_banner.merge(args)
42
42
  end
43
43
  end
44
44
  end
@@ -310,17 +310,17 @@ module Squared
310
310
  end
311
311
 
312
312
  def group(path, val, override: {}, **kwargs, &blk)
313
- rootpath(path).children.map do |dir|
313
+ rootpath(path).children.map! do |dir|
314
314
  next unless dir.directory?
315
315
 
316
316
  basename = dir.basename.to_s
317
317
  [dir, basename, override[basename.to_sym]]
318
318
  end
319
- .each do |dir, basename, opts|
320
- args = kwargs.dup
321
- args.merge!(opts) if opts
322
- add(dir, basename, group: val, **args, &blk)
323
- end
319
+ .each do |dir, basename, opts|
320
+ args = kwargs.dup
321
+ args.merge!(opts) if opts
322
+ add(dir, basename, group: val, **args, &blk)
323
+ end
324
324
  self
325
325
  end
326
326
 
@@ -350,7 +350,7 @@ module Squared
350
350
  end
351
351
 
352
352
  def describe(data)
353
- @describe = {
353
+ @describe ||= {
354
354
  alias: {},
355
355
  replace: [],
356
356
  pattern: {}
@@ -461,7 +461,7 @@ module Squared
461
461
  tasks.clear
462
462
  break
463
463
  end
464
- tasks += items
464
+ tasks.concat(items)
465
465
  end
466
466
  return tasks unless tasks.empty?
467
467
  end