squared 0.6.2 → 0.6.3

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: c638ae780897008e5115630f70db5a8ce7e1930fd31e7d1984b16d775218e16b
4
- data.tar.gz: 231f5fc087b0b3dfcff0289f5601b0c70f0a9e6db63ff7309b7c86d96ae0a1ef
3
+ metadata.gz: ac2411d2abc2d5caca8296cd25de89f28ede8458dd42809216e9ecb60dbc12e3
4
+ data.tar.gz: 2574d5d757f7405c47d792c47f83520325a633514801885706404efc3a10fa8b
5
5
  SHA512:
6
- metadata.gz: 175e72f4f5821922928b2b95a7f831dc42e91bbc41f093686cd253a68794b4b34db8af2bb9d103871cd19dfdf4d21ddd1d2bf30efdd8a8b4f5a7475be77b9988
7
- data.tar.gz: 7c619485cf6d8046ba0e2acd99afcb698137e6342fd68b454c1195f9f32517d133aada79783813c15978eb1af132113aa94c422d425ae76b36a033345c81a4e3
6
+ metadata.gz: 6623132213ca2b9510f867ffd711ce8541ef3d707290a51ae40eeca20dbe8ec027c4b47630d67ba96527faa9630a71b9befd89020bbba2ac329fc76925200c61
7
+ data.tar.gz: 909a95ac73cd5261d4d2bf184fb90ae6069d92fc30ba850d574da048f73938090ddea6ea7693fc6d0353df8a63213d964b2a964f44e3afa9f8f4188c47f8f5aa
data/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.6.3] - 2025-11-14
4
+
5
+ ### Added
6
+
7
+ - Node command package action rebuild was implemented.
8
+ - Node command add can remove packages using "-" prefix.
9
+ - Git command log action grep was implemented.
10
+ - Node command package action add was implemented.
11
+
12
+ ### Changed
13
+
14
+ - Application class extended Enumerable collection class.
15
+ - OptionPartition class is lazily loaded using autoload.
16
+ - Requiring individual project classes in Rakefile is optional.
17
+ - Application class uses static method register instead of series_wrap.
18
+ - Project support modules are required inside Base class module.
19
+ - Project graph print did not display parent and last child consequetively.
20
+ - Project outdated interactive prompts use exact column alignments.
21
+
22
+ ## [0.5.16] - 2025-11-14
23
+
24
+ ### Fixed
25
+
26
+ - See `0.4.30`.
27
+
28
+ ## [0.4.30] - 2025-11-14
29
+
30
+ ### Added
31
+
32
+ - Config viewer can read items by index in an Array.
33
+
34
+ ### Fixed
35
+
36
+ - Node command add uses event name "add" and not "depend".
37
+ - Node command add did not include packages with Yarn and PNPM.
38
+ - Git method revbuild did not splat build arguments.
39
+
3
40
  ## [0.6.2] - 2025-11-08
4
41
 
5
42
  ### Added
@@ -1351,9 +1388,11 @@
1351
1388
 
1352
1389
  - Changelog was created.
1353
1390
 
1391
+ [0.6.3]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.3
1354
1392
  [0.6.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.2
1355
1393
  [0.6.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.1
1356
1394
  [0.6.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.6.0
1395
+ [0.5.16]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.16
1357
1396
  [0.5.15]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.15
1358
1397
  [0.5.14]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.14
1359
1398
  [0.5.13]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.13
@@ -1370,6 +1409,7 @@
1370
1409
  [0.5.2]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.2-ruby
1371
1410
  [0.5.1]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.1-ruby
1372
1411
  [0.5.0]: https://github.com/anpham6/squared-ruby/releases/tag/v0.5.0-ruby
1412
+ [0.4.30]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.30
1373
1413
  [0.4.29]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.29
1374
1414
  [0.4.28]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.28
1375
1415
  [0.4.27]: https://github.com/anpham6/squared-ruby/releases/tag/v0.4.27
data/README.md CHANGED
@@ -75,6 +75,10 @@ require "squared/app" # All workspace related mod
75
75
  # sqd-serve = /workspaces/squared/publish/sqd-serve
76
76
  # sqd = /workspaces/squared/sqd
77
77
 
78
+ # Load external Project classes (optional)
79
+ Workspace::Application.load_ref('/home/user/.gem/ruby/3.4.0/gems/squared-0.6.0/lib/squared/workspace/project') # ref = :node => node.rb (absolute)
80
+ Workspace::Application.load_ref('lib/squared/workspace/project', gem: 'squared') # bundle env (relative)
81
+
78
82
  Workspace::Application
79
83
  .new(Dir.pwd, main: "squared") # Dir.pwd? (main? is implicitly basename)
80
84
  .banner("group", "project", styles: ["yellow", "black"], border: "bold") # name | project | path | ref | group? | parent? | version?
@@ -150,13 +154,13 @@ Node = Workspace::Project::Node # tsc
150
154
  Node.options("build:dev", "target=es2022", project: "tsconfig.json") # :node (ref)
151
155
  Node.options("build:dev", "outDir=tmp", :squared) # squared (project name)
152
156
 
153
- Ruby = Workspace::Project::Ruby # ruby | gem | rake | bundle | irb
157
+ Ruby = Workspace::Project::Ruby # ruby | gem | rake | bundle | irb | rbs
154
158
  Ruby.options("lint", "rubocop", opts: ["gemfile=Gemfile"]) # :ruby
155
159
  Ruby.options("lint", "--parallel", :squared)
156
160
 
157
- Python = Workspace::Project::Python # pip
158
- Python.options("build", opts: ["r=requirements.txt"]) # :python
159
- Python.options(:build, "build:dev", opts: ["no-deps"])
161
+ Python = Workspace::Project::Python # pip
162
+ Python.options("build", opts: ["r=requirements.txt"]) # :python
163
+ Python.options(:build, "build:dev", opts: ["no-deps"]) # inherits "build" as "build:dev"
160
164
 
161
165
  Workspace::Application
162
166
  .new(ENV["SQUARED_HOME"], prefix: "rb", common: false) # Local styles
@@ -692,7 +696,8 @@ GIT_AUTOSTASH_${NAME}=0 # rebase (project only)
692
696
  | checkout | track | COUNT=n |
693
697
  | checkout | global path | HEAD=s PATHSPEC=s |
694
698
  | checkout | * | F|FORCE MERGE |
695
- | clone | * | DEPTH=n ORIGIN=s BRANCH=s REVISION=s LOCAL=0,1 |
699
+ | clone | * | DEPTH=n ORIGIN=s BRANCH=s REVISION=s BARE=1 LOCAL=0,1 |
700
+ | | | SINGLE_BRANCH=0,1 NO_CHECKOUT=1 NO_TAGS=1 QUIET=1 |
696
701
  | commit | * | UPSTREAM=s DRY_RUN EDIT=0 M|MESSAGE=s |
697
702
  | diff | -between -contain | MERGE_BASE |
698
703
  | diff | head branch | INDEX=n |
@@ -742,14 +747,19 @@ BUILD_SQUARED_OPTS="NODE_TAG=24 RUBY_VERSION=3.4.0" DOCKER_SQUARED_OPTS="--no-ca
742
747
  docker build --no-cache --label=v1 --build-arg='NODE_TAG=24' --build-arg='RUBY_VERSION=3.4.0' .
743
748
  ```
744
749
 
745
- | Command | Flag | ENV |
746
- | :--------- | :---------------- | :---------------------------------------------- |
747
- | buildx | build | TAG=s |
748
- | buildx | bake | SERVICE=s |
749
- | compose | build | TARGET=s |
750
- | container | commit | REGISTRY=s PLATFORM=s DISABLE_CONTENT_TRUST=0,1 |
751
- | image | rm | Y=0,1 |
752
- | image | push | TAG=s REGISTRY=s |
750
+ | Command | Flag | ENV |
751
+ | :--------- | :----------------- | :---------------------------------------------- |
752
+ | buildx | build context | TAG=s |
753
+ | buildx | bake | SERVICE=s |
754
+ | compose | build | TARGET=s |
755
+ | compose | run | VERSION=s |
756
+ | container | commit | REGISTRY=s PLATFORM=s DISABLE_CONTENT_TRUST=0,1 |
757
+ | container | -run -create -exec | ALL=1 |
758
+ | | -update -commit | |
759
+ | image | rm | Y=1 |
760
+ | image | push | TAG=s REGISTRY=s |
761
+ | image | -push | ALL=1 |
762
+ | network | * | ALL=1 |
753
763
 
754
764
  ### asdf
755
765
 
@@ -14,8 +14,8 @@ module Squared
14
14
  CHOICE: 25,
15
15
  QUOTE: "'",
16
16
  SPACE: ' => ',
17
- GRAPH: ['|', '-', '|', '\\', '-'].freeze,
18
- BORDER: ['|', '-', '-', '-', '-', '-', '|', '|', '-', '-'].freeze,
17
+ GRAPH: %w[| - | \\ -].freeze,
18
+ BORDER: %w[| - - - - - | | - -].freeze,
19
19
  VIEW: 'view',
20
20
  BACKTRACE: $DEBUG || !$VERBOSE.nil?,
21
21
  LEVEL: ENV.fetch('LOG_LEVEL', 0).to_i,
@@ -28,8 +28,8 @@ module Squared
28
28
  bright_cyan!: '106',
29
29
  bright_white!: '107'
30
30
  }.freeze
31
- BOX_GRAPH = ['', '', '', '', ''].freeze
32
- BOX_BORDER = ['', '', '', '', '', '', '', '', '', ''].tap do |val|
31
+ BOX_GRAPH = %w[│ ─ ├ └ ┬].freeze
32
+ BOX_BORDER = %w[│ ─ ┌ ┐ ┘ └ ├ ┤ ┬ ┴].tap do |val|
33
33
  if ENV['TERM']&.end_with?('256color')
34
34
  val.slice!(2, 4)
35
35
  val.insert(2, '╭', '╮', '╯', '╰')
@@ -61,25 +61,25 @@ module Squared
61
61
  def sub_style(val, *args, styles: nil, pat: nil, index: 1)
62
62
  return val unless ARG[:COLOR]
63
63
 
64
- if pat && index != 0
65
- return val unless (data = pat.match(val))
64
+ ret = if pat && index != 0
65
+ return val unless (data = pat.match(val))
66
66
 
67
- ret = index == -1 ? data.to_a.drop(1) : data[index]
68
- else
69
- ret = val
70
- index = 0
71
- end
67
+ index == -1 ? data.to_a.drop(1) : data[index]
68
+ else
69
+ index = 0
70
+ val
71
+ end
72
72
  wrap = ->(s, n) { "\x1B[#{n.join(';')}m#{s}\x1B[0m" }
73
73
  code = []
74
+ args.clear if args.size == 1 && args.first.nil?
74
75
  args.concat(Array(styles)).flatten.each_with_index do |type, i|
75
76
  next unless type
76
77
 
77
- if index == -1
78
- s = ret[i]
79
- next ret[i] = '' if s.nil?
80
- else
81
- s = ret
82
- end
78
+ s = if index == -1
79
+ ret[i] || (next ret[i] = '')
80
+ else
81
+ ret
82
+ end
83
83
  if type.is_a?(::Numeric)
84
84
  f, b = type.to_s.split('.')
85
85
  s = wrap.call(s, ['38', '5', f]) if f[0] != '-' && f.to_i <= 255
@@ -125,6 +125,10 @@ module Squared
125
125
  out
126
126
  end
127
127
 
128
+ def sub_style!(val, *args, **kwargs)
129
+ val.replace(sub_style(val, *args, **kwargs))
130
+ end
131
+
128
132
  def check_style(args, empty: true)
129
133
  ret = []
130
134
  colors = __get__(:colors)
@@ -192,9 +196,9 @@ module Squared
192
196
  ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(::Logger)
193
197
  end
194
198
  end
195
- return false if !pass && level < ARG[:LEVEL]
199
+ return false unless pass || level >= ARG[:LEVEL]
196
200
  end
197
- if (args.size > 1 && !hint) || hint == false
201
+ if hint.nil? ? args.size > 1 : !hint
198
202
  title = log_title(level, color: false)
199
203
  emphasize(args,
200
204
  title: title + (subject ? " #{subject}" : ''),
@@ -204,7 +208,9 @@ module Squared
204
208
  end)
205
209
  else
206
210
  msg = [log_title(level, color: color)]
207
- msg << (color ? sub_style(subject.to_s, styles: (@theme && @theme[:subject]) || :bold) : subject) if subject
211
+ if subject
212
+ msg << (color ? sub_style(subject.to_s, (@theme.is_a?(::Hash) && @theme[:subject]) || :bold) : subject)
213
+ end
208
214
  msg << args.shift if msg.size == 1
209
215
  message(msg.join(' '), *args, hint: hint)
210
216
  end
@@ -236,7 +242,7 @@ module Squared
236
242
  end
237
243
 
238
244
  def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, pipe: nil,
239
- border: @theme && @theme[:border])
245
+ border: @theme.is_a?(::Hash) && @theme[:border])
240
246
  n = 0
241
247
  max = ->(a) { n = [n, a.max_by(&:size).size].max }
242
248
  set = ->(s) { Array(s).map(&:to_s).tap { |a| max.call(a) } }
@@ -257,17 +263,19 @@ module Squared
257
263
  out = []
258
264
  draw = lambda do |a, b|
259
265
  ret = a + (b1 * (n + 2)) + b
260
- ret = sub_style(ret, styles: border) if border
261
- ret
266
+ next ret unless border
267
+
268
+ sub_style ret, border
262
269
  end
263
270
  sub = sub.is_a?(::Hash) ? [sub] : Array(sub)
264
271
  pr = lambda do |line|
265
272
  s = line.ljust(n)
266
- sub.each { |h| s = sub_style(s, **h) }
273
+ sub.each { |h| sub_style!(s, **h) }
267
274
  s = "#{b0} #{s} #{b0}"
268
275
  if border
269
- s = sub_style(s, **opt_style(border, /\A(#{Regexp.escape(b0)})(.+)\z/om))
270
- s = sub_style(s, **opt_style(border, /\A(.+)(#{Regexp.escape(b0)})\z/om, 2))
276
+ [[/\A(#{Regexp.escape(b0)})(.+)\z/om], [/\A(.+)(#{Regexp.escape(b0)})\z/om, 2]].each do |args|
277
+ sub_style!(s, **opt_style(border, *args))
278
+ end
271
279
  end
272
280
  s
273
281
  end
@@ -282,7 +290,7 @@ module Squared
282
290
  unless sub.empty? && !right
283
291
  footer.map! do |s|
284
292
  s = s.rjust(n + 4) if right
285
- sub.each { |h| s = sub_style(s, **h) }
293
+ sub.each { |h| sub_style!(s, **h) }
286
294
  s
287
295
  end
288
296
  end
@@ -291,17 +299,16 @@ module Squared
291
299
  if block_given?
292
300
  yield out
293
301
  elsif pipe
302
+ return out if pipe == -1
303
+
294
304
  case pipe
295
- when -1
296
- return out
297
305
  when 0
298
- pipe = $stdin
306
+ $stdin
299
307
  when 2
300
- pipe = $stderr
308
+ $stderr
301
309
  else
302
- pipe = $stdout unless pipe.respond_to?(:puts)
303
- end
304
- pipe.puts out
310
+ pipe.respond_to?(:puts) ? pipe : $stdout
311
+ end.puts(out)
305
312
  else
306
313
  err ? warn(out) : puts(out)
307
314
  end
@@ -19,7 +19,7 @@ module Squared
19
19
  module Prompt
20
20
  module_function
21
21
 
22
- def confirm(msg, default = nil, agree: 'Y', cancel: 'N', attempts: 3, timeout: 60)
22
+ def confirm(msg, default = nil, agree: 'Y', cancel: 'N', force: false, attempts: 3, timeout: 60)
23
23
  require 'timeout'
24
24
  if agree == 'Y' && cancel == 'N' && !msg.match?(%r{\[(?:Yn|nY|Y/n|y/N)\]})
25
25
  case default
@@ -38,6 +38,7 @@ module Squared
38
38
  when agree
39
39
  return true
40
40
  when cancel
41
+ exit 1 if force
41
42
  return false
42
43
  end
43
44
  attempts -= 1
@@ -47,6 +48,7 @@ module Squared
47
48
  puts
48
49
  exit 0
49
50
  else
51
+ exit 1 if force
50
52
  false
51
53
  end
52
54
  end
@@ -129,7 +131,7 @@ module Squared
129
131
  multiline = if multiline && Readline.respond_to?(:readmultiline)
130
132
  multiline.is_a?(::Enumerable) || block_given? ? multiline : [multiline.to_s]
131
133
  end
132
- prompt = lambda do
134
+ read = lambda do
133
135
  if !multiline
134
136
  Readline.readline(msg, history)
135
137
  elsif block_given?
@@ -145,12 +147,12 @@ module Squared
145
147
  else
146
148
  [force ? ':' : '?', '']
147
149
  end
148
- ret = (prompt.call || '').strip
150
+ ret = (read.call || '').strip
149
151
  multiline.each { |val| break if ret.delete_suffix!(val.to_s) } if multiline.is_a?(::Enumerable)
150
152
  exit 1 if force && ret.empty?
151
153
  ret
152
154
  else
153
- prompt.call
155
+ read.call
154
156
  end
155
157
  end
156
158
  end
@@ -13,7 +13,7 @@ module Squared
13
13
 
14
14
  module_function
15
15
 
16
- def shell_escape(val, quote: false, force: false, double: false, option: false, override: false)
16
+ def shell_escape(val, quote: false, option: false, force: false, double: false, override: false)
17
17
  if (r = /\A(--?)([^=\s]+)((=|\s+)(["'])?(?(5)(.*)\5|(.*)))?\z/m.match(val = val.to_s))
18
18
  if (data = r[2].match(QUOTE_VALUE))
19
19
  double = data[1] == '"'
@@ -31,7 +31,7 @@ module Squared
31
31
  r[7]
32
32
  end
33
33
  r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, force: force, double: double, override: override)
34
- elsif option && val =~ /\A(-{0,2}[^\[\]=\s-][^\[\]=\s]*)=(.+)\z/m
34
+ elsif option && val =~ /\A(-{0,2}[^=\s-][^=\s]*)=(.+)\z/m
35
35
  return val if $2.match?(QUOTE_VALUE)
36
36
 
37
37
  "#{$1}=%s" % if $2.include?(' ')
@@ -55,7 +55,7 @@ module Squared
55
55
  return val if (!force && !val.include?(' ')) || val.empty?
56
56
 
57
57
  if option
58
- pat = /\A(?:-[^\[\]=\s-](?:=|\s+)?|(--)?[^\[\]=\s-][^\[\]=\s]*(?(1)(?:=|\s+)|=))(["']).+\2\z/m
58
+ pat = /\A(?:-[^=\s-](?:=|\s+)?|(--)?[^=\s-][^=\s]*(?(1)(?:=|\s+)|=))(["']).+\2\z/m
59
59
  return val if val.match?(pat)
60
60
  end
61
61
  q = ->(s) { s.gsub("'\\\\''", "'") }
@@ -103,7 +103,7 @@ module Squared
103
103
  end
104
104
 
105
105
  def shell_split(val, join: nil, **kwargs)
106
- ret = val.shellsplit.map! { |opt| shell_escape(opt, double: true, option: true, **kwargs) }
106
+ ret = val.shellsplit.map! { |opt| shell_escape(opt, option: true, double: true, **kwargs) }
107
107
  return ret unless join
108
108
 
109
109
  ret.join(join.is_a?(::String) ? join : ' ')
@@ -12,15 +12,14 @@ module Squared
12
12
  include Rake::DSL
13
13
 
14
14
  class << self
15
- def parse(gem, namespace, ext = [pkg])
15
+ def parse(gem, namespace, ext = [gem])
16
16
  require gem
17
- obj = eval namespace
18
- Array(ext).each { |val| @@mime_obj[val] = [obj, ext] }
17
+ [eval(namespace), Array(ext)].tap do |data|
18
+ data.last.each { |key| @@mime_obj[key] = data }
19
+ end
19
20
  rescue LoadError, NameError => e
20
21
  warn e
21
22
  nil
22
- else
23
- @@mime_obj[ext.first]
24
23
  end
25
24
 
26
25
  def link(project, main = project.dependfile.basename, name = nil, **kwargs, &blk)
@@ -245,7 +244,7 @@ module Squared
245
244
  opt_style(theme[:key], /\A((?~ : ))( : (?!undefined).+)\z/m),
246
245
  opt_style(theme[:number], /\A((?~: ): )(-?[\d.]+)(\s*)\z/m, 2),
247
246
  opt_style(theme[:string], /\A((?~: ): ")(.+)("\s*)\z/m, 2),
248
- opt_style(theme[:hash], /\A((?~: ): \{)(.+)(\}\s*)\z/m, 2),
247
+ opt_style(theme[:hash], /\A((?~: ): \{)(.+)(}\s*)\z/m, 2),
249
248
  opt_style(theme[:array], /\A((?~: ): \[)(.+)(\]\s*)\z/m, 2),
250
249
  opt_style(theme[:boolean], /\A((?~: ): )(true|false)(\s*)\z/m, 2),
251
250
  opt_style(theme[:value], /\A((?~: ): (?!undefined))([^"\[{].*)\z/m, 2)
@@ -259,7 +258,7 @@ module Squared
259
258
  symbolize = opts[:symbolize_names]
260
259
  keys.each do |key|
261
260
  begin
262
- items = key.split('.')
261
+ items = key.split('.').flat_map { |name| name =~ /^(.+)\[(\d+)\]$/ ? [$1, $2.to_i] : name }
263
262
  items = items.map(&:to_sym) if symbolize
264
263
  val = data.dig(*items)
265
264
  if val.nil?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.6.2'
4
+ VERSION = '0.6.3'
5
5
  end
@@ -3,6 +3,7 @@
3
3
  module Squared
4
4
  module Workspace
5
5
  class Application
6
+ include Enumerable
6
7
  include Common::Format
7
8
  include Utils
8
9
  include Support::Variables
@@ -49,10 +50,31 @@ module Squared
49
50
  @task_exclude.merge(args.map!(&:to_sym))
50
51
  end
51
52
 
52
- def series_wrap(app)
53
+ def register(app)
54
+ @session << app
53
55
  impl_series.new(app, exclude: @task_exclude.to_a)
54
56
  end
55
57
 
58
+ def load_ref(path, gem: nil)
59
+ if gem
60
+ unless @gemsdir
61
+ IO.popen('bundle env').each do |val|
62
+ next unless val =~ /^\s+Gem Home\s+(.+)$/
63
+
64
+ @gemsdir = File.join($1, 'gems')
65
+ break
66
+ end
67
+ end
68
+ dir = if gem.match?(/-\d+(?:\.|$)/)
69
+ gem
70
+ else
71
+ Dir.glob("#{gem}-*", base: @gemsdir).pop
72
+ end
73
+ path = File.join(@gemsdir, dir, path) if dir
74
+ end
75
+ @load_project.unshift(path.cleanpath.to_s) if (path = Pathname.new(path)).absolute? && path.exist?
76
+ end
77
+
56
78
  def baseref
57
79
  impl_project.ref
58
80
  end
@@ -61,11 +83,15 @@ module Squared
61
83
  super[/[^:]+\z/, 0]
62
84
  end
63
85
 
64
- attr_reader :kind_project
86
+ alias series_wrap register
87
+
88
+ attr_reader :kind_project, :load_project, :session
65
89
  attr_accessor :impl_series, :impl_project, :attr_banner
66
90
  end
67
91
 
68
92
  @kind_project = []
93
+ @load_project = [File.expand_path('project', __dir__)]
94
+ @session = []
69
95
  @task_exclude = Set.new
70
96
 
71
97
  attr_reader :root, :home, :main, :prefix, :theme, :series, :closed
@@ -84,7 +110,7 @@ module Squared
84
110
  @home.mkpath rescue nil
85
111
  @root = @home.parent
86
112
  @prefix = prefix
87
- @series = Application.series_wrap(self)
113
+ @series = Application.register(self)
88
114
  @project = {}
89
115
  @kind = hashlist
90
116
  @extensions = []
@@ -138,6 +164,12 @@ module Squared
138
164
  puts bord, msg, bord
139
165
  end
140
166
 
167
+ def each(&blk)
168
+ return to_enum(:each) unless block_given?
169
+
170
+ @project.each_value(&blk)
171
+ end
172
+
141
173
  def build(parallel: [], pass: nil, **kwargs)
142
174
  return self unless enabled? && !@closed
143
175
 
@@ -148,7 +180,8 @@ module Squared
148
180
  parallel.reject { |val| kwargs[:pattern] << val if val.is_a?(Regexp) }.map!(&:to_s)
149
181
  end
150
182
  @pass[:pattern].concat(pass.map { |val| val.is_a?(Regexp) ? val : val.to_s }) if pass
151
- @project.each_value do |proj|
183
+ series.reset
184
+ each do |proj|
152
185
  if proj.enabled?
153
186
  proj.populate(series.keys.dup, **kwargs)
154
187
  elsif proj.enabled?(base: false)
@@ -330,11 +363,12 @@ module Squared
330
363
  name = task_name "#{project}-#{index}"
331
364
  end
332
365
  proj = ((if !ref.is_a?(Class)
366
+ require_project ref
333
367
  Application.find(ref, path: path)
334
368
  elsif ref < Project::Base
335
369
  ref
336
370
  end) || @kind[name]&.last || Project::Base).new(self, path, name, **kwargs)
337
- proj.__send__(:index_set, @project.size)
371
+ proj.__send__(:index_set, size)
338
372
  @project[name] = proj
339
373
  __get__(:project)[name] = proj unless kwargs[:private]
340
374
  proj.instance_eval(&blk) if block_given?
@@ -348,11 +382,11 @@ module Squared
348
382
  basename = dir.basename.to_s
349
383
  [dir, basename, override[basename.to_sym]]
350
384
  end
351
- .each do |dir, basename, opts|
352
- args = kwargs.dup
353
- args.update(opts) if opts
354
- add(dir, basename, group: val, **args, &blk)
355
- end
385
+ .each do |dir, basename, opts|
386
+ args = kwargs.dup
387
+ args.update(opts) if opts
388
+ add(dir, basename, group: val, **args, &blk)
389
+ end
356
390
  self
357
391
  end
358
392
 
@@ -406,18 +440,21 @@ module Squared
406
440
  end
407
441
 
408
442
  def find(path = nil, name: nil, group: nil, ref: nil, &blk)
409
- ret = group ? @project.select { |_, item| item.group == group }.map(&:last) : []
443
+ return @project.values.find(&blk) if block_given? && !path && !name && !group && !ref
444
+
445
+ ret = group ? select { |item| item.group == group } : []
410
446
  if path.is_a?(Symbol)
411
447
  ref ||= path
412
448
  path = nil
413
449
  end
414
450
  if ret.empty?
415
- ret = @project.select { |_, item| item.ref?(ref) }.map(&:last) if ref
451
+ ret = select { |item| item.ref?(ref) } if ref
416
452
  if ret.empty? && (path || name)
417
453
  path &&= rootpath path
418
454
  name &&= name.to_s
419
- proj = @project.find { |_, item| (path && item.path == path) || (name && item.name == name) }&.last
420
- ret << proj if proj
455
+ if (proj = find { |item| (path && item.path == path) || (name && item.name == name) })
456
+ ret << proj
457
+ end
421
458
  end
422
459
  end
423
460
  return (group || ref ? ret : ret.first) unless block_given?
@@ -453,7 +490,7 @@ module Squared
453
490
  if @describe
454
491
  val = name || task_join(*args)
455
492
  found = false
456
- replace = lambda do |data, out|
493
+ sub = lambda do |data, out|
457
494
  index = data.size
458
495
  data.to_a.reverse_each { |group| out.sub!("%#{index -= 1}", group) }
459
496
  out
@@ -461,7 +498,7 @@ module Squared
461
498
  @describe[:replace].each do |pat, tmpl|
462
499
  next unless val =~ pat
463
500
 
464
- val = replace.call($~, tmpl.dup)
501
+ val = sub.call($~, tmpl.dup)
465
502
  found = true
466
503
  end
467
504
  if (out = @describe[:alias][val])
@@ -471,7 +508,7 @@ module Squared
471
508
  @describe[:pattern].each do |key, pat|
472
509
  next unless val =~ pat
473
510
 
474
- val = replace.call($~, key.dup)
511
+ val = sub.call($~, key.dup)
475
512
  found = true
476
513
  break
477
514
  end
@@ -579,7 +616,7 @@ module Squared
579
616
  end
580
617
 
581
618
  def enabled?
582
- !@extensions.empty? || @project.values.any? { |proj| proj.enabled?(base: false) }
619
+ !@extensions.empty? || any? { |proj| proj.enabled?(base: false) }
583
620
  end
584
621
 
585
622
  def task_base?(key)
@@ -726,7 +763,7 @@ module Squared
726
763
  a = data.after
727
764
  b = data.before
728
765
  level.each_with_index do |tasks, k|
729
- with = lambda do |n|
766
+ ac = lambda do |n|
730
767
  tasks.insert(n, *data.action)
731
768
  sync << tasks
732
769
  data.action.clear
@@ -735,14 +772,14 @@ module Squared
735
772
  index = k if w && has.call(w, v1)
736
773
  if a && has.call(a, v1)
737
774
  if index
738
- with.call(l.succ)
775
+ ac.call(l.succ)
739
776
  throw :found
740
777
  else
741
778
  index = k.succ
742
779
  end
743
780
  elsif b && has.call(b, v1)
744
781
  if index
745
- with.call(l)
782
+ ac.call(l)
746
783
  throw :found
747
784
  else
748
785
  index = k.pred
@@ -751,10 +788,10 @@ module Squared
751
788
  if a || b
752
789
  tasks.each_with_index do |v2, m|
753
790
  if a && has.call(a, v2)
754
- with.call(m.succ)
791
+ ac.call(m.succ)
755
792
  throw :found
756
793
  elsif b && has.call(b, v2)
757
- with.call(m)
794
+ ac.call(m)
758
795
  throw :found
759
796
  end
760
797
  end
@@ -865,6 +902,18 @@ module Squared
865
902
  end
866
903
  end
867
904
 
905
+ def require_project(ref)
906
+ return unless ref.is_a?(Symbol) && Application.kind_project.none? { |proj| proj.ref == ref }
907
+
908
+ name = ref.to_s
909
+ Application.load_project.each do |val|
910
+ next unless File.exist?("#{rb = File.join(val, name)}.rb")
911
+
912
+ require_relative rb
913
+ break
914
+ end
915
+ end
916
+
868
917
  def root?(path, pass: [])
869
918
  return false unless path.directory?
870
919