squared 0.6.0 → 0.6.1

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: ed078210213186745643650b4a73f7f376b5aba7033643c850b48d555c198501
4
- data.tar.gz: d4d8c0e6308f3bdc3aca66891980259ad52ce11f3a53112c7a22ae4de9e31f40
3
+ metadata.gz: 6a3b6e4109938a7ee4ddc9d778c798ad412cd2941a6b887cc62f9bd39779b4ad
4
+ data.tar.gz: 6912a295b0e64223d3130d8793bce44e954c0903fd74b65eb0f420726a41f82d
5
5
  SHA512:
6
- metadata.gz: fcf308f894ee49566103575561b74459afc1aa7e03af8d5c5397c7bb7432dfce996cbb1291f4f81af792d5b1dd8ed6a9075ce7b2fab6f41dca0c56431e38b78c
7
- data.tar.gz: 19f25542363b33fa567cbfcb0267c79fbc55a313ce0fba8ab25ec17dd43f276b004b00304e8bfe38dba1338a2e554170a8f1535d1bdc5981407fae6e9bff2bf8
6
+ metadata.gz: 137851028240806e553b125ec638df63cb20c25b6f73328a1c08f7af7603d666a1b61ff04dde1da27995a13d0bf2a6c28e644d20b6e8beb6e26fba061191d908
7
+ data.tar.gz: 21c7fce48d7638aa90b9c0ef40282b30557205065f6117e0602248771cee9e628910f90125295dac4a831615adda43296112809b437f31b4db0aa9d3f03de437
data/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.1] - 2025-11-05
4
+
5
+ ### Added
6
+
7
+ - Ruby method rbs supports stored command options.
8
+ - Ruby command rbs with Steep target was created.
9
+ - Common shell defined String instance method stripquote.
10
+
11
+ ### Fixed
12
+
13
+ - Project base method run argument series was backwards.
14
+ - Project base choice range did not detect empty list result.
15
+
16
+ ## [0.5.13] - 2025-11-05
17
+
18
+ ### Fixed
19
+
20
+ - See `0.4.27`.
21
+
22
+ ## [0.4.27] - 2025-11-05
23
+
24
+ ### Changed
25
+
26
+ - OptionPartition does not add quotes when an option flag is detected.
27
+ - Common shell method argument option only parses options with values.
28
+ - Shell options with empty flags are treated as quoted strings.
29
+
30
+ ### Fixed
31
+
32
+ - OptionPartition did not detect flags with middle dashes.
33
+
3
34
  ## [0.6.0] - 2025-10-31
4
35
 
5
36
  ### Added
@@ -1277,7 +1308,9 @@
1277
1308
 
1278
1309
  - Changelog was created.
1279
1310
 
1311
+ [0.6.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.1
1280
1312
  [0.6.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.0
1313
+ [0.5.13]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.13
1281
1314
  [0.5.12]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.12
1282
1315
  [0.5.11]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.11
1283
1316
  [0.5.10]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.10
@@ -1291,6 +1324,7 @@
1291
1324
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1292
1325
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1293
1326
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
1327
+ [0.4.27]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.27
1294
1328
  [0.4.26]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.26
1295
1329
  [0.4.25]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.25
1296
1330
  [0.4.24]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.24
@@ -6,11 +6,16 @@ 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
+
12
+ String.define_method(:stripquote) { sub(QUOTE_VALUE, '\2') }
13
+
9
14
  module_function
10
15
 
11
16
  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/))
17
+ if (r = /\A(--?)([^=\s]+)((=|\s+)(["'])?(?(5)(.*)\5|(.*)))?\z/m.match(val = val.to_s))
18
+ if (data = r[2].match(QUOTE_VALUE))
14
19
  double = data[1] == '"'
15
20
  override = true
16
21
  elsif !r[3] || r[6]
@@ -25,9 +30,9 @@ module Squared
25
30
 
26
31
  r[7]
27
32
  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)
33
+ r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, force: force, double: double, override: override)
34
+ elsif option && val =~ /\A(-{0,2}[^\[\]=\s-][^\[\]=\s]*)=(.+)\z/m
35
+ return val if $2.match?(QUOTE_VALUE)
31
36
 
32
37
  "#{$1}=%s" % if $2.include?(' ')
33
38
  shell_quote($2, option: false)
@@ -37,7 +42,7 @@ module Squared
37
42
  Shellwords.escape($2)
38
43
  end
39
44
  elsif Rake::Win32.windows?
40
- quote ? shell_quote(val, double: double, force: force) : val
45
+ quote ? shell_quote(val, force: force, double: double) : val
41
46
  elsif val.empty?
42
47
  ''
43
48
  else
@@ -45,46 +50,56 @@ module Squared
45
50
  end
46
51
  end
47
52
 
48
- def shell_quote(val, option: true, force: true, double: false, override: false)
53
+ def shell_quote(val, option: true, force: true, double: false, preserve: true, override: false)
49
54
  val = val.to_s
50
55
  return val if (!force && !val.include?(' ')) || val.empty?
51
56
 
52
- if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/mo)
53
- val
54
- elsif double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
55
- "\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
57
+ if option
58
+ pat = /\A(?:-[^\[\]=\s-](?:=|\s+)?|(--)?[^\[\]=\s-][^\[\]=\s]*(?(1)(?:=|\s+)|=))(["']).+\2\z/m
59
+ return val if val.match?(pat)
60
+ end
61
+ q = ->(s) { s.gsub("'\\\\''", "'") }
62
+ if val =~ QUOTE_VALUE
63
+ return val if $1 == '"' && Rake::Win32.windows? && val.match?(/(?:[#{File::SEPARATOR} ]|\\")/o)
64
+
65
+ base = $2 unless preserve
66
+ end
67
+ if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
68
+ "\"#{q.call(base || val).gsub(/(?<!\\)"/, '\\"')}\""
56
69
  else
57
- "'#{val.gsub("'", "'\\\\''")}'"
70
+ base ? val : "'#{q.call(val).gsub("'", "'\\\\''")}'"
58
71
  end
59
72
  end
60
73
 
61
74
  def shell_option(flag, val = nil, sep: '=', escape: true, quote: true, force: true, double: false, merge: false,
62
75
  override: false)
63
76
  flag = flag.to_s
64
- if flag =~ /\A(["'])(.+)\1\z/
77
+ if flag =~ QUOTE_VALUE
65
78
  double = $1 == '"'
66
79
  flag = $2
67
80
  escape = false
68
81
  override = true
69
82
  end
70
- b = if flag[0] == '-'
71
- flag[1] == '-' ? sep : ' '
72
- elsif flag.size == 1
73
- a = '-'
74
- merge ? '' : ' '
75
- else
76
- a = '--'
77
- sep
78
- end
79
- "#{a}#{flag}#{unless val.nil?
80
- "#{b}#{if escape
81
- shell_escape(val, quote: quote, double: double, override: override)
82
- elsif quote
83
- shell_quote(val, option: false, force: force, double: double, override: override)
84
- else
85
- val
86
- end}"
87
- end}"
83
+ sep = unless flag.empty?
84
+ if flag[0] == '-'
85
+ flag[1] == '-' ? sep : ' '
86
+ elsif flag.size == 1
87
+ pre = '-'
88
+ merge ? '' : ' '
89
+ else
90
+ pre = '--'
91
+ sep
92
+ end
93
+ end
94
+ "#{pre}#{flag}#{unless val.nil?
95
+ "#{sep}#{if escape
96
+ shell_escape(val, quote: quote, double: double, override: override)
97
+ elsif quote
98
+ shell_quote(val, option: false, force: force, double: double, override: override)
99
+ else
100
+ val
101
+ end}"
102
+ end}"
88
103
  end
89
104
 
90
105
  def shell_split(val, join: nil, **kwargs)
@@ -131,8 +146,8 @@ module Squared
131
146
 
132
147
  def shell_bin(name, env: true)
133
148
  key = name.upcase
134
- shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name, option: false, force: false,
135
- double: true)
149
+ shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
150
+ option: false, force: false, double: true)
136
151
  end
137
152
 
138
153
  def line_width(lines)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.6.0'
4
+ VERSION = '0.6.1'
5
5
  end
@@ -769,7 +769,7 @@ module Squared
769
769
  end
770
770
  break uri = url if data
771
771
  end
772
- unless data && (ext ||= URI.parse(uri).path[/\.(\w+)(?:\?|\z)/, 1])
772
+ unless data && (ext ||= URI.decode_www_form_component(URI.parse(uri).path[/\.([\w%]+)(?:\?|\z)/, 1]))
773
773
  raise_error(data ? TypeError : RuntimeError, "no content#{data ? ' type' : ''}", hint: uri)
774
774
  end
775
775
  end
@@ -913,7 +913,7 @@ module Squared
913
913
  end
914
914
 
915
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, **)
916
+ interactive: nil, hint: nil, series: false, **)
917
917
  return print_error('no command session started', subject: project, hint: from, pass: true) unless cmd
918
918
 
919
919
  cmd = cmd.target if cmd.is_a?(OptionPartition)
@@ -1468,9 +1468,9 @@ module Squared
1468
1468
  printsucc
1469
1469
  end
1470
1470
 
1471
- def print_item(*val, series: true)
1471
+ def print_item(*val, series: false)
1472
1472
  puts unless printfirst?
1473
- printsucc if series
1473
+ printsucc unless series
1474
1474
  puts val unless val.empty? || (val.size == 1 && !val.first)
1475
1475
  end
1476
1476
 
@@ -1841,7 +1841,7 @@ module Squared
1841
1841
  force: true, **kwargs)
1842
1842
  puts unless series || printfirst?
1843
1843
  ret = choice(msg, list, multiple: multiple, force: force, **kwargs).tap do |val|
1844
- next unless val.to_s.empty?
1844
+ next unless val.empty?
1845
1845
 
1846
1846
  exit 1 if force
1847
1847
  return nil
@@ -1853,7 +1853,7 @@ module Squared
1853
1853
  ret = ret.first unless multiple
1854
1854
  end
1855
1855
  if accept
1856
- hint = Array(ret).map { |val| sub_style(val, styles: theme[:inline]) }.join(', ')
1856
+ hint = Array(ret).map { |val| sub_style(val.to_s, styles: theme[:inline]) }.join(', ')
1857
1857
  accept = Array(accept).map { |val| Array(val) }
1858
1858
  ret = Array(ret) if accept.any? { |val| val[1] == true }
1859
1859
  loop do
@@ -462,15 +462,18 @@ module Squared
462
462
  when :add, :sign
463
463
  format_desc action, flag, 'name,message?,commit?,remote?'
464
464
  task flag, [:name, :message, :commit, :remote] do |_, args|
465
- if (name = args.name)
466
- message = args.message
467
- commit = commithead args.commit
468
- remote = args.remote
469
- else
470
- commit, name, message = choice_commit(reflog: false, series: true,
471
- values: [['Enter tag name', true], 'Enter message'])
472
- remote = choice_remote
473
- end
465
+ remote = if (name = args.name)
466
+ message = args.message
467
+ commit = commithead args.commit
468
+ args.remote
469
+ else
470
+ commit, name, message = choice_commit(reflog: false, series: true,
471
+ values: [
472
+ ['Enter tag name', true],
473
+ 'Enter message'
474
+ ])
475
+ choice_remote
476
+ end
474
477
  tag(flag, refs: [name], message: message, commit: commit, remote: remote).tap do |ret|
475
478
  success?(ret, !remote)
476
479
  end
@@ -996,7 +999,7 @@ module Squared
996
999
  end
997
1000
  end
998
1001
  append_pull(opts, OPT_GIT[:pull] + OPT_GIT[:fetch][:pull],
999
- no: OPT_GIT[:no][:pull] + OPT_GIT[:no][:fetch][:pull], remote: remote, flag: flag, from: :pull)
1002
+ flag: flag, from: :pull, remote: remote, no: OPT_GIT[:no][:pull] + OPT_GIT[:no][:fetch][:pull])
1000
1003
  source(sync: sync, sub: if stdout?
1001
1004
  [
1002
1005
  opt_style(color(:red), /^(.+)(\|\s+\d+\s+)([^-]*)(-+)(.*)$/, 4),
@@ -1044,8 +1047,8 @@ module Squared
1044
1047
  def fetch(flag = nil, opts = [], sync: invoked_sync?('fetch', flag), remote: nil)
1045
1048
  opts = git_session('fetch', opts: opts).last
1046
1049
  opts << 'all' if flag == :all || option('all')
1047
- append_pull(opts, collect_hash(OPT_GIT[:fetch]), no: collect_hash(OPT_GIT[:no][:fetch]),
1048
- remote: remote, flag: flag, from: :fetch)
1050
+ append_pull(opts, collect_hash(OPT_GIT[:fetch]), flag: flag, from: :fetch, remote: remote,
1051
+ no: collect_hash(OPT_GIT[:no][:fetch]))
1049
1052
  source(sync: sync, **threadargs)
1050
1053
  end
1051
1054
 
@@ -1427,7 +1430,7 @@ module Squared
1427
1430
  return ret
1428
1431
  end
1429
1432
  message ||= messageopt
1430
- if !message && !amend
1433
+ unless message || amend
1431
1434
  return if pass
1432
1435
 
1433
1436
  message = readline('Enter message', force: true)
@@ -1638,10 +1641,10 @@ module Squared
1638
1641
  case flag
1639
1642
  when :create
1640
1643
  cmd << quote_option(branch.delete_prefix!('^') ? 'C' : 'c', branch)
1641
- cmd << case (track ||= option('track', ignore: false))
1642
- when 'n', 'N', '0', 'false'
1644
+ cmd << case (track ||= option('track', ignore: false))&.downcase
1645
+ when 'n', '0', 'false'
1643
1646
  '--no-track'
1644
- when 'y', 'Y', '1', 'true'
1647
+ when 'y', '1', 'true'
1645
1648
  '--track'
1646
1649
  when 'direct', 'inherit'
1647
1650
  basic_option 'track', track
@@ -1844,9 +1847,10 @@ module Squared
1844
1847
  end
1845
1848
  if from.nil? && (from = cmd.drop(1).find { |val| val.match?(/\A[a-z]{1,2}[a-z-]*\z/) })
1846
1849
  from = :"git:#{from}"
1850
+ elsif from == false
1851
+ from = nil
1847
1852
  end
1848
1853
  banner &&= cmd.temp { |val| val.start_with?(/--(?:work-tree|git-dir)/) } if cmd.respond_to?(:temp)
1849
- from = nil if from == false
1850
1854
  end
1851
1855
  cmd = session_done cmd
1852
1856
  log&.info cmd
@@ -1969,7 +1973,7 @@ module Squared
1969
1973
  ret = {}
1970
1974
  status_data(*args).each do |file,|
1971
1975
  next if !glob.empty? && glob.none? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1972
- next if !pass.empty? && pass.any? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1976
+ next if pass.any? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
1973
1977
 
1974
1978
  ret[file] = algorithm.hexdigest(File.read(basepath(file)))
1975
1979
  end
@@ -1986,7 +1990,7 @@ module Squared
1986
1990
  end
1987
1991
  end
1988
1992
 
1989
- def append_pull(opts, list, target: @session, flag: nil, no: nil, remote: nil, from: nil)
1993
+ def append_pull(opts, list, flag:, from:, target: @session, no: nil, remote: nil)
1990
1994
  target << '--force' if option('f', 'force', target: target)
1991
1995
  append_submodules(target: target, from: from)
1992
1996
  return if !remote && opts.empty?
@@ -31,8 +31,8 @@ module Squared
31
31
  root-user-action=b t|target=p upgrade-strategy=b].freeze,
32
32
  install_a: %w[ignore-requires-python no-index pre extra-index-url=q f|find-links=q i|index-url=q no-binary=q
33
33
  only-binary=q].freeze,
34
- install_b: %w[check-build-dependencies no-build-isolation no-clean no-deps prefer-binary require-hashes
35
- use-pep517 c|constraint=p group=q progress-bar=b r|requirement=p src=p].freeze,
34
+ install_b: %w[build-constraint check-build-dependencies no-build-isolation no-clean no-deps prefer-binary
35
+ require-hashes use-pep517 c|constraint=p group=q progress-bar=b r|requirement=p src=p].freeze,
36
36
  install_c: %w[C|config-settings=q e|editable=v].freeze,
37
37
  hash: %w[a|algorithm].freeze,
38
38
  list: %w[e|editable exclude-editable include-editable l|local no-index not-required o|outdated pre u|uptodate
@@ -20,7 +20,8 @@ module Squared
20
20
  inspect multiline no-pager noautocomplete nocolorize noecho noecho-on-assignment noinspect
21
21
  nomultiline noprompt noscript nosingleline noverbose regexp-completor sample-book-mode script
22
22
  simple-prompt single-irb singleline tracer truncate-echo-on-assignment type-completor verbose
23
- back-trace-limit=i context-mode=i prompt=b prompt-mode=b].freeze
23
+ back-trace-limit=i context-mode=i prompt=b prompt-mode=b].freeze,
24
+ rbs: %w[I=pm r=bm no-stdlib no-collection collection=p log-level=b log-output=p repo=p].freeze
24
25
  }.freeze
25
26
  OPT_BUNDLE = {
26
27
  common: %w[no-color V|verbose r|retry=i].freeze,
@@ -124,6 +125,7 @@ module Squared
124
125
  ruby: %w[I disable enable dump r s].freeze,
125
126
  rake: %w[I libdir r require].freeze,
126
127
  irb: %w[I r].freeze,
128
+ rbs: %w[I r repo].freeze,
127
129
  gem: {
128
130
  contents: %w[s spec-dir].freeze,
129
131
  dependency: %w[s source].freeze,
@@ -159,11 +161,12 @@ module Squared
159
161
  'ruby' => %i[file script version].freeze,
160
162
  'gem' => %i[install uninstall outdated update pristine build push exec command].freeze,
161
163
  'bundle' => %i[install update cache exec config reinstall command].freeze,
164
+ 'rbs' => nil,
162
165
  'rake' => nil,
163
166
  'irb' => nil
164
167
  })
165
168
 
166
- def initialize(*, autodetect: false, gemspec: nil, asdf: 'ruby', **kwargs)
169
+ def initialize(*, autodetect: false, gemspec: nil, steep: 'Steepfile', asdf: 'ruby', **kwargs)
167
170
  super
168
171
  if @pass.include?(Ruby.ref)
169
172
  initialize_ref Ruby.ref
@@ -179,6 +182,7 @@ module Squared
179
182
  elsif gemspec
180
183
  basepath(gemspec.include?('.') ? gemspec : "#{gemspec}.gemspec")
181
184
  end
185
+ @steepfile = basepath(steep).yield_self { |file| file if file.exist? }
182
186
  return unless rakefile && @output[0].nil? && @copy.nil? && !version && !@autodetect
183
187
 
184
188
  begin
@@ -250,6 +254,72 @@ module Squared
250
254
  name = gemname if gemlib.any? { |file| exist?(file, "#{gemname}.rb") }
251
255
  irb(*args, opts: opts, name: name, verbose: false)
252
256
  end
257
+ when 'rbs'
258
+ next unless @steepfile
259
+
260
+ data = {}
261
+ target = nil
262
+ File.foreach(@steepfile) do |line|
263
+ if line =~ /^\s*target(?:\s+|\(\s*)(?::(\S+)|(["'])(.+)\2)/
264
+ target = [[], []]
265
+ data[$1 || $3.gsub(/[: ]/, '-')] = target
266
+ next
267
+ end
268
+ next unless target && line =~ /^\s*(check|signature)\s+(["'])(.+)\2/
269
+
270
+ target[$1 == 'check' ? 1 : 0] << $3
271
+ end
272
+ next if data.empty?
273
+
274
+ namespace 'rbs' do
275
+ data.each do |key, item|
276
+ sig, lib = item
277
+ next if sig.empty? || lib.empty?
278
+
279
+ format_desc action, key, 'sig?,path*'
280
+ task key do |_, args|
281
+ args = args.to_a
282
+ list = []
283
+ lib.each do |val|
284
+ val = File.join(val, '**/*.rb') unless val.include?('*') || val.end_with?('.rb')
285
+ list.concat(Dir.glob(val, base: path))
286
+ end
287
+ if args.empty?
288
+ files = choice_index('Select files', list, multiple: true, force: true, series: true,
289
+ accept: [accept_y('Generate?')])
290
+ else
291
+ files = []
292
+ args.each do |val|
293
+ if val.include?('*')
294
+ files.concat(Dir.glob(val, base: path))
295
+ elsif !(file = basepath(val)).exist?
296
+ print_error(val, hint: 'not found')
297
+ elsif file.directory?
298
+ files.concat(file.glob('**/*.rb'))
299
+ else
300
+ files << val
301
+ end
302
+ end
303
+ list.map! { |val| basepath(val).to_s }
304
+ files = files.select { |val| list.include?(basepath(val).to_s) }
305
+ if files.empty?
306
+ print_error('steep', 'no files matched', hint: "#{key}:check")
307
+ exit 1
308
+ end
309
+ files.uniq!
310
+ end
311
+ sig = if (n = sig.index(args.first))
312
+ args.shift
313
+ sig[n]
314
+ elsif sig.size > 1
315
+ choice_index('Select a sig', sig, force: true, series: true)
316
+ else
317
+ sig.first
318
+ end
319
+ rbs(:prototype, sig, *files)
320
+ end
321
+ end
322
+ end
253
323
  end
254
324
  else
255
325
  namespace action do
@@ -1161,6 +1231,56 @@ module Squared
1161
1231
  run(banner: false, from: :irb)
1162
1232
  end
1163
1233
 
1234
+ def rbs(flag, *args, banner: verbose?, with: nil, pass: nil, **kwargs)
1235
+ case pass
1236
+ when NilClass
1237
+ pass = PASS_RUBY[:rbs]
1238
+ when Array
1239
+ pass += PASS_RUBY[:rbs]
1240
+ end
1241
+ opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1242
+ cmd, opts = rbs_session(opts: opts)
1243
+ op = OptionPartition.new(opts, [], cmd << flag, project: self)
1244
+ case flag
1245
+ when :prototype
1246
+ sig = args.shift
1247
+ y = option('y', ignore: false)
1248
+ i = 1
1249
+ args.map { |val| basepath(val).relative_path_from(path) }.each do |file|
1250
+ dir = basepath sig, file.dirname
1251
+ dir.mkpath unless dir.exist?
1252
+ base = file.basename.to_s
1253
+ rbs = dir.join(base.stripext + '.rbs')
1254
+ status = if rbs.exist?
1255
+ case y
1256
+ when '0', 'false'
1257
+ 'ignored'
1258
+ else
1259
+ next unless y || confirm_basic('Overwrite?', rbs, 'N')
1260
+
1261
+ 'overwrite'
1262
+ end
1263
+ end
1264
+ unless status == 'ignored'
1265
+ ret = run(op.target.temp(File.extname(base) == '.rbi' ? 'rbi' : 'rb', file, '>', rbs), banner: false,
1266
+ series: true)
1267
+ if !ret
1268
+ status = 'FAIL'
1269
+ elsif File.empty?(rbs)
1270
+ status = 'empty'
1271
+ end
1272
+ end
1273
+ puts "#{i.to_s.rjust(2)}. #{rbs.relative_path_from(path)}".subhint(status)
1274
+ i += 1
1275
+ end
1276
+ else
1277
+ op.clear
1278
+ .append(*args)
1279
+ print_run(op, banner, **kwargs)
1280
+ run(banner: false, from: :"rbs:#{flag}")
1281
+ end
1282
+ end
1283
+
1164
1284
  def gemspec
1165
1285
  return @gemspec || nil unless @gemspec.nil?
1166
1286
 
@@ -1285,6 +1405,13 @@ module Squared
1285
1405
  session('rake', *preopts, *cmd, **kwargs)
1286
1406
  end
1287
1407
 
1408
+ def rbs_session(*cmd, opts: nil)
1409
+ return session('rbs', *cmd) unless opts
1410
+
1411
+ op = OptionPartition.new(opts, OPT_RUBY[:rbs], project: self)
1412
+ [session('rbs', *op.to_a, *cmd), op.extras]
1413
+ end
1414
+
1288
1415
  def gem_output(*cmd, **kwargs)
1289
1416
  session_output('gem', *cmd, **kwargs)
1290
1417
  end
@@ -1320,7 +1447,7 @@ module Squared
1320
1447
  end
1321
1448
 
1322
1449
  def config_set(key, *val)
1323
- run(bundle_output('config set', key, *val), banner: false, series: false)
1450
+ run(bundle_output('config set', key, *val), banner: false, series: true)
1324
1451
  end
1325
1452
 
1326
1453
  def preopts
@@ -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*|\s+)(.+)\z/
15
+ OPT_SINGLE = /\A-([^\[\]=\s-])(.+)\z/
16
16
  private_constant :OPT_NAME, :OPT_VALUE, :OPT_SINGLE
17
17
 
18
18
  class << self
@@ -47,7 +47,9 @@ module Squared
47
47
  end
48
48
  if escape || quote
49
49
  ret.map! do |val|
50
- if escape
50
+ if opt?(val)
51
+ val
52
+ elsif escape
51
53
  shell_escape(val, quote: quote, double: double)
52
54
  else
53
55
  shell_quote(val, force: force, double: double)
@@ -121,6 +123,10 @@ module Squared
121
123
  r.any? { |pat| s.any?(pat) }
122
124
  end
123
125
 
126
+ def opt?(val)
127
+ val.start_with?('-') && (OPT_NAME.match?(val) || OPT_VALUE.match?(val) || OPT_SINGLE.match?(val))
128
+ end
129
+
124
130
  def pattern?(val)
125
131
  val.match?(/(?:\A\^|\$\z)/) || val.match?(/(?:\.[*+]|\(\?:|\\[dsw]|\[.+\]|\{\d+,?\d*\})/)
126
132
  end
@@ -442,7 +448,7 @@ module Squared
442
448
 
443
449
  def add_path(*args, force: true, double: false, **kwargs)
444
450
  if args.empty?
445
- args = select { |s| s.is_a?(String) }
451
+ args = select { |val| val.is_a?(String) }
446
452
  args.map! { |val| path + val } if path
447
453
  append(args, force: force, **kwargs)
448
454
  else
@@ -452,7 +458,8 @@ module Squared
452
458
  end
453
459
 
454
460
  def add_quote(*args, **kwargs)
455
- merge(args.compact.map! { |val| val == '--' ? val : shell_quote(val, **kwargs) })
461
+ args.compact!
462
+ merge(args.map! { |val| val == '--' || OptionPartition.opt?(val) ? val : shell_quote(val, **kwargs) })
456
463
  self
457
464
  end
458
465
 
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.6.0
4
+ version: 0.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham