squared 0.6.5 → 0.6.6

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.
@@ -136,7 +136,7 @@ module Squared
136
136
  }.freeze
137
137
  }.freeze
138
138
  PASS_RUBY = {
139
- ruby: %w[I disable enable dump r s].freeze,
139
+ ruby: %w[e I disable enable dump r s].freeze,
140
140
  rake: %w[I libdir r require].freeze,
141
141
  irb: %w[I r].freeze,
142
142
  rbs: %w[I r repo].freeze,
@@ -161,7 +161,7 @@ module Squared
161
161
  end
162
162
 
163
163
  def bannerargs
164
- %i[dependfile gemname].freeze
164
+ %i[dependfile gemname gemdir].freeze
165
165
  end
166
166
 
167
167
  def config?(val)
@@ -182,6 +182,8 @@ module Squared
182
182
  'rubocop' => nil
183
183
  })
184
184
 
185
+ attr_reader :gemdir
186
+
185
187
  def initialize(*, autodetect: false, gemspec: nil, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby',
186
188
  **kwargs)
187
189
  super
@@ -199,8 +201,8 @@ module Squared
199
201
  elsif gemspec
200
202
  basepath(gemspec.include?('.') ? gemspec : "#{gemspec}.gemspec")
201
203
  end
202
- @steepfile = basepath! steep
203
- @rubocopfile = basepath!(rubocop) || basepath!(Dir.home, '.rubocop.yml')
204
+ @steepfile = basepath! steep if steep
205
+ @rubocopfile = Pathname.new(rubocop).realpath rescue basepath!(Dir.home, '.rubocop.yml') if rubocop
204
206
  return unless rakefile && @output[0].nil? && @copy.nil? && !version && !@autodetect
205
207
 
206
208
  begin
@@ -218,6 +220,14 @@ module Squared
218
220
  end
219
221
  end
220
222
 
223
+ def gemdir=(val)
224
+ @gemdir = if val.is_a?(Pathname)
225
+ val
226
+ else
227
+ Pathname.new(val).realdirpath rescue nil
228
+ end
229
+ end
230
+
221
231
  def ref
222
232
  Ruby.ref
223
233
  end
@@ -305,40 +315,41 @@ module Squared
305
315
  format_desc action, key, 'sig?,path*'
306
316
  task key do |_, args|
307
317
  args = args.to_a
308
- list = []
309
- lib.each do |val|
310
- val = File.join(val, '**/*.rb') unless val.include?('*') || val.end_with?('.rb')
311
- list.concat(Dir.glob(val, base: path))
318
+ list = lib.flat_map do |val|
319
+ val = File.join(val, '**/*.rb') unless val.include?('*') || val.match?(/\.[a-z\d]+$/i)
320
+ Dir.glob(val, base: path)
312
321
  end
313
- if args.empty?
314
- files = choice_index('Select files', list, multiple: true, force: true, series: true,
322
+ files = if args.empty?
323
+ choice_index('Select files', list, multiple: true, series: true,
315
324
  accept: [accept_y('Generate?')])
316
- else
317
- files = []
318
- args.each do |val|
319
- if val.include?('*')
320
- files.concat(Dir.glob(val, base: path))
321
- elsif !(file = basepath!(val))
322
- print_error(val, hint: 'not found')
323
- elsif file.directory?
324
- files.concat(file.glob('**/*.rb'))
325
- else
326
- files << val
327
- end
328
- end
329
- list.map! { |val| basepath(val).to_s }
330
- files = files.select { |val| list.include?(basepath(val).to_s) }
331
- if files.empty?
332
- print_error('steep', 'no files matched', hint: "#{key}:check")
333
- exit 1
334
- end
335
- files.uniq!
336
- end
325
+ else
326
+ list.map! { |val| basepath(val).to_s }
327
+ [].tap do |out|
328
+ ret = []
329
+ args.each do |val|
330
+ if val.include?('*')
331
+ ret.concat(Dir.glob(val, base: path))
332
+ elsif !(file = basepath!(val))
333
+ print_error(val, hint: 'not found')
334
+ elsif file.directory?
335
+ ret.concat(file.glob('**/*.rb'))
336
+ else
337
+ ret << val
338
+ end
339
+ end
340
+ ret = ret.select { |val| list.include?(basepath(val).to_s) }
341
+ if ret.empty?
342
+ print_error('steep', 'no files matched', hint: "#{key}:check")
343
+ exit 1
344
+ end
345
+ out.replace(ret.uniq)
346
+ end
347
+ end
337
348
  sig = if (n = sig.index(args.first))
338
349
  args.shift
339
350
  sig[n]
340
351
  elsif sig.size > 1
341
- choice_index('Select a sig', sig, force: true, series: true)
352
+ choice_index('Select a sig', sig, series: true)
342
353
  else
343
354
  sig.first
344
355
  end
@@ -356,9 +367,9 @@ module Squared
356
367
 
357
368
  !val.include?('*') && !val.end_with?('/')
358
369
  end
359
- if opts.delete(':') || !args.empty?
360
- args << 'lib/' if args.empty?
361
- list = args.map { |val| val.end_with?('/') ? "#{val}**/*.rb" : val }
370
+ if opts.delete(':')
371
+ args << (Dir.exist?('lib') ? 'lib/' : '**/*.rb') if args.empty?
372
+ list = args.map! { |val| val.end_with?('/') || Dir.exist?(val) ? File.join(val, '**/*.rb') : val }
362
373
  .flat_map { |val| Dir.glob(val, base: path) }
363
374
  args = choice_index('Select files', list, multiple: true)
364
375
  end
@@ -468,7 +479,7 @@ module Squared
468
479
  else
469
480
  a, b, c = choice_index('Select a file', Dir.glob(file || '*.rb', base: path),
470
481
  values: (file ? [] : ['Options']).push('Arguments'),
471
- force: true, series: true)
482
+ series: true)
472
483
  if file
473
484
  file = a
474
485
  b
@@ -478,18 +489,18 @@ module Squared
478
489
  c
479
490
  end
480
491
  end)
481
- ruby(*args, flag: flag, opts: opts, file: file)
492
+ ruby(flag, *args, opts: opts, file: file)
482
493
  end
483
494
  when :script
484
495
  format_desc action, flag, 'opts*'
485
496
  task flag do |_, args|
486
497
  command = ENV['RUBY_E'] || readline('Enter script', force: true, multiline: %w[## ;])
487
- ruby(flag: flag, opts: args.to_a, command: command)
498
+ ruby(flag, opts: args.to_a, command: command)
488
499
  end
489
500
  when :version
490
501
  format_desc action, flag
491
502
  task flag do
492
- ruby(flag: flag)
503
+ ruby flag
493
504
  end
494
505
  end
495
506
  end
@@ -506,8 +517,27 @@ module Squared
506
517
  elsif outdated?
507
518
  workspace.rev_clear(name, sync: sync)
508
519
  cmd = bundle_session 'install'
520
+ option('binstubs') do |val|
521
+ next if val == '0' || val == 'false'
522
+
523
+ run(bundle_output('binstubs --all', case val
524
+ when '1', 'true'
525
+ nil
526
+ else
527
+ if val.start_with?('~')
528
+ val = File.join(Dir.home, val == '~' ? '.bundle' : val[1..-1])
529
+ if prod?
530
+ config_set('binstubs', shell_quote(val), global: true)
531
+ val = nil
532
+ end
533
+ else
534
+ val = basepath val
535
+ end
536
+ quote_option('path', val) if val
537
+ end), exception: false, banner: false, series: true)
538
+ end
509
539
  if prod? && !config_get('without')
510
- if RUBY_VERSION > '3'
540
+ if semgte?('3')
511
541
  config_set 'without', 'development'
512
542
  else
513
543
  cmd << '--without=development'
@@ -518,7 +548,7 @@ module Squared
518
548
  end
519
549
  end
520
550
 
521
- def copy(from: gemlib, into: @gemdir, override: false, **kwargs)
551
+ def copy(from: gemlib, into: gemdir, override: false, **kwargs)
522
552
  return if @copy == false
523
553
 
524
554
  glob = kwargs[:include]
@@ -564,7 +594,7 @@ module Squared
564
594
  end
565
595
  OptionPartition.new(opts, bundleopts(:outdated), cmd << "--#{flag}", project: self)
566
596
  .clear
567
- elsif (up = option('u', 'update'))
597
+ elsif (up = option('u', 'update', prefix: 'bundle'))
568
598
  flag = case up
569
599
  when 'major', 'minor'
570
600
  up.to_sym
@@ -586,12 +616,11 @@ module Squared
586
616
  col = 0
587
617
  buffer = []
588
618
  out = ->(val) { sync ? puts(val) : buffer << val }
589
- IO.popen(cmd.temp('--no-color')).each do |line|
590
- line.chomp!
619
+ IO.popen(cmd.temp('--no-color')).readlines(chomp: true).each do |line|
591
620
  if start > 0
592
621
  n = line.size
593
622
  unless stdin?
594
- line = line[0...col] if col > 0
623
+ line = line[0, col] if col > 0
595
624
  data = line.scan(SEM_VER)
596
625
  next unless (cur = data.shift) && (lat = data.shift)
597
626
 
@@ -720,6 +749,7 @@ module Squared
720
749
  end
721
750
 
722
751
  def ruby(*args, flag: nil, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:ruby], **kwargs)
752
+ flag = args.shift if !flag && args.first.is_a?(Symbol)
723
753
  if flag == :version
724
754
  pwd_set do
725
755
  out = []
@@ -829,30 +859,36 @@ module Squared
829
859
  end
830
860
  return
831
861
  end
832
- op = OptionPartition.new(session_opts(with, args: args, kwargs: kwargs, pass: pass), OPT_RUBY[:ruby],
833
- ruby_session, project: self, args: true)
834
- if (val = kwargs[:file])
835
- op.unshift(shell_quote(basepath(val)))
836
- elsif (val = kwargs[:command])
837
- op << quote_option('e', val)
838
- end
839
- append = lambda do |file|
840
- op.concat(args)
841
- unless op.empty?
842
- op.exist?(add: true) if file
843
- op.append(delim: true, escape: false, quote: false)
862
+ opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
863
+ op = OptionPartition.new(opts, OPT_RUBY[:ruby], ruby_session, project: self, multiple: [/^-e/], args: true,
864
+ stdin: true)
865
+ if kwargs[:command]
866
+ op << quote_option('e', kwargs[:command])
867
+ elsif kwargs[:file]
868
+ if op.include?('-')
869
+ op.add_path(kwargs[:file])
870
+ else
871
+ op.unshift(basepath(kwargs[:file]))
844
872
  end
845
873
  end
846
- case flag
847
- when :file
848
- append.call(false)
849
- when :script
850
- op.clear
874
+ op.concat(args)
875
+ if op.include?('-')
876
+ op.exist?(add: true)
851
877
  else
852
- append.call(true)
853
- print_run(op, banner, **kwargs)
878
+ op.append_any { |val| OptionPartition.parse_arg!('e', val) }
879
+ if op.arg?('e')
880
+ op.clear
881
+ else
882
+ op.append(delim: true, escape: kwargs.fetch(:escape, false), quote: kwargs.fetch(:quote, false))
883
+ end
854
884
  end
855
- run_rb(sync: sync, banner: banner, from: flag.is_a?(Symbol) ? :"ruby:#{flag}" : :ruby)
885
+ from = if flag
886
+ :"ruby:#{flag}"
887
+ else
888
+ print_run(op, banner, **kwargs)
889
+ :ruby
890
+ end
891
+ run_rb(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: from)
856
892
  end
857
893
 
858
894
  def gem(flag, *args, sync: true, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -1085,7 +1121,7 @@ module Squared
1085
1121
  file = basepath(if !n && (spec = gemspec)
1086
1122
  "#{spec.name}-#{spec.version}.gem"
1087
1123
  else
1088
- choice_index('Select a file', Dir.glob('*.gem', base: path), force: true)
1124
+ choice_index 'Select a file', Dir.glob('*.gem', base: path)
1089
1125
  end)
1090
1126
  else
1091
1127
  file = basepath(op.shift.yield_self { |val| val.include?('.') ? val : "#{val}.gem" })
@@ -1144,7 +1180,7 @@ module Squared
1144
1180
  else
1145
1181
  [name[0, n], name[n.succ..-1]]
1146
1182
  end
1147
- op.adjoin(pre, shell_option('version', ver))
1183
+ op.adjoin(pre, basic_option('version', ver))
1148
1184
  .clear
1149
1185
  end
1150
1186
  if flag == :install
@@ -1152,7 +1188,7 @@ module Squared
1152
1188
  else
1153
1189
  op.append
1154
1190
  end
1155
- op << '--' << post if post
1191
+ op.delim << post if post
1156
1192
  when :check, :cleanup, :contents, :fetch, :list, :lock, :rdoc
1157
1193
  op.append
1158
1194
  when :dependency, :info, :search
@@ -1190,7 +1226,7 @@ module Squared
1190
1226
  end
1191
1227
  op.clear(errors: true) if gems
1192
1228
  print_run(op, banner, **kwargs)
1193
- run_rb(sync: sync, banner: banner, from: from)
1229
+ run_rb(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: from)
1194
1230
  end
1195
1231
 
1196
1232
  def bundle(flag, *args, sync: true, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -1289,7 +1325,8 @@ module Squared
1289
1325
  op.clear
1290
1326
  end
1291
1327
  print_run(op, banner, **kwargs)
1292
- run(sync: sync, banner: banner, from: :"bundle:#{flag}").tap { |ret| success?(ret, banner, output) }
1328
+ run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: :"bundle:#{flag}")
1329
+ .tap { |ret| success?(ret, banner, output) }
1293
1330
  end
1294
1331
 
1295
1332
  def rake(*args, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:rake], **kwargs)
@@ -1299,7 +1336,8 @@ module Squared
1299
1336
  op.concat(args)
1300
1337
  op.append(escape: true)
1301
1338
  print_run(op, banner, **kwargs)
1302
- run(op, ({ 'BANNER' => '0' } unless banner), sync: sync, banner: false, from: :rake)
1339
+ var = { 'BANNER' => '0' } unless banner
1340
+ run(op, var, sync: sync, banner: false, exception: kwargs.fetch(:exception, exception), from: :rake)
1303
1341
  end
1304
1342
 
1305
1343
  def irb(*args, banner: verbose?, with: nil, pass: PASS_RUBY[:irb], **kwargs)
@@ -1313,7 +1351,7 @@ module Squared
1313
1351
  op.concat(args)
1314
1352
  op.append(delim: true)
1315
1353
  print_run(op, banner, **kwargs)
1316
- run(banner: false, from: :irb)
1354
+ run(banner: false, exception: kwargs.fetch(:exception, exception), from: :irb)
1317
1355
  end
1318
1356
 
1319
1357
  def rbs(flag, *args, banner: verbose?, with: nil, pass: nil, **kwargs)
@@ -1331,11 +1369,11 @@ module Squared
1331
1369
  sig = args.shift
1332
1370
  y = option('y', ignore: false)
1333
1371
  i = 1
1334
- args.map { |val| basepath(val).relative_path_from(path) }.each do |file|
1372
+ args.map! { |val| basepath(val).relative_path_from(path) }.each do |file|
1335
1373
  dir = basepath sig, file.dirname
1336
1374
  dir.mkpath unless dir.exist?
1337
1375
  base = file.basename.to_s
1338
- rbs = dir.join("#{base.stripext}.rbs")
1376
+ rbs = dir + "#{base.stripext}.rbs"
1339
1377
  status = if rbs.exist?
1340
1378
  case y
1341
1379
  when '0', 'false'
@@ -1362,7 +1400,7 @@ module Squared
1362
1400
  op.clear
1363
1401
  .append(*args)
1364
1402
  print_run(op, banner, **kwargs)
1365
- run(banner: false, from: :"rbs:#{flag}")
1403
+ run(banner: false, exception: kwargs.fetch(:exception, exception), from: :"rbs:#{flag}")
1366
1404
  end
1367
1405
  end
1368
1406
 
@@ -1370,6 +1408,9 @@ module Squared
1370
1408
  opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1371
1409
  op = OptionPartition.new(opts, OPT_RUBY[:rubocop], session('rubocop'), project: self,
1372
1410
  no: OPT_RUBY[:no][:rubocop])
1411
+ if @rubocopfile && !op.arg?('c', 'config') && !rootpath('.rubocop.yml', ascend: true).exist?
1412
+ op.add_path(@rubocopfile, option: 'c')
1413
+ end
1373
1414
  op.concat(args)
1374
1415
  op.each do |val|
1375
1416
  if basepath(val).file?
@@ -1383,13 +1424,12 @@ module Squared
1383
1424
  op.append(delim: true)
1384
1425
  .clear(errors: true)
1385
1426
  print_run(op, banner, **kwargs)
1386
- run(sync: sync, banner: banner, from: :rubocop)
1427
+ run(sync: sync, banner: banner, exception: kwargs.fetch(:exception, exception), from: :rubocop)
1387
1428
  end
1388
1429
 
1389
1430
  def gemspec
1390
- return @gemspec || nil unless @gemspec.nil?
1391
-
1392
- @gemspec = gemfile && Gem::Specification.load(gemfile.to_s) rescue false
1431
+ @gemspec = !gemfile.nil? && Gem::Specification.load(gemfile.to_s) rescue false if @gemspec.nil?
1432
+ @gemspec || nil
1393
1433
  end
1394
1434
 
1395
1435
  def gemname
@@ -1402,7 +1442,7 @@ module Squared
1402
1442
 
1403
1443
  def copy?
1404
1444
  return true if @copy.is_a?(Hash) ? copy[:into] : super
1405
- return gemdir? if @gemdir
1445
+ return gemdir? if gemdir
1406
1446
 
1407
1447
  if version
1408
1448
  begin
@@ -1418,8 +1458,8 @@ module Squared
1418
1458
  val =~ /(\d\.\d)\.[^.]+$/ && File.join(val, 'lib/ruby/gems', "#{$1}.0")
1419
1459
  end
1420
1460
  when /bundler?/
1421
- pwd_set { `bundle env` }[/^\s+Gem Home\s+(.+)$/, 1]
1422
- end.tap { |val| @gemdir = Pathname.new(val) if val }
1461
+ pwd_set { `bundle env` }[/^\s+Gem Path\s+([^#{File::PATH_SEPARATOR}]+)/, 1]
1462
+ end.tap { |val| self.gemdir = val if val }
1423
1463
  rescue StandardError => e
1424
1464
  log.debug e
1425
1465
  end
@@ -1428,11 +1468,14 @@ module Squared
1428
1468
  return false unless @autodetect
1429
1469
 
1430
1470
  set = lambda do |val, path|
1471
+ dir = Pathname.new(path.strip) + gempath
1472
+ return false unless dir.writable?
1473
+
1431
1474
  if (ver = version) && ver != val
1432
1475
  log.warn "using version #{val}".subhint("given #{ver}")
1433
1476
  end
1434
1477
  self.version = val
1435
- @gemdir = Pathname.new(path.strip) + gempath
1478
+ self.gemdir = dir
1436
1479
  end
1437
1480
  if version
1438
1481
  opt = gempwd
@@ -1447,30 +1490,30 @@ module Squared
1447
1490
  next unless out =~ /\(#{Regexp.escape(val)}[^)]*\):([^\n]+)/
1448
1491
 
1449
1492
  set.call(val, $1)
1450
- return gemdir? if @gemdir
1493
+ return gemdir? if gemdir
1451
1494
  end
1452
1495
  end
1453
- @gemdir = Pathname.new(Gem.dir) + gempath
1496
+ self.gemdir = Pathname.new(Gem.dir) + gempath
1454
1497
  else
1455
1498
  parse = lambda do |path|
1456
- next unless path
1499
+ return false unless path
1457
1500
 
1458
- lib = Regexp.new(['', 'gems', "#{gemname}-([^#{File::SEPARATOR}]+)", ''].join(File::SEPARATOR))
1459
- if (ver = path[lib, 1]) && (val = path[/\A(.+)#{gempath(ver[1])}/, 1])
1501
+ ver = path[Regexp.new(['', 'gems', "#{gemname}-([^#{File::SEPARATOR}]+)", ''].join(File::SEPARATOR)), 1]
1502
+ if ver && (val = path[/\A(.+)#{Regexp.escape(gempath(ver))}/, 1])
1460
1503
  set.call(ver, val)
1461
1504
  end
1462
1505
  end
1463
- if RUBY_VERSION >= '2.6'
1506
+ if semgte?('2.6')
1464
1507
  target = RUBY_VERSION.start_with?('2.6') ? RubyVM : $LOAD_PATH
1465
1508
  parse.call(target.resolve_feature_path(gemname)&.last)
1466
1509
  end
1467
- unless @gemdir || pwd_set { parse.call(`#{bundle_output('show', gemname)}`) }
1510
+ unless gemdir || pwd_set { parse.call(`#{bundle_output('show', gemname)}`) }
1468
1511
  raise_error Errno::ENOENT, 'gems home'
1469
1512
  end
1470
1513
  end
1471
1514
  rescue StandardError => e
1472
1515
  log.error e
1473
- @version = nil
1516
+ self.version = nil
1474
1517
  @gemdir = nil
1475
1518
  @autodetect = false
1476
1519
  else
@@ -1544,8 +1587,8 @@ module Squared
1544
1587
  end
1545
1588
  end
1546
1589
 
1547
- def config_set(key, *val)
1548
- run(bundle_output('config set', key, *val), banner: false, series: true)
1590
+ def config_set(key, *val, global: false)
1591
+ run(bundle_output('config', ('--global' if global), 'set', key, *val), banner: false, series: true)
1549
1592
  end
1550
1593
 
1551
1594
  def preopts
@@ -1557,10 +1600,11 @@ module Squared
1557
1600
  end
1558
1601
 
1559
1602
  def rakefile
1560
- return @rakefile || nil unless @rakefile.nil?
1561
-
1562
- file = Rake::Application::DEFAULT_RAKEFILES.find { |val| exist?(val) }
1563
- @rakefile = file ? basepath(file) : false
1603
+ if @rakefile.nil?
1604
+ file = Rake::Application::DEFAULT_RAKEFILES.find { |val| exist?(val) }
1605
+ @rakefile = !file.nil? && basepath(file)
1606
+ end
1607
+ @rakefile || nil
1564
1608
  end
1565
1609
 
1566
1610
  def rakepwd
@@ -1621,11 +1665,12 @@ module Squared
1621
1665
  end
1622
1666
 
1623
1667
  def gemfile
1624
- return @gemfile || nil unless @gemfile.nil?
1625
-
1626
- @gemfile = [project, name].map! { |val| basepath("#{val}.gemspec") }
1627
- .concat(path.glob('*.gemspec'))
1628
- .find(&:exist?) || false
1668
+ if @gemfile.nil?
1669
+ @gemfile = [project, name].map! { |val| basepath("#{val}.gemspec") }
1670
+ .concat(path.glob('*.gemspec'))
1671
+ .find(&:exist?) || false
1672
+ end
1673
+ @gemfile || nil
1629
1674
  end
1630
1675
 
1631
1676
  def gemlib
@@ -1642,9 +1687,9 @@ module Squared
1642
1687
  end
1643
1688
 
1644
1689
  def gemdir?
1645
- return false unless @gemdir
1690
+ return false unless gemdir
1646
1691
 
1647
- @gemdir.exist? && !@gemdir.empty?
1692
+ gemdir.exist? && !gemdir.empty? && gemdir.writable?
1648
1693
  end
1649
1694
  end
1650
1695
 
@@ -27,9 +27,11 @@ module Squared
27
27
  def multiple=(val)
28
28
  case val
29
29
  when Enumerable
30
- @multiple.concat(val.to_a.map(&:to_s))
30
+ @multiple.concat(val.to_a.map { |val| val.is_a?(Regexp) ? val : val.to_s })
31
31
  when String, Symbol, Pathname
32
32
  @multiple << val.to_s
33
+ when Regexp
34
+ @multiple << val
33
35
  when NilClass, FalseClass
34
36
  @multiple.clear
35
37
  end
@@ -119,7 +121,7 @@ module Squared
119
121
  extras.concat(if n == 0
120
122
  data
121
123
  else
122
- super(data[0...n])
124
+ super(data[0, n])
123
125
  data[n..-1]
124
126
  end)
125
127
  self
@@ -131,35 +133,51 @@ module Squared
131
133
  def <<(obj)
132
134
  return super if extras.empty? && !extras?(obj)
133
135
 
134
- unless !extras.include?(@partition) && include?(obj) && @uniq.match?(s = obj.to_s) && !multiple.include?(s)
136
+ unless !extras.include?(@partition) && include?(obj) && @uniq.match?(s = obj.to_s) && !multiple?(s)
135
137
  extras << obj
136
138
  end
137
139
  self
138
140
  end
139
141
 
142
+ def size
143
+ super + extras.size
144
+ end
145
+
146
+ def include?(obj)
147
+ return true if super
148
+ return extras.include?(obj) unless (n = extras.index(@partition))
149
+
150
+ extras[0..n].include?(obj)
151
+ end
152
+
153
+ def multiple?(val)
154
+ multiple.any? { |obj| obj.is_a?(Regexp) ? obj.match?(val) : obj == val }
155
+ end
156
+
140
157
  def to_a
141
158
  pass
142
159
  end
143
160
 
144
161
  def to_s
145
- pass.join(@delim)
162
+ to_a.join(@delim)
146
163
  end
147
164
 
148
165
  def to_enum(*args)
149
- pass.to_enum(*args)
166
+ to_a.to_enum(*args)
150
167
  end
151
168
 
152
169
  def to_json(*args)
153
- pass.to_json(*args)
170
+ to_a.to_json(*args)
154
171
  end
155
172
 
156
173
  def to_yaml(*args)
157
- pass.to_yaml(*args)
174
+ to_a.to_yaml(*args)
158
175
  end
159
176
 
160
177
  alias add :<<
161
178
  alias add? :<<
162
179
  alias push :<<
180
+ alias member? include?
163
181
  alias concat merge
164
182
 
165
183
  private
@@ -169,7 +187,7 @@ module Squared
169
187
  end
170
188
 
171
189
  def extras?(obj)
172
- obj == @partition || (include?(obj) && (!@uniq.match?(s = obj.to_s) || multiple.include?(s)))
190
+ obj == @partition || (include?(obj) && (!@uniq.match?(s = obj.to_s) || multiple?(s)))
173
191
  end
174
192
  end
175
193
  end