squared 0.7.3 → 0.7.5

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,
@@ -194,11 +200,13 @@ module Squared
194
200
  'outdated' => %i[major minor patch].freeze,
195
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
@@ -303,13 +311,36 @@ module Squared
303
311
  queue.call
304
312
  end
305
313
  end
306
- when 'irb'
314
+ when 'irb', 'pry'
315
+ next unless action == 'irb' || gemspec?(action)
316
+
307
317
  format_desc action, nil, 'opts*,args*|:'
308
318
  task action do |_, args|
309
319
  opts = args.to_a
310
320
  args = Array(opts.delete(':') && readline('Enter file [arguments]', force: false))
311
321
  name = gemname if gemlib.any? { |file| exist?(file, "#{gemname}.rb") }
312
- 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)
313
344
  end
314
345
  when 'rbs'
315
346
  next unless @steepfile
@@ -322,9 +353,9 @@ module Squared
322
353
  data[$1 || $3.gsub(/[: ]/, '-')] = target
323
354
  next
324
355
  end
325
- next unless target && line =~ /^\s*(check|signature)\s+(["'])(.+)\2/
356
+ next unless target && line =~ /^\s*(?:(check)|signature)\s+(["'])(.+)\2/
326
357
 
327
- target[$1 == 'check' ? 1 : 0] << $3
358
+ target[$1 ? 1 : 0] << $3
328
359
  end
329
360
  next if data.empty?
330
361
 
@@ -459,6 +490,16 @@ module Squared
459
490
  task flag do |_, args|
460
491
  bundle(flag, opts: args.to_a, banner: flag == :exec ? verbose? : true)
461
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
462
503
  when :reinstall
463
504
  format_desc action, flag, 'f/orce?,l/ocal?,opts*'
464
505
  task flag do |_, args|
@@ -537,9 +578,6 @@ module Squared
537
578
  if s && (%w[system latest].include?(s) || SEM_VER.match?(s) || s.start_with?(/(path|ref):/))
538
579
  rbvm = exist?(ver.last) && !exist?(ver.first)
539
580
  case vmname
540
- when nil
541
- print_error('no version manager detected', subject: name)
542
- next
543
581
  when 'asdf'
544
582
  unless rbvm
545
583
  asdf(:set, **{ name: args.name, version: s, banner: verbose? }.compact)
@@ -555,6 +593,9 @@ module Squared
555
593
  run(banner: verbose?)
556
594
  next
557
595
  end
596
+ when nil
597
+ print_error('no version manager detected', subject: name)
598
+ next
558
599
  end
559
600
  File.write(basepath(ver.last), "#{s}\n") if SEM_VER.match?(s)
560
601
  next
@@ -563,16 +604,14 @@ module Squared
563
604
  out = []
564
605
  tool = args.name || (args.local && !SEM_VER.match?(args.local) ? args.local : 'ruby')
565
606
  trim = ->(s) { s[/^\D+\d+\.\d+(?:\.\S+)?/, 0].sub(/^([a-z]+)-/i, '\1 ') }
566
- out << trim.call(case (vm, bin = vmname(bin: true))
607
+ vm, bin = vmname(bin: true)
608
+ out << trim.call(case vm
567
609
  when 'rvm'
568
- ver.shift
569
610
  `rvm current`[/^\S+/, 0]
570
611
  when 'rbenv'
571
- ver.shift
572
612
  name = `rbenv version-name`
573
613
  (name =~ SEM_VER) == 0 ? "ruby #{name}" : name
574
614
  when 'chruby'
575
- ver.shift
576
615
  chruby = session_output 'source', bin
577
616
  `#{chruby.with('ruby --version')}`
578
617
  when 'mise'
@@ -592,7 +631,7 @@ module Squared
592
631
  end
593
632
  opt = [@asdf.first]
594
633
  opt.unshift('--no-header') unless @@asdf.version == 15
595
- cur = `asdf current #{opt.join(' ')}`
634
+ exit 1 unless (cur = `asdf current #{opt.join(' ')}`)
596
635
  if cur.match?(/\sfalse\b/)
597
636
  `ruby --version`
598
637
  else
@@ -626,32 +665,53 @@ module Squared
626
665
  when 'mise'
627
666
  `mise which #{tool}`
628
667
  else
629
- `which #{tool}`
668
+ `which ruby`
630
669
  end)
631
670
  rescue => e
632
671
  log.debug e
633
672
  end
634
673
  if ver
635
- ver = mise + ver if vm == 'mise'
674
+ if vm == 'mise'
675
+ ver = mise + ver
676
+ pat = /^\s*#{tool}\s*=\s*\[?(.+?)\]?\s*$/
677
+ elsif vm != 'asdf'
678
+ ver.shift
679
+ end
680
+ append = ->(file, hint) { out << message("found #{file}", hint: hint) }
636
681
  catch :found do
637
682
  path.ascend do |dir|
638
- ver.filter { |val| dir.join(val).exist? }.each do |val|
639
- dir += val
640
- file = File.read(dir)
683
+ ver.select { |val| dir.join(val).exist? }.each do |val|
684
+ file = dir + val
641
685
  hint = if val.include?('mise')
642
- line = file[/^\s*#{tool}\s*=\s*\[?(.+?)\]?\s*$/, 1]
643
- line&.gsub(/["']/, '')
686
+ file.read[pat, 1]&.gsub(/["']/, '')
644
687
  else
645
- file.lines
688
+ file.read
689
+ .lines
646
690
  .map { |line| line.sub(/#.*$/, '').strip }
647
691
  .reject(&:empty?)
648
692
  .join(', ')
649
693
  end
650
- out << message("found #{dir}", hint: hint)
694
+ append.call(file, hint)
651
695
  throw :found if hint&.include?(out.first[/^(?:j|truffle)?ruby ([\d.]+)/, 1])
652
696
  rescue
653
697
  nil
654
698
  end
699
+ file = case vm
700
+ when 'rbenv'
701
+ '.rbenv/version'
702
+ when 'rvm'
703
+ '.rvm/config/default'
704
+ when 'mise'
705
+ '.config/mise/config.toml'
706
+ else
707
+ next
708
+ end
709
+ if File.exist?(file = dir.join(file))
710
+ hint = out.first.split(' ', 2).last
711
+ pat ||= SEM_VER
712
+ append.call(file, file.read[/^(.*(?:#{Regexp.escape(hint)}|#{pat}).*)$/, 1])
713
+ throw :found
714
+ end
655
715
  end
656
716
  end
657
717
  end
@@ -673,7 +733,7 @@ module Squared
673
733
  when 'mise'
674
734
  cmd = session('mise', 'reshim', args.name || 'ruby')
675
735
  else
676
- print_error('not supported by version manager', subject: args.name)
736
+ print_error('reshim not supported by version manager', subject: args.name)
677
737
  end
678
738
  success?(run(banner: verbose?), verbose?) if cmd
679
739
  end
@@ -780,7 +840,7 @@ module Squared
780
840
  elsif se || ia || up
781
841
  items = []
782
842
  end
783
- OptionPartition.new(opts, bundleopts(:outdated), cmd << "--#{flag}", project: self)
843
+ OptionPartition.new(opts, bundleopts(:outdated), cmd << "--#{flag}", project: self, strict: strict?)
784
844
  .clear
785
845
  elsif (up = option('u', 'update', prefix: 'bundle'))
786
846
  flag = case up
@@ -851,10 +911,8 @@ module Squared
851
911
  when '~>'
852
912
  if c < v && cur[0] == val[0] && !semmajor?(cur, val)
853
913
  styles[0] = :yellow
854
- elsif semmajor?(val, lat)
855
- styles[1] = :underline
856
914
  else
857
- styles[1] = :bold
915
+ styles[1] = semmajor?(val, lat) ? :underline : :bold
858
916
  end
859
917
  end
860
918
  end
@@ -943,8 +1001,8 @@ module Squared
943
1001
  from = symjoin 'ruby', flag
944
1002
  end
945
1003
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
946
- op = OptionPartition.new(opts, OPT_RUBY[:ruby], ruby_session, project: self, multiple: [/^-e/], args: true,
947
- stdin: true)
1004
+ op = OptionPartition.new(opts, OPT_RUBY[:ruby], ruby_session, project: self, strict: strict?,
1005
+ multiple: [/^-e/], args: true, stdin: true)
948
1006
  if kwargs[:command]
949
1007
  op << quote_option('e', kwargs[:command])
950
1008
  elsif kwargs[:file]
@@ -987,7 +1045,7 @@ module Squared
987
1045
  opts.concat(args)
988
1046
  end
989
1047
  op = OptionPartition.new(opts, gemopts(flag), gem_session(flag),
990
- project: self, no: OPT_GEM[:no][flag == :update ? :install : flag])
1048
+ project: self, strict: strict?, no: OPT_GEM[:no][flag == :update ? :install : flag])
991
1049
  from = symjoin 'gem', flag
992
1050
  if flag == :outdated
993
1051
  op.adjoin(gempwd, start: 0) if gempwd
@@ -1341,7 +1399,7 @@ module Squared
1341
1399
  end
1342
1400
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1343
1401
  invalid = ->(a) { raise_error ArgumentError, "unrecognized args: #{a.join(', ')}", hint: flag }
1344
- cmd = bundle_session(flag)
1402
+ cmd = bundle_session flag
1345
1403
  case flag
1346
1404
  when :cache, :check, :clean, :init, :install, :lock, :pack, :package, :platform
1347
1405
  pre = true
@@ -1387,7 +1445,8 @@ module Squared
1387
1445
  flag
1388
1446
  end),
1389
1447
  cmd,
1390
- project: self, no: OPT_BUNDLE[:no][flag], args: flag == :exec || flag == :config)
1448
+ project: self, strict: strict?, no: OPT_BUNDLE[:no][flag],
1449
+ args: flag == :exec || flag == :config)
1391
1450
  op.concat(args) unless pre
1392
1451
  output = false
1393
1452
  case flag
@@ -1398,7 +1457,7 @@ module Squared
1398
1457
  a = op.dup
1399
1458
  b, c = op.slice!(0, 2)
1400
1459
  d = op.arg?('global', 'local')
1401
- getname = -> { op << (b || readline('Enter name', force: true)) }
1460
+ getname = -> { b ? op << b : op.readline('Enter name') }
1402
1461
  case pre
1403
1462
  when 'get'
1404
1463
  getname.call
@@ -1409,7 +1468,7 @@ module Squared
1409
1468
  c = op.shift
1410
1469
  end
1411
1470
  getname.call
1412
- op << (c || readline('Enter value', force: true))
1471
+ c ? op << c : op.readline('Enter value', quote: true)
1413
1472
  output = true
1414
1473
  when 'unset'
1415
1474
  if d
@@ -1433,9 +1492,8 @@ module Squared
1433
1492
  end
1434
1493
  op.clear
1435
1494
  else
1436
- val = readline('Enter arguments', force: false)
1437
- op << (val.empty? ? 'list' : val)
1438
- output = val.start_with?('set', 'unset')
1495
+ output = op.readline('Enter arguments', 'list')
1496
+ .start_with?('set', 'unset')
1439
1497
  end
1440
1498
  when :plugin
1441
1499
  case plu
@@ -1446,7 +1504,7 @@ module Squared
1446
1504
  end
1447
1505
  when :exec
1448
1506
  if op.empty? || (op.remove(':') && op.append(quote: false))
1449
- op << readline('Enter arguments', force: true)
1507
+ op.readline('Enter arguments')
1450
1508
  else
1451
1509
  op.append(quote: false)
1452
1510
  end
@@ -1470,7 +1528,7 @@ module Squared
1470
1528
 
1471
1529
  def rake(*args, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:rake], **kwargs)
1472
1530
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1473
- op = OptionPartition.new(opts, OPT_RUBY[:rake], rake_session, project: self)
1531
+ op = OptionPartition.new(opts, OPT_RUBY[:rake], rake_session, project: self, strict: strict?)
1474
1532
  op.adjoin(quote_option('f', rakefile)) if rakefile && !op.arg?('f', 'rakefile')
1475
1533
  op.concat(args)
1476
1534
  op.append(escape: true)
@@ -1481,16 +1539,30 @@ module Squared
1481
1539
 
1482
1540
  def irb(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:irb], **kwargs)
1483
1541
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1484
- op = OptionPartition.new(opts, OPT_RUBY[:irb], session('irb'), project: self, first: [/\.rb$/])
1485
- r = []
1486
- r << 'bundler/setup' if !op.arg?('r') && bundle_load
1487
- r.concat(Array(kwargs[:name])) if kwargs[:name]
1488
- r.each { |val| op.add_option('r', val, merge: true) }
1489
- op.merge((gemlib + Array(kwargs[:path])).map { |val| quote_option('I', val, merge: true) })
1542
+ run_repl(*args, opts: opts, banner: banner, from: :irb, **kwargs)
1543
+ end
1544
+
1545
+ def pry(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:pry], **kwargs)
1546
+ opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1547
+ run_repl(*args, opts: opts, banner: banner, from: :pry, delim: false, **kwargs)
1548
+ end
1549
+
1550
+ def rdbg(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:rdbg], **kwargs)
1551
+ opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1552
+ cmd = session 'rdbg'
1553
+ args.each_with_index do |val, index|
1554
+ break if val == '--'
1555
+ next unless exist?(val, type: 'f')
1556
+
1557
+ args[index] = shell_quote basepath(val)
1558
+ cmd.merge(args.slice!(0, index + 1))
1559
+ break
1560
+ end
1561
+ op = OptionPartition.new(opts, OPT_RUBY[:rdbg], cmd, project: self, strict: strict?, first: [/\.rb$/])
1490
1562
  op.concat(args)
1491
- op.append(delim: true)
1563
+ op.append(quote: false, delim: true)
1492
1564
  print_run(op, banner, **kwargs)
1493
- run(banner: false, exception: kwargs.fetch(:exception, exception?), from: :irb)
1565
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: :rdbg)
1494
1566
  end
1495
1567
 
1496
1568
  def rbs(flag, *args, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -1502,7 +1574,7 @@ module Squared
1502
1574
  end
1503
1575
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1504
1576
  cmd, opts = rbs_session(opts: opts)
1505
- op = OptionPartition.new(opts, [], cmd << flag, project: self)
1577
+ op = OptionPartition.new(opts, [], cmd << flag, project: self, strict: strict?)
1506
1578
  case flag
1507
1579
  when :prototype
1508
1580
  sig = args.shift
@@ -1545,7 +1617,7 @@ module Squared
1545
1617
 
1546
1618
  def rubocop(*args, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:rubocop], **kwargs)
1547
1619
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1548
- op = OptionPartition.new(opts, OPT_RUBY[:rubocop], session('rubocop'), project: self,
1620
+ op = OptionPartition.new(opts, OPT_RUBY[:rubocop], session('rubocop'), project: self, strict: strict?,
1549
1621
  no: OPT_RUBY[:no][:rubocop])
1550
1622
  if @rubocopfile && !op.arg?('c', 'config') && !rootpath('.rubocop.yml', ascend: true).exist?
1551
1623
  op.add_path(@rubocopfile, option: 'c')
@@ -1720,13 +1792,13 @@ module Squared
1720
1792
  parse.call(target.resolve_feature_path(gemname)&.last)
1721
1793
  end
1722
1794
  unless gemdir || pwd_set { parse.call(`#{bundle_output('show', gemname)}`) }
1723
- raise_error Errno::ENOENT, 'gems home'
1795
+ raise Errno::ENOENT, 'gems home'
1724
1796
  end
1725
1797
  end
1726
1798
  rescue => e
1727
1799
  log.error e
1728
- self.version = nil
1729
1800
  @gemdir = nil
1801
+ self.version = nil
1730
1802
  self.autodetect = false
1731
1803
  else
1732
1804
  gemdir?
@@ -1738,6 +1810,20 @@ module Squared
1738
1810
 
1739
1811
  private
1740
1812
 
1813
+ def run_repl(*args, opts:, banner:, from:, delim: true, **kwargs)
1814
+ op = OptionPartition.new(opts, OPT_RUBY[from], session(from), project: self, strict: strict?,
1815
+ first: [/\.rb$/])
1816
+ r = []
1817
+ r << 'bundler/setup' if !op.arg?('r') && bundle_load
1818
+ r.concat(Array(kwargs[:name])) if kwargs[:name]
1819
+ r.each { |val| op.add_option('r', val, merge: true) }
1820
+ op.merge((gemlib + Array(kwargs[:path])).map { |val| quote_option('I', val, merge: true) })
1821
+ op.concat(args)
1822
+ op.append(delim: delim)
1823
+ print_run(op, banner, **kwargs)
1824
+ run(banner: false, exception: kwargs.fetch(:exception, exception?), from: from)
1825
+ end
1826
+
1741
1827
  def ruby_session(*cmd, **kwargs)
1742
1828
  session('ruby', *preopts, *cmd, **kwargs)
1743
1829
  end
@@ -1759,7 +1845,7 @@ module Squared
1759
1845
  def rbs_session(*cmd, opts: nil)
1760
1846
  return session('rbs', *cmd) unless opts
1761
1847
 
1762
- op = OptionPartition.new(opts, OPT_RUBY[:rbs], project: self)
1848
+ op = OptionPartition.new(opts, OPT_RUBY[:rbs], project: self, strict: strict?)
1763
1849
  [session('rbs', *op.to_a, *cmd), op.extras]
1764
1850
  end
1765
1851
 
@@ -1943,13 +2029,11 @@ module Squared
1943
2029
  end
1944
2030
 
1945
2031
  def gemdir?
1946
- return false unless gemdir
1947
-
1948
- gemdir.exist? && !gemdir.empty? && gemdir.writable?
2032
+ !gemdir.nil? && gemdir.exist? && !gemdir.empty? && gemdir.writable?
1949
2033
  end
1950
2034
 
1951
2035
  def compat?(min, max = Float::INFINITY, gem: nil)
1952
- return false unless !gem || (bundle = gem.match?(/bundler?/))
2036
+ return false if gem && !gem.match?(/bundler?/)
1953
2037
 
1954
2038
  n = @rubygems
1955
2039
  if n.is_a?(Numeric) && n > 0
@@ -1960,14 +2044,20 @@ module Squared
1960
2044
  when String
1961
2045
  n
1962
2046
  when Array
1963
- n[bundle ? 1 : 0]
2047
+ n[gem ? 1 : 0]
1964
2048
  else
1965
- min.tap { min = (bundle && bundle_load) || Gem::VERSION }
2049
+ min.tap { min = (gem && bundle_load) || Gem::VERSION }
1966
2050
  end
1967
2051
  semgte?(ver.to_s, min.to_s) && (max == Float::INFINITY || !semgte?(ver.to_s, max.to_s))
1968
2052
  end
1969
2053
  end
1970
2054
 
2055
+ def gemspec?(name)
2056
+ !Gem::Specification.find_by_name(name).nil?
2057
+ rescue Gem::MissingSpecError
2058
+ false
2059
+ end
2060
+
1971
2061
  def serve?
1972
2062
  !Gem::Specification.find_by_name('webrick').nil?
1973
2063
  rescue Gem::MissingSpecError => e