squared 0.8.6 → 0.8.8

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: d49aff6b1cd9bedf0f0057bd7f9afe30cee588a2d86224f59585f53f16003ac6
4
- data.tar.gz: 445bcbd6ae09304dc4797404de44819600abae31b5f41f8bc61ce1951428a25c
3
+ metadata.gz: dabd702e6d76fec691fb926ac596d794146c3eaa6688d2c65c8506525ef18d56
4
+ data.tar.gz: 0fa0f20be1f5b9fba992764320d07336b827f46178920a0ff7070efff269d997
5
5
  SHA512:
6
- metadata.gz: 66c420cde0388bbb2c284fc83b365014bdd770cf30d9edb4a5c5b903b9c95752a87a3c8d951acd1c9b73473d2ce5b1167c6bff63fa582d75f79418ed80e468a5
7
- data.tar.gz: 0b89a2327e97e8f26e077134dfa228bfb1234a09cc6e499a96cd042d23d9e004aea623c63f8b34e3251b198b9f9806b6d191db9978f251c0d52608d1b4e452dd
6
+ metadata.gz: 2c5afc38add70c38951a8b30f92d6d205c354a6d8b1e59ea8d7bc47f789b7c180ec4e71b90ecec91ca69e5126f8570f6e34cbce0bca3ffc3d8191a705be85f6a
7
+ data.tar.gz: 5db957c61a34ea75e1ed09e8d2c0fb4b6a7832bf08c9e10254013645408598b59dd75eeb3c49cba40f5f51dd6ac7ca22f64108a71fea44a1ede192e4e74250bb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,54 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.8] - 2026-11-04
4
+
5
+ - See `0.7.15`.
6
+
7
+ ## [0.7.15]
8
+
9
+ ### Added
10
+
11
+ - Git command commit action pathspec was implemented.
12
+ - Common base argument TAB for column alignment was created.
13
+ - Node command package action deny can modify currently approved scripts.
14
+
15
+ ### Changed
16
+
17
+ - Node command package action [approve|deny] uses install-scripts ls.
18
+
19
+ ### Fixed
20
+
21
+ - Bundle exec wrapper as a Hash did not support using alternate Gemfile.
22
+ - Common base ARG data objects were not frozen with __freeze__.
23
+
24
+ ## [0.8.7] - 2026-10-22
25
+
26
+ ### Added
27
+
28
+ - OptionPartition can be initialized with enum and pattern options.
29
+
30
+ ### Fixed
31
+
32
+ - Python venv creation did not run post-install for package managers.
33
+
34
+ ## [0.7.14]
35
+
36
+ ### Changed
37
+
38
+ - Python program meson prefix options use local path resolution.
39
+ - Bundle exec wrapper can be configured per application.
40
+
41
+ ### Fixed
42
+
43
+ - Bundle exec wrapper did not accept boolean values.
44
+
45
+ ## [0.6.21]
46
+
47
+ ### Fixed
48
+
49
+ - RuboCop did not resolve config to project directory.
50
+ - Python program did not use correct separator for double dash options.
51
+
3
52
  ## [0.8.6] - 2026-10-01
4
53
 
5
54
  ### Added
@@ -18,7 +67,7 @@
18
67
 
19
68
  - OptionPartition did not parse quoted option values.
20
69
 
21
- ## [0.6.20] - 2026-09-25
70
+ ## [0.6.20]
22
71
 
23
72
  ### Added
24
73
 
@@ -2153,6 +2202,8 @@
2153
2202
 
2154
2203
  - Changelog was created.
2155
2204
 
2205
+ [0.8.8]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.8
2206
+ [0.8.7]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.7
2156
2207
  [0.8.6]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.6
2157
2208
  [0.8.5]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.5
2158
2209
  [0.8.4]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.4
@@ -2160,6 +2211,8 @@
2160
2211
  [0.8.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.2
2161
2212
  [0.8.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.1
2162
2213
  [0.8.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.8.0
2214
+ [0.7.15]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.15
2215
+ [0.7.14]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.14
2163
2216
  [0.7.13]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.13
2164
2217
  [0.7.12]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.12
2165
2218
  [0.7.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.11
@@ -2174,6 +2227,7 @@
2174
2227
  [0.7.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.2
2175
2228
  [0.7.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.1
2176
2229
  [0.7.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.7.0
2230
+ [0.6.21]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.21
2177
2231
  [0.6.20]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.20
2178
2232
  [0.6.19]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.19
2179
2233
  [0.6.18]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.18
data/README.md CHANGED
@@ -10,11 +10,11 @@
10
10
  | 2024-12-07 | 0.1.0 | 2.4.0 | 3.3.6 | |
11
11
  | 2025-01-07 | 0.2.0 | | 3.4.0 | |
12
12
  | 2025-02-07 | 0.3.0 | | 3.4.1 | |
13
- | 2025-03-06 | 0.4.0 | | 3.4.2 | * |
13
+ | 2025-03-06 | 0.4.0 | | 3.4.2 | |
14
14
  | 2025-06-16 | 0.5.0 | 2.5.0 | 3.4.4 | |
15
15
  | ---------- | ----- | ----- | ----- | --- |
16
16
  | 2025-08-23 | 0.5.5 | | 3.4.5 | |
17
- | 2025-10-31 | 0.6.0 | | 3.4.7 | * |
17
+ | 2025-10-31 | 0.6.0 | | 3.4.7 | |
18
18
  | 2026-01-07 | 0.7.0 | 2.5.0 | 4.0.0 | * |
19
19
  | 2026-06-16 | 0.8.0 | | 4.0.5 | * |
20
20
 
@@ -13,6 +13,7 @@ module Squared
13
13
  STRICT: false,
14
14
  BANNER: true,
15
15
  CHOICE: 25,
16
+ TAB: 4,
16
17
  QUOTE: "'",
17
18
  SPACE: ' => ',
18
19
  SUCCESS: 'Success',
@@ -101,6 +102,7 @@ module Squared
101
102
 
102
103
  def __freeze__
103
104
  PATH.freeze
105
+ ARG.each_value { |val| val.freeze if val.is_a?(::Hash) || val.is_a?(::Array) }
104
106
  ARG.freeze
105
107
  VAR.each_value(&:freeze)
106
108
  VAR[:theme].each_value { |val| val.freeze.each_value(&:freeze) }
@@ -296,7 +296,7 @@ module Squared
296
296
  if footer
297
297
  unless sub.empty? && !right
298
298
  footer.map! do |s|
299
- s = s.rjust(n + 4) if right
299
+ s = s.rjust(n + ARG[:TAB]) if right
300
300
  sub.each { |h| sub_style!(s, **h) }
301
301
  s
302
302
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.8.6'
4
+ VERSION = '0.8.8'
5
5
  end
@@ -645,16 +645,24 @@ module Squared
645
645
  val = val.split(':') if val.is_a?(String)
646
646
  if before || after || opts
647
647
  pos = []
648
- pos << (before.is_a?(Array) ? before.join(',') : before) if before
649
- if opts
650
- pos << if opts.is_a?(Array)
651
- arg ? "#{arg}=#{opts.join(',')}" : opts.join('|')
648
+ append = lambda do |data|
649
+ pos << case data
650
+ when Array
651
+ data.join(',')
652
+ when Hash
653
+ data.keys.join('|')
652
654
  else
653
- opts
655
+ data
654
656
  end
655
657
  end
656
- pos << (after.is_a?(Array) ? after.join(',') : after) if after
657
- val << "#{val.pop}[#{pos.join(',')}]"
658
+ append.call(before)
659
+ pos << if opts.is_a?(Array)
660
+ arg ? "#{arg}=#{opts.join(',')}" : opts.join('|')
661
+ else
662
+ opts
663
+ end
664
+ append.call(after)
665
+ val << "#{val.pop}[#{pos.compact.join(',')}]"
658
666
  end
659
667
  out ? message(*val) : task_desc(*val)
660
668
  end
@@ -1911,7 +1911,7 @@ module Squared
1911
1911
  out << ''
1912
1912
  end
1913
1913
  if from
1914
- out << from
1914
+ out << (from = from.to_s)
1915
1915
  /\A(#{Regexp.escape(from)})(.*)\z/
1916
1916
  end
1917
1917
  else
@@ -181,7 +181,7 @@ module Squared
181
181
  if flags.nil?
182
182
  case action
183
183
  when 'ls'
184
- format_desc(action, nil, VAL_DOCKER[:ls].keys, after: 'a/ll?,s/tandard?,range*', arg: nil)
184
+ format_desc(action, nil, 'a/ll?,s/tandard?,range*', before: VAL_DOCKER[:ls])
185
185
  task action, [:command] do |_, args|
186
186
  command = param_guard(action, 'command', args: args, key: :command)
187
187
  args = args.extras
@@ -974,7 +974,7 @@ module Squared
974
974
  end
975
975
  pad = cols.map(&:size).max
976
976
  cols.each { |key| puts "#{g + f} #{key.rjust(pad)}: #{Array(data[key]).join(', ')}" }
977
- w = 9 + flag.to_s.size + 4 + ee.size
977
+ w = 9 + flag.to_s.size + ARG[:TAB] + ee.size
978
978
  puts g + sub_style(ARG[:BORDER][6] + (ARG[:BORDER][1] * w), theme[:inline])
979
979
  index += 1
980
980
  next unless confirm("#{h + b}?", no ? 'N' : 'Y')
@@ -364,7 +364,7 @@ module Squared
364
364
  subtasks({
365
365
  'branch' => %i[create track delete move copy list all current].freeze,
366
366
  'checkout' => %i[commit branch track detach path].freeze,
367
- 'commit' => %i[head add all amend amend-orig fixup].freeze,
367
+ 'commit' => %i[head add all pathspec amend amend-orig fixup].freeze,
368
368
  'clone' => %i[branch tag].freeze,
369
369
  'diff' => %i[head branch files view between contain].freeze,
370
370
  'range-diff' => %i[view between contain].freeze,
@@ -533,7 +533,7 @@ module Squared
533
533
  if flag == :add
534
534
  opts = param_guard(action, flag, args: args.to_a)
535
535
  elsif (refs = args.to_a).empty?
536
- refs = readline('Enter file patterns', force: true).shellsplit
536
+ refs = readline('Enter glob patterns', force: true).shellsplit
537
537
  end
538
538
  end
539
539
  commit(flag, opts, refs: refs, ref: ref, squash: squash, pick: pick)
@@ -1106,7 +1106,7 @@ module Squared
1106
1106
  git(:remote, args.extras, extras: [name, url])
1107
1107
  end
1108
1108
  else
1109
- format_desc action, flag, "#{OPT_GIT[:remote].keys.join('|')},opts*" if TASK_METADATA
1109
+ format_desc(action, flag, 'opts*', before: OPT_GIT[:remote])
1110
1110
  task flag, [:command] do |_, args|
1111
1111
  command = param_guard(action, flag, args: args, key: :command)
1112
1112
  cmd, opts = git_session('remote', opts: args.extras)
@@ -1798,7 +1798,7 @@ module Squared
1798
1798
  pathspec = false if pick == 'reword'
1799
1799
  end
1800
1800
  if pathspec.nil?
1801
- pathspec = if (flag == :fixup || amend) && refs.size == 1 && refs.first == '*'
1801
+ pathspec = if (flag == :pathspec || flag == :fixup || amend) && refs.size == 1 && refs.first == '*'
1802
1802
  '--all'
1803
1803
  elsif (refs = projectmap(refs)).empty?
1804
1804
  raise 'no qualified pathspec'
@@ -11,7 +11,7 @@ module Squared
11
11
  install_a: %w[audit=! bin-links=! engine-strict=!? foreground-scripts=!? fund=! ignore-scripts=!?
12
12
  install-links=!? package-lock=! strict-peer-deps=!? include=b install-strategy=b omit=b].freeze,
13
13
  install_b: %w[no-save B|save-bundle D|save-dev O|save-optional save-peer P|save-prod g|global=!?
14
- S|save=!?].freeze,
14
+ min-release-age=i min-release-age-exclude=q S|save=!?].freeze,
15
15
  install_c: %w[allow-directory=b? allow-file=b? allow-git=b? allow-remote=b?].freeze,
16
16
  run: %w[foreground-scripts=!? if-present=!? ignore-scripts=!? script-shell=p].freeze,
17
17
  exec: %w[c|call=q package=b].freeze,
@@ -69,7 +69,7 @@ module Squared
69
69
  install: %w[check-cache check-resolutions immutable immutable-cache inline-builds json refresh-lockfile
70
70
  mode=b].freeze,
71
71
  add: %w[cached D|dev json O|optional P|peer prefer-dev].freeze,
72
- add_a: %w[C|caret E|exact F|fixed interactive T|tilde mode=b].freeze,
72
+ add_a: %w[C|caret E|exact F|fixed i|interactive no-time-gate T|tilde mode=b].freeze,
73
73
  update: %w[R|recursive].freeze,
74
74
  dedupe: %w[check json mode=b strategy=b].freeze,
75
75
  run: %w[B|binaries-only inspect inspect-brk T|top-level require=q].freeze,
@@ -305,13 +305,11 @@ module Squared
305
305
  format_desc action, nil, 'version|pre?{major,minor,patch}|prerelease'
306
306
  task action, [:version] do |_, args|
307
307
  version = param_guard(action, 'to', args: args, key: :version)
308
- if version.match?(/^((pre)?(major|minor|patch))|prerelease$/)
309
- flag = version.to_sym
310
- version = nil
308
+ if version.match?(/^(pre)?(major|minor|patch)|prerelease$/)
309
+ bump version.to_sym
311
310
  else
312
- flag = :version
311
+ bump :version, version
313
312
  end
314
- bump flag, version
315
313
  end
316
314
  when 'pack'
317
315
  format_desc action, nil, 'opts*'
@@ -331,26 +329,39 @@ module Squared
331
329
  when 'package'
332
330
  case flag
333
331
  when :approve, :deny
334
- format_desc action, flag, 'name*|:,opts*'
332
+ format_desc(action, flag, 'opts*', before: flag == :approve ? 'name*|:' : 'name*|:|::')
335
333
  task flag do |_, args|
336
334
  args = args.to_a
337
- if choice!(args)
335
+ if choice!(args) || (flag == :deny && (all = choice!(args, char: '::')))
336
+ list = []
337
+ pad = 0
338
+ size = ->(s) { pad = [pad, s.size].max }
338
339
  pwd_set do
339
- pad = 0
340
- list = IO.popen(npm_output('approve-scripts --allow-scripts-pending').to_s)
341
- .each_with_object([]) do |line, out|
342
- next unless line =~ /^\s+([a-z\d@][^@]*)@(\S+)/
343
-
344
- pad = [pad, $1.size].max
345
- out << [$1, $2]
346
- end
347
- .map { |name, ver| name.ljust(pad + 4) + ver }
348
- if list.empty?
349
- puts log_message('no packages to review', subject: name, hint: "#{flag}-scripts")
350
- exit 0
340
+ json = JSON.parse(`#{npm_output('install-scripts ls --json')}`)
341
+ json&.fetch('allowScripts', [])&.each do |data|
342
+ line = data['changes']&.find { |item| item['change'] == 'pending' }
343
+ next unless line && line['key'] =~ /^(.+)@([^@]+)$/
344
+
345
+ size.call($1)
346
+ list << [$1, $2]
347
+ end
348
+ if all
349
+ current = read_package 'allowScripts'
350
+ current&.each_pair do |key, val|
351
+ next unless val
352
+
353
+ md = key.match(/^(.+?)(?:@([^@]+))?$/)
354
+ size.call(md[1])
355
+ list << [md[1], sub_style(md[2] || 'any', theme[:inline])]
356
+ end
351
357
  end
352
- args.concat(choice_index('Select packages', list, multiple: true, column: /^(\S+)/))
353
358
  end
359
+ if list.empty?
360
+ puts log_message('no packages to review', subject: name, hint: "#{flag}-scripts")
361
+ exit 0
362
+ end
363
+ list.map! { |name, ver| name.ljust(pad + ARG[:TAB]) + ver }
364
+ args.concat(choice_index('Select packages', list, multiple: true, column: /^(\S+)/))
354
365
  end
355
366
  package flag, args
356
367
  end
@@ -662,7 +673,7 @@ module Squared
662
673
  end
663
674
  if nolockfile?(prefix: 'yarn')
664
675
  cmd << '--no-lockfile'
665
- elsif option('ci') || (ci? && exist?('yarn.lock'))
676
+ elsif option('ci') || (ci? && exist?(yarnlock))
666
677
  if yarn == 1
667
678
  cmd << '--frozen-lockfile'
668
679
  elsif !flag
@@ -698,13 +709,13 @@ module Squared
698
709
  '--force'
699
710
  elsif nolockfile?(prefix: 'pnpm')
700
711
  '--no-lockfile'
701
- elsif option('ci') || (ci? && exist?('pnpm-lock.yaml'))
712
+ elsif option('ci') || (ci? && exist?(pnpmlock))
702
713
  '--frozen-lockfile'
703
714
  end
704
715
  cmd << '--ignore-scripts' if option('ignore-scripts')
705
716
  cmd << '--dangerously-allow-all-builds' if option('approve-builds')
706
717
  else
707
- ci = option('ci', prefix: 'npm') || (ci? && exist?('package-lock.json'))
718
+ ci = option('ci', prefix: 'npm') || (ci? && exist?(npmlock))
708
719
  cmd = session('npm', ci ? 'ci' : 'install')
709
720
  option('approve-scripts') do |val|
710
721
  cmd = npm_output 'approve-scripts'
@@ -758,7 +769,7 @@ module Squared
758
769
  append_platform
759
770
  end
760
771
  end
761
- cmd << '--package-lock=false' << 'save=false' if nolockfile?(prefix: 'npm')
772
+ cmd << '--package-lock=false' << '--save=false' if nolockfile?(prefix: 'npm')
762
773
  cmd << '--ignore-scripts' if option('ignore-scripts')
763
774
  end
764
775
  if add
@@ -771,7 +782,7 @@ module Squared
771
782
  end
772
783
 
773
784
  def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
774
- cmd = session(pnpm? && exist?('pnpm-lock.yaml') ? 'pnpm' : 'npm', 'outdated')
785
+ cmd = session(pnpm? && exist?(pnpmlock) ? 'pnpm' : 'npm', 'outdated')
775
786
  dryrun = has_value?(opts, 'd', 'dry-run') || dryrun?
776
787
  unless dryrun
777
788
  log.info cmd.to_s
@@ -888,9 +899,9 @@ module Squared
888
899
  end
889
900
  print_item banner unless sync
890
901
  if !found.empty?
891
- col1 = width.call(found, 0) + 4
892
- col2 = width.call(found, 1) + 4
893
- col3 = pad.call(found, found.size).size + 2 + col1 + col2 + width.call(found, 2)
902
+ col1 = width.call(found, 0) + ARG[:TAB]
903
+ col2 = width.call(found, 1) + ARG[:TAB]
904
+ col3 = pad.call(found, found.size).size + (ARG[:TAB] / 2) + col1 + col2 + width.call(found, 2)
894
905
  packages = []
895
906
  pat = ->(a) { /("#{Regexp.escape(a[0])}"\s*:\s*)"([~^])#{'?' if a[4]}#{Regexp.escape(a[1])}"/ }
896
907
  edit = lambda do |a, pkg, mod|
@@ -986,9 +997,9 @@ module Squared
986
997
  end
987
998
  end
988
999
  elsif !avail.empty?
989
- col1 = width.call(avail, 0) + 4
1000
+ col1 = width.call(avail, 0) + ARG[:TAB]
990
1001
  col2 = width.call(avail, 1)
991
- col3 = width.call(avail, 2) + 4
1002
+ col3 = width.call(avail, 2) + ARG[:TAB]
992
1003
  avail.each_with_index do |item, i|
993
1004
  a, b, c, d = item
994
1005
  a = a.ljust(col1)
@@ -1452,7 +1463,7 @@ module Squared
1452
1463
  end
1453
1464
 
1454
1465
  def yarn?
1455
- (@pm[:yarn] ||= if rootpath('yarn.lock', ascend: dependroot).exist?
1466
+ (@pm[:yarn] ||= if rootpath(yarnlock, ascend: dependroot).exist?
1456
1467
  yarntype
1457
1468
  elsif (ver = read_package || read_install)
1458
1469
  if ver =~ /^yarn(?:@(\d)|$)/
@@ -1473,7 +1484,7 @@ module Squared
1473
1484
  end
1474
1485
 
1475
1486
  def pnpm?
1476
- (@pm[:pnpm] ||= if rootpath('pnpm-lock.yaml', ascend: dependroot).exist?
1487
+ (@pm[:pnpm] ||= if rootpath(pnpmlock, ascend: dependroot).exist?
1477
1488
  pnpmtype
1478
1489
  elsif (ver = read_package || read_install)
1479
1490
  ver.start_with?('pnpm') ? pnpmtype : 0
@@ -1582,7 +1593,7 @@ module Squared
1582
1593
  require 'yaml'
1583
1594
  doc = YAML.load_file(rc)
1584
1595
  doc.nodeLinker == 'node-modules' ? 2 : 3
1585
- elsif exist && !exist?('yarn.lock')
1596
+ elsif exist && !exist?(yarnlock)
1586
1597
  0
1587
1598
  else
1588
1599
  1
@@ -1594,6 +1605,10 @@ module Squared
1594
1605
  3
1595
1606
  end
1596
1607
 
1608
+ def yarnlock
1609
+ 'yarn.lock'
1610
+ end
1611
+
1597
1612
  def pnpmtype(exist: false)
1598
1613
  require 'yaml'
1599
1614
  doc = YAML.load_file(basepath('node_modules/.modules.yaml', ascend: dependroot))
@@ -1608,13 +1623,21 @@ module Squared
1608
1623
  end
1609
1624
  rescue => e
1610
1625
  if exist
1611
- %w[pnpm-lock.yaml pnpm-workspace.yaml].any? { |val| exist?(val) } ? 4 : 0
1626
+ %W[#{pnpmlock} pnpm-workspace.yaml].any? { |val| exist?(val) } ? 4 : 0
1612
1627
  else
1613
1628
  log.debug e
1614
1629
  4
1615
1630
  end
1616
1631
  end
1617
1632
 
1633
+ def pnpmlock
1634
+ 'pnpm-lock.yaml'
1635
+ end
1636
+
1637
+ def pnpmopts(*args)
1638
+ OPT_PNPM[:common] + args.flat_map { |name| OPT_PNPM.fetch(name, []) }
1639
+ end
1640
+
1618
1641
  def remove_modules(prefix: dependbin)
1619
1642
  modules = basepath!('node_modules', type: 'd')
1620
1643
  return false unless modules && confirm_basic('Remove?', modules, prefix: prefix)
@@ -1696,16 +1719,16 @@ module Squared
1696
1719
  ].concat(args)
1697
1720
  end
1698
1721
 
1699
- def npmopts(*args)
1700
- OPT_NPM[:common] + args.flat_map { |name| OPT_NPM.fetch(name, []) }
1722
+ def npmlock
1723
+ 'package-lock.json'
1701
1724
  end
1702
1725
 
1703
- def pnpmopts(*args)
1704
- OPT_PNPM[:common] + args.flat_map { |name| OPT_PNPM.fetch(name, []) }
1726
+ def npmopts(*args)
1727
+ OPT_NPM[:common] + args.flat_map { |name| OPT_NPM.fetch(name, []) }
1705
1728
  end
1706
1729
 
1707
1730
  def lockfile(delete = false)
1708
- ret = basepath(yarn? ? 'yarn.lock' : pnpm? ? 'pnpm-lock.yaml' : 'package-lock.json')
1731
+ ret = basepath(yarn? ? yarnlock : pnpm? ? pnpmlock : npmlock)
1709
1732
  if ret.exist?
1710
1733
  if delete
1711
1734
  ret.delete
@@ -7,16 +7,18 @@ module Squared
7
7
  DEP_PYTHON = %w[poetry.lock setup.cfg pyproject.toml setup.py requirements.txt].freeze
8
8
  DIR_PYTHON = (DEP_PYTHON + %w[meson.build README.rst]).freeze
9
9
  OPT_PYTHON = {
10
- common: %w[b=+ B d E h i I O P q=+ s S u v=+ V=+ x c=q m=b W=b X=q check-hash-based-pycs=b].freeze,
10
+ common: %w[b=+ B d E h i I O P q=+ s S u v=+ V=+ x c=q m=b W=b X=q
11
+ check-hash-based-pycs={always,default,never}].freeze,
11
12
  build: %w[C=bm n|no-isolation s|sdist x|skip-dependency-check v|verbose w|wheel config-json=q config-setting=q
12
13
  installer=b o|outdir=p].freeze,
13
14
  venv: %w[clear copies symlinks system-site-packages upgrade upgrade-deps without-scm-ignore-files without-pip
14
15
  prompt=q].freeze,
15
16
  virtualenv: %w[always-copy clear copies download never-download no-download no-periodic-update no-pip no-seed
16
- no-setuptools no-vcs-ignore q|quiet read-only-app-data reset-app-data symlink-app-data symlinks
17
- system-site-packages with-traceback without-pip upgrade-embed-wheels v|verbose=+ activators=q
18
- app-data=p creator=b discovery=b extra-search-dir=p pip=b prompt=q p|python=q seeder=b
19
- setuptools=b try-first-with=q].freeze
17
+ no-setuptools no-vcs-ignore no-venv-redirect q|quiet read-only-app-data reset-app-data
18
+ symlink-app-data symlinks system-site-packages with-traceback without-pip upgrade-embed-wheels
19
+ venv-redirect v|verbose=+ activators={bash,batch,cshell,fish,nushell,powershell,python,xonsh}
20
+ app-data=p creator=b discovery={builtin} extra-search-dir=p pip=b prompt=q p|python=q
21
+ seeder={app-data,pip} setuptools=b try-first-with=q].freeze
20
22
  }.freeze
21
23
  OPT_PIP = {
22
24
  common: %w[debug disable-pip-version-check isolated no-cache-dir no-color no-input no-proxy-env
@@ -77,15 +79,20 @@ module Squared
77
79
  sign-with=b u|username=qq].freeze
78
80
  }.freeze
79
81
  OPT_MESON = {
80
- build: %w[D=q clearcache debug errorlogs fatal-meson-warnings pkgconfig.relocatable prefer-static
81
- python.allow-limited-api reconfigure stdsplit strip vsenv werror wipe auto-features=b backend=b
82
- bindir=p build.cmake-prefix-path=p build.pkg-config-path=p buildtype=b cmake-prefix-path=p
83
- cross-file=p datadir=p default-library=b default-both-libraries=b force-fallback-for=q genvslite=b
84
- includedir=p infodir=p install-umask=b layout=b libdir=p libexecdir=p licensedir=p localedir=p
85
- localstatedir=p mandir=p native-file=p optimization=b pkg-config-path=p prefix=p
86
- python.bytecompile=i python.platlibdir=p python.purelibdir=p python.install-env=b sbindir=p
87
- sharedstatedir=p sysconfdir=p unity=b unity-size=i warnlevel=b wrap-mode=b].freeze,
88
- compile: %w[clean v|verbose j|jobs=i l|load-average=b ninja-args=q vs-args=q xcode-args=q].freeze
82
+ build: %w[D=q clearcache debug errorlogs fatal-meson-warnings os2-emxomf pkgconfig.relocatable prefer-static
83
+ python.allow-limited-api reconfigure stdsplit strip vsenv werror wipe auto-features=b
84
+ backend={ninja,vs,vs2010,vs2012,vs2013,vs2015,vs2017,vs2019,vs2022,vs2026,xcode,none}
85
+ bindir=q build.cmake-prefix-path=p build.pkg-config-path=p
86
+ buildtype={plain,debug,debugoptimized,release,minsize,custom} cmake-prefix-path=p cross-file=p
87
+ datadir=q default-library={shared,static,both} default-both-libraries={shared,static,auto}
88
+ force-fallback-for=q genvslite={vs2022,vs2026} includedir=q infodir=q install-umask=b
89
+ layout={mirror,flat} libdir=q libexecdir=q licensedir=q localedir=q localstatedir=q mandir=q
90
+ namingscheme={platform,classic} native-file=p optimization={plain,0,g,1,2,3,s} pkg-config-path=p
91
+ prefix=p python.build-config=p python.bytecompile=b python.platlibdir=p python.purelibdir=p
92
+ python.install-env={auto,prefix,system,venv} sbindir=q sharedstatedir=q sysconfdir=q
93
+ unity={on,off,subprojects} unity-size=i warnlevel={0,1,2,3,everything}
94
+ wrap-mode={default,nofallback,nodownload,forcefallback,nopromote}].freeze,
95
+ compile: %w[C=p clean v|verbose j|jobs=i l|load-average=b ninja-args=q vs-args=q xcode-args=q].freeze
89
96
  }.freeze
90
97
  PASS_PYTHON = {
91
98
  python: %w[c v V].freeze,
@@ -276,7 +283,7 @@ module Squared
276
283
  args = args.to_a
277
284
  if args.empty?
278
285
  args = readline('Enter command', force: true).split(' ', 2)
279
- elsif args.size == 1 && option('interactive', notequals: '0', prefix: ref)
286
+ elsif args.size == 1 && option('interactive', notequals: '0', prefix: 'python')
280
287
  args << readline('Enter arguments', force: false) unless args.first.include?(' ')
281
288
  end
282
289
  venv_init
@@ -346,18 +353,18 @@ module Squared
346
353
  case flag
347
354
  when :upgrade
348
355
  task flag, [:strategy] do |_, args|
349
- install flag, (case args.strategy
350
- when 'eager'
351
- 'eager'
352
- when /^only-if|needed$/
353
- 'only-if-needed'
354
- end.yield_self do |val|
355
- if val
356
- args.extras << "upgrade-strategy=#{val}"
357
- else
358
- args.to_a
359
- end
360
- end)
356
+ val = case args.strategy
357
+ when 'eager'
358
+ 'eager'
359
+ when /^only-if/, /needed$/
360
+ 'only-if-needed'
361
+ end
362
+ args = if val
363
+ args.extras << "upgrade-strategy=#{val}"
364
+ else
365
+ args.to_a
366
+ end
367
+ install flag, args
361
368
  end
362
369
  when :requirement, :target
363
370
  task flag, [:path] do |_, args|
@@ -735,7 +742,7 @@ module Squared
735
742
  op = OptionPartition.new(session_opts(with, args: args, kwargs: kwargs, pass: pass), OPT_PYTHON[:common],
736
743
  session('python', path: !venv?),
737
744
  project: self, strict: strict?, multiple: [/^-c/], single: singleopt(:python),
738
- args: true, stdin: true)
745
+ sep: ' ', args: true, stdin: true)
739
746
  op.concat(args)
740
747
  if op.include?('-')
741
748
  op.exist?(add: true)
@@ -745,7 +752,7 @@ module Squared
745
752
  op.clear
746
753
  else
747
754
  op.exist?(add: true, first: true) unless op.arg?('m')
748
- op.append(escape: kwargs.fetch(:escape, false), quote: kwargs.fetch(:quote, false))
755
+ op.append(context: kwargs)
749
756
  end
750
757
  end
751
758
  print_run(op, banner, **kwargs)
@@ -936,7 +943,8 @@ module Squared
936
943
  pre = preopts(quiet: quiet)
937
944
  return session(name, *pre, *cmd, path: !venv?) unless opts
938
945
 
939
- op = OptionPartition.new(opts, common, project: self, strict: strict?, single: singleopt(name.to_sym))
946
+ op = OptionPartition.new(opts, common, project: self, strict: strict?, sep: name == 'python' ? ' ' : '=',
947
+ single: singleopt(name.to_sym))
940
948
  [session(name, *pre, *op.to_a, *cmd, path: !venv?), op.extras]
941
949
  end
942
950
 
@@ -1197,6 +1205,7 @@ module Squared
1197
1205
  status = true
1198
1206
  :virtualenv
1199
1207
  else
1208
+ status = !banner
1200
1209
  :venv
1201
1210
  end
1202
1211
  cmd, opts = python_session('-m', flag, opts: opts)
@@ -1204,32 +1213,31 @@ module Squared
1204
1213
  op.append(dir, delim: true)
1205
1214
  .clear(pass: false)
1206
1215
  status ||= op.arg?(/\A-v+\z/)
1207
- ret = run(op, env, exception: true, banner: banner)
1208
- args = []
1209
- requires = read_pyproject 'build-system', 'requires'
1210
- args.concat(requires) if requires.is_a?(Array)
1211
- if poetry?
1212
- requires = read_pyproject 'tool.poetry', 'requires-poetry'
1213
- args << "poetry#{requires}"
1214
- elsif setuptools? && !virtualenv?
1215
- args << 'setuptools' << 'wheel'
1216
- end
1217
- pip(:install, *args, banner: false) unless args.empty?
1218
- success?(ret, banner, !status) do |out|
1219
- if out && dir.directory?
1220
- if poetry?
1221
- dir += (windows? ? 'Scripts/python.exe' : 'bin/python')
1222
- cmd = poetry_session 'env use'
1223
- else
1224
- puts "Success: #{dir}"
1225
- return
1226
- end
1227
- cmd << shell_quote(dir)
1228
- print_run cmd, silent?
1229
- run(banner: false)
1216
+ if run(op, env, exception: true, banner: banner) && dir.directory?
1217
+ args = []
1218
+ requires = read_pyproject 'build-system', 'requires'
1219
+ args.concat(requires) if requires.is_a?(Array)
1220
+ if poetry?
1221
+ requires = read_pyproject 'tool.poetry', 'requires-poetry'
1222
+ args << "poetry#{requires}"
1223
+ elsif setuptools? && !virtualenv?
1224
+ args << 'setuptools' << 'wheel'
1225
+ end
1226
+ pip(:install, *args, banner: false) unless args.empty?
1227
+ if poetry?
1228
+ dir += (windows? ? 'Scripts/python.exe' : 'bin/python')
1229
+ poetry_session 'env use'
1230
+ elsif pdm?
1231
+ pdm_session 'use -f'
1230
1232
  else
1231
- puts 'Failed'
1233
+ puts "Success: #{dir}" unless status
1234
+ return
1232
1235
  end
1236
+ cmd << shell_quote(dir)
1237
+ print_run cmd, silent?
1238
+ run(banner: false)
1239
+ elsif !status
1240
+ puts 'Failed'
1233
1241
  end
1234
1242
  end
1235
1243
 
@@ -227,7 +227,7 @@ module Squared
227
227
  serve_set kwargs[:serve]
228
228
  gemfile_set kwargs[:gemspec]
229
229
  self.autodetect = autodetect
230
- @bundle = { exec: exec.is_a?(String) ? basepath!(exec) : exec }
230
+ @bundle = { exec: exec }
231
231
  @steepfile = basepath! steep if steep
232
232
  rubocop = rootpath('.rubocop.yml', ascend: Dir.home) if rubocop == true
233
233
  @rubocopfile = basepath! rubocop if rubocop
@@ -949,7 +949,7 @@ module Squared
949
949
  end
950
950
  s = '%2d. %s' % [start, line]
951
951
  if ia
952
- unless confirm_semver(s.ljust(col + 4 + line.size - n), type)
952
+ unless confirm_semver(s.ljust(col + ARG[:TAB] + line.size - n), type)
953
953
  start += 1
954
954
  next
955
955
  end
@@ -1037,7 +1037,7 @@ module Squared
1037
1037
  if op.arg?('e')
1038
1038
  op.clear
1039
1039
  else
1040
- op.append(delim: true, escape: kwargs.fetch(:escape, false), quote: kwargs.fetch(:quote, false))
1040
+ op.append(delim: true, context: kwargs)
1041
1041
  end
1042
1042
  end
1043
1043
  print_run(op, banner, **kwargs) unless flag
@@ -1376,10 +1376,10 @@ module Squared
1376
1376
  end
1377
1377
  if flag == :install
1378
1378
  op.append_any(escape: true)
1379
+ op.delim << post if post
1379
1380
  else
1380
1381
  op.append(escape: true)
1381
1382
  end
1382
- op.delim << post if post
1383
1383
  when :check, :cleanup, :contents, :fetch, :list, :lock, :rdoc
1384
1384
  op.append
1385
1385
  when :dependency, :info, :search
@@ -1583,7 +1583,7 @@ module Squared
1583
1583
 
1584
1584
  def rdbg(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:rdbg], **kwargs)
1585
1585
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1586
- cmd = session 'rdbg'
1586
+ cmd = session(*bundle_args('rdbg'))
1587
1587
  args.each_with_index do |val, i|
1588
1588
  break if val == '--'
1589
1589
  next unless exist?(val, type: 'f')
@@ -1866,7 +1866,7 @@ module Squared
1866
1866
  end
1867
1867
 
1868
1868
  def ruby_session(*cmd, **kwargs)
1869
- session('ruby', *preopts, *cmd, **kwargs)
1869
+ session(*bundle_args('ruby'), *preopts, *cmd, **kwargs)
1870
1870
  end
1871
1871
 
1872
1872
  def gem_session(*cmd, **kwargs)
@@ -1884,11 +1884,10 @@ module Squared
1884
1884
  end
1885
1885
 
1886
1886
  def rbs_session(*cmd, opts: nil)
1887
- args = bundle_args 'rbs'
1888
- return session(*args, *cmd) unless opts
1887
+ return session(*bundle_args('rbs'), *cmd) unless opts
1889
1888
 
1890
1889
  op = OptionPartition.new(opts, OPT_RUBY[:rbs], project: self, strict: strict?)
1891
- [session(*args, *op.to_a, *cmd), op.extras]
1890
+ [session(*bundle_args('rbs'), *op.to_a, *cmd), op.extras]
1892
1891
  end
1893
1892
 
1894
1893
  def gem_output(*cmd, **kwargs)
@@ -1896,7 +1895,7 @@ module Squared
1896
1895
  end
1897
1896
 
1898
1897
  def ruby_output(*cmd, **kwargs)
1899
- session_output('ruby', *cmd, **kwargs)
1898
+ session_output(*bundle_args('ruby'), *cmd, **kwargs)
1900
1899
  end
1901
1900
 
1902
1901
  def bundle_output(*cmd, **kwargs)
@@ -1908,11 +1907,20 @@ module Squared
1908
1907
  end
1909
1908
 
1910
1909
  def bundle_args(*args)
1911
- if (val = @bundle[:exec])
1912
- args.unshift(quote_option('gemfile', val)) unless val == true
1913
- args.unshift('bundle', 'exec')
1910
+ return args unless (val = @bundle[:exec])
1911
+
1912
+ app = args.first
1913
+ if val.is_a?(Hash)
1914
+ val = val[app.to_s] || val[app.to_sym]
1915
+ elsif app == 'ruby'
1916
+ return args
1917
+ end
1918
+ case val
1919
+ when String, Pathname
1920
+ val = basepath!(val, type: 'f')
1921
+ args.unshift("--gemfile=#{shell_escape(val.relative_path_from(path), quote: true)}") if val
1914
1922
  end
1915
- args
1923
+ val ? args.unshift('bundle', 'exec') : args
1916
1924
  end
1917
1925
 
1918
1926
  def bundle_load
@@ -59,10 +59,10 @@ module Squared
59
59
  ret.map! do |val|
60
60
  next val if opt?(val)
61
61
 
62
- if !(pa = val.is_a?(Pathname)) && escape
63
- shell_escape(val, quote: quote, double: double)
64
- elsif quote || pa
62
+ if (quote && !escape) || val.is_a?(Pathname)
65
63
  shell_quote(val, double: double, **kwargs)
64
+ elsif escape
65
+ shell_escape(val, quote: quote, double: double)
66
66
  else
67
67
  val
68
68
  end
@@ -247,7 +247,7 @@ module Squared
247
247
  end
248
248
 
249
249
  def parse(list, opts = extras, no: nil, single: nil, args: false, multiple: nil, first: nil, underscore: nil,
250
- explicit: false, bool: %w[true false], auto: [], stdin: false, &blk)
250
+ explicit: false, bool: %w[true false], auto: [], regexp: {}, enum: {}, stdin: false, &blk)
251
251
  @extras = []
252
252
  @values = []
253
253
  bare = []
@@ -264,8 +264,6 @@ module Squared
264
264
  bl = []
265
265
  ex = []
266
266
  ml = []
267
- re = {}
268
- ar = {}
269
267
  sw = {}
270
268
  se = {}
271
269
  list.flat_map do |val|
@@ -287,10 +285,10 @@ module Squared
287
285
  end
288
286
  if (n = val.index('='))
289
287
  flag = val[0, n]
290
- enum = flag.split(':')
291
- mod = if enum.size > 1
292
- pre = enum.shift
293
- enum.map { |s| "#{pre}:#{s}" }
288
+ opt = flag.split(':')
289
+ mod = if opt.size > 1
290
+ pre = opt.shift
291
+ opt.map { |s| "#{pre}:#{s}" }
294
292
  else
295
293
  [flag]
296
294
  end
@@ -325,14 +323,14 @@ module Squared
325
323
  pat = eval(val)
326
324
  raise SyntaxError unless pat.is_a?(Regexp)
327
325
 
328
- mod.each { |key| re[key] = pat }
326
+ mod.each { |key| regexp[key] = pat }
329
327
  rescue SyntaxError
330
328
  warn "#{self.class}: invalid pattern (#{val})"
331
329
  end
332
330
  when '{'
333
331
  group = val[(n + 2)..-1].chomp!('}')&.split(',')
334
332
  if group
335
- mod.each { |key| ar[key] = group }
333
+ mod.each { |key| enum[key] = group }
336
334
  else
337
335
  warn "#{self.class}: invalid group (#{val})"
338
336
  end
@@ -439,8 +437,8 @@ module Squared
439
437
  else
440
438
  push opt
441
439
  end
442
- elsif !ar.empty? && has.call(ar.keys, key)
443
- group = get.call(ar)
440
+ elsif !enum.empty? && has.call(enum.keys, key)
441
+ group = get.call(enum)
444
442
  if group.include?(val)
445
443
  add shell_option(key, val, force: false, **kwargs)
446
444
  elsif @strict
@@ -448,10 +446,10 @@ module Squared
448
446
  else
449
447
  push opt
450
448
  end
451
- elsif !re.empty? && has.call(re.keys, key)
452
- pat = get.call(re)
449
+ elsif !regexp.empty? && has.call(regexp.keys, key)
450
+ pat = get.call(regexp)
453
451
  if val.match?(pat)
454
- add quote_option(key, val, **kwargs)
452
+ add __send__(kwargs[:merge] ? :basic_option : :quote_option, key, val, **kwargs)
455
453
  elsif @strict
456
454
  clear([opt], hint: "match != /#{pat.source}/")
457
455
  else
@@ -488,7 +486,11 @@ module Squared
488
486
  self
489
487
  end
490
488
 
491
- def append(*args, clear: false, preserve: '"', **kwargs, &blk)
489
+ def append(*args, clear: false, preserve: '"', context: nil, **kwargs, &blk)
490
+ if context
491
+ kwargs[:escape] = context.fetch(:escape, false) unless kwargs.key?(:escape)
492
+ kwargs[:quote] = context.fetch(:quote, false) unless kwargs.key?(:quote)
493
+ end
492
494
  args = clear ? extras.dup.tap { extras.clear } : extras if args.empty?
493
495
  pass = kwargs[:pass] ||= []
494
496
  OptionPartition.append(target, *args, preserve: preserve, **kwargs, &blk)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.6
4
+ version: 0.8.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham