squared 0.6.9 → 0.7.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.
@@ -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,
@@ -188,25 +203,21 @@ module Squared
188
203
 
189
204
  attr_reader :gemdir
190
205
 
191
- def initialize(*, autodetect: false, gemspec: nil, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby',
192
- **kwargs)
206
+ def initialize(*, autodetect: false, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby', **kwargs)
193
207
  super
194
208
  if @pass.include?(Ruby.ref)
195
209
  initialize_ref Ruby.ref
196
- initialize_logger(**kwargs)
210
+ initialize_logger kwargs[:log]
197
211
  else
198
212
  initialize_build(Ruby.ref, **kwargs)
199
213
  initialize_env(**kwargs)
200
214
  end
201
215
  dependfile_set GEMFILE
216
+ gemfile_set kwargs[:gemspec]
202
217
  @autodetect = autodetect
203
- @gemfile = if gemspec == false
204
- false
205
- elsif gemspec
206
- basepath(gemspec.include?('.') ? gemspec : "#{gemspec}.gemspec")
207
- end
208
218
  @steepfile = basepath! steep if steep
209
219
  @rubocopfile = Pathname.new(rubocop).realpath rescue basepath!(Dir.home, '.rubocop.yml') if rubocop
220
+ @rubygems = kwargs.fetch(:rubygems, 0)
210
221
  return unless rakefile && @output[0].nil? && @copy.nil? && !version && !@autodetect
211
222
 
212
223
  begin
@@ -219,7 +230,7 @@ module Squared
219
230
  @clean = "#{cmd} clean" if @clean.nil?
220
231
  break
221
232
  end
222
- rescue StandardError => e
233
+ rescue => e
223
234
  log.error e
224
235
  end
225
236
  end
@@ -279,7 +290,7 @@ module Squared
279
290
  elsif exception
280
291
  indexerror n, tasks
281
292
  else
282
- log.warn "rake task #{n} of #{tasks.size} (out of range)"
293
+ log.warn "rake task #{n} of #{tasks.size}".subhint('out of range')
283
294
  opts.clear
284
295
  next
285
296
  end
@@ -327,32 +338,28 @@ module Squared
327
338
  val = File.join(val, '**/*.rb') unless val.include?('*') || val.match?(/\.[a-z\d]+$/i)
328
339
  Dir.glob(val, base: path)
329
340
  end
330
- files = if args.empty?
331
- choice_index('Select files', list, multiple: true, series: true,
341
+ if args.empty?
342
+ files = choice_index('Select files', list, multiple: true, series: true,
332
343
  accept: [accept_y('Generate?')])
333
- else
334
- list.map! { |val| basepath(val).to_s }
335
- [].tap do |out|
336
- ret = []
337
- args.each do |val|
338
- if val.include?('*')
339
- ret.concat(Dir.glob(val, base: path))
340
- elsif !(file = basepath!(val))
341
- print_error(val, hint: 'not found')
342
- elsif file.directory?
343
- ret.concat(file.glob('**/*.rb'))
344
- else
345
- ret << val
346
- end
347
- end
348
- ret = ret.select { |val| list.include?(basepath(val).to_s) }
349
- if ret.empty?
350
- print_error('steep', 'no files matched', hint: "#{key}:check")
351
- exit 1
352
- end
353
- out.replace(ret.uniq)
354
- end
355
- 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
356
363
  sig = if (n = sig.index(args.first))
357
364
  args.shift
358
365
  sig[n]
@@ -371,15 +378,15 @@ module Squared
371
378
  format_desc action, nil, 'opts*,path*/:'
372
379
  task action do |_, args|
373
380
  opts, args = args.to_a.partition do |val|
374
- 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]+)*$)/)
375
382
 
376
383
  !val.include?('*') && !val.end_with?('/')
377
384
  end
378
385
  if opts.delete(':')
379
386
  args << (Dir.exist?('lib') ? 'lib/' : '**/*.rb') if args.empty?
380
- 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 }
381
388
  .flat_map { |val| Dir.glob(val, base: path) }
382
- args = choice_index('Select files', list, multiple: true)
389
+ args = choice_index('Select files', args, multiple: true)
383
390
  end
384
391
  rubocop(*args, opts: opts, banner: true)
385
392
  end
@@ -437,6 +444,11 @@ module Squared
437
444
  end
438
445
  when 'bundle'
439
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
440
452
  when :install, :update, :cache, :exec
441
453
  format_desc(action, flag, 'opts*', after: case flag
442
454
  when :update then 'gems*'
@@ -445,11 +457,6 @@ module Squared
445
457
  task flag do |_, args|
446
458
  bundle(flag, opts: args.to_a, banner: flag == :exec ? verbose? : true)
447
459
  end
448
- when :config
449
- format_desc action, flag, 'list|set|get|unset?,opts*,args*'
450
- task flag do |_, args|
451
- bundle(flag, *args.to_a, banner: true)
452
- end
453
460
  when :reinstall
454
461
  format_desc action, flag, 'f/orce?,opts*'
455
462
  task flag do |_, args|
@@ -502,13 +509,168 @@ module Squared
502
509
  when :script
503
510
  format_desc action, flag, 'opts*'
504
511
  task flag do |_, args|
505
- 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)
506
526
  ruby(flag, opts: args.to_a, command: command)
507
527
  end
508
528
  when :version
509
529
  format_desc action, flag
510
530
  task flag do
511
- 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
512
674
  end
513
675
  end
514
676
  end
@@ -524,25 +686,37 @@ module Squared
524
686
  super
525
687
  elsif outdated?
526
688
  workspace.rev_clear(name, sync: sync)
527
- cmd = bundle_session 'install'
528
- option('binstubs') do |val|
529
- next if val == '0' || val == 'false'
530
-
531
- run(bundle_output('binstubs --all', case val
532
- when '1', 'true'
533
- nil
534
- else
535
- if val.start_with?('~')
536
- val = File.join(Dir.home, val == '~' ? '.bundle' : val[1..-1])
537
- if prod?
538
- config_set('binstubs', shell_quote(val), global: true)
539
- val = nil
540
- 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
541
707
  else
542
- val = basepath val
543
- end
544
- quote_option('path', val) if val
545
- 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
546
720
  end
547
721
  if prod? && !config_get('without')
548
722
  if semgte?('3')
@@ -551,8 +725,8 @@ module Squared
551
725
  cmd << '--without=development'
552
726
  end
553
727
  end
554
- option('jobs') { |n| cmd << "-j#{n}" if n.to_i > 0 }
555
- run_rb(sync: sync, from: :depend)
728
+ option('jobs', pat: /^\d+$/) { |val| cmd << "-j#{val}" }
729
+ run(sync: sync, from: :depend)
556
730
  end
557
731
  end
558
732
 
@@ -581,8 +755,8 @@ module Squared
581
755
  c = glob[i] || glob.first
582
756
  log.info "cp #{a + c} #{b}"
583
757
  copy_dir(a, b, c, pass: pass, verbose: !silent?)
584
- rescue StandardError => e
585
- on_error e, :copy
758
+ rescue => e
759
+ on_error e
586
760
  end
587
761
  on :last, :copy
588
762
  end
@@ -618,7 +792,7 @@ module Squared
618
792
  on :first, :outdated
619
793
  banner = format_banner cmd.to_s
620
794
  print_item banner if sync
621
- pwd_set(from: :outdated) do
795
+ pwd_set(cmd, dryrun: dryrun) do
622
796
  tc = theme[:current]
623
797
  start = 0
624
798
  found = 0
@@ -725,7 +899,7 @@ module Squared
725
899
  unless Array(items).empty?
726
900
  gems = if se
727
901
  choice('Select a package', items.map(&:first),
728
- 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 }
729
903
  else
730
904
  items.map(&:last)
731
905
  end
@@ -747,7 +921,7 @@ module Squared
747
921
  break
748
922
  end
749
923
  end
750
- rescue StandardError => e
924
+ rescue => e
751
925
  log.debug e
752
926
  end
753
927
  puts print_footer(status || 'Updates are available', right: status.include?('/'))
@@ -758,117 +932,10 @@ module Squared
758
932
  on :last, :outdated
759
933
  end
760
934
 
761
- def ruby(*args, flag: nil, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:ruby], **kwargs)
762
- flag = args.shift if !flag && args.first.is_a?(Symbol)
763
- if flag == :version
764
- pwd_set do
765
- out = []
766
- order = { 'rbenv' => -1, 'rvm' => -1, 'asdf' => -1, 'chruby' => -1 }
767
- ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
768
- order.each_key do |key|
769
- next unless val.match?(%r{[/.]#{key}/})
770
-
771
- order[key] = index
772
- break
773
- end
774
- end
775
- if @asdf
776
- [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
777
- else
778
- [
779
- "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
780
- '$HOME/.rvm/bin/rvm',
781
- '/usr/bin/rbenv',
782
- '/usr/local/rvm/bin/rvm',
783
- '/usr/share/rvm/bin/rvm',
784
- '/usr/local/share/chruby/chruby.sh'
785
- ].sort do |a, b|
786
- c = -1
787
- d = -1
788
- order.each do |key, val|
789
- pat = %r{/\.?#{key}}
790
- c = val if a.match?(pat)
791
- d = val if b.match?(pat)
792
- end
793
- if c == d
794
- 0
795
- elsif c == -1
796
- 1
797
- elsif d == -1
798
- -1
799
- else
800
- c < d ? -1 : 1
801
- end
802
- end
803
- .push('')
804
- end.each do |val|
805
- next unless val.empty? || File.exist?(val.sub('$HOME', Dir.home))
806
-
807
- trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
808
- ver = '.ruby-version'
809
- out << trim.call(case (cmd = File.basename(val))
810
- when 'rvm'
811
- `rvm current`[/^\S+/, 0]
812
- when 'rbenv'
813
- name = `rbenv version-name`
814
- name.match?(SEM_VER) ? "ruby #{name}" : name
815
- when 'chruby.sh'
816
- chruby = session_output 'source', val
817
- `#{chruby.with('ruby --version')}`
818
- else
819
- if @asdf
820
- cmd = 'asdf'
821
- ver = '.tool-versions'
822
- opt = [@asdf.first]
823
- opt.unshift('--no-header') unless @@asdf.version == 15
824
- `asdf current #{opt.join(' ')}`[/^\S+\s+\S+/, 0].sub(/\s+/, ' ')
825
- else
826
- ver = nil
827
- `ruby --version`
828
- end
829
- end)
830
- break if workspace.windows?
831
-
832
- unless val.empty?
833
- out << trim.call(case cmd
834
- when 'chruby.sh'
835
- `#{chruby.with('chruby --version')}`.sub(':', '')
836
- when 'asdf'
837
- "asdf #{`asdf version`.delete_prefix('v')}"
838
- else
839
- `#{cmd} --version`
840
- end)
841
- end
842
- begin
843
- out << ('which %s' % case cmd
844
- when 'rbenv'
845
- `rbenv which ruby`
846
- when 'chruby.sh'
847
- `#{chruby.with('which ruby')}`
848
- when 'asdf'
849
- `asdf which #{@asdf.first}`
850
- else
851
- `which ruby`
852
- end)
853
- rescue StandardError => e
854
- log.debug e
855
- end
856
- if ver
857
- path.ascend do |ent|
858
- next unless (ent += ver).exist?
859
-
860
- hint = File.read(ent).lines(chomp: true).reject(&:empty?).join(', ') rescue nil
861
- out << message("found #{ent}", hint: hint)
862
- end
863
- end
864
- break
865
- end
866
- out.map!(&:split)
867
- pad = out.map(&:first).map!(&:size).max
868
- print_item
869
- puts(out.map! { |line| '%*s %s' % [pad, line.first, line[1..-1].join(' ')] })
870
- end
871
- 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
872
939
  end
873
940
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
874
941
  op = OptionPartition.new(opts, OPT_RUBY[:ruby], ruby_session, project: self, multiple: [/^-e/], args: true,
@@ -893,13 +960,8 @@ module Squared
893
960
  op.append(delim: true, escape: kwargs.fetch(:escape, false), quote: kwargs.fetch(:quote, false))
894
961
  end
895
962
  end
896
- from = if flag
897
- :"ruby:#{flag}"
898
- else
899
- print_run(op, banner, **kwargs)
900
- :ruby
901
- end
902
- 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)
903
965
  end
904
966
 
905
967
  def gem(flag, *args, sync: true, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -921,14 +983,14 @@ module Squared
921
983
  end
922
984
  op = OptionPartition.new(opts, gemopts(flag), gem_session(flag),
923
985
  project: self, no: OPT_GEM[:no][flag == :update ? :install : flag])
924
- from = :"gem:#{flag}"
986
+ from = symjoin 'gem', flag
925
987
  if flag == :outdated
926
988
  op.adjoin(gempwd, start: 0) if gempwd
927
989
  op.clear
928
990
  cmd = session_done op.target
929
991
  log.info cmd
930
992
  on :first, from
931
- banner = format_banner(cmd)
993
+ banner = format_banner cmd
932
994
  print_item banner if sync
933
995
  major = [0, 0, 0]
934
996
  buffer = []
@@ -947,7 +1009,7 @@ module Squared
947
1009
  []
948
1010
  end
949
1011
  out = ->(val) { sync ? puts(val) : buffer << val }
950
- pwd_set(pass: !gempwd.nil?, from: from) do
1012
+ pwd_set(op.target, from: from, pass: !gempwd.nil?) do
951
1013
  rows = [[%w[Gem Current Latest], nil]]
952
1014
  IO.popen(cmd).each do |line|
953
1015
  if line =~ /^(\S+) \((\S+) < ([^)]+)\)$/
@@ -1003,7 +1065,7 @@ module Squared
1003
1065
  unless stdin?
1004
1066
  sub_style! g, theme[:major]
1005
1067
  styles = %i[green bold]
1006
- pat = (pat.first if pre)
1068
+ pat = pre ? pat.first : nil
1007
1069
  latest << :bold
1008
1070
  end
1009
1071
  major[0] += 1
@@ -1042,10 +1104,9 @@ module Squared
1042
1104
  out.call(queue)
1043
1105
  queue = nil
1044
1106
  end
1045
- s = ('%s %s %s' % [g, b, h]).yield_self do |val|
1046
- items&.push([val, a])
1047
- '%*s %s' % [pad, "#{j}.", val]
1048
- end
1107
+ s = '%s %s %s' % [g, b, h]
1108
+ items&.push([s, a])
1109
+ s = '%*s %s' % [pad, "#{j}.", s]
1049
1110
  if ia
1050
1111
  unless confirm_semver(s, type)
1051
1112
  update.delete(a)
@@ -1067,7 +1128,7 @@ module Squared
1067
1128
  else
1068
1129
  if items
1069
1130
  update = choice('Select a package', items.map(&:first),
1070
- 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 }
1071
1132
  end
1072
1133
  unless Array(update).empty?
1073
1134
  opts = ['f']
@@ -1140,7 +1201,7 @@ module Squared
1140
1201
  raise_error ArgumentError, "unrecognized args: #{op.join(', ')}", hint: flag unless op.empty?
1141
1202
  end
1142
1203
  op.add_path(file)
1143
- return run_rb(from: from, interactive: ['Push', 'N', gemname]) unless with || !banner
1204
+ return run(from: from, interactive: ['Push', 'N', gemname]) unless with || !banner
1144
1205
  when :exec
1145
1206
  min = if op.arg?('g', 'gem')
1146
1207
  1
@@ -1154,9 +1215,7 @@ module Squared
1154
1215
  0
1155
1216
  end
1156
1217
  op.concat(args)
1157
- if (args = command_args(op.extras, min: min, force: min == 1 && op.empty?))
1158
- op.push(args)
1159
- end
1218
+ command_args(op.extras, min: min, force: min == 1 && op.empty?)
1160
1219
  op.append(quote: false)
1161
1220
  when :update
1162
1221
  if !op.arg?('n', 'bindir') && (bin = config_get('bin')) && Dir.exist?(bin)
@@ -1189,7 +1248,8 @@ module Squared
1189
1248
  end
1190
1249
  elsif (n = op.index { |val| val.match?(/(\A|[a-z])@\d/) })
1191
1250
  name = op.remove_at(n)
1192
- pre, ver = if (n = name.index('@')) == 0
1251
+ n = name.index('@')
1252
+ pre, ver = if n == 0
1193
1253
  [gemname, name[1..-1]]
1194
1254
  else
1195
1255
  [name[0, n], name[n.succ..-1]]
@@ -1240,7 +1300,8 @@ module Squared
1240
1300
  end
1241
1301
  op.clear(errors: true) if gems
1242
1302
  print_run(op, banner, **kwargs)
1243
- 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)
1244
1305
  end
1245
1306
 
1246
1307
  def bundle(flag, *args, sync: true, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -1286,7 +1347,7 @@ module Squared
1286
1347
  end
1287
1348
  opts.concat(args)
1288
1349
  when :plugin
1289
- case (plu = args.shift || opts.shift)
1350
+ case (plu = args.shift)
1290
1351
  when 'install', 'uninstall', 'help', 'list'
1291
1352
  cmd << plu
1292
1353
  else
@@ -1296,7 +1357,7 @@ module Squared
1296
1357
  op = OptionPartition.new(opts, bundleopts(if pre == 'ssl'
1297
1358
  :doctor_ssl
1298
1359
  elsif plu
1299
- plu == 'install' ? :plugin : :"plugin_#{plu}"
1360
+ plu == 'install' ? :plugin : symjoin('plugin', plu, char: '_')
1300
1361
  else
1301
1362
  flag
1302
1363
  end),
@@ -1304,7 +1365,6 @@ module Squared
1304
1365
  project: self, no: OPT_BUNDLE[:no][flag], args: flag == :exec || flag == :config)
1305
1366
  op.concat(args) unless pre
1306
1367
  output = false
1307
- invalid = ->(a) { raise_error ArgumentError, "unrecognized args: #{a.join(', ')}", hint: flag }
1308
1368
  case flag
1309
1369
  when :config
1310
1370
  if pre == 'list'
@@ -1350,7 +1410,7 @@ module Squared
1350
1410
  else
1351
1411
  val = readline('Enter arguments', force: false)
1352
1412
  op << (val.empty? ? 'list' : val)
1353
- output = val.match?(/^(un)?set/)
1413
+ output = val.start_with?('set', 'unset')
1354
1414
  end
1355
1415
  when :plugin
1356
1416
  case plu
@@ -1378,8 +1438,9 @@ module Squared
1378
1438
  op.clear
1379
1439
  end
1380
1440
  print_run(op, banner, **kwargs)
1381
- run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: :"bundle:#{flag}")
1382
- .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)
1383
1444
  end
1384
1445
 
1385
1446
  def rake(*args, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:rake], **kwargs)
@@ -1390,26 +1451,26 @@ module Squared
1390
1451
  op.append(escape: true)
1391
1452
  print_run(op, banner, **kwargs)
1392
1453
  var = { 'BANNER' => '0' } unless banner
1393
- 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)
1394
1455
  end
1395
1456
 
1396
1457
  def irb(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:irb], **kwargs)
1397
1458
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1398
1459
  op = OptionPartition.new(opts, OPT_RUBY[:irb], session('irb'), project: self, first: [/\.rb$/])
1399
1460
  r = []
1400
- r << 'bundler/setup' unless op.arg?('r')
1401
- 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]
1402
1463
  r.each { |val| op.add_option('r', val, merge: true) }
1403
- 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) })
1404
1465
  op.concat(args)
1405
1466
  op.append(delim: true)
1406
1467
  print_run(op, banner, **kwargs)
1407
- run(banner: false, exception: kwargs.fetch(:exception, exception), from: :irb)
1468
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: :irb)
1408
1469
  end
1409
1470
 
1410
1471
  def rbs(flag, *args, banner: verbose?, with: nil, pass: nil, **kwargs)
1411
1472
  case pass
1412
- when NilClass
1473
+ when nil
1413
1474
  pass = PASS_RUBY[:rbs]
1414
1475
  when Array
1415
1476
  pass += PASS_RUBY[:rbs]
@@ -1422,7 +1483,7 @@ module Squared
1422
1483
  sig = args.shift
1423
1484
  y = option('y', ignore: false)
1424
1485
  i = 1
1425
- 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|
1426
1487
  dir = basepath sig, file.dirname
1427
1488
  dir.mkpath unless dir.exist?
1428
1489
  base = file.basename.to_s
@@ -1438,8 +1499,8 @@ module Squared
1438
1499
  end
1439
1500
  end
1440
1501
  unless status == 'ignored'
1441
- ret = run(op.target.temp(File.extname(base) == '.rbi' ? 'rbi' : 'rb', file, '>', rbs), banner: false,
1442
- series: true)
1502
+ ret = run(op.target.temp(File.extname(base) == '.rbi' ? 'rbi' : 'rb', file, '>', rbs),
1503
+ banner: false, series: true)
1443
1504
  if !ret
1444
1505
  status = 'FAIL'
1445
1506
  elsif File.empty?(rbs)
@@ -1453,7 +1514,7 @@ module Squared
1453
1514
  op.clear
1454
1515
  .append(*args)
1455
1516
  print_run(op, banner, **kwargs)
1456
- run(banner: false, exception: kwargs.fetch(:exception, exception), from: :"rbs:#{flag}")
1517
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: symjoin('rbs', flag))
1457
1518
  end
1458
1519
  end
1459
1520
 
@@ -1472,12 +1533,11 @@ module Squared
1472
1533
  op.errors << val
1473
1534
  end
1474
1535
  end
1475
- op.swap
1476
- .map! { |val| basepath(val).relative_path_from(path) }
1536
+ op.swap.map! { |val| basepath(val).relative_path_from(path) }
1477
1537
  op.append(delim: true)
1478
1538
  .clear(errors: true)
1479
1539
  print_run(op, banner, **kwargs)
1480
- 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)
1481
1541
  end
1482
1542
 
1483
1543
  def gemspec
@@ -1522,20 +1582,20 @@ module Squared
1522
1582
  if pwd_set { `rbenv which ruby` } =~ %r{^(.+[\\/]versions[\\/](\d\.\d)\.[^\\/]+)[\\/]bin[\\/]ruby$}
1523
1583
  File.join($1, 'lib/ruby/gems', "#{$2}.0")
1524
1584
  end
1525
- when 'asdf'
1526
- pwd_set { `asdf where ruby`.chomp }.yield_self do |val|
1527
- val =~ /(\d\.\d)\.[^.]+$/ && File.join(val, 'lib/ruby/gems', "#{$1}.0")
1528
- 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)\.[^.]+$/
1529
1588
  when /bundler?/
1530
1589
  pwd_set { `bundle env` }[/^\s+Gem Path\s+(.+)$/, 1].split(File::PATH_SEPARATOR).find do |val|
1531
1590
  Dir.exist?(File.join(val, 'gems'))
1532
1591
  end
1533
1592
  else
1534
1593
  ENV['GEM_HOME'] || ENV['GEM_ROOT']
1535
- end.tap do |val|
1594
+ end
1595
+ .tap do |val|
1536
1596
  return true if val && set.call(version, val)
1537
1597
  end
1538
- rescue StandardError => e
1598
+ rescue => e
1539
1599
  log.debug e
1540
1600
  end
1541
1601
  pwd_set(pass: !gempwd.nil?) do
@@ -1569,7 +1629,7 @@ module Squared
1569
1629
  raise_error Errno::ENOENT, 'gems home'
1570
1630
  end
1571
1631
  end
1572
- rescue StandardError => e
1632
+ rescue => e
1573
1633
  log.error e
1574
1634
  self.version = nil
1575
1635
  @gemdir = nil
@@ -1584,10 +1644,6 @@ module Squared
1584
1644
 
1585
1645
  private
1586
1646
 
1587
- def run_rb(**kwargs)
1588
- run(banner: !@session&.include?('--quiet'), **kwargs)
1589
- end
1590
-
1591
1647
  def ruby_session(*cmd, **kwargs)
1592
1648
  session('ruby', *preopts, *cmd, **kwargs)
1593
1649
  end
@@ -1597,7 +1653,9 @@ module Squared
1597
1653
  end
1598
1654
 
1599
1655
  def bundle_session(*cmd, **kwargs)
1600
- session('bundle', *cmd, *preopts, **kwargs).tap { append_nocolor }
1656
+ ret = session('bundle', *cmd, *preopts, **kwargs)
1657
+ append_nocolor
1658
+ ret
1601
1659
  end
1602
1660
 
1603
1661
  def rake_session(*cmd, **kwargs)
@@ -1627,22 +1685,47 @@ module Squared
1627
1685
  session_output('rake', *cmd, **kwargs)
1628
1686
  end
1629
1687
 
1630
- def config_get(key)
1631
- out = pwd_set { `#{bundle_output('config get --parseable', key)}`.chomp }
1632
- 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
1695
+
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
1633
1703
 
1634
- case (out = $2)
1635
- when 'true'
1636
- true
1637
- when '', '[]'
1638
- nil
1639
- else
1640
- if out =~ /\A\[:(.+)\]\z/
1641
- $1.split(', :').map { |val| ((val.delete_prefix!('"') && val.delete_suffix!('"')) || val).to_sym }
1642
- else
1643
- out || false
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
1644
1726
  end
1645
1727
  end
1728
+ ret unless first && ret.empty?
1646
1729
  end
1647
1730
 
1648
1731
  def config_set(key, *val, global: false)
@@ -1650,9 +1733,11 @@ module Squared
1650
1733
  end
1651
1734
 
1652
1735
  def unpack_get(tag, ext)
1653
- return super unless ext == 'gem'
1654
-
1655
- "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
1736
+ if ext == 'gem'
1737
+ "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
1738
+ else
1739
+ super
1740
+ end
1656
1741
  end
1657
1742
 
1658
1743
  def preopts
@@ -1679,9 +1764,8 @@ module Squared
1679
1764
 
1680
1765
  def raketasks
1681
1766
  @raketasks ||= [].tap do |ret|
1682
- opt = rakepwd
1683
- pwd_set(pass: !opt.nil?) do
1684
- 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|
1685
1769
  next unless line =~ /^rake ((?:[^\[: ]+:?)+)(\[[^\]]+\])?/
1686
1770
 
1687
1771
  ret << [$1, $2]
@@ -1696,12 +1780,15 @@ module Squared
1696
1780
  args << :install_a
1697
1781
  when :add, :plugin
1698
1782
  args << :common_git
1699
- when :binstubs, :cache
1700
- args << :common_all
1701
1783
  when :lock, :outdated
1702
1784
  args << :common_version
1703
1785
  end
1704
- 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
1705
1792
  end
1706
1793
 
1707
1794
  def gemopts(*args)
@@ -1720,8 +1807,15 @@ module Squared
1720
1807
  case args.first
1721
1808
  when :info, :list, :search
1722
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, [])
1723
1818
  end
1724
- OPT_GEM[:common] + args.flat_map { |name| OPT_GEM.fetch(name, []) }
1725
1819
  end
1726
1820
 
1727
1821
  def gempwd
@@ -1744,7 +1838,7 @@ module Squared
1744
1838
  if (spec = gemspec)
1745
1839
  lib.merge(spec.require_paths || [])
1746
1840
  end
1747
- lib.select { |file| exist?(file) }
1841
+ lib.select { |file| exist?(file, type: 'd') }
1748
1842
  end
1749
1843
  end
1750
1844
 
@@ -1759,6 +1853,26 @@ module Squared
1759
1853
 
1760
1854
  gemdir.exist? && !gemdir.empty? && gemdir.writable?
1761
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
1762
1876
  end
1763
1877
 
1764
1878
  Application.implement Ruby