squared 0.5.12 → 0.5.14

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: e711136d645a7a32cb93a09fc7562525a7fd9bc725436c5db5846fa217ac013c
4
- data.tar.gz: 9fe647b2d3021fb50a2d4d4a3983d12422ecbbdbcb92324461382faf5efcb4c7
3
+ metadata.gz: 128dc5736d403e4d43f62cc3a02d1267c7e3f0d96f40f1bc109195ad2b98c723
4
+ data.tar.gz: 7136af7bd97d0fc6613d1923c9b9c15e1788dcffe56811bc052acbe53eccf0f7
5
5
  SHA512:
6
- metadata.gz: 58dee7d115025166ad1326dc11e76f9708ce4af715f1d85b53e2d19799b07aab81118eb82283913a2fee9401b005c0eb9c883f1c820d3b7bfadf9eed2a845013
7
- data.tar.gz: 2bac7d7f87848d78327542d4be5f5535f4d8ed45e818afa27b5a408f921c90363655de8a88dcf4d49d5da44902b5c87c6628cc75b1afe8875eee5bdecc48e3c6
6
+ metadata.gz: 88e6c7b1dd96ce81de2432cc17336bca03c3619e9bb8121983daed0134a5fff63292075a22327eafd824c17962a8ef603feaf66c1dc250657c7740de8d0110cb
7
+ data.tar.gz: 11a2cccda6d069e4b1d7b961fa7c43a7ddbff7562a9754efd26389e26f2f89ee0d232df769e118fd463edb56525d646729eda9c740ec0b774ba577faf3770d89
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.14] - 2025-11-08
4
+
5
+ ### Fixed
6
+
7
+ - See `0.4.28`.
8
+
9
+ ## [0.4.28] - 2025-11-08
10
+
11
+ ### Fixed
12
+
13
+ - Project base method build as arrays parsed unrelated arguments.
14
+ - OptionPartition method arg? does not check after "--" delimiter.
15
+ - OptionPartition did not support duplicate values after "--" delimiter.
16
+ - OptionPartition method opt? did not type check for String.
17
+
18
+ ## [0.5.13] - 2025-11-05
19
+
20
+ ### Fixed
21
+
22
+ - See `0.4.27`.
23
+
24
+ ## [0.4.27] - 2025-11-05
25
+
26
+ ### Changed
27
+
28
+ - OptionPartition does not add quotes when an option flag is detected.
29
+ - Common shell method argument option only parses options with values.
30
+ - Shell options with empty flags are treated as quoted strings.
31
+
32
+ ### Fixed
33
+
34
+ - OptionPartition did not detect flags with middle dashes.
35
+
3
36
  ## [0.5.12] - 2025-10-31
4
37
 
5
38
  ### Changed
@@ -1184,6 +1217,8 @@
1184
1217
 
1185
1218
  - Changelog was created.
1186
1219
 
1220
+ [0.5.14]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.14
1221
+ [0.5.13]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.13
1187
1222
  [0.5.12]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.12
1188
1223
  [0.5.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.11
1189
1224
  [0.5.10]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.10
@@ -1197,6 +1232,8 @@
1197
1232
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1198
1233
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1199
1234
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
1235
+ [0.4.28]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.28
1236
+ [0.4.27]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.27
1200
1237
  [0.4.26]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.26
1201
1238
  [0.4.25]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.25
1202
1239
  [0.4.24]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.24
@@ -255,8 +255,8 @@ module Squared
255
255
  sub.each { |h| s = sub_style(s, **h) }
256
256
  s = "#{b0} #{s} #{b0}"
257
257
  if border
258
- s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/m, styles: border)
259
- s = sub_style(s, pat: /\A(.+)(#{Regexp.escape(b0)})\z/m, styles: border, index: 2)
258
+ s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/om, styles: border)
259
+ s = sub_style(s, pat: /\A(.+)(#{Regexp.escape(b0)})\z/om, styles: border, index: 2)
260
260
  end
261
261
  s
262
262
  end
@@ -6,11 +6,14 @@ require 'shellwords'
6
6
  module Squared
7
7
  module Common
8
8
  module Shell
9
+ QUOTE_VALUE = /\A(["'])(.*)\1\z/m.freeze
10
+ private_constant :QUOTE_VALUE
11
+
9
12
  module_function
10
13
 
11
14
  def shell_escape(val, quote: false, force: false, double: false, option: false, override: false)
12
- if (r = /\A(--?)([^= ]+)((=|\s+)(["'])?(?(5)(.*)\5|(.*)))?\z/m.match(val = val.to_s))
13
- if (data = r[2].match(/\A(["'])(.+)\1\z/))
15
+ if (r = /\A(--?)([^=\s]+)((=|\s+)(["'])?(?(5)(.*)\5|(.*)))?\z/m.match(val = val.to_s))
16
+ if (data = r[2].match(QUOTE_VALUE))
14
17
  double = data[1] == '"'
15
18
  override = true
16
19
  elsif !r[3] || r[6]
@@ -25,9 +28,9 @@ module Squared
25
28
 
26
29
  r[7]
27
30
  end
28
- r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, double: double, force: force, override: override)
29
- elsif option && val =~ /\A([^=]+)=(.+)\z/m
30
- return val if $2.match?(/\A(["']).+\1\z/m)
31
+ r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, force: force, double: double, override: override)
32
+ elsif option && val =~ /\A(-{0,2}[^\[\]=\s-][^\[\]=\s]*)=(.+)\z/m
33
+ return val if $2.match?(QUOTE_VALUE)
31
34
 
32
35
  "#{$1}=%s" % if $2.include?(' ')
33
36
  shell_quote($2, option: false)
@@ -37,7 +40,7 @@ module Squared
37
40
  Shellwords.escape($2)
38
41
  end
39
42
  elsif Rake::Win32.windows?
40
- quote ? shell_quote(val, double: double, force: force) : val
43
+ quote ? shell_quote(val, force: force, double: double) : val
41
44
  elsif val.empty?
42
45
  ''
43
46
  else
@@ -45,48 +48,56 @@ module Squared
45
48
  end
46
49
  end
47
50
 
48
- def shell_quote(val, option: true, force: true, double: false, override: false)
51
+ def shell_quote(val, option: true, force: true, double: false, preserve: true, override: false)
49
52
  val = val.to_s
50
53
  return val if (!force && !val.include?(' ')) || val.empty?
51
54
 
52
- if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/m)
53
- return val
55
+ if option
56
+ pat = /\A(?:-[^\[\]=\s-](?:=|\s+)?|(--)?[^\[\]=\s-][^\[\]=\s]*(?(1)(?:=|\s+)|=))(["']).+\2\z/m
57
+ return val if val.match?(pat)
54
58
  end
59
+ q = ->(s) { s.gsub("'\\\\''", "'") }
60
+ if val =~ QUOTE_VALUE
61
+ return val if $1 == '"' && Rake::Win32.windows? && val.match?(/(?:[#{File::SEPARATOR} ]|\\")/o)
55
62
 
63
+ base = $2 unless preserve
64
+ end
56
65
  if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
57
- "\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
66
+ "\"#{q.call(base || val).gsub(/(?<!\\)"/, '\\"')}\""
58
67
  else
59
- "'#{val.gsub("'", "'\\\\''")}'"
68
+ base ? val : "'#{q.call(val).gsub("'", "'\\\\''")}'"
60
69
  end
61
70
  end
62
71
 
63
72
  def shell_option(flag, val = nil, escape: true, quote: true, option: true, force: true, double: false,
64
73
  merge: false, override: false)
65
74
  flag = flag.to_s
66
- if flag =~ /\A(["'])(.+)\1\z/
75
+ if flag =~ QUOTE_VALUE
67
76
  double = $1 == '"'
68
77
  flag = $2
69
78
  escape = false
70
79
  override = true
71
80
  end
72
- b = if flag[0] == '-'
73
- flag[1] == '-' ? '=' : ' '
74
- elsif flag.size == 1
75
- a = '-'
76
- merge ? '' : ' '
77
- else
78
- a = '--'
79
- '='
80
- end
81
- "#{a}#{flag}#{unless val.nil?
82
- "#{b}#{if escape
83
- shell_escape(val, quote: quote, double: double, override: override)
84
- elsif quote
85
- shell_quote(val, option: option, force: force, double: double, override: override)
86
- else
87
- val
88
- end}"
89
- end}"
81
+ sep = unless flag.empty?
82
+ if flag[0] == '-'
83
+ flag[1] == '-' ? '=' : ' '
84
+ elsif flag.size == 1
85
+ pre = '-'
86
+ merge ? '' : ' '
87
+ else
88
+ pre = '--'
89
+ '='
90
+ end
91
+ end
92
+ "#{pre}#{flag}#{unless val.nil?
93
+ "#{sep}#{if escape
94
+ shell_escape(val, quote: quote, double: double, override: override)
95
+ elsif quote
96
+ shell_quote(val, option: option, force: force, double: double, override: override)
97
+ else
98
+ val
99
+ end}"
100
+ end}"
90
101
  end
91
102
 
92
103
  def shell_split(val, join: nil, **kwargs)
@@ -98,8 +109,8 @@ module Squared
98
109
 
99
110
  def shell_bin(name, env: true)
100
111
  key = name.upcase
101
- shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name, option: false, force: false,
102
- double: true)
112
+ shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
113
+ option: false, force: false, double: true)
103
114
  end
104
115
 
105
116
  def line_width(lines)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.5.12'
4
+ VERSION = '0.5.14'
5
5
  end
@@ -525,31 +525,31 @@ module Squared
525
525
  cmd = cmd.join(' && ')
526
526
  else
527
527
  cmd, opts, var, flags, extra = args
528
- end
529
- if cmd
530
- return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
528
+ if cmd
529
+ return run_b(cmd, sync: sync, from: from) if cmd.is_a?(Proc) || cmd.is_a?(Method)
531
530
 
532
- cmd = as_get(cmd, from)
533
- opts = compose(opts, script: false) if opts && respond_to?(:compose)
534
- flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
535
- case opts
536
- when Hash
537
- cmd = Array(cmd).append(flags)
538
- .concat(append_hash(opts, target: [], build: true))
539
- .compact
540
- .join(' ')
541
- when Enumerable
542
- cmd = Array(cmd).concat(opts.to_a)
543
- cmd.map! { |val| "#{val} #{flags}" } if flags
544
- cmd = cmd.join(' && ')
531
+ cmd = as_get(cmd, from)
532
+ opts = compose(opts, script: false) if opts && respond_to?(:compose)
533
+ flags = append_hash(flags, target: []).join(' ') if flags.is_a?(Hash)
534
+ case opts
535
+ when Hash
536
+ cmd = Array(cmd).append(flags)
537
+ .concat(append_hash(opts, target: [], build: true))
538
+ .compact
539
+ .join(' ')
540
+ when Enumerable
541
+ cmd = Array(cmd).concat(opts.to_a)
542
+ cmd.map! { |val| "#{val} #{flags}" } if flags
543
+ cmd = cmd.join(' && ')
544
+ else
545
+ cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
546
+ end
545
547
  else
546
- cmd = [cmd, flags, opts].compact.join(' ') if opts || flags
547
- end
548
- else
549
- return unless (opts || extra) && respond_to?(:compose)
548
+ return unless (opts || extra) && respond_to?(:compose)
550
549
 
551
- cmd = compose(as_get(opts, from), flags, script: true, args: extra, from: from)
552
- from = :script if from == :run && script?
550
+ cmd = compose(as_get(opts, from), flags, script: true, args: extra, from: from)
551
+ from = :script if from == :run && script?
552
+ end
553
553
  end
554
554
  run(cmd, var, sync: sync, from: from, banner: banner)
555
555
  end
@@ -568,12 +568,12 @@ module Squared
568
568
  if proj.respond_to?(meth.to_sym)
569
569
  begin
570
570
  proj.__send__(meth, sync: sync)
571
- next
572
571
  rescue StandardError => e
573
572
  on_error(e, :prereqs, exception: true)
574
573
  end
574
+ else
575
+ print_error(name, "method: #{meth}", subject: 'prereqs', hint: 'undefined')
575
576
  end
576
- print_error(name, 'method not found', subject: 'prereqs', hint: meth)
577
577
  end
578
578
  elsif proj.build?
579
579
  proj.build(sync: sync)
@@ -739,7 +739,7 @@ module Squared
739
739
  end
740
740
  break uri = url if data
741
741
  end
742
- unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
742
+ unless data && (ext ||= URI.decode_www_form_component(URI.parse(uri).path[/\.([\w%]+)(?:\?|\z)/, 1]))
743
743
  raise_error("no content#{data ? ' type' : ''}", hint: uri)
744
744
  end
745
745
  end
@@ -1307,7 +1307,7 @@ module Squared
1307
1307
  end
1308
1308
  ret = JoinSet.new(cmd.flatten(1))
1309
1309
  if options && (val = env("#{prefix.upcase}_OPTIONS"))
1310
- split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^ =]+)[ =].+\z/m) }
1310
+ split_escape(val).each { |opt| ret.last(fill_option(opt), /\A(--?[^\[\]=\s-][^\[\]=\s]*)[=\s].+\z/m) }
1311
1311
  end
1312
1312
  main ? @session = ret : ret
1313
1313
  end
@@ -1593,11 +1593,12 @@ module Squared
1593
1593
  **kwargs)
1594
1594
  return if list.empty?
1595
1595
 
1596
+ kwargs[:ignore] = false if no && !kwargs.key?(:ignore)
1596
1597
  [].tap do |ret|
1597
1598
  list.flatten.each do |flag|
1598
1599
  next unless (val = option(flag, target: target, **kwargs))
1599
1600
 
1600
- if val == '0' && no
1601
+ if no && val == '0'
1601
1602
  flag = "no-#{flag}"
1602
1603
  val = nil
1603
1604
  end
@@ -10,9 +10,9 @@ module Squared
10
10
  include Common::Shell
11
11
  extend Forwardable
12
12
 
13
- OPT_NAME = /\A(?:(--)|-)((?(1)[A-Za-z\d]+|[A-Za-z\d]))\z/
14
- OPT_VALUE = /\A-{0,2}([^= ]+)(?: *= *| +)(.+)\z/
15
- OPT_SINGLE = /\A-([A-Za-z\d])(.+)\z/
13
+ OPT_NAME = /\A(?:(--)|-)((?(1)[^\[\]=\s-][^\[\]=\s]*|[^\[\]=\s-]))\z/
14
+ OPT_VALUE = /\A-{0,2}([^\[\]=\s-][^\[\]=\s]*)(?:=|\s+)(\S.*)\z/
15
+ OPT_SINGLE = /\A-([^\[\]=\s-])(.+)\z/
16
16
  private_constant :OPT_NAME, :OPT_VALUE, :OPT_SINGLE
17
17
 
18
18
  class << self
@@ -27,11 +27,13 @@ module Squared
27
27
  target << '--' if delim && !target.include?('--')
28
28
  if strip
29
29
  pat, s = Array(strip)
30
- ret.map! { |val| val.gsub(pat, s || '') }
30
+ ret.map! { |val| val.is_a?(String) ? val.gsub(pat, s || '') : val }
31
31
  end
32
32
  if escape || quote
33
33
  ret.map! do |val|
34
- if escape
34
+ if opt?(val)
35
+ val
36
+ elsif escape
35
37
  shell_escape(val, quote: quote, double: double)
36
38
  else
37
39
  shell_quote(val, force: force, double: double)
@@ -87,8 +89,17 @@ module Squared
87
89
  def arg?(target, *args, value: false, **)
88
90
  r, s = args.partition { |val| val.is_a?(Regexp) }
89
91
  r << matchopts(s, value) unless s.empty?
90
- s = target.to_a.compact
91
- r.any? { |pat| s.any?(pat) }
92
+ a = target.to_a
93
+ if (n = a.index('--'))
94
+ a = a[0..n]
95
+ end
96
+ r.any? { |pat| a.any?(pat) }
97
+ end
98
+
99
+ def opt?(val)
100
+ return false unless val.is_a?(String)
101
+
102
+ val.start_with?('-') && (OPT_NAME.match?(val) || OPT_VALUE.match?(val) || OPT_SINGLE.match?(val))
92
103
  end
93
104
 
94
105
  def pattern?(val)
@@ -415,7 +426,8 @@ module Squared
415
426
  end
416
427
 
417
428
  def add_quote(*args, **kwargs)
418
- merge(args.compact.map! { |val| val == '--' ? val : shell_quote(val, **kwargs) })
429
+ args.compact!
430
+ merge(args.map! { |val| val == '--' || OptionPartition.opt?(val) ? val : shell_quote(val, **kwargs) })
419
431
  self
420
432
  end
421
433
 
@@ -523,11 +535,16 @@ module Squared
523
535
  super[/[^:]+\z/, 0]
524
536
  end
525
537
 
526
- attr_reader :delim
538
+ alias to_ary to_a
527
539
 
528
- def initialize(data = [], delim: ' ')
529
- super(data.compact)
540
+ attr_reader :delim, :extras
541
+
542
+ def initialize(data = [], delim: ' ', partition: '--', uniq: /\A--?[^\[\]=\s-][^\[\]=\s]*(?:=|\s+)\S/)
530
543
  @delim = delim
544
+ @partition = partition
545
+ @uniq = uniq
546
+ @extras = []
547
+ super(data.compact)
531
548
  end
532
549
 
533
550
  def last(val, pat)
@@ -536,7 +553,7 @@ module Squared
536
553
  end
537
554
 
538
555
  def pass(&blk)
539
- ret = to_a.map!(&:to_s).reject(&:empty?)
556
+ ret = to_ary.map!(&:to_s).reject(&:empty?)
540
557
  @last&.each do |val, pat, key|
541
558
  i = []
542
559
  j = nil
@@ -557,6 +574,7 @@ module Squared
557
574
  end
558
575
  ret[i.last] = val
559
576
  end
577
+ ret.concat(extras.map(&:to_s).reject(&:empty?)) unless extras.empty?
560
578
  return ret unless block_given?
561
579
 
562
580
  ret.reject(&blk)
@@ -578,18 +596,73 @@ module Squared
578
596
 
579
597
  def temp(*args, &blk)
580
598
  args.compact!
581
- ret = pass(&blk)
582
- ret = Set.new(ret.concat(args)).to_a unless args.empty?
583
- ret.join(@delim)
599
+ pass(&blk)
600
+ .concat(args)
601
+ .join(@delim)
584
602
  end
585
603
 
586
604
  def done
587
605
  to_s.tap { clear }
588
606
  end
589
607
 
608
+ def merge(enum)
609
+ if !extras.empty?
610
+ extras.concat(enum.to_a)
611
+ self
612
+ elsif (n = enum.find_index { |val| extras?(val) })
613
+ data = enum.to_a
614
+ @extras = if n == 0
615
+ data
616
+ else
617
+ super(data[0...n])
618
+ data[n..-1]
619
+ end
620
+ self
621
+ else
622
+ super
623
+ end
624
+ end
625
+
626
+ def <<(obj)
627
+ extras!(obj) || super
628
+ end
629
+
630
+ def add?(obj)
631
+ extras!(obj) || super
632
+ end
633
+
634
+ def to_a
635
+ pass
636
+ end
637
+
590
638
  def to_s
591
639
  pass.join(@delim)
592
640
  end
641
+
642
+ def to_enum(*args)
643
+ pass.to_enum(*args)
644
+ end
645
+
646
+ def to_json(*args)
647
+ pass.to_json(*args)
648
+ end
649
+
650
+ def to_yaml(*args)
651
+ pass.to_yaml(*args)
652
+ end
653
+
654
+ private
655
+
656
+ def extras!(obj)
657
+ return if extras.empty? && !extras?(obj)
658
+
659
+ extras << obj unless !extras.include?(@partition) && include?(obj) && @uniq.match?(obj.to_s)
660
+ self
661
+ end
662
+
663
+ def extras?(obj)
664
+ obj == @partition || (include?(obj) && !@uniq.match?(obj.to_s))
665
+ end
593
666
  end
594
667
  end
595
668
  end
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.5.12
4
+ version: 0.5.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
@@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  requirements: []
127
- rubygems_version: 3.7.2
127
+ rubygems_version: 3.6.9
128
128
  specification_version: 4
129
129
  summary: Rake task generator for managing multi-language workspaces.
130
130
  test_files: []