squared 0.0.9 → 0.0.11

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.
@@ -7,14 +7,28 @@ module Squared
7
7
  include Format
8
8
  include ::Rake::DSL
9
9
 
10
+ SCRIPT_OBJ = {
11
+ run: nil,
12
+ script: nil,
13
+ dev: nil,
14
+ prod: nil,
15
+ global: false,
16
+ env: false
17
+ }.freeze
18
+ private_constant :SCRIPT_OBJ
19
+
10
20
  class << self
11
21
  def implement(*objs)
12
22
  objs.each do |obj|
13
- if obj < Project::Base
14
- @impl_project.unshift(obj)
15
- obj.tasks&.each { |task| @impl_series.add(task, obj) }
16
- elsif obj < Workspace::Series
17
- @impl_series = obj
23
+ next unless obj < base_project
24
+
25
+ impl_project.unshift(obj)
26
+ obj.tasks&.each { |task| impl_series.add(task, obj) }
27
+ if (args = obj.batchargs)
28
+ impl_series.batch(*args)
29
+ end
30
+ if (args = obj.aliasargs)
31
+ impl_series.alias(*args)
18
32
  end
19
33
  end
20
34
  end
@@ -23,87 +37,109 @@ module Squared
23
37
  if ref && (ret = impl_project.find { |proj| proj.ref == ref.to_sym })
24
38
  ret
25
39
  elsif path
26
- impl_project.find { |proj| proj.is_a?(path) }
40
+ impl_project.find { |proj| proj.config?(path) }
27
41
  end
28
42
  end
29
43
 
44
+ def baseref
45
+ base_project.ref
46
+ end
47
+
30
48
  def to_s
31
49
  super.to_s.match(/[^:]+$/)[0]
32
50
  end
33
51
 
34
- attr_reader :impl_project, :impl_series
52
+ attr_reader :impl_project, :attr_banner
53
+ attr_accessor :impl_series, :base_project
35
54
  end
36
55
 
37
56
  @impl_project = []
38
- @impl_series = Workspace::Series
57
+ @attr_banner = SymSet.new(%i[name project path ref group parent version])
39
58
 
40
- attr_reader :root, :home, :main, :prefix, :series, :theme
41
- attr_accessor :exception, :warning, :pipe, :verbose
59
+ attr_reader :root, :home, :main, :prefix, :exception, :warning, :pipe, :verbose, :theme, :series, :closed
42
60
 
43
- def initialize(home = Dir.pwd, *, main: nil, prefix: nil, exception: false, pipe: false, verbose: nil, **kwargs)
44
- @home = (home = Pathname.new(home)).realdirpath
45
- @main = (main || home.basename).to_s
61
+ def initialize(home = Dir.pwd, *, main: nil, prefix: nil, verbose: nil,
62
+ common: ARG[:COMMON], pipe: ARG[:PIPE], exception: ARG[:FAIL], **)
63
+ @home = Pathname.new(home).realdirpath
46
64
  @root = @home.parent
65
+ @main = (main || @home.basename).to_s.freeze
47
66
  @prefix = prefix
48
67
  @series = Application.impl_series.new(self)
49
68
  @project = {}
50
69
  @extensions = []
51
- @script = {
52
- group: {},
53
- ref: {},
54
- build: nil,
55
- dev: nil,
56
- prod: nil,
57
- env: false
58
- }
59
- @exception = exception.is_a?(String) ? !env(exception, ignore: '0').nil? : exception
60
- @pipe = pipe.is_a?(String) ? !env(pipe, ignore: '0').nil? : pipe
61
- @verbose = verbose.nil? ? !@pipe : verbose
62
- @warning = @verbose
63
- if kwargs.fetch(:common, true)
70
+ @pipe = env_pipe(pipe, (ARG[:OUT] && env(ARG[:OUT])) || 1, root: @home)
71
+ @exception = env_bool(exception)
72
+ @verbose = verbose.nil? ? @pipe != 0 : verbose
73
+ @warning = @verbose != false
74
+ @closed = false
75
+ if common
64
76
  @theme = __get__(:theme)[:workspace]
65
- __set__(:no_color, true) if @pipe
77
+ ARG[:COLOR] = false if @pipe == 0 || @pipe.is_a?(::Pathname)
66
78
  else
67
79
  @theme = {}
68
80
  end
69
- @banner = {}
81
+ @script = {
82
+ group: {},
83
+ ref: {},
84
+ group!: {},
85
+ ref!: {}
86
+ }.freeze
87
+ @banner = {
88
+ group: {},
89
+ ref: {}
90
+ }.freeze
91
+ initialize_session
70
92
  end
71
93
 
72
- def build(**kwargs)
73
- kwargs[:parallel] = kwargs.fetch(:parallel, []).map(&:to_s)
74
- return unless enabled?
94
+ def initialize_session
95
+ @envname = @main.gsub(/[^\w]+/, '_').upcase.freeze
96
+ return unless @pipe.is_a?(::Pathname)
97
+
98
+ bord = '#' * Project.line_width
99
+ puts bord, format('Session started on %s by %s', Time.now.to_s, @main), bord
100
+ end
101
+
102
+ def build(parallel: [], **kwargs)
103
+ kwargs[:parallel] = parallel.map(&:to_s)
104
+ return if @closed || !enabled?
75
105
 
76
106
  @project.each_value do |proj|
77
107
  next unless proj.enabled?
78
108
 
79
109
  proj.populate(**kwargs)
80
- series.__populate__(proj)
110
+ series.populate(proj)
81
111
  end
82
112
 
83
113
  Application.impl_project.each { |obj| obj.populate(self, **kwargs) }
84
114
  @extensions.each { |ext| __send__(ext, **kwargs) }
85
115
 
86
- series.__build__(**kwargs)
116
+ series.build(**kwargs)
87
117
  __build__(**kwargs)
88
118
 
89
119
  yield self if block_given?
120
+ @closed = true
90
121
  end
91
122
 
92
- def with(val, &blk)
123
+ def with(*val, group: nil, **kwargs, &blk)
93
124
  @group = nil
94
125
  @ref = nil
95
- if val.is_a?(::String)
126
+ @withargs = kwargs.empty? ? nil : kwargs
127
+ val = [group || kwargs[:ref]].compact.flatten if val.empty?
128
+ kind = val.first
129
+ val = kind if val.size == 1
130
+ case kind
131
+ when ::String
96
132
  @group = val
97
- if block_given?
98
- instance_eval(&blk)
99
- @group = nil
100
- end
101
- elsif val.is_a?(::Symbol)
133
+ when ::Symbol
102
134
  @ref = val
103
- if block_given?
104
- instance_eval(&blk)
105
- @ref = nil
106
- end
135
+ else
136
+ raise_error('group{Symbol} | ref{String}', hint: 'missing') if block_given?
137
+ end
138
+ if block_given?
139
+ instance_eval(&blk)
140
+ @group = nil
141
+ @ref = nil
142
+ @withargs = nil
107
143
  end
108
144
  self
109
145
  end
@@ -128,50 +164,105 @@ module Squared
128
164
  script_command :test, script, group, ref
129
165
  end
130
166
 
167
+ def log(script, group: @group, ref: @ref)
168
+ script_command :log, script, group, ref
169
+ end
170
+
131
171
  def exclude(base, group: @group, ref: @ref)
132
172
  script_command :exclude, as_a(base, :to_sym).freeze, group, ref
133
173
  end
134
174
 
135
- def add(name, path = nil, **kwargs)
175
+ def banner(*args, command: true, styles: nil, border: nil, group: @group, ref: @ref)
176
+ data = { command: command, order: [], styles: check_style(styles, empty: false), border: check_style(border) }
177
+ args.each do |meth|
178
+ if meth.is_a?(::Array)
179
+ found = false
180
+ meth = meth.select do |val|
181
+ case val
182
+ when ::Symbol
183
+ found = true
184
+ Application.attr_banner.include?(val)
185
+ when ::String
186
+ true
187
+ else
188
+ false
189
+ end
190
+ end
191
+ if !found
192
+ next
193
+ elsif meth.size == 1
194
+ meth = meth.first
195
+ end
196
+ elsif !Application.attr_banner.include?(meth = meth.to_sym)
197
+ next
198
+ end
199
+ data[:order] << meth
200
+ end
201
+ unless !command && data[:order].empty?
202
+ if group
203
+ label = :group
204
+ items = as_a(group)
205
+ else
206
+ label = :ref
207
+ items = ref ? as_a(ref) : %i[_]
208
+ end
209
+ items.each { |val| @banner[label][val.to_sym] = data }
210
+ end
211
+ self
212
+ end
213
+
214
+ def add(path, val = nil, **kwargs, &blk)
215
+ if @withargs
216
+ data = @withargs.dup
217
+ data.merge!(kwargs)
218
+ kwargs = data
219
+ end
136
220
  ref = if kwargs.key?(:ref)
221
+ kwargs = kwargs.dup unless @withargs
137
222
  kwargs.delete(:ref)
138
- elsif !@ref.is_a?(::Array)
223
+ elsif @ref.is_a?(::Symbol)
139
224
  @ref
140
225
  end
141
- kwargs[:group] = @group if !kwargs.key?(:group) && !@group.is_a?(::Array)
142
- path = root_path(path || name.to_s)
226
+ if @group.is_a?(::String) && !kwargs.key?(:group)
227
+ kwargs = kwargs.dup unless @withargs
228
+ kwargs[:group] = @group
229
+ end
230
+ path = root_path(path)
231
+ val = (val || path.basename).to_s
232
+ name = val.to_sym
233
+ index = 0
234
+ while @project[name]
235
+ index += 1
236
+ name = :"#{val}-#{index}"
237
+ end
143
238
  proj = ((if !ref.is_a?(::Class)
144
239
  Application.find(ref, path: path)
145
240
  elsif ref < Project::Base
146
241
  ref
147
- end) || Project::Base).new(task_name(name), path, self, **kwargs)
148
- @project[name = name.to_sym] = proj
242
+ end) || Project::Base).new(self, path, task_name(name), **kwargs)
243
+ @project[name] = proj
149
244
  __get__(:project)[name] = proj unless kwargs[:private]
245
+ proj.instance_eval(&blk) if block_given?
150
246
  self
151
247
  end
152
248
 
153
- def group(name, path, override: {}, **kwargs)
154
- root_path(path).children.map do |ent|
155
- next unless (dir = Pathname.new(ent)).directory?
249
+ def group(path, val, override: {}, **kwargs, &blk)
250
+ root_path(path).children.map do |dir|
251
+ next unless dir.directory?
156
252
 
157
- index = 0
158
253
  basename = dir.basename.to_s.to_sym
159
- while @project[basename]
160
- index += 1
161
- basename = :"#{basename}-#{index}"
162
- end
163
- [basename, dir, override[basename]]
254
+ [dir, basename, override[basename]]
164
255
  end
165
- .each do |basename, dir, opts|
256
+ .each do |dir, basename, opts|
166
257
  args = kwargs.dup
167
258
  args.merge!(opts) if opts
168
- add(basename, dir, group: name, **args)
259
+ add(dir, basename, group: val, **args, &blk)
169
260
  end
170
261
  self
171
262
  end
172
263
 
173
264
  def compose(name, &blk)
174
- namespace(task_name(name), &blk)
265
+ namespace(task_name(name), &blk) if block_given?
175
266
  self
176
267
  end
177
268
 
@@ -191,49 +282,77 @@ module Squared
191
282
  end
192
283
  end
193
284
  end
194
- apply_style(data || theme, name, *args, empty: empty) unless target && !data
285
+ apply_style(data || theme, name, args, empty: empty) unless target && !data
195
286
  self
196
287
  end
197
288
 
198
- def banner(*order, command: true, styles: [], border: [], group: nil, ref: nil)
199
- return (group && @banner[group.to_sym]) || @banner[:"_#{ref || ''}"] if order.empty?
289
+ def find(path = nil, name: nil)
290
+ path = root_path(path) if path
291
+ ret = @project.find { |_, item| (path && item.path == path) || (name && item.name == name.to_s) }&.last
292
+ return ret unless block_given?
200
293
 
201
- key = if group ||= @group
202
- group.to_sym
203
- else
204
- :"_#{ref || @ref || ''}"
205
- end
206
- data = { command: command, order: [], styles: check_style(styles, empty: false), border: check_style(border) }
207
- order.flatten.each do |val|
208
- case (val = val.to_sym)
209
- when :name, :project, :path, :ref, :group
210
- data[:order] << val
211
- end
212
- end
213
- @banner[key] = data if command || !data[:order].empty?
294
+ yield ret if ret
214
295
  self
215
296
  end
216
297
 
217
- def script(*args, group: nil, ref: nil)
218
- if group
219
- @script[:group][group.to_sym]
220
- elsif ref
221
- @script[:ref][ref.to_sym]
222
- elsif (val = @script[:build])
223
- r = @script[:ref][:_]
224
- g = @script[:group][:_]
225
- args.empty? || (!r && !g) || (r && args.include?(r)) || (g && args.include?(g)) ? [val, @script[:env]] : []
226
- else
227
- []
228
- end
298
+ def find_base(obj)
299
+ Application.impl_project.find { |proj| obj.instance_of?(proj) }
229
300
  end
230
301
 
231
- def env(key, default = nil, equals: nil, ignore: nil)
232
- @env ||= main.gsub(/[^\w]+/, '_').upcase
233
- ret = ENV.fetch("#{key}_#{@env}", ENV[key]).to_s
234
- return ret == equals.to_s unless equals.nil?
302
+ def task_name(val, desc: false)
303
+ ret = @prefix ? task_join(@prefix, val) : val.to_s
304
+ desc ? ret.split(':').join(ARG[:SPACE]) : ret
305
+ end
306
+
307
+ def task_namespace(val, first: false)
308
+ return nil unless (ret = val.to_s.split(':')).size > 1
235
309
 
236
- ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
310
+ first ? ret.first : task_join(*ret[0..-2])
311
+ end
312
+
313
+ def task_join(*val)
314
+ val.join(':')
315
+ end
316
+
317
+ def task_resolve(obj, key)
318
+ tasks = []
319
+ if (base = task_base?(key))
320
+ tasks << key if obj.has?(key, baseref)
321
+ elsif (batch = series.batch_get(key))
322
+ obj.allref.each do |ref|
323
+ next unless (data = batch[ref])
324
+
325
+ data.each do |val|
326
+ if (items = task_resolve(obj, val)).empty?
327
+ tasks.clear
328
+ break
329
+ end
330
+ tasks += items
331
+ end
332
+ return tasks unless tasks.empty?
333
+ end
334
+ elsif task_extend?(obj, key)
335
+ tasks << key
336
+ end
337
+ ret = []
338
+ if tasks.empty?
339
+ return [] if (base && !obj.ref?(baseref)) || !(data = series.alias_get(key))
340
+
341
+ obj.allref.each do |ref|
342
+ next unless (alt = data[ref])
343
+
344
+ ret = task_resolve(obj, alt)
345
+ break unless ret.empty?
346
+ end
347
+ else
348
+ tasks.each do |val|
349
+ target = task_join(obj.name, series.name_get(val))
350
+ return [] unless task_defined?(target)
351
+
352
+ ret << target
353
+ end
354
+ end
355
+ ret
237
356
  end
238
357
 
239
358
  def root_path(*args)
@@ -244,24 +363,33 @@ module Squared
244
363
  home.join(*args)
245
364
  end
246
365
 
247
- def find_base(obj)
248
- Application.impl_project.find { |proj| obj.instance_of?(proj) }
366
+ def script_find(*args)
367
+ args.reverse_each do |val|
368
+ next unless val && (ret = val.is_a?(::Symbol) ? @script[:ref!][val] : @script[:group!][val.to_sym])
369
+
370
+ return ret
371
+ end
372
+ @script[:ref!][:_] || SCRIPT_OBJ
249
373
  end
250
374
 
251
- def task_name(val, desc: false)
252
- ret = @prefix ? "#{@prefix}:#{val}" : val.to_s
253
- desc ? ret.split(':').join(' => ') : ret
375
+ def script_get(group: nil, ref: nil)
376
+ if group
377
+ @script[:group][group.to_sym]
378
+ elsif ref
379
+ @script[:ref][ref]
380
+ end
254
381
  end
255
382
 
256
- def task_namespace(val, first: false)
257
- return nil unless (val = val.to_s).include?(':')
383
+ def banner_get(*ref, group: nil)
384
+ ret = nil
385
+ return ret if group && (ret = @banner[:group][group.to_sym])
258
386
 
259
- ret = val.split(':')
260
- first ? ret.first : ret[0..-2].join(':')
387
+ ref.reverse_each { |val| return ret if (ret = @banner[:ref][val]) }
388
+ @banner[:ref][:_]
261
389
  end
262
390
 
263
391
  def to_s
264
- root.to_s
392
+ (home? ? home : root).to_s
265
393
  end
266
394
 
267
395
  def inspect
@@ -269,42 +397,55 @@ module Squared
269
397
  end
270
398
 
271
399
  def enabled?
272
- !@extensions.empty? || @project.any? { |_, proj| proj.enabled? }
400
+ !@extensions.empty? || @project.values.any?(&:enabled?)
401
+ end
402
+
403
+ def task_base?(key)
404
+ series.base?(key)
273
405
  end
274
406
 
275
407
  def task_extend?(obj, key)
276
408
  series.extend?(obj, key)
277
409
  end
278
410
 
279
- def task_defined?(key, *)
280
- ::Rake::Task.task_defined?(key)
411
+ def task_include?(obj, key, ref = nil)
412
+ task_base?(key) ? obj.has?(key, ref || baseref) : task_extend?(obj, key)
281
413
  end
282
414
 
283
- def dev?(global: nil, **kwargs)
284
- script?(:dev, global: global.nil? ? kwargs[:pat].nil? : global, **kwargs)
415
+ def task_defined?(*key)
416
+ ::Rake::Task.task_defined?(key.size == 1 ? key.first : task_join(*key))
285
417
  end
286
418
 
287
- def prod?(global: false, **kwargs)
288
- return false if global && (@script[:dev] == true || !@script[:prod])
419
+ def dev?(**kwargs)
420
+ script?(:dev, **kwargs)
421
+ end
289
422
 
290
- script?(:prod, global: global, **kwargs)
423
+ def prod?(**kwargs)
424
+ script?(:prod, **kwargs)
291
425
  end
292
426
 
293
- private
427
+ def home?
428
+ !(proj = find(home)).nil? && proj.enabled?
429
+ end
294
430
 
295
- def __build__(**kwargs)
296
- if !task_defined?('default') && (target = kwargs[:default]) && task_defined?(target = task_name(target))
297
- task 'default' => target
298
- end
299
- return unless series.some?(:build)
431
+ def baseref
432
+ Application.baseref
433
+ end
300
434
 
301
- init = [task_name('depend'), task_name(dev? && series.some?(:refresh) ? 'refresh' : 'build')]
435
+ def invokeargs
436
+ { exception: exception, warning: warning }
437
+ end
438
+
439
+ private
302
440
 
303
- task 'default' => init[1] unless task_defined?('default')
304
- return unless series.some?(:depend) && !task_defined?(key = task_name('init'))
441
+ def __build__(default: nil, **)
442
+ if default && task_defined?(t = task_name(default)) && !task_defined?(n = ::Rake.application.default_task_name)
443
+ task n => t
444
+ end
445
+ end
305
446
 
306
- desc key
307
- task key => init
447
+ def puts(*args)
448
+ puts_oe(*args, pipe: pipe)
308
449
  end
309
450
 
310
451
  def script_command(task, val, group, ref)
@@ -319,23 +460,30 @@ module Squared
319
460
  self
320
461
  end
321
462
 
322
- def script?(state, script: nil, pat: nil, ref: nil, group: nil, global: false)
323
- r = @script[:ref][:_]
324
- g = @script[:group][:_]
325
- if global && ((!ref && !group) || (!r && !g) || (ref && contains?(r, ref)) || (group && contains?(g, group)))
326
- pat = @script[state] if pat.nil?
327
- script ||= @script[:build]
328
- end
329
- if pat.is_a?(::Regexp)
330
- script = script[state == :prod ? 1 : 0] if script.is_a?(::Array)
331
- pat.match?(script)
463
+ def script_set(data, group: nil, ref: nil)
464
+ data.freeze
465
+ if group
466
+ as_a(group).each { |val| @script[:group!][val.to_sym] = data }
467
+ elsif ref
468
+ as_a(ref).each { |val| @script[:ref!][val.to_sym] = data }
332
469
  else
333
- pat == true
470
+ @script[:ref!][:_] = data
334
471
  end
335
472
  end
336
473
 
337
- def contains?(data, val)
338
- as_a(data).any? { |item| item.to_s == val.to_s }
474
+ def script_obj
475
+ SCRIPT_OBJ.dup
476
+ end
477
+
478
+ def script?(state, target: nil, pat: nil, group: nil, ref: baseref, global: false)
479
+ data = script_find(ref, group)
480
+ if global
481
+ target = data[:script] || data[:run] if target.nil?
482
+ pat = data[state] if pat.nil?
483
+ end
484
+ return false if state == :prod && data[:dev] == true && data[:global]
485
+
486
+ target && pat.is_a?(::Regexp) ? as_a(target).any? { |val| pat.match?(val) } : pat == true
339
487
  end
340
488
  end
341
489
  end