squared 0.7.2 → 0.7.4

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.
@@ -16,11 +16,13 @@ module Squared
16
16
  D|describe=q? e|execute=q E|execute-continue=q p|execute-print=q f|rakefile=p job-stats=b? j|jobs=i?
17
17
  I|libdir=p R|rakelib=p rakelibdir=p r|require=b suppress-backtrace=q T|tasks=q? t|trace=b?
18
18
  W|where=q?].freeze,
19
- irb: %w[d f U w E=b I=p r=b W=im? autocomplete colorize echo echo-on-assignment extra-doc-dir inf-ruby-mode
19
+ irb: %w[d f U w E=b I=p r=bm W=im? autocomplete colorize echo echo-on-assignment extra-doc-dir inf-ruby-mode
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
23
  back-trace-limit=i context-mode=i prompt=b prompt-mode=b].freeze,
24
+ rdbg: %w[no-color no-rc no-sigint-hook c|command n|nonstop stop-at-load cookie=q e=q host=q x|init-script=p
25
+ O|open=q? port=i port-range=b session-name=q sock-path=q util=q].freeze,
24
26
  rbs: %w[I=pm r=bm no-stdlib no-collection collection=p log-level=b log-output=p repo=p].freeze,
25
27
  rubocop: %w[D P r=bm auto-gen-config a|autocorrect A|autocorrect-all d|debug disable-pending-cops
26
28
  display-only-correctable display-only-fail-level-offenses display-only-failed
@@ -32,6 +34,8 @@ module Squared
32
34
  start-server stderr stop-server C|cache=b cache-root=p config=p exclude-limit=i fail-level=b
33
35
  f|format=b except=q only=q o|out=p plugin=p require=p show-cops=q show-docs-url=q
34
36
  s|stdin=p].freeze,
37
+ pry: %w[f I=pm no-color no-history no-multiline no-pager no-plugins simple-prompt c|context=q
38
+ d|disable-plugin=q e=q gem=b r|require=bm s|select-plugin=q].freeze,
35
39
  no: {
36
40
  rubocop: %w[auto-gen-enforced-style auto-gen-only-exclude auto-gen-timestamp color display-cop-names
37
41
  offense-counts parallel server].freeze
@@ -158,7 +162,9 @@ module Squared
158
162
  rake: %w[I libdir r require].freeze,
159
163
  irb: %w[I r].freeze,
160
164
  rbs: %w[I r repo].freeze,
165
+ rdbg: %w[cookie].freeze,
161
166
  rubocop: %w[format plugin r require].freeze,
167
+ pry: %w[I d disable-plugin r require].freeze,
162
168
  gem: {
163
169
  contents: %w[s spec-dir].freeze,
164
170
  dependency: %w[s source].freeze,
@@ -192,16 +198,19 @@ module Squared
192
198
 
193
199
  subtasks({
194
200
  'outdated' => %i[major minor patch].freeze,
195
- 'ruby' => %i[file script version].freeze,
201
+ 'ruby' => %i[file script version reshim].freeze,
196
202
  'gem' => %i[install uninstall outdated update pristine build push exec command].freeze,
197
- 'bundle' => %i[config install update cache exec reinstall command].freeze,
203
+ 'bundle' => %i[config install update cache exec check reinstall command].freeze,
198
204
  'rake' => nil,
199
205
  'irb' => nil,
206
+ 'rdbg' => nil,
200
207
  'rbs' => nil,
201
- 'rubocop' => nil
208
+ 'rubocop' => nil,
209
+ 'pry' => nil
202
210
  })
203
211
 
204
212
  attr_reader :gemdir
213
+ attr_accessor :autodetect
205
214
 
206
215
  def initialize(*, autodetect: false, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby', **kwargs)
207
216
  super
@@ -215,11 +224,11 @@ module Squared
215
224
  dependfile_set GEMFILE
216
225
  serve_set kwargs[:serve]
217
226
  gemfile_set kwargs[:gemspec]
218
- @autodetect = autodetect
227
+ self.autodetect = autodetect
219
228
  @steepfile = basepath! steep if steep
220
229
  @rubocopfile = Pathname.new(rubocop).realpath rescue basepath!(Dir.home, '.rubocop.yml') if rubocop
221
230
  @rubygems = kwargs.fetch(:rubygems, 0)
222
- return unless rakefile && @output[0].nil? && @copy.nil? && !version && !@autodetect
231
+ return unless rakefile && @output[0].nil? && @copy.nil? && !version && !self.autodetect
223
232
 
224
233
  begin
225
234
  File.foreach(rakefile) do |line|
@@ -302,13 +311,36 @@ module Squared
302
311
  queue.call
303
312
  end
304
313
  end
305
- when 'irb'
314
+ when 'irb', 'pry'
315
+ next unless action == 'irb' || gemspec?(action)
316
+
306
317
  format_desc action, nil, 'opts*,args*|:'
307
318
  task action do |_, args|
308
319
  opts = args.to_a
309
320
  args = Array(opts.delete(':') && readline('Enter file [arguments]', force: false))
310
321
  name = gemname if gemlib.any? { |file| exist?(file, "#{gemname}.rb") }
311
- irb(*args, opts: opts, name: name, verbose: false)
322
+ __send__(action, *args, opts: opts, name: name, verbose: false)
323
+ end
324
+ when 'rdbg'
325
+ format_desc action, nil, 'file?/:,opts*,debuggee?/::'
326
+ task action do |_, args|
327
+ opts = args.to_a
328
+ cmd = opts.delete('::')
329
+ if (n = opts.index('c'))
330
+ args = opts.slice!(n.succ..-1)
331
+ else
332
+ file = opts.shift
333
+ args = []
334
+ if (file == ':' && (d = path)) || (file && (d = basepath(file)).directory?)
335
+ args << choice_index('Select file', d.glob('*.rb').map { |f| f.relative_path_from(path) })
336
+ elsif exist?(file, type: 'f')
337
+ args << file
338
+ else
339
+ opts.unshift(file)
340
+ end
341
+ end
342
+ args << readline('Enter debuggee [arguments]', force: false) if cmd
343
+ rdbg(*args.compact, opts: opts, banner: false, verbose: false)
312
344
  end
313
345
  when 'rbs'
314
346
  next unless @steepfile
@@ -321,9 +353,9 @@ module Squared
321
353
  data[$1 || $3.gsub(/[: ]/, '-')] = target
322
354
  next
323
355
  end
324
- next unless target && line =~ /^\s*(check|signature)\s+(["'])(.+)\2/
356
+ next unless target && line =~ /^\s*(?:(check)|signature)\s+(["'])(.+)\2/
325
357
 
326
- target[$1 == 'check' ? 1 : 0] << $3
358
+ target[$1 ? 1 : 0] << $3
327
359
  end
328
360
  next if data.empty?
329
361
 
@@ -458,6 +490,16 @@ module Squared
458
490
  task flag do |_, args|
459
491
  bundle(flag, opts: args.to_a, banner: flag == :exec ? verbose? : true)
460
492
  end
493
+ when :check
494
+ format_desc action, flag, 'gemfile?,d/ry-run?'
495
+ task flag do |_, args|
496
+ args = args.to_a
497
+ opts = []
498
+ opts << 'dry-run' if has_value!(args, 'd', 'dry-run')
499
+ opts << "gemfile=#{shell_quote(args.pop, option: false, force: false)}" if exist?(args.first)
500
+ opts.concat(args)
501
+ bundle(:check, opts: opts, banner: true)
502
+ end
461
503
  when :reinstall
462
504
  format_desc action, flag, 'f/orce?,l/ocal?,opts*'
463
505
  task flag do |_, args|
@@ -528,120 +570,102 @@ module Squared
528
570
  ruby(flag, opts: args.to_a, command: command)
529
571
  end
530
572
  when :version
531
- format_desc action, flag
532
- task flag do
533
- pwd_set do
534
- out = []
535
- order = { 'rbenv' => -1, 'rvm' => -1, 'chruby' => -1, 'mise' => -1 }
536
- ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
537
- order.each_key do |key|
538
- next unless val.match?(%r{[/.]#{key}/})
539
-
540
- order[key] = index
541
- break
573
+ format_desc action, flag, 'local?,alias?'
574
+ task flag, [:local, :name] do |_, args|
575
+ ver = %w[.tool-versions .ruby-version]
576
+ mise = %w[mise.local.toml mise.toml]
577
+ s = args.local
578
+ if s && (%w[system latest].include?(s) || SEM_VER.match?(s) || s.start_with?(/(path|ref):/))
579
+ rbvm = exist?(ver.last) && !exist?(ver.first)
580
+ case vmname
581
+ when nil
582
+ print_error('no version manager detected', subject: name)
583
+ next
584
+ when 'asdf'
585
+ unless rbvm
586
+ asdf(:set, **{ name: args.name, version: s, banner: verbose? }.compact)
587
+ next
542
588
  end
543
- end
544
- if @asdf
545
- [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
546
- else
547
- [
548
- "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
549
- '$HOME/.rvm/bin/rvm',
550
- '$HOME/.local/bin/mise',
551
- '/usr/bin/rbenv',
552
- '/usr/bin/mise',
553
- '/usr/local/rvm/bin/rvm',
554
- '/usr/share/rvm/bin/rvm',
555
- '/usr/local/share/chruby/chruby.sh'
556
- ]
557
- .sort do |a, b|
558
- c = -1
559
- d = -1
560
- order.each do |key, val|
561
- pat = %r{/\.?#{key}}
562
- c = val if a.match?(pat)
563
- d = val if b.match?(pat)
564
- end
565
- if c == d
566
- 0
567
- elsif c == -1
568
- 1
569
- elsif d == -1
570
- -1
571
- else
572
- c < d ? -1 : 1
573
- end
589
+ when 'mise'
590
+ if mise.none? { |val| exist?(val) } && rbvm.call
591
+ save.call
592
+ else
593
+ cmd = session 'mise', 'use'
594
+ cmd << '--env local' if exist?(mise.first)
595
+ cmd << "#{args.name || 'ruby'}@#{s}"
596
+ run(banner: verbose?)
597
+ next
574
598
  end
575
- .push('')
576
599
  end
577
- .each do |val|
578
- next unless val.empty? || File.exist?(val.sub('$HOME', Dir.home))
579
-
580
- trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
581
- ver = %w[.tool-versions .ruby-version]
582
- out << trim.call(case (cmd = File.basename(val))
583
- when 'rvm'
584
- ver.shift
585
- `rvm current`[/^\S+/, 0]
586
- when 'rbenv'
587
- ver.shift
588
- name = `rbenv version-name`
589
- name.match?(SEM_VER) ? "ruby #{name}" : name
590
- when 'chruby.sh'
591
- ver.shift
592
- chruby = session_output 'source', val
593
- `#{chruby.with('ruby --version')}`
594
- when 'mise'
595
- data = parse_json(`mise ls ruby --json`, kind: Array)
596
- data = data.find { |item| item['active'] } || data.first
597
- "ruby #{data['version']}"
598
- else
599
- if @asdf
600
- cmd = 'asdf'
601
- if @@asdf.config && File.exist?(@@asdf.config)
602
- pat = /legacy_version_file\s+=\s+(yes|no)/
603
- ver.pop unless File.read(@@asdf.config)[pat, 1] == 'yes'
604
- else
605
- ver.pop
606
- end
607
- opt = [@asdf.first]
608
- opt.unshift('--no-header') unless @@asdf.version == 15
609
- cur = `asdf current #{opt.join(' ')}`
610
- if cur.match?(/\sfalse\b/)
611
- `ruby --version`
612
- else
613
- cur[/^\S+\s+\S+/, 0].sub(/\s+/, ' ')
614
- end
615
- else
616
- ver = nil
617
- `ruby --version`
600
+ File.write(basepath(ver.last), "#{s}\n") if SEM_VER.match?(s)
601
+ next
602
+ end
603
+ pwd_set do
604
+ out = []
605
+ tool = args.name || (args.local && !SEM_VER.match?(args.local) ? args.local : 'ruby')
606
+ trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
607
+ out << trim.call(case (vm, bin = vmname(bin: true))
608
+ when 'rvm'
609
+ ver.shift
610
+ `rvm current`[/^\S+/, 0]
611
+ when 'rbenv'
612
+ ver.shift
613
+ name = `rbenv version-name`
614
+ (name =~ SEM_VER) == 0 ? "ruby #{name}" : name
615
+ when 'chruby'
616
+ ver.shift
617
+ chruby = session_output 'source', bin
618
+ `#{chruby.with('ruby --version')}`
619
+ when 'mise'
620
+ data = parse_json(`mise ls #{tool} --json`, kind: Array)
621
+ cur = `mise current #{tool}`.split.find do |val|
622
+ data.any? do |item|
623
+ item['version'] == val && item['installed'] && item['active']
618
624
  end
619
- end)
620
- break if workspace.windows?
621
-
622
- unless val.empty?
623
- out << trim.call(case cmd
624
- when 'chruby.sh'
625
+ end
626
+ "ruby #{cur || data.first['version']}"
627
+ when 'asdf'
628
+ if @@asdf.config && File.exist?(@@asdf.config)
629
+ pat = /legacy_version_file\s+=\s+(yes|no)/
630
+ ver.pop unless File.read(@@asdf.config)[pat, 1] == 'yes'
631
+ else
632
+ ver.pop
633
+ end
634
+ opt = [@asdf.first]
635
+ opt.unshift('--no-header') unless @@asdf.version == 15
636
+ exit 1 unless (cur = `asdf current #{opt.join(' ')}`)
637
+ if cur.match?(/\sfalse\b/)
638
+ `ruby --version`
639
+ else
640
+ cur[/^\S+\s+\S+/, 0].sub(/\s+/, ' ')
641
+ end
642
+ else
643
+ ver = nil
644
+ `ruby --version`
645
+ end)
646
+ unless workspace.windows?
647
+ if vm
648
+ out << trim.call(case vm
649
+ when 'chruby'
625
650
  `#{chruby.with('chruby --version')}`.sub(':', '')
626
651
  when 'asdf'
627
652
  "asdf #{`asdf version`.delete_prefix('v')}"
628
653
  when 'mise'
629
- data = parse_json `mise version --json`
630
- "mise #{data['latest']}"
654
+ "mise #{parse_json(`mise version --json`, key: 'latest')}"
631
655
  else
632
- `#{cmd} --version`
656
+ `#{vm} --version`
633
657
  end)
634
658
  end
635
659
  begin
636
- out << ('which %s' % case cmd
660
+ out << ('which %s' % case vm
637
661
  when 'rbenv'
638
- `rbenv which ruby`
639
- when 'chruby.sh'
662
+ `rbenv which #{tool}`
663
+ when 'chruby'
640
664
  `#{chruby.with('which ruby')}`
641
665
  when 'asdf'
642
666
  `asdf which #{@asdf.first}`
643
667
  when 'mise'
644
- `mise which ruby`
668
+ `mise which #{tool}`
645
669
  else
646
670
  `which ruby`
647
671
  end)
@@ -649,24 +673,29 @@ module Squared
649
673
  log.debug e
650
674
  end
651
675
  if ver
676
+ ver = mise + ver if vm == 'mise'
652
677
  catch :found do
653
678
  path.ascend do |dir|
654
679
  ver.filter { |val| dir.join(val).exist? }.each do |val|
655
680
  dir += val
656
- hint = File.read(dir)
657
- .lines
658
- .map { |s| s.sub(/#.*$/, '').strip }
659
- .reject(&:empty?)
660
- .join(', ')
681
+ file = File.read(dir)
682
+ hint = if val.include?('mise')
683
+ line = file[/^\s*#{tool}\s*=\s*\[?(.+?)\]?\s*$/, 1]
684
+ line&.gsub(/["']/, '')
685
+ else
686
+ file.lines
687
+ .map { |line| line.sub(/#.*$/, '').strip }
688
+ .reject(&:empty?)
689
+ .join(', ')
690
+ end
661
691
  out << message("found #{dir}", hint: hint)
662
- throw :found if hint.include?(out.first[/^ruby (.+)$/, 1])
692
+ throw :found if hint&.include?(out.first[/^(?:j|truffle)?ruby ([\d.]+)/, 1])
663
693
  rescue
664
694
  nil
665
695
  end
666
696
  end
667
697
  end
668
698
  end
669
- break
670
699
  end
671
700
  out.map!(&:split)
672
701
  pad = as_a(out, :first, :size).max
@@ -674,6 +703,21 @@ module Squared
674
703
  puts(out.map { |line| '%*s %s' % [pad, line.first, line[1..-1].join(' ')] })
675
704
  end
676
705
  end
706
+ when :reshim
707
+ format_desc action, flag, 'name?'
708
+ task flag, [:name] do |_, args|
709
+ case vmname
710
+ when 'rbenv'
711
+ cmd = session 'rbenv', 'rehash'
712
+ when 'asdf'
713
+ asdf(:reshim, **{ name: args.name, banner: verbose? }.compact)
714
+ when 'mise'
715
+ cmd = session('mise', 'reshim', args.name || 'ruby')
716
+ else
717
+ print_error('not supported by version manager', subject: args.name)
718
+ end
719
+ success?(run(banner: verbose?), verbose?) if cmd
720
+ end
677
721
  end
678
722
  end
679
723
  end
@@ -848,10 +892,8 @@ module Squared
848
892
  when '~>'
849
893
  if c < v && cur[0] == val[0] && !semmajor?(cur, val)
850
894
  styles[0] = :yellow
851
- elsif semmajor?(val, lat)
852
- styles[1] = :underline
853
- else
854
- styles[1] = :bold
895
+ else
896
+ styles[1] = semmajor?(val, lat) ? :underline : :bold
855
897
  end
856
898
  end
857
899
  end
@@ -906,7 +948,7 @@ module Squared
906
948
  items.map(&:last)
907
949
  end
908
950
  if dryrun
909
- print_run bundle_output("update --#{flag}", *gems.quote!), false
951
+ print_run bundle_output("update --#{flag}", *gems.quote!(escape: true)), false
910
952
  else
911
953
  bundle(:update, *gems, opts: [flag.to_s])
912
954
  end
@@ -1151,7 +1193,7 @@ module Squared
1151
1193
  end
1152
1194
  end
1153
1195
  if filter[:dryrun]
1154
- print_run gem_output('update -f', *update.quote!), false
1196
+ print_run gem_output('update -f', *update.quote!(escape: true)), false
1155
1197
  else
1156
1198
  gem(:update, *update, opts: opts)
1157
1199
  end
@@ -1227,7 +1269,7 @@ module Squared
1227
1269
  if op.arg?('system')
1228
1270
  op.add_first(quote: false) { |val| val if val.match?(SEM_VER) }
1229
1271
  else
1230
- op.append
1272
+ op.append(escape: true)
1231
1273
  end
1232
1274
  when :install, :uninstall, :pristine
1233
1275
  if flag == :install
@@ -1241,18 +1283,18 @@ module Squared
1241
1283
  args.join(' ')
1242
1284
  end
1243
1285
  elsif ia
1244
- name = op.shift || args.shift || (s = readline('Enter gem name', force: true))
1286
+ name = op.shift || args.shift || (out = readline('Enter gem name', force: true))
1245
1287
  list = []
1246
1288
  pwd_set do
1247
1289
  pat = /^#{name}\s+\((.+)\)$/
1248
1290
  IO.popen(gem_output("list -a #{shell_quote(name)}").to_s).each do |val|
1249
1291
  next unless val =~ pat
1250
1292
 
1251
- split_escape($1).each { |val| list << val unless val.start_with?('default:') }
1293
+ split_escape($1).each { |s| list << s unless s.start_with?('default:') }
1252
1294
  break
1253
1295
  end
1254
1296
  end
1255
- ver = choice_index('Select version', list, force: s.nil?) unless list.empty?
1297
+ ver = choice_index('Select version', list, force: out.nil?) unless list.empty?
1256
1298
  if ver
1257
1299
  op << '--force'
1258
1300
  op.unshift("#{name}@#{ver}")
@@ -1280,9 +1322,9 @@ module Squared
1280
1322
  .clear
1281
1323
  end
1282
1324
  if flag == :install
1283
- op.append_any
1325
+ op.append_any(escape: true)
1284
1326
  else
1285
- op.append
1327
+ op.append(escape: true)
1286
1328
  end
1287
1329
  op.delim << post if post
1288
1330
  when :check, :cleanup, :contents, :fetch, :list, :lock, :rdoc
@@ -1478,16 +1520,30 @@ module Squared
1478
1520
 
1479
1521
  def irb(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:irb], **kwargs)
1480
1522
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1481
- op = OptionPartition.new(opts, OPT_RUBY[:irb], session('irb'), project: self, first: [/\.rb$/])
1482
- r = []
1483
- r << 'bundler/setup' if !op.arg?('r') && bundle_load
1484
- r.concat(Array(kwargs[:name])) if kwargs[:name]
1485
- r.each { |val| op.add_option('r', val, merge: true) }
1486
- op.merge((gemlib + Array(kwargs[:path])).map { |val| quote_option('I', val, merge: true) })
1523
+ run_repl(*args, opts: opts, banner: banner, from: :irb, **kwargs)
1524
+ end
1525
+
1526
+ def pry(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:pry], **kwargs)
1527
+ opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1528
+ run_repl(*args, opts: opts, banner: banner, from: :pry, delim: false, **kwargs)
1529
+ end
1530
+
1531
+ def rdbg(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:rdbg], **kwargs)
1532
+ opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1533
+ cmd = session 'rdbg'
1534
+ args.each_with_index do |val, index|
1535
+ break if val == '--'
1536
+ next unless exist?(val, type: 'f')
1537
+
1538
+ args[index] = shell_quote(basepath(val))
1539
+ cmd.merge(args.slice!(0, index + 1))
1540
+ break
1541
+ end
1542
+ op = OptionPartition.new(opts, OPT_RUBY[:rdbg], cmd, project: self, first: [/\.rb$/])
1487
1543
  op.concat(args)
1488
- op.append(delim: true)
1544
+ op.append(quote: false, delim: true)
1489
1545
  print_run(op, banner, **kwargs)
1490
- run(banner: false, exception: kwargs.fetch(:exception, exception?), from: :irb)
1546
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: :rdbg)
1491
1547
  end
1492
1548
 
1493
1549
  def rbs(flag, *args, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -1562,7 +1618,7 @@ module Squared
1562
1618
  run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception?), from: :rubocop)
1563
1619
  end
1564
1620
 
1565
- def serve(root, *, bind: nil, port: nil, **kwargs)
1621
+ def serve(root, *, bind: nil, port: 3000, **kwargs)
1566
1622
  require 'webrick'
1567
1623
  config = kwargs.merge({ DocumentRoot: root })
1568
1624
  config[:BindAddress] = bind if bind
@@ -1574,6 +1630,61 @@ module Squared
1574
1630
  server.start
1575
1631
  end
1576
1632
 
1633
+ def vmname(bin: false)
1634
+ order = { 'rbenv' => -1, 'rvm' => -1, 'chruby' => -1, 'mise' => -1 }
1635
+ ENV.fetch('PATH', '').split(':').each_with_index do |val, index|
1636
+ order.each_key do |key|
1637
+ next unless val.match?(%r{[/.]#{key}/})
1638
+
1639
+ order[key] = index
1640
+ break
1641
+ end
1642
+ end
1643
+ if @asdf
1644
+ [File.join(ENV.fetch('ASDF_DATA_DIR', '$HOME/.asdf'), "installs/#{@asdf.first}")]
1645
+ else
1646
+ [
1647
+ "#{ENV.fetch('RBENV_ROOT', '$HOME/.rbenv')}/bin/rbenv",
1648
+ '$HOME/.rvm/bin/rvm',
1649
+ '$HOME/.local/bin/mise',
1650
+ '/usr/bin/rbenv',
1651
+ '/usr/bin/mise',
1652
+ '/usr/local/rvm/bin/rvm',
1653
+ '/usr/share/rvm/bin/rvm',
1654
+ '/usr/local/share/chruby/chruby.sh'
1655
+ ]
1656
+ .sort do |a, b|
1657
+ c = -1
1658
+ d = -1
1659
+ order.each do |key, val|
1660
+ pat = %r{/\.?#{key}}
1661
+ c = val if a.match?(pat)
1662
+ d = val if b.match?(pat)
1663
+ end
1664
+ if c == d
1665
+ 0
1666
+ elsif c == -1
1667
+ 1
1668
+ elsif d == -1
1669
+ -1
1670
+ else
1671
+ c < d ? -1 : 1
1672
+ end
1673
+ end
1674
+ end
1675
+ .each do |val|
1676
+ next unless File.exist?(val = val.sub('$HOME', Dir.home))
1677
+
1678
+ case (ret = File.basename(val, '.*'))
1679
+ when 'rvm', 'rbenv', 'mise', 'chruby'
1680
+ return bin ? [ret, val] : ret
1681
+ else
1682
+ return bin ? ['asdf', val] : 'asdf' if @asdf
1683
+ end
1684
+ end
1685
+ nil
1686
+ end
1687
+
1577
1688
  def gemspec
1578
1689
  @gemspec = !gemfile.nil? && Gem::Specification.load(gemfile.to_s) rescue false if @gemspec.nil?
1579
1690
  @gemspec || nil
@@ -1596,7 +1707,7 @@ module Squared
1596
1707
  def copy?
1597
1708
  return true if @copy.is_a?(Hash) ? copy[:into] : super
1598
1709
  return gemdir? if gemdir
1599
- return false unless @autodetect
1710
+ return false unless autodetect
1600
1711
 
1601
1712
  set = lambda do |val, path|
1602
1713
  base = Pathname.new(path.strip)
@@ -1609,7 +1720,7 @@ module Squared
1609
1720
  end
1610
1721
  if version
1611
1722
  begin
1612
- case @autodetect
1723
+ case autodetect
1613
1724
  when 'rvm'
1614
1725
  pwd_set { `rvm info homes` }[/^\s+gem:\s+"(.+)"$/, 1]
1615
1726
  when 'rbenv'
@@ -1617,8 +1728,10 @@ module Squared
1617
1728
  File.join($1, 'lib/ruby/gems', "#{$2}.0")
1618
1729
  end
1619
1730
  when 'asdf', 'mise'
1620
- val = pwd_set { `#{@autodetect} where ruby`.chomp }
1621
- File.join(val, 'lib/ruby/gems', "#{$1}.0") if val =~ /(\d\.\d)\.[^.]+$/
1731
+ pwd_set do
1732
+ val = `#{autodetect} where ruby`.chomp
1733
+ File.join(val, 'lib/ruby/gems', "#{$1}.0") if val =~ /(\d\.\d)\.[^.]+$/
1734
+ end
1622
1735
  when /bundler?/
1623
1736
  pwd_set { `bundle env` }[/^\s+Gem Path\s+(.+)$/, 1].split(File::PATH_SEPARATOR).find do |val|
1624
1737
  Dir.exist?(File.join(val, 'gems'))
@@ -1665,9 +1778,9 @@ module Squared
1665
1778
  end
1666
1779
  rescue => e
1667
1780
  log.error e
1668
- self.version = nil
1669
1781
  @gemdir = nil
1670
- @autodetect = false
1782
+ self.version = nil
1783
+ self.autodetect = false
1671
1784
  else
1672
1785
  gemdir?
1673
1786
  end
@@ -1678,6 +1791,19 @@ module Squared
1678
1791
 
1679
1792
  private
1680
1793
 
1794
+ def run_repl(*args, opts:, banner:, from:, delim: true, **kwargs)
1795
+ op = OptionPartition.new(opts, OPT_RUBY[from], session(from), project: self, first: [/\.rb$/])
1796
+ r = []
1797
+ r << 'bundler/setup' if !op.arg?('r') && bundle_load
1798
+ r.concat(Array(kwargs[:name])) if kwargs[:name]
1799
+ r.each { |val| op.add_option('r', val, merge: true) }
1800
+ op.merge((gemlib + Array(kwargs[:path])).map { |val| quote_option('I', val, merge: true) })
1801
+ op.concat(args)
1802
+ op.append(delim: delim)
1803
+ print_run(op, banner, **kwargs)
1804
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: from)
1805
+ end
1806
+
1681
1807
  def ruby_session(*cmd, **kwargs)
1682
1808
  session('ruby', *preopts, *cmd, **kwargs)
1683
1809
  end
@@ -1768,7 +1894,7 @@ module Squared
1768
1894
 
1769
1895
  def unpack_get(tag, ext)
1770
1896
  if ext == 'gem'
1771
- "https://rubygems.org/downloads/#{File.basename(tag, '.gem')}.gem"
1897
+ "https://rubygems.org/downloads/#{tag.sub_ext('.gem')}"
1772
1898
  else
1773
1899
  super
1774
1900
  end
@@ -1883,13 +2009,11 @@ module Squared
1883
2009
  end
1884
2010
 
1885
2011
  def gemdir?
1886
- return false unless gemdir
1887
-
1888
- gemdir.exist? && !gemdir.empty? && gemdir.writable?
2012
+ !gemdir.nil? && gemdir.exist? && !gemdir.empty? && gemdir.writable?
1889
2013
  end
1890
2014
 
1891
2015
  def compat?(min, max = Float::INFINITY, gem: nil)
1892
- return false unless !gem || (bundle = gem.match?(/bundler?/))
2016
+ return false if gem && !gem.match?(/bundler?/)
1893
2017
 
1894
2018
  n = @rubygems
1895
2019
  if n.is_a?(Numeric) && n > 0
@@ -1900,14 +2024,20 @@ module Squared
1900
2024
  when String
1901
2025
  n
1902
2026
  when Array
1903
- n[bundle ? 1 : 0]
2027
+ n[gem ? 1 : 0]
1904
2028
  else
1905
- min.tap { min = (bundle && bundle_load) || Gem::VERSION }
2029
+ min.tap { min = (gem && bundle_load) || Gem::VERSION }
1906
2030
  end
1907
2031
  semgte?(ver.to_s, min.to_s) && (max == Float::INFINITY || !semgte?(ver.to_s, max.to_s))
1908
2032
  end
1909
2033
  end
1910
2034
 
2035
+ def gemspec?(name)
2036
+ !Gem::Specification.find_by_name(name).nil?
2037
+ rescue Gem::MissingSpecError
2038
+ false
2039
+ end
2040
+
1911
2041
  def serve?
1912
2042
  !Gem::Specification.find_by_name('webrick').nil?
1913
2043
  rescue Gem::MissingSpecError => e