squared 0.0.10 → 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.
@@ -2,8 +2,6 @@
2
2
 
3
3
  require 'json'
4
4
 
5
- require_relative 'common'
6
-
7
5
  module Squared
8
6
  module Config
9
7
  class Viewer
@@ -21,9 +19,8 @@ module Squared
21
19
  attr_reader :main, :name, :project, :theme
22
20
  attr_accessor :pipe
23
21
 
24
- def initialize(main, name = nil,
25
- project: nil, prefix: nil, dump: nil, opts: {}, auto: true,
26
- common: Common::KEY[:COMMON], pipe: Common::KEY[:PIPE], **)
22
+ def initialize(main, name = nil, project: nil, prefix: nil, dump: nil, opts: {}, auto: true,
23
+ common: ARG[:COMMON], pipe: ARG[:PIPE], **)
27
24
  if project
28
25
  main = @project.base_path(main).to_s if (@project = __get__(:project)[project.to_sym])
29
26
  @required = true
@@ -63,10 +60,10 @@ module Squared
63
60
  def build
64
61
  return unless enabled?
65
62
 
66
- params = ->(args) { exist? ? [realpath, [args.keys] + args.extras] : [args.keys, args.extras] }
67
-
68
63
  namespace(ns = task_name(name)) do
69
64
  view = @command && @command != name ? @command : 'view'
65
+ params = ->(args) { exist? ? [realpath, [args.keys] + args.extras] : [args.keys, args.extras] }
66
+
70
67
  namespace view do
71
68
  if @mime['json'] && (exist? || !::Rake::Task.task_defined?("#{ns}:#{view}:json"))
72
69
  desc format_desc(view, 'json')
@@ -96,7 +93,7 @@ module Squared
96
93
  require(gem || type)
97
94
  obj = eval(parse)
98
95
  ext << type if (ext = as_a(ext)).empty?
99
- file = realpath if file.nil? && exist?
96
+ file = realpath if !file && exist?
100
97
 
101
98
  namespace task_name(name) do
102
99
  desc format_desc(command, *ext, exist: exist)
@@ -142,7 +139,7 @@ module Squared
142
139
  end
143
140
 
144
141
  def style(name, *args)
145
- apply_style(theme, name, *args)
142
+ apply_style(theme, name, args)
146
143
  self
147
144
  end
148
145
 
@@ -163,11 +160,15 @@ module Squared
163
160
  def enabled?
164
161
  return File.exist?(realpath) if exist?
165
162
 
166
- !@required || (!project.nil? && project.enabled?)
163
+ !@required || !!project&.enabled?
167
164
  end
168
165
 
169
166
  private
170
167
 
168
+ def puts(*args)
169
+ puts_oe(*args, pipe: pipe)
170
+ end
171
+
171
172
  def read_keys(reader, type, file, keys, ext: [type])
172
173
  if (mime = mime_type(file)) && base_path(file).exist?
173
174
  raise_error(file, mime, hint: 'invalid') unless ext.include?(mime)
@@ -208,7 +209,7 @@ module Squared
208
209
  { pat: /^(.+ : (?!undefined))([^"\[{].*)$/m, styles: theme[:value], index: 2 }
209
210
  ]
210
211
  end
211
- emphasize(lines, title: title, sub: sub, pipe: pipe == 2 ? $stderr : nil)
212
+ emphasize(lines, title: title, sub: sub)
212
213
  end
213
214
 
214
215
  def print_keys(type, data, keys, file: nil)
@@ -266,19 +267,20 @@ module Squared
266
267
  'yaml'
267
268
  when 'js'
268
269
  'json'
270
+ when ''
271
+ nil
269
272
  else
270
- ret.empty? ? nil : ret
273
+ ret
271
274
  end
272
275
  end
273
276
 
274
277
  def format_desc(command, *ext, exist: exist?)
275
- message(@prefix || '', *name.split(':'), command,
276
- "#{ext.first}[#{exist ? '' : "file?=#{File.basename(main)}.#{ext.last},"}keys*]")
278
+ val = "#{ext.first}[#{exist ? '' : "file?=#{File.basename(main)}.#{ext.last},"}keys+]"
279
+ message(@prefix, *name.split(':'), command, val, empty: true)
277
280
  end
278
281
 
279
282
  def realpath
280
- file = main + @ext
281
- Pathname.new(file).realdirpath.to_s rescue file
283
+ base_path(file = main + @ext).to_s rescue file
282
284
  end
283
285
 
284
286
  def exist?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.0.10'
4
+ VERSION = '0.0.11'
5
5
  end
@@ -20,11 +20,15 @@ module Squared
20
20
  class << self
21
21
  def implement(*objs)
22
22
  objs.each do |obj|
23
- if obj < Project::Base
24
- @impl_project.unshift(obj)
25
- obj.tasks&.each { |task| @impl_series.add(task, obj) }
26
- elsif obj < Workspace::Series
27
- @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)
28
32
  end
29
33
  end
30
34
  end
@@ -33,41 +37,44 @@ module Squared
33
37
  if ref && (ret = impl_project.find { |proj| proj.ref == ref.to_sym })
34
38
  ret
35
39
  elsif path
36
- impl_project.find { |proj| proj.is_a?(path) }
40
+ impl_project.find { |proj| proj.config?(path) }
37
41
  end
38
42
  end
39
43
 
44
+ def baseref
45
+ base_project.ref
46
+ end
47
+
40
48
  def to_s
41
49
  super.to_s.match(/[^:]+$/)[0]
42
50
  end
43
51
 
44
- attr_reader :impl_project, :impl_series
52
+ attr_reader :impl_project, :attr_banner
53
+ attr_accessor :impl_series, :base_project
45
54
  end
46
55
 
47
56
  @impl_project = []
48
- @impl_series = Workspace::Series
57
+ @attr_banner = SymSet.new(%i[name project path ref group parent version])
49
58
 
50
- attr_reader :root, :home, :main, :prefix, :series, :theme
51
- attr_accessor :exception, :pipe, :verbose, :warning
59
+ attr_reader :root, :home, :main, :prefix, :exception, :warning, :pipe, :verbose, :theme, :series, :closed
52
60
 
53
- def initialize(home = Dir.pwd, *,
54
- main: nil, prefix: nil, verbose: nil,
55
- common: Common::KEY[:COMMON], pipe: Common::KEY[:PIPE], exception: Common::KEY[:FAIL], **)
56
- @home = (home = Pathname.new(home)).realdirpath
57
- @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
58
64
  @root = @home.parent
65
+ @main = (main || @home.basename).to_s.freeze
59
66
  @prefix = prefix
60
67
  @series = Application.impl_series.new(self)
61
68
  @project = {}
62
69
  @extensions = []
63
- @pipe = env_pipe(pipe)
70
+ @pipe = env_pipe(pipe, (ARG[:OUT] && env(ARG[:OUT])) || 1, root: @home)
64
71
  @exception = env_bool(exception)
65
- @verbose = verbose.nil? ? @pipe > 0 : verbose
72
+ @verbose = verbose.nil? ? @pipe != 0 : verbose
66
73
  @warning = @verbose != false
67
- @envname = @main.gsub(/[^\w]+/, '_').upcase
74
+ @closed = false
68
75
  if common
69
76
  @theme = __get__(:theme)[:workspace]
70
- __set__(:no_color, true) if @pipe == 0
77
+ ARG[:COLOR] = false if @pipe == 0 || @pipe.is_a?(::Pathname)
71
78
  else
72
79
  @theme = {}
73
80
  end
@@ -81,46 +88,58 @@ module Squared
81
88
  group: {},
82
89
  ref: {}
83
90
  }.freeze
91
+ initialize_session
92
+ end
93
+
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
84
100
  end
85
101
 
86
- def build(**kwargs)
87
- kwargs[:parallel] = kwargs.fetch(:parallel, []).map(&:to_s)
88
- return unless enabled?
102
+ def build(parallel: [], **kwargs)
103
+ kwargs[:parallel] = parallel.map(&:to_s)
104
+ return if @closed || !enabled?
89
105
 
90
106
  @project.each_value do |proj|
91
107
  next unless proj.enabled?
92
108
 
93
109
  proj.populate(**kwargs)
94
- series.__populate__(proj)
110
+ series.populate(proj)
95
111
  end
96
112
 
97
113
  Application.impl_project.each { |obj| obj.populate(self, **kwargs) }
98
114
  @extensions.each { |ext| __send__(ext, **kwargs) }
99
115
 
100
- series.__build__(**kwargs)
116
+ series.build(**kwargs)
101
117
  __build__(**kwargs)
102
118
 
103
119
  yield self if block_given?
120
+ @closed = true
104
121
  end
105
122
 
106
- def with(*val, &blk)
123
+ def with(*val, group: nil, **kwargs, &blk)
107
124
  @group = nil
108
125
  @ref = nil
126
+ @withargs = kwargs.empty? ? nil : kwargs
127
+ val = [group || kwargs[:ref]].compact.flatten if val.empty?
109
128
  kind = val.first
110
129
  val = kind if val.size == 1
111
130
  case kind
112
131
  when ::String
113
132
  @group = val
114
- if block_given?
115
- instance_eval(&blk)
116
- @group = nil
117
- end
118
133
  when ::Symbol
119
134
  @ref = val
120
- if block_given?
121
- instance_eval(&blk)
122
- @ref = nil
123
- 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
124
143
  end
125
144
  self
126
145
  end
@@ -153,48 +172,97 @@ module Squared
153
172
  script_command :exclude, as_a(base, :to_sym).freeze, group, ref
154
173
  end
155
174
 
156
- def add(path, name = nil, **kwargs, &blk)
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
157
220
  ref = if kwargs.key?(:ref)
221
+ kwargs = kwargs.dup unless @withargs
158
222
  kwargs.delete(:ref)
159
223
  elsif @ref.is_a?(::Symbol)
160
224
  @ref
161
225
  end
162
- kwargs[:group] = @group if !kwargs.key?(:group) && @group.is_a?(::String)
226
+ if @group.is_a?(::String) && !kwargs.key?(:group)
227
+ kwargs = kwargs.dup unless @withargs
228
+ kwargs[:group] = @group
229
+ end
163
230
  path = root_path(path)
164
- name ||= path.basename.to_s
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
165
238
  proj = ((if !ref.is_a?(::Class)
166
239
  Application.find(ref, path: path)
167
240
  elsif ref < Project::Base
168
241
  ref
169
- end) || Project::Base).new(task_name(name), path, self, **kwargs)
170
- @project[name = name.to_sym] = proj
242
+ end) || Project::Base).new(self, path, task_name(name), **kwargs)
243
+ @project[name] = proj
171
244
  __get__(:project)[name] = proj unless kwargs[:private]
172
245
  proj.instance_eval(&blk) if block_given?
173
246
  self
174
247
  end
175
248
 
176
- def group(path, name, override: {}, **kwargs)
177
- root_path(path).children.map do |ent|
178
- 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?
179
252
 
180
- index = 0
181
253
  basename = dir.basename.to_s.to_sym
182
- while @project[basename]
183
- index += 1
184
- basename = :"#{basename}-#{index}"
185
- end
186
- [basename, dir, override[basename]]
254
+ [dir, basename, override[basename]]
187
255
  end
188
- .each do |basename, dir, opts|
256
+ .each do |dir, basename, opts|
189
257
  args = kwargs.dup
190
258
  args.merge!(opts) if opts
191
- add(basename, dir, group: name, **args)
259
+ add(dir, basename, group: val, **args, &blk)
192
260
  end
193
261
  self
194
262
  end
195
263
 
196
264
  def compose(name, &blk)
197
- namespace(task_name(name), &blk)
265
+ namespace(task_name(name), &blk) if block_given?
198
266
  self
199
267
  end
200
268
 
@@ -214,52 +282,77 @@ module Squared
214
282
  end
215
283
  end
216
284
  end
217
- apply_style(data || theme, name, *args, empty: empty) unless target && !data
285
+ apply_style(data || theme, name, args, empty: empty) unless target && !data
218
286
  self
219
287
  end
220
288
 
221
- def banner(*order, command: true, styles: [], border: [], group: nil, ref: nil)
222
- if order.empty?
223
- return (group && @banner[:group][group.to_sym]) || (ref && @banner[:ref][ref]) || @banner[:ref][:_]
224
- end
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?
225
293
 
226
- data = { command: command, order: [], styles: check_style(styles, empty: false), border: check_style(border) }
227
- order.flatten.each do |val|
228
- case (val = val.to_sym)
229
- when :name, :project, :path, :ref, :group
230
- data[:order] << val
231
- end
232
- end
233
- if command || !data[:order].empty?
234
- if group ||= @group
235
- label = :group
236
- items = as_a(group)
237
- else
238
- label = :ref
239
- items = as_a(ref || @ref || :_)
240
- end
241
- items.each { |val| @banner[label][val.to_sym] = data }
242
- end
294
+ yield ret if ret
243
295
  self
244
296
  end
245
297
 
246
- def script(*args, group: nil, ref: nil)
247
- return @script[:group][group.to_sym] if group
248
- return @script[:ref][ref] if ref
298
+ def find_base(obj)
299
+ Application.impl_project.find { |proj| obj.instance_of?(proj) }
300
+ end
249
301
 
250
- args.reverse_each do |val|
251
- next unless val && (ret = val.is_a?(::Symbol) ? @script[:ref!][val] : @script[:group!][val.to_sym])
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
252
306
 
253
- return ret
254
- end
255
- @script[:ref][:_] || SCRIPT_OBJ
307
+ def task_namespace(val, first: false)
308
+ return nil unless (ret = val.to_s.split(':')).size > 1
309
+
310
+ first ? ret.first : task_join(*ret[0..-2])
311
+ end
312
+
313
+ def task_join(*val)
314
+ val.join(':')
256
315
  end
257
316
 
258
- def env(key, default = nil, equals: nil, ignore: nil)
259
- ret = (ENV["#{key}_#{@envname}"] || ENV[key]).to_s
260
- return ret == equals.to_s unless equals.nil?
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])
261
324
 
262
- ret.empty? || (ignore && as_a(ignore).any? { |val| ret == val.to_s }) ? default : ret
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
263
356
  end
264
357
 
265
358
  def root_path(*args)
@@ -270,23 +363,33 @@ module Squared
270
363
  home.join(*args)
271
364
  end
272
365
 
273
- def find_base(obj)
274
- 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
275
373
  end
276
374
 
277
- def task_name(val, desc: false)
278
- ret = @prefix ? "#{@prefix}:#{val}" : val.to_s
279
- 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
280
381
  end
281
382
 
282
- def task_namespace(val, first: false)
283
- return nil unless (ret = val.to_s.split(':')).size > 1
383
+ def banner_get(*ref, group: nil)
384
+ ret = nil
385
+ return ret if group && (ret = @banner[:group][group.to_sym])
284
386
 
285
- first ? ret.first : ret[0..-2].join(':')
387
+ ref.reverse_each { |val| return ret if (ret = @banner[:ref][val]) }
388
+ @banner[:ref][:_]
286
389
  end
287
390
 
288
391
  def to_s
289
- root.to_s
392
+ (home? ? home : root).to_s
290
393
  end
291
394
 
292
395
  def inspect
@@ -297,12 +400,20 @@ module Squared
297
400
  !@extensions.empty? || @project.values.any?(&:enabled?)
298
401
  end
299
402
 
403
+ def task_base?(key)
404
+ series.base?(key)
405
+ end
406
+
300
407
  def task_extend?(obj, key)
301
408
  series.extend?(obj, key)
302
409
  end
303
410
 
304
- def task_defined?(key, *)
305
- ::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)
413
+ end
414
+
415
+ def task_defined?(*key)
416
+ ::Rake::Task.task_defined?(key.size == 1 ? key.first : task_join(*key))
306
417
  end
307
418
 
308
419
  def dev?(**kwargs)
@@ -313,25 +424,28 @@ module Squared
313
424
  script?(:prod, **kwargs)
314
425
  end
315
426
 
316
- private
427
+ def home?
428
+ !(proj = find(home)).nil? && proj.enabled?
429
+ end
317
430
 
318
- def __build__(default: nil, **)
319
- if !task_defined?('default') && default && task_defined?(target = task_name(default))
320
- task 'default' => target
321
- end
322
- return unless series.some?(:build)
431
+ def baseref
432
+ Application.baseref
433
+ end
323
434
 
324
- init = [task_name('depend'), task_name(dev?(global: true) && series.some?(:refresh) ? 'refresh' : 'build')]
435
+ def invokeargs
436
+ { exception: exception, warning: warning }
437
+ end
325
438
 
326
- task 'default' => init[1] unless default || task_defined?('default')
327
- return unless series.some?(:depend) && !task_defined?(key = task_name('init'))
439
+ private
328
440
 
329
- desc key
330
- task key => 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
331
445
  end
332
446
 
333
447
  def puts(*args)
334
- @pipe == 2 ? $stderr.puts(*args) : $stdout.puts(*args)
448
+ puts_oe(*args, pipe: pipe)
335
449
  end
336
450
 
337
451
  def script_command(task, val, group, ref)
@@ -353,7 +467,7 @@ module Squared
353
467
  elsif ref
354
468
  as_a(ref).each { |val| @script[:ref!][val.to_sym] = data }
355
469
  else
356
- @script[:ref][:_] = data
470
+ @script[:ref!][:_] = data
357
471
  end
358
472
  end
359
473
 
@@ -361,8 +475,8 @@ module Squared
361
475
  SCRIPT_OBJ.dup
362
476
  end
363
477
 
364
- def script?(state, target: nil, pat: nil, group: nil, ref: Project::Base.ref, global: false)
365
- data = script(ref, group)
478
+ def script?(state, target: nil, pat: nil, group: nil, ref: baseref, global: false)
479
+ data = script_find(ref, group)
366
480
  if global
367
481
  target = data[:script] || data[:run] if target.nil?
368
482
  pat = data[state] if pat.nil?