squared 0.6.21 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@ module Squared
8
8
  GEMNAME = /\A[A-Za-z\d][A-Za-z\d_.-]*\z/.freeze
9
9
  DIR_RUBY = (GEMFILE + Rake::Application::DEFAULT_RAKEFILES + ['README.rdoc']).freeze
10
10
  OPT_RUBY = {
11
- ruby: %w[a c l n p s S w 0=im? C=pm e=q E=bm F=qm i=bm? I=pm r=bm W=bm? x=pm? d|debug jit rjit verbose
11
+ ruby: %w[0=im? a c C=pm e=q E=bm F=qm i=bm? I=pm l n p r=bm s S w W=bm? x=pm? d|debug jit rjit verbose
12
12
  y|yydebug backtrace-limit=i crash-report=q disable=q dump=q enable=q encoding=b external-encoding=b
13
13
  internal-encoding=b parser=b].freeze,
14
14
  rake: %w[A|all B|build-all comments n|dry-run m|multitask P|prereqs q|quiet X|no-deprecation-warnings
@@ -21,7 +21,7 @@ module Squared
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
23
  back-trace-limit=i context-mode=i prompt=b prompt-mode=b].freeze,
24
- rbs: %w[I=pm r=bm no-collection no-stdlib collection=p log-level=b log-output=p repo=p].freeze,
24
+ rbs: %w[I=pm r=bm no-stdlib no-collection collection=p log-level=b log-output=p repo=p].freeze,
25
25
  rubocop: %w[D P r=bm auto-gen-config a|autocorrect A|autocorrect-all d|debug disable-pending-cops
26
26
  display-only-correctable display-only-fail-level-offenses display-only-failed
27
27
  display-only-safe-correctable S|display-style-guide display-time editor-mode enable-pending-cops
@@ -39,23 +39,22 @@ module Squared
39
39
  }.freeze
40
40
  OPT_BUNDLE = {
41
41
  common: %w[no-color V|verbose r|retry=i].freeze,
42
- common_all: %w[all all-platforms path=p].freeze,
43
42
  common_git: %w[branch=q git=q path=p ref=q].freeze,
44
43
  common_version: %w[local major minor patch pre strict].freeze,
45
44
  add: %w[optimistic quiet skip-install strict github=q glob=q g|group=q require=q s|source=q
46
45
  v|version=q].freeze,
47
- binstubs: %w[force standalone shebang=q].freeze,
48
- cache: %w[frozen no-all no-install no-prune quiet cache-path=p gemfile=p].freeze,
46
+ binstubs: %w[all-platforms force standalone shebang=q].freeze,
47
+ cache: %w[all-platforms no-install quiet cache-path=p gemfile=p].freeze,
49
48
  check: %w[dry-run gemfile=p path=p].freeze,
50
49
  clean: %w[dry-run force].freeze,
51
50
  config: %w[global local skip-parseable].freeze,
52
51
  doctor: %w[quiet ssl gemfile=p].freeze,
53
52
  doctor_ssl: %w[host=q tls-version=b verify-mode=b].freeze,
54
53
  exec: %w[gemfile=p].freeze,
55
- gem: %w[b|bin git no-exe rubocop ci=b e|edit=p? ext=b github-username=q linter=b t|test=b?].freeze,
56
- init: %w[gemfile=p gemspec=p].freeze,
57
- install: %w[frozen no-cache no-prune system binstubs=p? path=p standalone=q? target-rbconfig=p trust-policy=b
58
- with=q without=q].freeze,
54
+ gem: %w[b|bin git ci=b e|edit=p? ext=b github-username=q linter=b t|test=b?].freeze,
55
+ init: %w[gemspec=p].freeze,
56
+ install: %w[no-cache no-lock prefer-local binstubs=p? lockfile=p standalone=q? target-rbconfig=p
57
+ trust-policy=b].freeze,
59
58
  install_a: %w[force full-index local quiet redownload gemfile=p j|jobs=i].freeze,
60
59
  lock: %w[add-checksums conservative full-index normalize-platforms print add-platform=q bundler=b? gemfile=p
61
60
  lockfile=p remove-platform=p update=q?].freeze,
@@ -65,9 +64,17 @@ module Squared
65
64
  platform: %w[ruby].freeze,
66
65
  plugin: %w[source=q version=q].freeze,
67
66
  plugin_uninstall: %w[all].freeze,
68
- remove: %w[install].freeze,
69
- show: %w[outdated paths].freeze,
70
- update: %w[all conservative local major minor patch pre ruby strict bundler=b? g|group=q source=q].freeze,
67
+ show: %w[paths].freeze,
68
+ update: %w[all conservativepre ruby strict bundler=b? g|group=q source=q].freeze,
69
+ v3: {
70
+ binstubs: %w[all].freeze,
71
+ cache: %w[all frozen no-prune].freeze,
72
+ gem: %w[rubocop].freeze,
73
+ init: %w[gemfile=p].freeze,
74
+ install: %w[frozen no-prune system gemfile=p path=p with=q without=q].freeze,
75
+ remove: %w[install].freeze,
76
+ show: %w[outdated].freeze
77
+ }.freeze,
71
78
  no: {
72
79
  config: %w[parseable].freeze,
73
80
  gem: %w[changelog ci coc exe linter mit test].freeze
@@ -79,20 +86,21 @@ module Squared
79
86
  common_domain: %w[b|both clear-sources l|local r|remote].freeze,
80
87
  common_otp: %w[host=q k|key=b otp=b].freeze,
81
88
  common_all: %w[a|all e|exact v|version=q].freeze,
82
- build: %w[C=p force strict o|output=p platform=q].freeze,
83
- cert: %w[a|add=p b|build=q C|certificate=p d|days=i l|list=q A|key-algorithm=b K|private-key=p r|remove=q
89
+ common_platform: %w[platform=q v|version=q].freeze,
90
+ build: %w[force strict o|output=p platform=q].freeze,
91
+ cert: %w[a|add=p b|build=q C|certificate=p d|days=i l|list=q? A|key-algorithm=b K|private-key=p r|remove=q
84
92
  R|re-sign s|sign=p].freeze,
85
93
  check: %w[a v|version=q].freeze,
86
94
  cleanup: %w[D n d|dry-run].freeze,
87
95
  contents: %w[l all s|spec-dir=q v|version=q].freeze,
88
- dependency: %w[R pipe platform=q v|version=q].freeze,
96
+ dependency: %w[R pipe].freeze,
89
97
  exec: %w[conservative g|gem=b v|version=q].freeze,
90
- fetch: %w[clear-sources platform=q v|version=q].freeze,
98
+ fetch: %w[clear-sources].freeze,
91
99
  generate_index: %w[update d|directory=p].freeze,
92
100
  info: %w[i I].freeze,
93
101
  install: %w[v|version=q].freeze,
94
- install_a: %w[E f w conservative default development development-all explain ignore-dependencies N|no-document
95
- vendor n|bindir=p build-root=p document=b? g|file=p? i|install-dir=p platform=q
102
+ install_a: %w[E f w conservative development development-all explain ignore-dependencies N|no-document vendor
103
+ n|bindir=p j|build-jobs=i build-root=p document=b? g|file=p? i|install-dir=p platform=q
96
104
  target-rbconfig=p? P|trust-policy=b without=q].freeze,
97
105
  list: %w[d i I].freeze,
98
106
  lock: %w[s].freeze,
@@ -105,14 +113,19 @@ module Squared
105
113
  rdoc: %w[all v|version=q].freeze,
106
114
  rebuild: %w[C=p diff force strict gemspec=p original=p source=q].freeze,
107
115
  search: %w[d i I].freeze,
116
+ server: %w[b|bind=q d|dir=p l|launch=q p|port=b].freeze,
108
117
  signin: %w[otp=b host=q].freeze,
109
- sources: %w[f c|clear-all l|list u|update a|add=q p|http-proxy=q? r|remove=q].freeze,
110
- specification: %w[all marshal ruby yaml platform=q v|version=q].freeze,
111
- uninstall: %w[a D I x vendor n|bindir=p i|install-dir=p platform=q v|version=q].freeze,
118
+ sources: %w[f c|clear-all l|list u|update a|add=q append=q p|http-proxy=q? prepend=q r|remove=q].freeze,
119
+ specification: %w[all marshal ruby yaml].freeze,
120
+ uninstall: %w[a D I x vendor n|bindir=p i|install-dir=p].freeze,
112
121
  unpack: %w[spec target=p P|trust-policy=b v|version=q],
113
122
  update: %w[system=b?].freeze,
114
123
  which: %w[a g].freeze,
115
- yank: %w[platform=q v|version=q].freeze,
124
+ v3: {
125
+ build: %w[C=p].freeze,
126
+ install: %w[default].freeze,
127
+ update: %w[default].freeze
128
+ }.freeze,
116
129
  no: {
117
130
  check: %w[alien doctor dry-run gems].freeze,
118
131
  cleanup: %w[check-development user-install].freeze,
@@ -132,6 +145,7 @@ module Squared
132
145
  push: %w[http-proxy].freeze,
133
146
  rdoc: %w[overwrite rdoc ri].freeze,
134
147
  search: %w[details http-proxy installed prerelease versions].freeze,
148
+ server: %w[daemon].freeze,
135
149
  sources: %w[force http-proxy].freeze,
136
150
  specification: %w[prerelease].freeze,
137
151
  uninstall: %w[abort-on-dependent all check-development executables force format-executable
@@ -149,7 +163,8 @@ module Squared
149
163
  contents: %w[s spec-dir].freeze,
150
164
  dependency: %w[s source].freeze,
151
165
  install: %w[document s source without].freeze,
152
- pristine: %w[skip].freeze
166
+ pristine: %w[skip].freeze,
167
+ sources: %w[append prepend].freeze
153
168
  }.freeze,
154
169
  bundle: {
155
170
  install: %w[standalone with without].freeze,
@@ -165,7 +180,7 @@ module Squared
165
180
  end
166
181
 
167
182
  def bannerargs
168
- %i[dependfile gemname gemdir].freeze
183
+ %i[version dependfile gemname gemdir].freeze
169
184
  end
170
185
 
171
186
  def config?(val)
@@ -179,7 +194,7 @@ module Squared
179
194
  'outdated' => %i[major minor patch].freeze,
180
195
  'ruby' => %i[file script version].freeze,
181
196
  'gem' => %i[install uninstall outdated update pristine build push exec command].freeze,
182
- 'bundle' => %i[install update cache exec config reinstall command].freeze,
197
+ 'bundle' => %i[config install update cache exec reinstall command].freeze,
183
198
  'rake' => nil,
184
199
  'irb' => nil,
185
200
  'rbs' => nil,
@@ -187,29 +202,23 @@ module Squared
187
202
  })
188
203
 
189
204
  attr_reader :gemdir
190
- attr_accessor :autodetect
191
205
 
192
- def initialize(*, autodetect: false, gemspec: nil, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby',
193
- **kwargs)
206
+ def initialize(*, autodetect: false, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby', **kwargs)
194
207
  super
195
208
  if @pass.include?(Ruby.ref)
196
209
  initialize_ref Ruby.ref
197
- initialize_logger(**kwargs)
210
+ initialize_logger kwargs[:log]
198
211
  else
199
212
  initialize_build(Ruby.ref, **kwargs)
200
213
  initialize_env(**kwargs)
201
214
  end
202
215
  dependfile_set GEMFILE
203
- self.autodetect = autodetect
204
- @gemfile = if gemspec == false
205
- false
206
- elsif gemspec
207
- basepath(gemspec.include?('.') ? gemspec : "#{gemspec}.gemspec")
208
- end
216
+ gemfile_set kwargs[:gemspec]
217
+ @autodetect = autodetect
209
218
  @steepfile = basepath! steep if steep
210
- rubocop = rootpath('.rubocop.yml', ascend: Dir.home) if rubocop == true
211
- @rubocopfile = basepath! rubocop if rubocop
212
- return unless rakefile && @output[0].nil? && @copy.nil? && !version && !self.autodetect
219
+ @rubocopfile = Pathname.new(rubocop).realpath rescue basepath!(Dir.home, '.rubocop.yml') if rubocop
220
+ @rubygems = kwargs.fetch(:rubygems, 0)
221
+ return unless rakefile && @output[0].nil? && @copy.nil? && !version && !@autodetect
213
222
 
214
223
  begin
215
224
  File.foreach(rakefile) do |line|
@@ -221,7 +230,7 @@ module Squared
221
230
  @clean = "#{cmd} clean" if @clean.nil?
222
231
  break
223
232
  end
224
- rescue StandardError => e
233
+ rescue => e
225
234
  log.error e
226
235
  end
227
236
  end
@@ -281,7 +290,7 @@ module Squared
281
290
  elsif exception
282
291
  indexerror n, tasks
283
292
  else
284
- log.warn "rake task #{n} of #{tasks.size} (out of range)"
293
+ log.warn "rake task #{n} of #{tasks.size}".subhint('out of range')
285
294
  opts.clear
286
295
  next
287
296
  end
@@ -329,32 +338,28 @@ module Squared
329
338
  val = File.join(val, '**/*.rb') unless val.include?('*') || val.match?(/\.[a-z\d]+$/i)
330
339
  Dir.glob(val, base: path)
331
340
  end
332
- files = if args.empty?
333
- choice_index('Select files', list, multiple: true, series: true,
341
+ if args.empty?
342
+ files = choice_index('Select files', list, multiple: true, series: true,
334
343
  accept: [accept_y('Generate?')])
335
- else
336
- list.map! { |val| basepath(val).to_s }
337
- [].tap do |out|
338
- ret = []
339
- args.each do |val|
340
- if val.include?('*')
341
- ret.concat(Dir.glob(val, base: path))
342
- elsif !(file = basepath!(val))
343
- print_error(val, hint: 'not found')
344
- elsif file.directory?
345
- ret.concat(file.glob('**/*.rb'))
346
- else
347
- ret << val
348
- end
349
- end
350
- ret = ret.select { |val| list.include?(basepath(val).to_s) }
351
- if ret.empty?
352
- print_error('steep', 'no files matched', hint: "#{key}:check")
353
- exit 1
354
- end
355
- out.replace(ret.uniq)
356
- end
357
- end
344
+ else
345
+ list.map! { |val| basepath(val).to_s }
346
+ files = args.each_with_object([]) do |val, out|
347
+ if val.include?('*')
348
+ out.concat(Dir.glob(val, base: path))
349
+ elsif !(file = basepath!(val))
350
+ print_error(val, hint: 'not found')
351
+ elsif file.directory?
352
+ out.concat(file.glob('**/*.rb'))
353
+ else
354
+ out << val
355
+ end
356
+ end.select { |val| list.include?(basepath(val).to_s) }
357
+ if files.empty?
358
+ print_error('steep', 'no files matched', hint: "#{key}:check")
359
+ exit 1
360
+ end
361
+ files.uniq!
362
+ end
358
363
  sig = if (n = sig.index(args.first))
359
364
  args.shift
360
365
  sig[n]
@@ -373,15 +378,15 @@ module Squared
373
378
  format_desc action, nil, 'opts*,path*/:'
374
379
  task action do |_, args|
375
380
  opts, args = args.to_a.partition do |val|
376
- next true if val.match?(/\A(?:(?:[A-Z]|[a-z-]+)=.|[a-z]+(?:-[a-z]+)*\Z)/)
381
+ next true if val.match?(/(^([A-Z]|[a-z-]+)=.|^[a-z]+(-[a-z]+)*$)/)
377
382
 
378
383
  !val.include?('*') && !val.end_with?('/')
379
384
  end
380
385
  if opts.delete(':')
381
386
  args << (Dir.exist?('lib') ? 'lib/' : '**/*.rb') if args.empty?
382
- list = args.map! { |val| val.end_with?('/') || Dir.exist?(val) ? File.join(val, '**/*.rb') : val }
387
+ args = args.map { |val| val.end_with?('/') || Dir.exist?(val) ? File.join(val, '**/*.rb') : val }
383
388
  .flat_map { |val| Dir.glob(val, base: path) }
384
- args = choice_index('Select files', list, multiple: true)
389
+ args = choice_index('Select files', args, multiple: true)
385
390
  end
386
391
  rubocop(*args, opts: opts, banner: true)
387
392
  end
@@ -439,6 +444,11 @@ module Squared
439
444
  end
440
445
  when 'bundle'
441
446
  case flag
447
+ when :config
448
+ format_desc action, flag, 'list|set|get|unset?,opts*,args*'
449
+ task flag do |_, args|
450
+ bundle(flag, *args.to_a, banner: true)
451
+ end
442
452
  when :install, :update, :cache, :exec
443
453
  format_desc(action, flag, 'opts*', after: case flag
444
454
  when :update then 'gems*'
@@ -447,11 +457,6 @@ module Squared
447
457
  task flag do |_, args|
448
458
  bundle(flag, opts: args.to_a, banner: flag == :exec ? verbose? : true)
449
459
  end
450
- when :config
451
- format_desc action, flag, 'list|set|get|unset?,opts*,args*'
452
- task flag do |_, args|
453
- bundle(flag, *args.to_a, banner: true)
454
- end
455
460
  when :reinstall
456
461
  format_desc action, flag, 'f/orce?,opts*'
457
462
  task flag do |_, args|
@@ -504,13 +509,168 @@ module Squared
504
509
  when :script
505
510
  format_desc action, flag, 'opts*'
506
511
  task flag do |_, args|
507
- command = ENV['RUBY_E'] || readline('Enter script', force: true, multiline: %w[## ;])
512
+ args = args.to_a
513
+ multiline = case args.first
514
+ when ';', '#'
515
+ args.shift
516
+ else
517
+ %w[## ;]
518
+ end
519
+ msg = if Readline.respond_to?(:readmultiline)
520
+ 'ruby>'
521
+ else
522
+ multiline = Array(multiline)
523
+ 'Enter script'
524
+ end
525
+ command = ENV['RUBY_E'] || readline(msg, force: true, multiline: multiline)
508
526
  ruby(flag, opts: args.to_a, command: command)
509
527
  end
510
528
  when :version
511
529
  format_desc action, flag
512
530
  task flag do
513
- ruby flag
531
+ pwd_set do
532
+ out = []
533
+ order = { 'rbenv' => -1, 'rvm' => -1, 'chruby' => -1, 'mise' => -1 }
534
+ ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
535
+ order.each_key do |key|
536
+ next unless val.match?(%r{[/.]#{key}/})
537
+
538
+ order[key] = index
539
+ break
540
+ end
541
+ end
542
+ if @asdf
543
+ [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
544
+ else
545
+ [
546
+ "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
547
+ '$HOME/.rvm/bin/rvm',
548
+ '$HOME/.local/bin/mise',
549
+ '/usr/bin/rbenv',
550
+ '/usr/bin/mise',
551
+ '/usr/local/rvm/bin/rvm',
552
+ '/usr/share/rvm/bin/rvm',
553
+ '/usr/local/share/chruby/chruby.sh'
554
+ ]
555
+ .sort do |a, b|
556
+ c = -1
557
+ d = -1
558
+ order.each do |key, val|
559
+ pat = %r{/\.?#{key}}
560
+ c = val if a.match?(pat)
561
+ d = val if b.match?(pat)
562
+ end
563
+ if c == d
564
+ 0
565
+ elsif c == -1
566
+ 1
567
+ elsif d == -1
568
+ -1
569
+ else
570
+ c < d ? -1 : 1
571
+ end
572
+ end
573
+ .push('')
574
+ end
575
+ .each do |val|
576
+ next unless val.empty? || File.exist?(val.sub('$HOME', Dir.home))
577
+
578
+ trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
579
+ ver = %w[.tool-versions .ruby-version]
580
+ out << trim.call(case (cmd = File.basename(val))
581
+ when 'rvm'
582
+ ver.shift
583
+ `rvm current`[/^\S+/, 0]
584
+ when 'rbenv'
585
+ ver.shift
586
+ name = `rbenv version-name`
587
+ name.match?(SEM_VER) ? "ruby #{name}" : name
588
+ when 'chruby.sh'
589
+ ver.shift
590
+ chruby = session_output 'source', val
591
+ `#{chruby.with('ruby --version')}`
592
+ when 'mise'
593
+ data = parse_json(`mise ls ruby --json`, kind: Array)
594
+ data = data.find { |item| item['active'] } || data.first
595
+ "ruby #{data['version']}"
596
+ else
597
+ if @asdf
598
+ cmd = 'asdf'
599
+ if @@asdf.config && File.exist?(@@asdf.config)
600
+ pat = /legacy_version_file\s+=\s+(yes|no)/
601
+ ver.pop unless File.read(@@asdf.config)[pat, 1] == 'yes'
602
+ else
603
+ ver.pop
604
+ end
605
+ opt = [@asdf.first]
606
+ opt.unshift('--no-header') unless @@asdf.version == 15
607
+ cur = `asdf current #{opt.join(' ')}`
608
+ if cur.match?(/\sfalse\b/)
609
+ `ruby --version`
610
+ else
611
+ cur[/^\S+\s+\S+/, 0].sub(/\s+/, ' ')
612
+ end
613
+ else
614
+ ver = nil
615
+ `ruby --version`
616
+ end
617
+ end)
618
+ break if workspace.windows?
619
+
620
+ unless val.empty?
621
+ out << trim.call(case cmd
622
+ when 'chruby.sh'
623
+ `#{chruby.with('chruby --version')}`.sub(':', '')
624
+ when 'asdf'
625
+ "asdf #{`asdf version`.delete_prefix('v')}"
626
+ when 'mise'
627
+ data = parse_json `mise version --json`
628
+ "mise #{data['latest']}"
629
+ else
630
+ `#{cmd} --version`
631
+ end)
632
+ end
633
+ begin
634
+ out << ('which %s' % case cmd
635
+ when 'rbenv'
636
+ `rbenv which ruby`
637
+ when 'chruby.sh'
638
+ `#{chruby.with('which ruby')}`
639
+ when 'asdf'
640
+ `asdf which #{@asdf.first}`
641
+ when 'mise'
642
+ `mise which ruby`
643
+ else
644
+ `which ruby`
645
+ end)
646
+ rescue => e
647
+ log.debug e
648
+ end
649
+ if ver
650
+ catch :found do
651
+ path.ascend do |dir|
652
+ ver.filter { |val| dir.join(val).exist? }.each do |val|
653
+ dir += val
654
+ hint = File.read(dir)
655
+ .lines
656
+ .map { |s| s.sub(/#.*$/, '').strip }
657
+ .reject(&:empty?)
658
+ .join(', ')
659
+ out << message("found #{dir}", hint: hint)
660
+ throw :found if hint.include?(out.first[/^ruby (.+)$/, 1])
661
+ rescue
662
+ nil
663
+ end
664
+ end
665
+ end
666
+ end
667
+ break
668
+ end
669
+ out.map!(&:split)
670
+ pad = as_a(out, :first, :size).max
671
+ print_item
672
+ puts(out.map { |line| '%*s %s' % [pad, line.first, line[1..-1].join(' ')] })
673
+ end
514
674
  end
515
675
  end
516
676
  end
@@ -526,25 +686,37 @@ module Squared
526
686
  super
527
687
  elsif outdated?
528
688
  workspace.rev_clear(name, sync: sync)
529
- cmd = bundle_session 'install'
530
- option('binstubs') do |val|
531
- next if val == '0' || val == 'false'
532
-
533
- run(bundle_output('binstubs --all', case val
534
- when '1', 'true'
535
- nil
536
- else
537
- if val.start_with?('~')
538
- val = File.join(Dir.home, val == '~' ? '.bundle' : val[1..-1])
539
- if prod?
540
- config_set('binstubs', shell_quote(val), global: true)
541
- val = nil
542
- end
689
+ if env('UPDATE') || env('RUBY_UPDATE')
690
+ cmd = bundle_session 'update --all'
691
+ option('version') do |val|
692
+ case val
693
+ when 'patch', 'minor', 'major'
694
+ cmd << "--#{val}"
695
+ end
696
+ end
697
+ cmd << '--strict' if option('strict')
698
+ cmd << '--conservative' if option('conservative')
699
+ else
700
+ cmd = bundle_session 'install'
701
+ option('binstubs') do |val|
702
+ next if val == '0' || val == 'false'
703
+
704
+ run(bundle_output('binstubs --all', case val
705
+ when '1', 'true'
706
+ nil
543
707
  else
544
- val = basepath val
545
- end
546
- quote_option('path', val) if val
547
- end), exception: false, banner: false, series: true)
708
+ if val.start_with?('~')
709
+ val = File.join(Dir.home, val == '~' ? '.bundle' : val[1..-1])
710
+ if prod?
711
+ config_set('binstubs', shell_quote(val), global: true)
712
+ val = nil
713
+ end
714
+ else
715
+ val = basepath val
716
+ end
717
+ quote_option('path', val) if val
718
+ end), exception: false, banner: false, series: true)
719
+ end
548
720
  end
549
721
  if prod? && !config_get('without')
550
722
  if semgte?('3')
@@ -553,8 +725,8 @@ module Squared
553
725
  cmd << '--without=development'
554
726
  end
555
727
  end
556
- option('jobs') { |n| cmd << "-j#{n}" if n.to_i > 0 }
557
- run_rb(sync: sync, from: :depend)
728
+ option('jobs', pat: /^\d+$/) { |val| cmd << "-j#{val}" }
729
+ run(sync: sync, from: :depend)
558
730
  end
559
731
  end
560
732
 
@@ -583,8 +755,8 @@ module Squared
583
755
  c = glob[i] || glob.first
584
756
  log.info "cp #{a + c} #{b}"
585
757
  copy_dir(a, b, c, pass: pass, verbose: !silent?)
586
- rescue StandardError => e
587
- on_error e, :copy
758
+ rescue => e
759
+ on_error e
588
760
  end
589
761
  on :last, :copy
590
762
  end
@@ -620,7 +792,7 @@ module Squared
620
792
  on :first, :outdated
621
793
  banner = format_banner cmd.to_s
622
794
  print_item banner if sync
623
- pwd_set(from: :outdated) do
795
+ pwd_set(cmd, dryrun: dryrun) do
624
796
  tc = theme[:current]
625
797
  start = 0
626
798
  found = 0
@@ -727,7 +899,7 @@ module Squared
727
899
  unless Array(items).empty?
728
900
  gems = if se
729
901
  choice('Select a package', items.map(&:first),
730
- multiple: true, force: false, index: true, border: true).map! { |n| items[n.pred].last }
902
+ multiple: true, force: false, index: true, border: true).map { |n| items[n.pred].last }
731
903
  else
732
904
  items.map(&:last)
733
905
  end
@@ -749,7 +921,7 @@ module Squared
749
921
  break
750
922
  end
751
923
  end
752
- rescue StandardError => e
924
+ rescue => e
753
925
  log.debug e
754
926
  end
755
927
  puts print_footer(status || 'Updates are available', right: status.include?('/'))
@@ -760,118 +932,10 @@ module Squared
760
932
  on :last, :outdated
761
933
  end
762
934
 
763
- def ruby(*args, flag: nil, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:ruby], **kwargs)
764
- flag = args.shift if !flag && args.first.is_a?(Symbol)
765
- if flag == :version
766
- pwd_set do
767
- out = []
768
- order = { 'rbenv' => -1, 'rvm' => -1, 'asdf' => -1, 'chruby' => -1 }
769
- ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
770
- order.each_key do |key|
771
- next unless val.match?(%r{[/.]#{key}/})
772
-
773
- order[key] = index
774
- break
775
- end
776
- end
777
- if @asdf
778
- [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
779
- else
780
- [
781
- "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
782
- '$HOME/.rvm/bin/rvm',
783
- '/usr/bin/rbenv',
784
- '/usr/local/rvm/bin/rvm',
785
- '/usr/share/rvm/bin/rvm',
786
- '/usr/local/share/chruby/chruby.sh'
787
- ].sort do |a, b|
788
- c = -1
789
- d = -1
790
- order.each do |key, val|
791
- pat = %r{/\.?#{key}}
792
- c = val if a.match?(pat)
793
- d = val if b.match?(pat)
794
- end
795
- if c == d
796
- 0
797
- elsif c == -1
798
- 1
799
- elsif d == -1
800
- -1
801
- else
802
- c < d ? -1 : 1
803
- end
804
- end
805
- .push('')
806
- end.each do |val|
807
- next unless val.empty? || File.exist?(val.sub('$HOME', Dir.home))
808
-
809
- trim = ->(s) { s =~ /^\D+\d+\.\d+(?:\.\S+)?/ ? $&.sub(/^([a-z]+)-/i, '\1 ') : s }
810
- ver = '.ruby-version'
811
- out << trim.call(case (cmd = File.basename(val))
812
- when 'rvm'
813
- `rvm current`[/^\S+/, 0]
814
- when 'rbenv'
815
- name = `rbenv version-name`
816
- (name =~ SEM_VER) == 0 ? "ruby #{name}" : name
817
- when 'chruby.sh'
818
- chruby = session_output 'source', val
819
- `#{chruby.with('ruby --version')}`
820
- else
821
- if @asdf
822
- cmd = 'asdf'
823
- ver = '.tool-versions'
824
- opt = [@asdf.first]
825
- opt.unshift('--no-header') unless @@asdf.version == 15
826
- exit 1 unless (cur = `asdf current #{opt.join(' ')}`[/^\S+\s+\S+/, 0])
827
- cur.sub(/\s+/, ' ')
828
- else
829
- ver = nil
830
- `ruby --version`
831
- end
832
- end)
833
- break if workspace.windows?
834
-
835
- unless val.empty?
836
- out << trim.call(case cmd
837
- when 'chruby.sh'
838
- `#{chruby.with('chruby --version')}`.sub(':', '')
839
- when 'asdf'
840
- "asdf #{`asdf version`.delete_prefix('v')}"
841
- else
842
- `#{cmd} --version`
843
- end)
844
- end
845
- begin
846
- out << ('which %s' % case cmd
847
- when 'rbenv'
848
- `rbenv which ruby`
849
- when 'chruby.sh'
850
- `#{chruby.with('which ruby')}`
851
- when 'asdf'
852
- `asdf which #{@asdf.first}`
853
- else
854
- `which ruby`
855
- end)
856
- rescue StandardError => e
857
- log.debug e
858
- end
859
- if ver
860
- path.ascend do |ent|
861
- next unless (ent += ver).exist?
862
-
863
- hint = File.read(ent).lines(chomp: true).reject(&:empty?).join(', ') rescue nil
864
- out << message("found #{ent}", hint: hint)
865
- end
866
- end
867
- break
868
- end
869
- out.map!(&:split)
870
- pad = out.map(&:first).map!(&:size).max
871
- print_item
872
- puts(out.map! { |line| '%*s %s' % [pad, line.first, line[1..-1].join(' ')] })
873
- end
874
- return
935
+ def ruby(*args, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:ruby], **kwargs)
936
+ if args.first.is_a?(Symbol)
937
+ flag = args.shift
938
+ from = symjoin 'ruby', flag
875
939
  end
876
940
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
877
941
  op = OptionPartition.new(opts, OPT_RUBY[:ruby], ruby_session, project: self, multiple: [/^-e/], args: true,
@@ -896,13 +960,8 @@ module Squared
896
960
  op.append(delim: true, escape: kwargs.fetch(:escape, false), quote: kwargs.fetch(:quote, false))
897
961
  end
898
962
  end
899
- from = if flag
900
- :"ruby:#{flag}"
901
- else
902
- print_run(op, banner, **kwargs)
903
- :ruby
904
- end
905
- run_rb(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: from)
963
+ print_run(op, banner, **kwargs) unless flag
964
+ run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception?), from: from || :ruby)
906
965
  end
907
966
 
908
967
  def gem(flag, *args, sync: true, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -924,20 +983,19 @@ module Squared
924
983
  end
925
984
  op = OptionPartition.new(opts, gemopts(flag), gem_session(flag),
926
985
  project: self, no: OPT_GEM[:no][flag == :update ? :install : flag])
927
- from = :"gem:#{flag}"
986
+ from = symjoin 'gem', flag
928
987
  if flag == :outdated
929
988
  op.adjoin(gempwd, start: 0) if gempwd
930
989
  op.clear
931
990
  cmd = session_done op.target
932
991
  log.info cmd
933
992
  on :first, from
934
- banner = format_banner(cmd)
993
+ banner = format_banner cmd
935
994
  print_item banner if sync
936
995
  major = [0, 0, 0]
937
996
  buffer = []
938
997
  filter = kwargs.fetch(:filter, {})
939
998
  semver = filter[:semver]
940
- dryrun = filter[:dryrun] || dryrun?(prefix: 'gem')
941
999
  update = if sync && filter[:select]
942
1000
  semver ||= 'major'
943
1001
  items = []
@@ -951,7 +1009,7 @@ module Squared
951
1009
  []
952
1010
  end
953
1011
  out = ->(val) { sync ? puts(val) : buffer << val }
954
- pwd_set(pass: !gempwd.nil?, from: from) do
1012
+ pwd_set(op.target, from: from, pass: !gempwd.nil?) do
955
1013
  rows = [[%w[Gem Current Latest], nil]]
956
1014
  IO.popen(cmd).each do |line|
957
1015
  if line =~ /^(\S+) \((\S+) < ([^)]+)\)$/
@@ -1007,7 +1065,7 @@ module Squared
1007
1065
  unless stdin?
1008
1066
  sub_style! g, theme[:major]
1009
1067
  styles = %i[green bold]
1010
- pat = (pat.first if pre)
1068
+ pat = pre ? pat.first : nil
1011
1069
  latest << :bold
1012
1070
  end
1013
1071
  major[0] += 1
@@ -1046,10 +1104,9 @@ module Squared
1046
1104
  out.call(queue)
1047
1105
  queue = nil
1048
1106
  end
1049
- s = ('%s %s %s' % [g, b, h]).yield_self do |val|
1050
- items&.push([val, a])
1051
- '%*s %s' % [pad, "#{j}.", val]
1052
- end
1107
+ s = '%s %s %s' % [g, b, h]
1108
+ items&.push([s, a])
1109
+ s = '%*s %s' % [pad, "#{j}.", s]
1053
1110
  if ia
1054
1111
  unless confirm_semver(s, type)
1055
1112
  update.delete(a)
@@ -1071,7 +1128,7 @@ module Squared
1071
1128
  else
1072
1129
  if items
1073
1130
  update = choice('Select a package', items.map(&:first),
1074
- multiple: true, force: false, index: true, border: true).map! { |n| items[n.pred].last }
1131
+ multiple: true, force: false, index: true, border: true).map { |n| items[n.pred].last }
1075
1132
  end
1076
1133
  unless Array(update).empty?
1077
1134
  opts = ['f']
@@ -1091,7 +1148,7 @@ module Squared
1091
1148
  'user-install'
1092
1149
  end
1093
1150
  end
1094
- if dryrun
1151
+ if filter[:dryrun]
1095
1152
  print_run gem_output('update -f', *update.quote!), false
1096
1153
  else
1097
1154
  gem(:update, *update, opts: opts)
@@ -1110,7 +1167,6 @@ module Squared
1110
1167
  when :dependency, :environment, :list, :search, :specification, :which
1111
1168
  op.concat(args)
1112
1169
  end
1113
- ia = op.remove(':')
1114
1170
  op.each do |opt|
1115
1171
  if gems && !opt.start_with?('-') && !opt.match?(GEMNAME)
1116
1172
  op.errors << opt
@@ -1133,8 +1189,8 @@ module Squared
1133
1189
  .clear(pass: false)
1134
1190
  end
1135
1191
  when :push
1136
- if op.empty? || ia
1137
- file = basepath(if !ia && (spec = gemspec)
1192
+ if op.empty? || (n = op.index(':'))
1193
+ file = basepath(if !n && (spec = gemspec)
1138
1194
  "#{spec.name}-#{spec.version}.gem"
1139
1195
  else
1140
1196
  choice_index 'Select a file', Dir.glob('*.gem', base: path)
@@ -1145,7 +1201,7 @@ module Squared
1145
1201
  raise_error ArgumentError, "unrecognized args: #{op.join(', ')}", hint: flag unless op.empty?
1146
1202
  end
1147
1203
  op.add_path(file)
1148
- return run_rb(from: from, interactive: ['Push', 'N', gemname]) unless with || !banner
1204
+ return run(from: from, interactive: ['Push', 'N', gemname]) unless with || !banner
1149
1205
  when :exec
1150
1206
  min = if op.arg?('g', 'gem')
1151
1207
  1
@@ -1159,9 +1215,7 @@ module Squared
1159
1215
  0
1160
1216
  end
1161
1217
  op.concat(args)
1162
- if (args = command_args(op.extras, min: min, force: min == 1 && op.empty?))
1163
- op.push(args)
1164
- end
1218
+ command_args(op.extras, min: min, force: min == 1 && op.empty?)
1165
1219
  op.append(quote: false)
1166
1220
  when :update
1167
1221
  if !op.arg?('n', 'bindir') && (bin = config_get('bin')) && Dir.exist?(bin)
@@ -1174,7 +1228,7 @@ module Squared
1174
1228
  end
1175
1229
  when :install, :uninstall, :pristine
1176
1230
  if flag == :install
1177
- post = if ia
1231
+ post = if op.remove(':')
1178
1232
  op.concat(args)
1179
1233
  readline('Enter command [args]', force: true)
1180
1234
  elsif op.empty?
@@ -1192,14 +1246,15 @@ module Squared
1192
1246
  else
1193
1247
  op.clear
1194
1248
  end
1195
- elsif (n = op.index { |val| val.match?(/(\A|[\w.-])@\d/) })
1249
+ elsif (n = op.index { |val| val.match?(/(\A|[a-z])@\d/) })
1196
1250
  name = op.remove_at(n)
1197
- pre, ver = if (n = name.index('@')) == 0
1251
+ n = name.index('@')
1252
+ pre, ver = if n == 0
1198
1253
  [gemname, name[1..-1]]
1199
1254
  else
1200
1255
  [name[0, n], name[n.succ..-1]]
1201
1256
  end
1202
- op.adjoin(pre, quote_option('version', ver))
1257
+ op.adjoin(pre, basic_option('version', ver))
1203
1258
  .clear
1204
1259
  end
1205
1260
  if flag == :install
@@ -1245,7 +1300,8 @@ module Squared
1245
1300
  end
1246
1301
  op.clear(errors: true) if gems
1247
1302
  print_run(op, banner, **kwargs)
1248
- run_rb(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: from)
1303
+ run(banner: banner && %w[q silent quiet no-verbose].none? { |s| op.include?(shell_option(s)) },
1304
+ exception: kwargs.fetch(:exception, exception?), from: from)
1249
1305
  end
1250
1306
 
1251
1307
  def bundle(flag, *args, sync: true, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -1291,7 +1347,7 @@ module Squared
1291
1347
  end
1292
1348
  opts.concat(args)
1293
1349
  when :plugin
1294
- case (plu = args.shift || opts.shift)
1350
+ case (plu = args.shift)
1295
1351
  when 'install', 'uninstall', 'help', 'list'
1296
1352
  cmd << plu
1297
1353
  else
@@ -1301,7 +1357,7 @@ module Squared
1301
1357
  op = OptionPartition.new(opts, bundleopts(if pre == 'ssl'
1302
1358
  :doctor_ssl
1303
1359
  elsif plu
1304
- plu == 'install' ? :plugin : :"plugin_#{plu}"
1360
+ plu == 'install' ? :plugin : symjoin('plugin', plu, char: '_')
1305
1361
  else
1306
1362
  flag
1307
1363
  end),
@@ -1309,7 +1365,6 @@ module Squared
1309
1365
  project: self, no: OPT_BUNDLE[:no][flag], args: flag == :exec || flag == :config)
1310
1366
  op.concat(args) unless pre
1311
1367
  output = false
1312
- invalid = ->(a) { raise_error ArgumentError, "unrecognized args: #{a.join(', ')}", hint: flag }
1313
1368
  case flag
1314
1369
  when :config
1315
1370
  if pre == 'list'
@@ -1355,7 +1410,7 @@ module Squared
1355
1410
  else
1356
1411
  val = readline('Enter arguments', force: false)
1357
1412
  op << (val.empty? ? 'list' : val)
1358
- output = val.match?(/^(un)?set/)
1413
+ output = val.start_with?('set', 'unset')
1359
1414
  end
1360
1415
  when :plugin
1361
1416
  case plu
@@ -1383,8 +1438,9 @@ module Squared
1383
1438
  op.clear
1384
1439
  end
1385
1440
  print_run(op, banner, **kwargs)
1386
- run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: :"bundle:#{flag}")
1387
- .tap { |ret| success?(ret, banner, output) }
1441
+ ret = run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception?),
1442
+ from: symjoin('bundle', flag))
1443
+ success?(ret, banner, output)
1388
1444
  end
1389
1445
 
1390
1446
  def rake(*args, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:rake], **kwargs)
@@ -1395,26 +1451,26 @@ module Squared
1395
1451
  op.append(escape: true)
1396
1452
  print_run(op, banner, **kwargs)
1397
1453
  var = { 'BANNER' => '0' } unless banner
1398
- run(op, var, sync: sync, banner: false, exception: kwargs.fetch(:exception, exception), from: :rake)
1454
+ run(op, var, sync: sync, banner: false, exception: kwargs.fetch(:exception, exception?), from: :rake)
1399
1455
  end
1400
1456
 
1401
1457
  def irb(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:irb], **kwargs)
1402
1458
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1403
1459
  op = OptionPartition.new(opts, OPT_RUBY[:irb], session('irb'), project: self, first: [/\.rb$/])
1404
1460
  r = []
1405
- r << 'bundler/setup' unless op.arg?('r')
1406
- r << kwargs[:name] if kwargs[:name]
1461
+ r << 'bundler/setup' if !op.arg?('r') && bundle_load
1462
+ r.concat(Array(kwargs[:name])) if kwargs[:name]
1407
1463
  r.each { |val| op.add_option('r', val, merge: true) }
1408
- Array(kwargs.fetch(:path, gemlib)).each { |val| op << quote_option('I', val, merge: true) }
1464
+ op.merge((gemlib + Array(kwargs[:path])).map { |val| quote_option('I', val, merge: true) })
1409
1465
  op.concat(args)
1410
1466
  op.append(delim: true)
1411
1467
  print_run(op, banner, **kwargs)
1412
- run(banner: false, exception: kwargs.fetch(:exception, exception), from: :irb)
1468
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: :irb)
1413
1469
  end
1414
1470
 
1415
1471
  def rbs(flag, *args, banner: verbose?, with: nil, pass: nil, **kwargs)
1416
1472
  case pass
1417
- when NilClass
1473
+ when nil
1418
1474
  pass = PASS_RUBY[:rbs]
1419
1475
  when Array
1420
1476
  pass += PASS_RUBY[:rbs]
@@ -1427,7 +1483,7 @@ module Squared
1427
1483
  sig = args.shift
1428
1484
  y = option('y', ignore: false)
1429
1485
  i = 1
1430
- args.map! { |val| basepath(val).relative_path_from(path) }.each do |file|
1486
+ args.map { |val| basepath(val).relative_path_from(path) }.each do |file|
1431
1487
  dir = basepath sig, file.dirname
1432
1488
  dir.mkpath unless dir.exist?
1433
1489
  base = file.basename.to_s
@@ -1443,8 +1499,8 @@ module Squared
1443
1499
  end
1444
1500
  end
1445
1501
  unless status == 'ignored'
1446
- ret = run(op.target.temp(File.extname(base) == '.rbi' ? 'rbi' : 'rb', file, '>', rbs), banner: false,
1447
- series: true)
1502
+ ret = run(op.target.temp(File.extname(base) == '.rbi' ? 'rbi' : 'rb', file, '>', rbs),
1503
+ banner: false, series: true)
1448
1504
  if !ret
1449
1505
  status = 'FAIL'
1450
1506
  elsif File.empty?(rbs)
@@ -1458,7 +1514,7 @@ module Squared
1458
1514
  op.clear
1459
1515
  .append(*args)
1460
1516
  print_run(op, banner, **kwargs)
1461
- run(banner: false, exception: kwargs.fetch(:exception, exception), from: :"rbs:#{flag}")
1517
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: symjoin('rbs', flag))
1462
1518
  end
1463
1519
  end
1464
1520
 
@@ -1477,12 +1533,11 @@ module Squared
1477
1533
  op.errors << val
1478
1534
  end
1479
1535
  end
1480
- op.swap
1481
- .map! { |val| basepath(val).relative_path_from(path) }
1536
+ op.swap.map! { |val| basepath(val).relative_path_from(path) }
1482
1537
  op.append(delim: true)
1483
1538
  .clear(errors: true)
1484
1539
  print_run(op, banner, **kwargs)
1485
- run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: :rubocop)
1540
+ run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception?), from: :rubocop)
1486
1541
  end
1487
1542
 
1488
1543
  def gemspec
@@ -1507,7 +1562,7 @@ module Squared
1507
1562
  def copy?
1508
1563
  return true if @copy.is_a?(Hash) ? copy[:into] : super
1509
1564
  return gemdir? if gemdir
1510
- return false unless autodetect
1565
+ return false unless @autodetect
1511
1566
 
1512
1567
  set = lambda do |val, path|
1513
1568
  base = Pathname.new(path.strip)
@@ -1520,27 +1575,27 @@ module Squared
1520
1575
  end
1521
1576
  if version
1522
1577
  begin
1523
- case autodetect
1578
+ case @autodetect
1524
1579
  when 'rvm'
1525
1580
  pwd_set { `rvm info homes` }[/^\s+gem:\s+"(.+)"$/, 1]
1526
1581
  when 'rbenv'
1527
1582
  if pwd_set { `rbenv which ruby` } =~ %r{^(.+[\\/]versions[\\/](\d\.\d)\.[^\\/]+)[\\/]bin[\\/]ruby$}
1528
1583
  File.join($1, 'lib/ruby/gems', "#{$2}.0")
1529
1584
  end
1530
- when 'asdf'
1531
- pwd_set { `asdf where ruby`.chomp }.yield_self do |val|
1532
- val =~ /(\d\.\d)\.[^.]+$/ && File.join(val, 'lib/ruby/gems', "#{$1}.0")
1533
- end
1585
+ when 'asdf', 'mise'
1586
+ val = pwd_set { `#{@autodetect} where ruby`.chomp }
1587
+ File.join(val, 'lib/ruby/gems', "#{$1}.0") if val =~ /(\d\.\d)\.[^.]+$/
1534
1588
  when /bundler?/
1535
1589
  pwd_set { `bundle env` }[/^\s+Gem Path\s+(.+)$/, 1].split(File::PATH_SEPARATOR).find do |val|
1536
1590
  Dir.exist?(File.join(val, 'gems'))
1537
1591
  end
1538
1592
  else
1539
1593
  ENV['GEM_HOME'] || ENV['GEM_ROOT']
1540
- end.tap do |val|
1594
+ end
1595
+ .tap do |val|
1541
1596
  return true if val && set.call(version, val)
1542
1597
  end
1543
- rescue StandardError => e
1598
+ rescue => e
1544
1599
  log.debug e
1545
1600
  end
1546
1601
  pwd_set(pass: !gempwd.nil?) do
@@ -1574,11 +1629,11 @@ module Squared
1574
1629
  raise_error Errno::ENOENT, 'gems home'
1575
1630
  end
1576
1631
  end
1577
- rescue StandardError => e
1632
+ rescue => e
1578
1633
  log.error e
1579
1634
  self.version = nil
1580
1635
  @gemdir = nil
1581
- self.autodetect = false
1636
+ @autodetect = false
1582
1637
  else
1583
1638
  gemdir?
1584
1639
  end
@@ -1589,10 +1644,6 @@ module Squared
1589
1644
 
1590
1645
  private
1591
1646
 
1592
- def run_rb(**kwargs)
1593
- run(banner: !@session&.include?('--quiet'), **kwargs)
1594
- end
1595
-
1596
1647
  def ruby_session(*cmd, **kwargs)
1597
1648
  session('ruby', *preopts, *cmd, **kwargs)
1598
1649
  end
@@ -1602,7 +1653,9 @@ module Squared
1602
1653
  end
1603
1654
 
1604
1655
  def bundle_session(*cmd, **kwargs)
1605
- session('bundle', *cmd, *preopts, **kwargs).tap { append_nocolor }
1656
+ ret = session('bundle', *cmd, *preopts, **kwargs)
1657
+ append_nocolor
1658
+ ret
1606
1659
  end
1607
1660
 
1608
1661
  def rake_session(*cmd, **kwargs)
@@ -1632,22 +1685,47 @@ module Squared
1632
1685
  session_output('rake', *cmd, **kwargs)
1633
1686
  end
1634
1687
 
1635
- def config_get(key)
1636
- out = pwd_set { `#{bundle_output('config get --parseable', key)}`.chomp }
1637
- return unless out =~ /\A([^=]+)=(.*)\z/ && $1 == key
1688
+ def bundle_load
1689
+ require 'bundler' unless defined?(Bundler)
1690
+ rescue LoadError
1691
+ nil
1692
+ else
1693
+ Bundler::VERSION
1694
+ end
1638
1695
 
1639
- case (out = $2)
1640
- when 'true'
1641
- true
1642
- when '', '[]'
1643
- nil
1644
- else
1645
- if out =~ /\A\[:(.+)\]\z/
1646
- $1.split(', :').map { |val| ((val.delete_prefix!('"') && val.delete_suffix!('"')) || val).to_sym }
1647
- else
1648
- out || false
1696
+ def gemfile_set(val)
1697
+ @gemfile = if val == false
1698
+ false
1699
+ elsif val
1700
+ basepath(val).sub_ext('.gemspec')
1701
+ end
1702
+ end
1703
+
1704
+ def config_get(key, first: true)
1705
+ ret = []
1706
+ pwd_set do
1707
+ IO.popen(bundle_output('config get --parseable', key).to_s).each do |line|
1708
+ line.chomp!
1709
+ next unless line[/\A([^=]+)=(.*)\z/, 1] == key
1710
+
1711
+ val = case (val = $2)
1712
+ when 'true'
1713
+ true
1714
+ when '', '[]'
1715
+ nil
1716
+ else
1717
+ if val =~ /\A\[:(.+)\]\z/
1718
+ $1.split(', :').map { |s| (s[/\A"(.+)"\z/, 1] || s).to_sym }
1719
+ else
1720
+ val || false
1721
+ end
1722
+ end
1723
+ return val if first
1724
+
1725
+ ret << val
1649
1726
  end
1650
1727
  end
1728
+ ret unless first && ret.empty?
1651
1729
  end
1652
1730
 
1653
1731
  def config_set(key, *val, global: false)
@@ -1655,9 +1733,11 @@ module Squared
1655
1733
  end
1656
1734
 
1657
1735
  def unpack_get(tag, ext)
1658
- return super unless ext == 'gem'
1659
-
1660
- "https://rubygems.org/downloads/#{tag.sub_ext('.gem')}"
1736
+ if ext == 'gem'
1737
+ "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
1738
+ else
1739
+ super
1740
+ end
1661
1741
  end
1662
1742
 
1663
1743
  def preopts
@@ -1684,9 +1764,8 @@ module Squared
1684
1764
 
1685
1765
  def raketasks
1686
1766
  @raketasks ||= [].tap do |ret|
1687
- opt = rakepwd
1688
- pwd_set(pass: !opt.nil?) do
1689
- IO.popen(rake_output(opt, '-AT').to_s).each do |line|
1767
+ pwd_set(pass: !rakepwd.nil?) do
1768
+ IO.popen(rake_output(rakepwd, '-AT').to_s).each do |line|
1690
1769
  next unless line =~ /^rake ((?:[^\[: ]+:?)+)(\[[^\]]+\])?/
1691
1770
 
1692
1771
  ret << [$1, $2]
@@ -1701,12 +1780,15 @@ module Squared
1701
1780
  args << :install_a
1702
1781
  when :add, :plugin
1703
1782
  args << :common_git
1704
- when :binstubs, :cache
1705
- args << :common_all
1706
1783
  when :lock, :outdated
1707
1784
  args << :common_version
1708
1785
  end
1709
- OPT_BUNDLE[:common] + args.flat_map { |name| OPT_BUNDLE.fetch(name, []) }
1786
+ OPT_BUNDLE[:common] + args.flat_map do |name|
1787
+ opts = OPT_BUNDLE.fetch(name, [])
1788
+ next opts if compat?(4, gem: 'bundle')
1789
+
1790
+ opts + OPT_BUNDLE[:v3].fetch(name, [])
1791
+ end
1710
1792
  end
1711
1793
 
1712
1794
  def gemopts(*args)
@@ -1725,8 +1807,15 @@ module Squared
1725
1807
  case args.first
1726
1808
  when :info, :list, :search
1727
1809
  args << :common_all
1810
+ when :dependency, :fetch, :specification, :uninstall, :yank
1811
+ args << :common_platform
1812
+ end
1813
+ OPT_GEM[:common] + args.flat_map do |name|
1814
+ opts = OPT_GEM.fetch(name, [])
1815
+ next opts if compat?(4)
1816
+
1817
+ opts + OPT_GEM[:v3].fetch(name, [])
1728
1818
  end
1729
- OPT_GEM[:common] + args.flat_map { |name| OPT_GEM.fetch(name, []) }
1730
1819
  end
1731
1820
 
1732
1821
  def gempwd
@@ -1749,7 +1838,7 @@ module Squared
1749
1838
  if (spec = gemspec)
1750
1839
  lib.merge(spec.require_paths || [])
1751
1840
  end
1752
- lib.select { |file| exist?(file) }
1841
+ lib.select { |file| exist?(file, type: 'd') }
1753
1842
  end
1754
1843
  end
1755
1844
 
@@ -1764,6 +1853,26 @@ module Squared
1764
1853
 
1765
1854
  gemdir.exist? && !gemdir.empty? && gemdir.writable?
1766
1855
  end
1856
+
1857
+ def compat?(min, max = Float::INFINITY, gem: nil)
1858
+ return false unless !gem || (bundle = gem.match?(/bundler?/))
1859
+
1860
+ n = @rubygems
1861
+ if n.is_a?(Numeric) && n > 0
1862
+ max = max.to_f unless max.is_a?(Numeric)
1863
+ n >= min.to_f && n < max
1864
+ else
1865
+ ver = case n
1866
+ when String
1867
+ n
1868
+ when Array
1869
+ n[bundle ? 1 : 0]
1870
+ else
1871
+ min.tap { min = (bundle && bundle_load) || Gem::VERSION }
1872
+ end
1873
+ semgte?(ver.to_s, min.to_s) && (max == Float::INFINITY || !semgte?(ver.to_s, max.to_s))
1874
+ end
1875
+ end
1767
1876
  end
1768
1877
 
1769
1878
  Application.implement Ruby