squared 0.0.9 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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