squared 0.6.4 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f66aceeba825bcfd6afd3b20e5c39431d94450639cc70e07c3c8c22725426595
4
- data.tar.gz: b23a0282dbe08d322ed19931ddaa59be93c4b5caeb603fb90ca4283a0f195bb0
3
+ metadata.gz: 42ae11aaf561b6e6d821f7590e37982c408cb4f09aa4946084e4d3ec29c6fdff
4
+ data.tar.gz: 3ef75c9101dfd1676c035396055bd5585b33e3be41498dbd19eac2a98ea80a81
5
5
  SHA512:
6
- metadata.gz: ffa105272b8235dd427597c590d372d910edc40e2cd988dfe6b779355c2f036f32fdf6ec909d336cb84a7bf38db425e456a982b51cfad4d4fa499cb583382f27
7
- data.tar.gz: cb767f0c63b833b4550199caf2d0fc2f2d98bda119e4f0c128de5e7083fe6da7813402a46aaabfabb0b19dd56c23f77d7732167673df2bf50996ca47c55d9fa0
6
+ metadata.gz: cf24602228107b3e1a760749acf96f367cd0877ea6d45a2b0153ea08ba2a3bb014b547986e2406d2aaca4744e005bad2d9994d4a5807a7cc1afe517191aca775
7
+ data.tar.gz: 87e429e0eb78518ea637ecd863aab3359fef584b3c87340cc5a4d9f83718e7b89ac7b258a9e7a9f7d7ece3169776a8fb61d6e5f575c7420778510f3a122d84db
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.5] - 2025-11-18
4
+
5
+ ### Added
6
+
7
+ - Ruby command rubocop with stored command options was created.
8
+
9
+ ### Changed
10
+
11
+ - Node command outdated uses inline interactive prompts.
12
+ - Python task outdated no longer updates packages directly.
13
+
14
+ ### Fixed
15
+
16
+ - Common format method emphasize modified frozen string in Ruby 2.5.
17
+
3
18
  ## [0.6.4] - 2025-11-16
4
19
 
5
20
  ### Added
@@ -1419,6 +1434,7 @@
1419
1434
 
1420
1435
  - Changelog was created.
1421
1436
 
1437
+ [0.6.5]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.5
1422
1438
  [0.6.4]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.4
1423
1439
  [0.6.3]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.3
1424
1440
  [0.6.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.2
data/README.md CHANGED
@@ -154,7 +154,7 @@ Node = Workspace::Project::Node # tsc
154
154
  Node.options("build:dev", "target=es2022", project: "tsconfig.json") # :node (ref)
155
155
  Node.options("build:dev", "outDir=tmp", :squared) # squared (project name)
156
156
 
157
- Ruby = Workspace::Project::Ruby # ruby | gem | rake | bundle | irb | rbs
157
+ Ruby = Workspace::Project::Ruby # ruby | gem | rake | bundle | irb | rbs | rubocop
158
158
  Ruby.options("lint", "rubocop", opts: ["gemfile=Gemfile"]) # :ruby
159
159
  Ruby.options("lint", "--parallel", :squared)
160
160
 
@@ -196,9 +196,8 @@ module Squared
196
196
  args = args.map(&:to_s)
197
197
  if level.is_a?(::Numeric)
198
198
  if append && respond_to?(:log)
199
- (log rescue nil).tap do |ref|
200
- ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(::Logger)
201
- end
199
+ ref = log rescue nil
200
+ ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(::Logger)
202
201
  end
203
202
  return false unless pass || level >= ARG[:LEVEL]
204
203
  end
@@ -275,7 +274,7 @@ module Squared
275
274
  pr = lambda do |line|
276
275
  s = line.ljust(n)
277
276
  sub.each { |h| sub_style!(s, **h) }
278
- s = "#{b0} #{s} #{b0}"
277
+ s = +"#{b0} #{s} #{b0}"
279
278
  if border
280
279
  [[/\A(#{Regexp.escape(b0)})(.+)\z/om], [/\A(.+)(#{Regexp.escape(b0)})\z/om, 2]].each do |args|
281
280
  sub_style!(s, **opt_style(border, *args))
@@ -233,10 +233,8 @@ module Squared
233
233
  end
234
234
  return unless (lines = print_keys(type, doc, keys, file: file, opts: opts))
235
235
 
236
- title = Pathname.new(file)
237
- .realpath
238
- .to_s
239
- .sub(/^#{Regexp.escape(File.join(Dir.pwd, ''))}/, '')
236
+ title = File.realpath(file)
237
+ .sub(/^#{Regexp.escape(File.join(Dir.pwd, ''))}/, '')
240
238
  emphasize(lines, title: title, sub: unless stdin?
241
239
  [
242
240
  opt_style(theme[:banner], /\A((?:[^:]|(?<! ):(?! ))+)\z/),
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.6.4'
4
+ VERSION = '0.6.5'
5
5
  end
@@ -529,7 +529,7 @@ module Squared
529
529
  if (base = task_base?(key))
530
530
  tasks << key if obj.has?(key, baseref)
531
531
  elsif (batch = series.batch_get(key))
532
- obj.allref.each do |ref|
532
+ obj.allref do |ref|
533
533
  next unless obj.has?(key, ref) && (data = batch[ref])
534
534
 
535
535
  data.each do |val|
@@ -548,7 +548,7 @@ module Squared
548
548
  if tasks.empty?
549
549
  return [] if (base && !obj.ref?(baseref)) || !(data = series.alias_get(key))
550
550
 
551
- obj.allref.each do |ref|
551
+ obj.allref do |ref|
552
552
  next unless obj.has?(key, ref) && (alt = data[ref])
553
553
 
554
554
  ret = task_resolve obj, alt
@@ -251,7 +251,7 @@ module Squared
251
251
  print_error e
252
252
  end
253
253
  log[:progname] ||= @name
254
- log[:level] = val.match?(/\d/) ? log_sym(val.to_i) : val if (val = env('LOG_LEVEL', ignore: false))
254
+ env('LOG_LEVEL', ignore: false) { |val| log[:level] = val.start_with?(/\d/) ? log_sym(val.to_i) : val }
255
255
  log.delete(:file)
256
256
  @log = [file, log]
257
257
  end
@@ -259,28 +259,24 @@ module Squared
259
259
  def initialize_env(dev: nil, prod: nil, **)
260
260
  @dev = env_match('BUILD', dev, suffix: 'DEV', strict: true)
261
261
  @prod = env_match('BUILD', prod, suffix: 'PROD', strict: true)
262
- if @output[2] != false && (val = env('BUILD', suffix: 'ENV'))
263
- @output[2] = parse_json(val, hint: "BUILD_#{@envname}_ENV") || @output[2]
264
- end
262
+ env('BUILD', suffix: 'ENV') { |val| @output[2] = val if (val = parse_json(val)) } unless @output[0] == false
265
263
  unless @output[0] == false || @output[0].is_a?(Array)
266
- if (val = env('BUILD', suffix: 'OPTS'))
264
+ env('BUILD', suffix: 'OPTS') do |val|
267
265
  n = @output[0] ? 1 : 3
268
266
  @output[n] = merge_opts(@output[n], shell_split(val))
269
267
  end
270
- if (val = env(ref.to_s.upcase, suffix: 'OPTS'))
271
- @output[4] = merge_opts(@output[4], shell_split(val))
268
+ env(ref.to_s.upcase, suffix: 'OPTS') { |val| @output[4] = merge_opts(@output[4], shell_split(val)) }
269
+ end
270
+ env('BUILD', suffix: 'VERSION') { |val| self.version = val }
271
+ env('BUILD', strict: true) do |val|
272
+ if val == '0'
273
+ @output = [false]
274
+ elsif script?
275
+ script_set val
276
+ else
277
+ run_set val
272
278
  end
273
279
  end
274
- @version = val if (val = env('BUILD', suffix: 'VERSION'))
275
- return unless (val = env('BUILD', strict: true))
276
-
277
- if val == '0'
278
- @output = [false]
279
- elsif script?
280
- script_set val
281
- else
282
- run_set val
283
- end
284
280
  end
285
281
 
286
282
  def ==(other)
@@ -702,7 +698,9 @@ module Squared
702
698
  if order
703
699
  out.map! do |val|
704
700
  name = ret.find { |proj| val.match?(/ #{Regexp.escape(proj.name)}(?:@\d|\z)/) }&.name
705
- (n = name && order[name]) ? val.subhint(n.succ) : val
701
+ next val unless (n = name && order[name])
702
+
703
+ val.subhint(n.succ)
706
704
  end
707
705
  else
708
706
  [out, ret]
@@ -743,9 +741,9 @@ module Squared
743
741
  end
744
742
  end
745
743
  env('HEADERS') do |val|
746
- if (data = parse_json(val, hint: "HEADERS_#{@envname}"))
747
- headers = headers.is_a?(Hash) ? headers.merge(data) : data
748
- end
744
+ next unless (data = parse_json(val))
745
+
746
+ headers = headers.is_a?(Hash) ? headers.merge(data) : data
749
747
  end
750
748
  if file
751
749
  ext ||= File.extname(file)[1..-1]
@@ -888,13 +886,9 @@ module Squared
888
886
  end
889
887
 
890
888
  def event(name, key, *args, override: false, **kwargs, &blk)
891
- data = @events[name.to_sym]
892
- items = if override
893
- data[key.to_sym] = []
894
- else
895
- data[key.to_sym] ||= []
896
- end
897
- items << [block_given? ? [blk] + args : args, kwargs]
889
+ args.unshift(blk) if block_given?
890
+ ev = @events[name.to_sym]
891
+ (override ? ev[key.to_sym] = [] : ev[key.to_sym] ||= []) << [args, kwargs]
898
892
  self
899
893
  end
900
894
 
@@ -919,8 +913,10 @@ module Squared
919
913
 
920
914
  def run(cmd = @session, var = nil, exception: self.exception, sync: true, banner: true, from: nil, chdir: path,
921
915
  interactive: nil, hint: nil, series: false, **)
922
- return print_error('no command session started', subject: project, hint: from, pass: true) unless cmd
923
-
916
+ unless cmd
917
+ print_error('no command session started', subject: project, hint: from, pass: true)
918
+ return
919
+ end
924
920
  cmd = cmd.target if cmd.is_a?(OptionPartition)
925
921
  if interactive && sync && (!@session || !option('y'))
926
922
  msg, y, h = case interactive
@@ -1120,14 +1116,41 @@ module Squared
1120
1116
  @log = Logger.new((@log.first if enabled?), **@log.last)
1121
1117
  end
1122
1118
 
1123
- def allref
1124
- @ref.reverse_each
1119
+ def allref(&blk)
1120
+ @ref.reverse_each(&blk)
1125
1121
  end
1126
1122
 
1127
1123
  def basepath(*args)
1128
1124
  path.join(*args)
1129
1125
  end
1130
1126
 
1127
+ def basepath!(*args, type: nil)
1128
+ ret = basepath(*args)
1129
+ return unless ret.exist?
1130
+
1131
+ if type
1132
+ (type.is_a?(String) ? type.chars : type).each do |ch|
1133
+ case ch
1134
+ when 'f'
1135
+ return nil unless ret.file?
1136
+ when 'd'
1137
+ return nil unless ret.directory?
1138
+ when 'l'
1139
+ return nil unless ret.symlink?
1140
+ when 'r'
1141
+ return nil unless ret.readable?
1142
+ when 'w'
1143
+ return nil unless ret.writable?
1144
+ when 'e'
1145
+ return nil unless ret.executable?
1146
+ else
1147
+ return nil
1148
+ end
1149
+ end
1150
+ end
1151
+ ret
1152
+ end
1153
+
1131
1154
  def rootpath(*args, ascend: nil)
1132
1155
  ret = basepath(*args)
1133
1156
  return ret unless ascend && !ret.exist?
@@ -1162,6 +1185,15 @@ module Squared
1162
1185
  name.to_sym
1163
1186
  end
1164
1187
 
1188
+ protected
1189
+
1190
+ def script_get(*args, key: nil)
1191
+ ret = workspace.script_get(*args, group: group, ref: allref)
1192
+ return ret unless ret && key
1193
+
1194
+ ret.fetch(key, nil)
1195
+ end
1196
+
1165
1197
  private
1166
1198
 
1167
1199
  def puts(*args, **kwargs)
@@ -1216,7 +1248,6 @@ module Squared
1216
1248
  def graph_branch(target, data, tasks = nil, out = nil, sync: true, pass: [], done: [], order: nil, depth: 0,
1217
1249
  single: false, last: false, context: nil)
1218
1250
  tag = ->(proj) { "#{proj.name}#{"@#{proj.version}" if SEM_VER.match?(proj.version)}" }
1219
- script = ->(proj) { workspace.script_get(:graph, group: proj.group, ref: proj.allref)&.fetch(:graph, nil) }
1220
1251
  uniq = lambda do |name|
1221
1252
  next [] unless (ret = data[name])
1222
1253
 
@@ -1296,21 +1327,22 @@ module Squared
1296
1327
  end
1297
1328
  end
1298
1329
  else
1299
- (tasks || (subtasks = script.call(proj)) || (dev? ? %w[build copy] : %w[depend build])).each do |meth|
1300
- next if pass.include?(meth)
1330
+ (tasks || (graph = proj.script_get(:graph, key: :graph)) || (dev? ? %w[build copy] : %w[depend build]))
1331
+ .each do |meth|
1332
+ next if pass.include?(meth)
1301
1333
 
1302
- if workspace.task_defined?(cmd = task_join(name, meth))
1303
- if ENV.key?(key = "BANNER_#{name.upcase}")
1304
- key = nil
1305
- else
1306
- ENV[key] = '0'
1334
+ if workspace.task_defined?(cmd = task_join(name, meth))
1335
+ if ENV.key?(key = "BANNER_#{name.upcase}")
1336
+ key = nil
1337
+ else
1338
+ ENV[key] = '0'
1339
+ end
1340
+ run(cmd, sync: false, banner: false)
1341
+ ENV.delete(key) if key
1342
+ elsif proj.has?(meth, (workspace.baseref unless tasks || graph))
1343
+ proj.__send__(meth.to_sym, sync: sync)
1307
1344
  end
1308
- run(cmd, sync: false, banner: false)
1309
- ENV.delete(key) if key
1310
- elsif proj.has?(meth, (workspace.baseref unless tasks || subtasks))
1311
- proj.__send__(meth.to_sym, sync: sync)
1312
1345
  end
1313
- end
1314
1346
  end
1315
1347
  done << proj
1316
1348
  end
@@ -1376,12 +1408,13 @@ module Squared
1376
1408
  ignore = ['0'].freeze if ignore.nil?
1377
1409
  ENV[name] || ENV.fetch(key, '')
1378
1410
  end
1379
- if !equals.nil?
1411
+ if equals.nil?
1412
+ ret = default if ret.empty? || (ignore && Array(ignore).any? { |val| ret == val.to_s })
1413
+ return ret if ret.nil?
1414
+ else
1380
1415
  ret = Array(equals).any? { |val| ret == val.to_s }
1381
- elsif ret.empty? || (ignore && Array(ignore).any? { |val| ret == val.to_s })
1382
- ret = default
1383
1416
  end
1384
- return yield ret if block_given? && !ret.nil?
1417
+ return yield ret if block_given?
1385
1418
 
1386
1419
  ret
1387
1420
  end
@@ -1658,7 +1691,9 @@ module Squared
1658
1691
  end
1659
1692
 
1660
1693
  def empty_status(msg, title, obj, always: false)
1661
- "#{msg}#{message(hint: message(title, obj.to_s)) unless !always && (!obj || obj == 0 || obj.to_s.empty?)}"
1694
+ return msg if !always && (!obj || obj == 0 || obj.to_s.empty?)
1695
+
1696
+ msg.subhint(obj.is_a?(Numeric) ? "#{obj} #{title}" : message(title, obj.to_s))
1662
1697
  end
1663
1698
 
1664
1699
  def append_repeat(flag, opts, target: @session)
@@ -1959,7 +1994,9 @@ module Squared
1959
1994
  end
1960
1995
 
1961
1996
  def block_args(fallback = nil, &blk)
1962
- (ret = instance_eval(&blk)).nil? ? fallback : Array(ret)
1997
+ return fallback if (ret = instance_eval(&blk)).nil?
1998
+
1999
+ Array(ret)
1963
2000
  end
1964
2001
 
1965
2002
  def runenv
@@ -1973,8 +2010,6 @@ module Squared
1973
2010
  end
1974
2011
 
1975
2012
  def relativepath(*list, all: false)
1976
- return [] if list.empty?
1977
-
1978
2013
  list.flatten.map! { |val| Pathname.new(val) }.select { |val| projectpath?(val) }.map! do |val|
1979
2014
  ret = (val.absolute? ? val.relative_path_from(path) : val.cleanpath).to_s
1980
2015
  all && val.to_s.end_with?('/') ? "#{ret}/*" : ret
@@ -2286,7 +2321,7 @@ module Squared
2286
2321
  def asdf_set(val)
2287
2322
  @asdf = if @@asdf && val
2288
2323
  dir = @@asdf.path.join('installs', val)
2289
- [val, dir] if dir.exist? && !dir.empty?
2324
+ [val, dir] if dir.directory? && !dir.empty?
2290
2325
  end
2291
2326
  end
2292
2327
 
@@ -2310,7 +2345,7 @@ module Squared
2310
2345
  end
2311
2346
 
2312
2347
  def as_get(val, from)
2313
- (@global && @as[from][val]) || val
2348
+ (global && @as[from][val]) || val
2314
2349
  end
2315
2350
 
2316
2351
  def task_build(keys)
@@ -2449,7 +2484,7 @@ module Squared
2449
2484
  return false unless target.is_a?(Enumerable)
2450
2485
 
2451
2486
  args = args.first if args.size == 1 && args.first.is_a?(Enumerable)
2452
- args.any? { |obj| target.include?(obj) }
2487
+ args.any? { |obj,| target.include?(obj) }
2453
2488
  end
2454
2489
 
2455
2490
  def has_value!(target, *args, first: false)
@@ -2487,7 +2522,7 @@ module Squared
2487
2522
  end
2488
2523
 
2489
2524
  def scriptargs
2490
- { target: script? ? @output[1] : @output[0], script: script?, ref: ref, group: group, global: @global }
2525
+ { target: script? ? @output[1] : @output[0], script: script?, ref: ref, group: group, global: global }
2491
2526
  end
2492
2527
  end
2493
2528
 
@@ -200,7 +200,7 @@ module Squared
200
200
 
201
201
  case flag
202
202
  when :build
203
- format_desc action, flag, 'opts*,target*,context/:'
203
+ format_desc action, flag, 'opts*,target*,context|:'
204
204
  task flag do |_, args|
205
205
  args = args.to_a
206
206
  if args.first == ':'
@@ -221,7 +221,7 @@ module Squared
221
221
 
222
222
  case flag
223
223
  when :exec, :run
224
- format_desc action, flag, "service|:,command#{'?' unless flag == :exec}|::,args*,opts*"
224
+ format_desc action, flag, "service/:,command#{'?' unless flag == :exec}/::,args*,opts*"
225
225
  task flag, [:service] do |_, args|
226
226
  service = param_guard(action, flag, args: args, key: :service)
227
227
  compose!(flag, args.extras, service: service)
@@ -711,7 +711,7 @@ module Squared
711
711
  when 2, 4
712
712
  return
713
713
  when 3
714
- return unless COMPOSEFILE.select { |val| basepath(val).exist? }.size > 1
714
+ return unless COMPOSEFILE.select { |val| basepath!(val) }.size > 1
715
715
  end
716
716
  end
717
717
  files = Array(@file).map { |val| quote_option('file', basepath(val)) }
@@ -489,7 +489,7 @@ module Squared
489
489
  when :push then 'pathspec*,:'
490
490
  when :branch then 'name,stash/:'
491
491
  when :clear, :list, :all then nil
492
- else 'stash/:'
492
+ else 'stash?|:'
493
493
  end)
494
494
  task flag do |_, args|
495
495
  stash flag, args.to_a
@@ -751,7 +751,7 @@ module Squared
751
751
  switch(flag, commit: commit)
752
752
  end
753
753
  when :branch
754
- format_desc action, flag, 'name|:,opts*'
754
+ format_desc action, flag, 'name/:,opts*'
755
755
  task flag, [:name] do |_, args|
756
756
  args = if (branch = args.name)
757
757
  branch = nil if branch == ':'
@@ -765,7 +765,7 @@ module Squared
765
765
  when 'reset'
766
766
  case flag
767
767
  when :commit
768
- format_desc action, flag, 'ref|:,opts*'
768
+ format_desc action, flag, 'ref/:,opts*'
769
769
  task flag, [:commit] do |_, args|
770
770
  commit = commithead args.commit
771
771
  args = if commit && commit != ':'
@@ -921,7 +921,7 @@ module Squared
921
921
  restore(flag, args, commit: commit, files: files)
922
922
  end
923
923
  when :staged, :worktree
924
- format_desc action, flag, 'opts*,pathspec*,:?'
924
+ format_desc action, flag, 'opts*,pathspec*|:'
925
925
  task flag do |_, args|
926
926
  args = args.to_a
927
927
  if args.empty? || args.last == ':'
@@ -1243,8 +1243,8 @@ module Squared
1243
1243
  def revbuild(flag = nil, opts = [], sync: nil, **kwargs)
1244
1244
  kw = lambda do
1245
1245
  {
1246
- include: relativepath(Array(kwargs[:include]), all: true),
1247
- exclude: relativepath(Array(kwargs[:exclude]), all: true)
1246
+ include: relativepath(*Array(kwargs[:include]), all: true),
1247
+ exclude: relativepath(*Array(kwargs[:exclude]), all: true)
1248
1248
  }
1249
1249
  end
1250
1250
  unless workspace.closed
@@ -159,7 +159,7 @@ module Squared
159
159
  end
160
160
  @dependname = 'package.json'
161
161
  dependfile_set [@dependname]
162
- @tsfile = basepath(ts).yield_self { |file| file if file.exist? }
162
+ @tsfile = basepath! ts
163
163
  @pm = { __: init }
164
164
  end
165
165
 
@@ -630,13 +630,20 @@ module Squared
630
630
  end
631
631
  found = []
632
632
  avail = []
633
- rev = flag || (prod? ? :patch : :minor)
633
+ flag ||= case (up = option('u', 'update'))
634
+ when 'major', 'minor'
635
+ up.to_sym
636
+ else
637
+ prod? ? :patch : :minor
638
+ end
634
639
  if sync && !stdin?
635
- if has_value?(opts, 's', 'select') && !dryrun
636
- items = []
637
- elsif has_value?(opts, 'i', 'interactive')
638
- ia = true
639
- end
640
+ items = if has_value?(opts, 's', 'select')
641
+ se = true
642
+ []
643
+ elsif has_value?(opts, 'i', 'interactive')
644
+ ia = true
645
+ []
646
+ end
640
647
  end
641
648
  unless data.empty?
642
649
  JSON.parse(data).each_pair do |key, val|
@@ -647,7 +654,7 @@ module Squared
647
654
  ch = file[0]
648
655
  if ch.match?(/[~^]/)
649
656
  file = file[1..-1]
650
- elsif ia && rev == :major
657
+ elsif ia && flag == :major
651
658
  major = true
652
659
  else
653
660
  avail << [key, file, latest, true]
@@ -656,7 +663,7 @@ module Squared
656
663
  current = val['current'] || file
657
664
  want = val['wanted']
658
665
  unless latest[SEM_VER, 6]
659
- case rev
666
+ case flag
660
667
  when :major
661
668
  want = latest
662
669
  when :minor
@@ -675,7 +682,7 @@ module Squared
675
682
  b = f[2]
676
683
  c = w[0]
677
684
  d = w[2]
678
- upgrade = case rev
685
+ upgrade = case flag
679
686
  when :major
680
687
  a == '0' ? c == '0' || c == '1' : true
681
688
  when :minor
@@ -717,6 +724,7 @@ module Squared
717
724
  if !found.empty?
718
725
  col1 = width.call(found, 0) + 4
719
726
  col2 = width.call(found, 1) + 4
727
+ col3 = pad.call(found.size, found).size + 2 + col1 + col2 + width.call(found, 2)
720
728
  packages = []
721
729
  pat = ->(a) { /("#{Regexp.escape(a[0])}"\s*:\s*)"([~^])#{'?' if a[4]}#{Regexp.escape(a[1])}"/ }
722
730
  edit = lambda do |a, pkg, mod|
@@ -724,60 +732,57 @@ module Squared
724
732
  modified += 1
725
733
  "#{pkg}\"#{mod || (a[3] == 1 && a[4] ? '^' : '')}#{a[2]}\""
726
734
  end
727
- kwargs = { col1: col1, col2: col2, col3: width.call(found, 2), timeout: 0 }
728
735
  found.each_with_index do |item, i|
729
736
  a, b, c, d, e = item
730
- f = ia && (rev != :major || e || semmajor?(item[5], item[6]))
731
- col0 = "#{pad.call(i, found)}. "
732
- if f && !confirm_outdated(a, c, (d / 2.0).ceil, b, lock: e, col0: col0, **kwargs)
733
- cur = -1
734
- else
735
- cur = modified
736
- doc.send(items ? :sub : :sub!, pat.call(item)) do |capture|
737
- if $2 == '~' && rev != :patch
738
- cur = -1
739
- pending += 1
740
- capture
741
- else
742
- edit.call(item, $1, $2)
743
- end
737
+ cur = modified
738
+ doc.send(items ? :sub : :sub!, pat.call(item)) do |capture|
739
+ if $2 == '~' && flag != :patch
740
+ cur = -1
741
+ pending += 1
742
+ capture
743
+ else
744
+ edit.call(item, $1, $2)
744
745
  end
745
746
  end
746
- if f
747
- a = ' ' * col1
748
- b = ' ' * col2
749
- else
750
- a = a.ljust(col1)
751
- b = b.ljust(col2)
752
- sub_style! b, theme[:current] if theme[:current] && !stdin?
747
+ a = a.ljust(col1)
748
+ b = b.ljust(col2)
749
+ sub_style! b, theme[:current] if theme[:current] && !stdin?
750
+ if cur == -1
751
+ c = 'SKIP'
752
+ elsif modified == cur
753
+ c = 'FAIL'
754
+ elsif !stdin?
755
+ if d == 1
756
+ sub_style! a, theme[:major]
757
+ sub_style! c, :bold, color(:green)
758
+ else
759
+ sub_style!(c, **opt_style(color(d == 3 ? :green : :yellow), SEM_VER, d))
760
+ end
761
+ g = item
753
762
  end
754
- c = if cur == -1
755
- 'SKIP'
756
- elsif modified == cur
757
- 'FAIL'
758
- elsif stdin?
759
- c
760
- else
761
- g = item
762
- if d == 1
763
- sub_style! a, theme[:major]
764
- sub_style c, :bold, color(:green)
765
- else
766
- sub_style(c, **opt_style(color(d == 3 ? :green : :yellow), SEM_VER, d))
767
- end
768
- end
769
- s = a + b + c
770
- if !items
771
- puts "#{f ? ' ' * col0.size : col0}#{s}"
772
- elsif g
763
+ s = "#{pad.call(i, found)}. #{a}#{b}#{c}"
764
+ if se
773
765
  items << [s, g]
766
+ next
767
+ elsif ia && g
768
+ items << [g]
769
+ if flag != :major || e || semmajor?(item[5], item[6])
770
+ items.pop unless confirm_semver(s.ljust(col3 + s.size - s.stripstyle.size), (d / 2.0).ceil)
771
+ next
772
+ end
774
773
  end
774
+ puts s
775
775
  end
776
776
  pending = avail.reduce(pending) { |a, b| a + (b[3] ? 0 : 1) }
777
- if dryrun || (modified == 0 && (pending > 0 || (items && pending == 0)))
777
+ if (dryrun && Array(items).empty?) || (modified == 0 && (pending > 0 || (items && pending == 0)))
778
778
  n = if items
779
- puts(items.empty? ? 'No updates were found' : items.map(&:first))
780
- items.size
779
+ if items.empty?
780
+ puts 'No updates were selected'
781
+ 0
782
+ else
783
+ puts items.map(&:first) if se
784
+ items.size
785
+ end
781
786
  else
782
787
  found.size
783
788
  end
@@ -785,24 +790,32 @@ module Squared
785
790
  elsif modified > 0
786
791
  if items
787
792
  packages.clear
788
- choice('Select a package', items.map(&:first), multiple: true, force: false, index: true, border: true)
789
- .each do |n|
790
- item = items[n.pred].last
791
- doc.sub!(pat.call(item)) { edit.call(item, $1, $2) }
792
- end
793
+ if ia
794
+ (1..items.size)
795
+ else
796
+ choice('Select a package', items.map(&:first), multiple: true, force: false, index: true,
797
+ border: true)
798
+ end.each do |n|
799
+ item = items[n.pred].last
800
+ doc.sub!(pat.call(item)) { edit.call(item, $1, $2) }
801
+ end
793
802
  end
794
803
  unless packages.empty?
795
- File.write(dependfile, doc)
796
- if sync && (opts.include?('diff') || option('diff'))
797
- run(git_output('diff', shell_quote(dependfile)), banner: false)
798
- end
799
- if has_value?(opts, 'u', 'update') || option('update')
800
- package(:update, packages: packages, from: :'outdated:update')
801
- else
802
- modified = -1
804
+ modified = -1
805
+ if dryrun
803
806
  footer.call(0, found.size)
807
+ else
808
+ File.write(dependfile, doc)
809
+ if sync && (opts.include?('diff') || option('diff'))
810
+ run(git_output('diff', shell_quote(dependfile)), banner: false)
811
+ end
812
+ if has_value?(opts, 'u', 'update') || up
813
+ package(:update, packages: packages, from: :'outdated:update')
814
+ else
815
+ footer.call(0, found.size)
816
+ end
817
+ commit(:add, [dependname], pass: true)
804
818
  end
805
- commit(:add, [dependname], pass: true)
806
819
  end
807
820
  end
808
821
  elsif !avail.empty?
@@ -330,7 +330,7 @@ module Squared
330
330
  end
331
331
  end
332
332
  when 'outdated'
333
- format_desc(action, flag, "eager?,no-deps?,#{shortname('h', 'i', 's', 'd')}",
333
+ format_desc(action, flag, "eager?,no-deps?,#{shortname('h', 'i', 's', 'u', 'd')}",
334
334
  before: ('user?' unless venv))
335
335
  task flag do |_, args|
336
336
  outdated flag, args.to_a
@@ -408,18 +408,28 @@ module Squared
408
408
  def outdated(flag = nil, opts = [], sync: invoked_sync?('outdated', flag))
409
409
  cmd = pip_session 'list --outdated'
410
410
  cmd << if flag
411
- se = has_value!(opts, 's', 'select')
411
+ se = has_value! opts, 's', 'select'
412
412
  ia = has_value!(opts, 'i', 'interactive') && !se
413
+ up = has_value! opts, 'u', 'update'
413
414
  hide = has_value! opts, 'h', 'hide'
414
415
  dryrun = has_value! opts, 'd', 'dry-run'
415
416
  if !sync || stdin?
416
417
  se = false
417
418
  ia = false
418
419
  elsif se || ia
420
+ up = true
419
421
  items = []
420
422
  end
421
423
  '--not-required' if opts.include?('no-deps')
422
424
  else
425
+ if (up = option('u', 'update'))
426
+ flag = case up
427
+ when 'major', 'minor'
428
+ up.to_sym
429
+ else
430
+ :patch
431
+ end
432
+ end
423
433
  '--not-required' unless option('not-required', equals: '0')
424
434
  end
425
435
  cmd << '--local' if option('l', 'local')
@@ -521,7 +531,7 @@ module Squared
521
531
  patch
522
532
  end
523
533
  end.tap do |packages|
524
- unless packages.empty?
534
+ if up && !packages.empty?
525
535
  base = %w[eager no-deps]
526
536
  base << 'user' unless venv
527
537
  opts = (base & opts).map! { |val| val == 'eager' ? "upgrade-strategy=#{val}" : val }
@@ -624,7 +634,7 @@ module Squared
624
634
  op = OptionPartition.new(opts, list, @session, project: self, single: singleopt(flag))
625
635
  dist = lambda do
626
636
  dir = basepath 'dist'
627
- return dir if dir.directory? && !dir.empty?
637
+ next dir if dir.directory? && !dir.empty?
628
638
 
629
639
  if dir.exist?
630
640
  raise_error 'no source to publish', hint: dir
@@ -729,26 +739,26 @@ module Squared
729
739
  run(sync: sync, banner: banner, from: :"pip:#{flag}").yield_self { |val| ret || val }
730
740
  end
731
741
 
732
- def variable_set(key, *val, **, &blk)
742
+ def variable_set(key, *args, **, &blk)
733
743
  if block_given?
734
744
  case key
735
745
  when :dependfile, :venv, :editable
736
- val = block_args val, &blk
746
+ args = block_args args, &blk
737
747
  end
738
748
  end
739
749
  case key
740
750
  when :dependfile
741
- req = basepath(*val)
742
- if (index = DEP_PYTHON.index(req.basename.to_s))
751
+ val = basepath(*args)
752
+ if (index = DEP_PYTHON.index(val.basename.to_s))
743
753
  @dependindex = index
744
- @dependfile = req
754
+ @dependfile = val
745
755
  else
746
- log.warn "variable_set: @#{key}=#{req} (not supported)"
756
+ log.warn "variable_set: @#{key}=#{val} (not supported)"
747
757
  end
748
758
  when :editable
749
- editable_set val.first
759
+ editable_set args.first
750
760
  when :venv
751
- instance_variable_set(:"@#{key}", (basepath(*val) unless val.empty?))
761
+ instance_variable_set(:"@#{key}", (basepath(*args) unless args.empty?))
752
762
  else
753
763
  super
754
764
  end
@@ -21,7 +21,21 @@ module Squared
21
21
  nomultiline noprompt noscript nosingleline noverbose regexp-completor sample-book-mode script
22
22
  simple-prompt single-irb singleline tracer truncate-echo-on-assignment type-completor verbose
23
23
  back-trace-limit=i context-mode=i prompt=b prompt-mode=b].freeze,
24
- rbs: %w[I=pm r=bm no-stdlib no-collection collection=p log-level=b log-output=p repo=p].freeze
24
+ rbs: %w[I=pm r=bm no-stdlib no-collection collection=p log-level=b log-output=p repo=p].freeze,
25
+ rubocop: %w[D P r=bm auto-gen-config a|autocorrect A|autocorrect-all d|debug disable-pending-cops
26
+ display-only-correctable display-only-fail-level-offenses display-only-failed
27
+ display-only-safe-correctable S|display-style-guide display-time editor-mode enable-pending-cops
28
+ E|extra-details F|fail-fast force-default-config force-exclusion x|fix-layout
29
+ ignore-disable-comments ignore-parent-exclusion ignore-unrecognized-cops init l|lint
30
+ L|list-target-files lsp memory no-detach only-guide-cops only-recognized-file-types
31
+ no-exclude-limit profile raise-cop-error regenerate-todo restart-server safe server-status
32
+ start-server stderr stop-server C|cache=b cache-root=p config=p exclude-limit=i fail-level=b
33
+ f|format=b except=q only=q o|out=p plugin=p require=p show-cops=q show-docs-url=q
34
+ s|stdin=p].freeze,
35
+ no: {
36
+ rubocop: %w[auto-gen-enforced-style auto-gen-only-exclude auto-gen-timestamp color display-cop-names
37
+ offense-counts parallel server].freeze
38
+ }
25
39
  }.freeze
26
40
  OPT_BUNDLE = {
27
41
  common: %w[no-color V|verbose r|retry=i].freeze,
@@ -126,6 +140,7 @@ module Squared
126
140
  rake: %w[I libdir r require].freeze,
127
141
  irb: %w[I r].freeze,
128
142
  rbs: %w[I r repo].freeze,
143
+ rubocop: %w[format plugin r require].freeze,
129
144
  gem: {
130
145
  contents: %w[s spec-dir].freeze,
131
146
  dependency: %w[s source].freeze,
@@ -161,12 +176,14 @@ module Squared
161
176
  'ruby' => %i[file script version].freeze,
162
177
  'gem' => %i[install uninstall outdated update pristine build push exec command].freeze,
163
178
  'bundle' => %i[install update cache exec config reinstall command].freeze,
164
- 'rbs' => nil,
165
179
  'rake' => nil,
166
- 'irb' => nil
180
+ 'irb' => nil,
181
+ 'rbs' => nil,
182
+ 'rubocop' => nil
167
183
  })
168
184
 
169
- def initialize(*, autodetect: false, gemspec: nil, steep: 'Steepfile', asdf: 'ruby', **kwargs)
185
+ def initialize(*, autodetect: false, gemspec: nil, steep: 'Steepfile', rubocop: '.rubocop.yml', asdf: 'ruby',
186
+ **kwargs)
170
187
  super
171
188
  if @pass.include?(Ruby.ref)
172
189
  initialize_ref Ruby.ref
@@ -182,7 +199,8 @@ module Squared
182
199
  elsif gemspec
183
200
  basepath(gemspec.include?('.') ? gemspec : "#{gemspec}.gemspec")
184
201
  end
185
- @steepfile = basepath(steep).yield_self { |file| file if file.exist? }
202
+ @steepfile = basepath! steep
203
+ @rubocopfile = basepath!(rubocop) || basepath!(Dir.home, '.rubocop.yml')
186
204
  return unless rakefile && @output[0].nil? && @copy.nil? && !version && !@autodetect
187
205
 
188
206
  begin
@@ -300,7 +318,7 @@ module Squared
300
318
  args.each do |val|
301
319
  if val.include?('*')
302
320
  files.concat(Dir.glob(val, base: path))
303
- elsif !(file = basepath(val)).exist?
321
+ elsif !(file = basepath!(val))
304
322
  print_error(val, hint: 'not found')
305
323
  elsif file.directory?
306
324
  files.concat(file.glob('**/*.rb'))
@@ -328,6 +346,24 @@ module Squared
328
346
  end
329
347
  end
330
348
  end
349
+ when 'rubocop'
350
+ next unless @rubocopfile
351
+
352
+ format_desc action, nil, 'opts*,path*/:'
353
+ task action do |_, args|
354
+ opts, args = args.to_a.partition do |val|
355
+ next true if val.match?(/\A(?:(?:[A-Z]|[a-z-]+)=.|[a-z]+(?:-[a-z]+)*\Z)/)
356
+
357
+ !val.include?('*') && !val.end_with?('/')
358
+ end
359
+ if opts.delete(':') || !args.empty?
360
+ args << 'lib/' if args.empty?
361
+ list = args.map { |val| val.end_with?('/') ? "#{val}**/*.rb" : val }
362
+ .flat_map { |val| Dir.glob(val, base: path) }
363
+ args = choice_index('Select files', list, multiple: true)
364
+ end
365
+ rubocop(*args, opts: opts, banner: true)
366
+ end
331
367
  end
332
368
  else
333
369
  namespace action do
@@ -400,7 +436,7 @@ module Squared
400
436
  task flag do |_, args|
401
437
  opts = args.to_a
402
438
  opts << 'redownload' if has_value!(opts, 'f', 'force')
403
- if (lock = basepath('Gemfile.lock')).exist?
439
+ if (lock = basepath!('Gemfile.lock'))
404
440
  config = basepath '.bundle', 'config'
405
441
  if config.exist? && config.read.match?(/\bBUNDLE_FROZEN:\s+"true"/)
406
442
  if opts.include?('redownload')
@@ -477,9 +513,7 @@ module Squared
477
513
  cmd << '--without=development'
478
514
  end
479
515
  end
480
- if (n = option('jobs')).to_i > 0
481
- cmd << "-j#{n}"
482
- end
516
+ option('jobs') { |n| cmd << "-j#{n}" if n.to_i > 0 }
483
517
  run_rb(from: :depend, sync: sync)
484
518
  end
485
519
  end
@@ -530,6 +564,14 @@ module Squared
530
564
  end
531
565
  OptionPartition.new(opts, bundleopts(:outdated), cmd << "--#{flag}", project: self)
532
566
  .clear
567
+ elsif (up = option('u', 'update'))
568
+ flag = case up
569
+ when 'major', 'minor'
570
+ up.to_sym
571
+ else
572
+ :patch
573
+ end
574
+ items = []
533
575
  end
534
576
  dryrun ||= dryrun?(prefix: 'bundle')
535
577
  log.info cmd.to_s
@@ -655,16 +697,21 @@ module Squared
655
697
  end
656
698
  end
657
699
  begin
658
- status = if gems
659
- "#{gems.size} packages were updated"
660
- elsif dependfile.read =~ /\b(?:source\s+(["'])((?~\1))\1|remote:\s+(\S+))/
661
- right = true
662
- ($2 || $3).chomp('/')
663
- end
700
+ status = nil
701
+ if gems
702
+ status = "#{gems.size} packages were updated"
703
+ else
704
+ File.foreach(dependfile) do |line|
705
+ next unless line =~ /\b(?:source\s+(["'])((?~\1))\1|remote:\s+(\S+))/
706
+
707
+ status = ($2 || $3).chomp('/')
708
+ break
709
+ end
710
+ end
664
711
  rescue StandardError => e
665
712
  log.debug e
666
713
  end
667
- puts print_footer(status || 'Updates are available', right: right)
714
+ puts print_footer(status || 'Updates are available', right: status.include?('/'))
668
715
  elsif start == 0 && banner
669
716
  puts 'No updates were found'
670
717
  end
@@ -1319,6 +1366,26 @@ module Squared
1319
1366
  end
1320
1367
  end
1321
1368
 
1369
+ def rubocop(*args, sync: true, banner: verbose?, with: nil, pass: PASS_RUBY[:rubocop], **kwargs)
1370
+ opts = session_opts(with, args: args, kwargs: kwargs, pass: pass)
1371
+ op = OptionPartition.new(opts, OPT_RUBY[:rubocop], session('rubocop'), project: self,
1372
+ no: OPT_RUBY[:no][:rubocop])
1373
+ op.concat(args)
1374
+ op.each do |val|
1375
+ if basepath(val).file?
1376
+ op.found << val
1377
+ else
1378
+ op.errors << val
1379
+ end
1380
+ end
1381
+ op.swap
1382
+ .map! { |val| basepath(val).relative_path_from(path) }
1383
+ op.append(delim: true)
1384
+ .clear(errors: true)
1385
+ print_run(op, banner, **kwargs)
1386
+ run(sync: sync, banner: banner, from: :rubocop)
1387
+ end
1388
+
1322
1389
  def gemspec
1323
1390
  return @gemspec || nil unless @gemspec.nil?
1324
1391
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.4
4
+ version: 0.6.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham