squared 0.0.2 → 0.0.4

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: 117c669053bf0539d41840f655c1f7cb9a87af7d90366ded3c19803949184cdc
4
- data.tar.gz: 84266b0dd2bc5736eb05b5799692fd4fbed756e8a096343dc85f670e9257ae07
3
+ metadata.gz: 1795e8352e8278c8f4e26ced26ac936ce906ee8e626a9cf2ff2bf6a86412f09c
4
+ data.tar.gz: '08b8e2538b6316ffb141c15e560187222cbb18e0a37f5c74af6ed5fda87e6dc3'
5
5
  SHA512:
6
- metadata.gz: 862884efb840359442202f1670ba4b8ff032397a3e6e6d5720289f844f63ec3119045bfb60b1f2c41673472d32861228587e7a33ab0fbf87d2c7df5e5fa37cde
7
- data.tar.gz: f775903d05491cbe92d80e9db391afa970c866fa4ae885666ffe4e95282d102df5b9faab6f20b17d9368243ff73c6552ff3c56ecf11423d6f68eaeaf4f242288
6
+ metadata.gz: a8d6bd537e66b744edd760ead7441aad45961bdc746e9ca81f577e8183893cd6209203f2ba507b5ab608bbf3ebe7a15aeb23aa84005a76bf10d0f3b3704c403d
7
+ data.tar.gz: 9a29c720ce14050bc604c9b561c376f55437865610827075dd6a2a961ce82b22c1f4b3fd303884186f9c59b1a330ed73ce14ad16169724c3578d8d4e01388bfe
data/README.ruby.md CHANGED
@@ -33,7 +33,7 @@ require "squared"
33
33
 
34
34
  Repo::Workspace
35
35
  .new("squared") # REPO_HOME
36
- .repo("https://github.com/anpham6/squared-repo", "nightly") # Optional
36
+ .repo("https://github.com/anpham6/squared-repo", "nightly", run: 'build') # Optional
37
37
  .run("rake install", ref: :ruby)
38
38
  .clean("rake clean", group: "default") # depend test doc
39
39
  .clean(["build/"], group: "app")
@@ -27,13 +27,13 @@ module Squared
27
27
  private_constant :AIX_TERM, :TEXT_STYLE
28
28
 
29
29
  def enable_aixterm
30
- unless (colors = get!(:colors)).frozen?
30
+ unless (colors = __get__(:colors)).frozen?
31
31
  colors.merge!(AIX_TERM)
32
32
  end
33
33
  block_given? ? yield(self) : self
34
34
  end
35
35
 
36
- def emphasize(val, title: nil, cols: nil, sub: nil)
36
+ def emphasize(val, title: nil, cols: nil, sub: nil, pipe: nil)
37
37
  n = 0
38
38
  if title
39
39
  title = title.to_s
@@ -64,8 +64,12 @@ module Squared
64
64
  out << bord
65
65
  if block_given?
66
66
  yield out
67
+ elsif pipe.respond_to?(:puts)
68
+ pipe.puts out
69
+ elsif err
70
+ defined?(__warn__) == 'method' ? __warn__(out) : warn(out)
67
71
  else
68
- err ? Warning.warn(out) : puts(out)
72
+ puts out
69
73
  end
70
74
  end
71
75
 
@@ -100,7 +104,7 @@ module Squared
100
104
  end
101
105
  else
102
106
  t = type.to_sym
103
- if (c = get!(:colors)[t])
107
+ if (c = __get__(:colors)[t])
104
108
  if index == -1
105
109
  s = wrap.(s, [c])
106
110
  else
@@ -138,7 +142,7 @@ module Squared
138
142
 
139
143
  def check_style(*args, empty: true)
140
144
  ret = []
141
- colors = get!(:colors)
145
+ colors = __get__(:colors)
142
146
  as_a(args, flat: true).each do |val|
143
147
  if !val.is_a?(Numeric)
144
148
  val = val.to_sym
@@ -153,6 +157,17 @@ module Squared
153
157
  !empty && ret.empty? ? nil : ret
154
158
  end
155
159
 
160
+ def apply_style(data, key, *args, empty: true)
161
+ return unless !data.is_a?(Symbol) || (data = __get__(:theme)[data])
162
+
163
+ set = ->(k, v) { data[k.to_sym] = check_style(v, empty: empty) }
164
+ if key.is_a?(Hash)
165
+ key.each { |k, v| set.(k, v || args.flatten) }
166
+ else
167
+ set.(key, args.flatten)
168
+ end
169
+ end
170
+
156
171
  def log_title(level, color: true)
157
172
  level = if level.is_a?(::Numeric)
158
173
  case level
@@ -172,7 +187,8 @@ module Squared
172
187
  else
173
188
  level.to_s.downcase.to_sym
174
189
  end
175
- val = get!(:logger)[level] || get!(:logger)[level = :unknown]
190
+ theme = __get__(:theme)[:logger]
191
+ val = theme[level] || theme[level = :unknown]
176
192
  level = +level.to_s.upcase
177
193
  case level
178
194
  when 'WARN', 'ERROR', 'FATAL'
@@ -5,8 +5,6 @@ require 'pathname'
5
5
  module Squared
6
6
  module Common
7
7
  module System
8
- include Common
9
-
10
8
  def shell(*cmd, **kwargs)
11
9
  if /^2\.[0-5]\./.match?(RUBY_VERSION)
12
10
  exception = kwargs.delete(:exception)
@@ -20,7 +18,7 @@ module Squared
20
18
  end
21
19
 
22
20
  def copy_d(src, dest, glob: ['**/*'], create: false, verbose: true)
23
- raise message(src, dest, hint: 'not found') if !create && !dest.exist?
21
+ raise "#{dest} (not found)" if !create && !dest.exist?
24
22
 
25
23
  subdir = []
26
24
  files = 0
@@ -40,7 +38,7 @@ module Squared
40
38
  files += 1
41
39
  end
42
40
  end
43
- puts message(dest.realpath, subdir.size.to_s, files.to_s) if verbose
41
+ puts [dest.realpath, subdir.size.to_s, files.to_s].join(' => ') if verbose
44
42
  end
45
43
 
46
44
  def copy_f(src, dest, overwrite: true, verbose: false)
@@ -16,7 +16,7 @@ module Squared
16
16
  rescue StandardError => e
17
17
  raise if exception
18
18
 
19
- warn e
19
+ defined?(__warn__) == 'method' ? __warn__(e) : warn(e)
20
20
  end
21
21
 
22
22
  def invoked?(name)
@@ -26,22 +26,36 @@ module Squared
26
26
  cyan!: '46',
27
27
  white!: '47'
28
28
  },
29
- logger: {
30
- unknown: %i[cyan],
31
- fatal: %i[white bold red!],
32
- error: %i[red bold],
33
- warn: %i[yellow bold],
34
- info: %i[blue],
35
- debug: %i[green]
36
- }.freeze
29
+ theme: {
30
+ workspace: {},
31
+ project: {},
32
+ viewer: {
33
+ banner: %i[blue bold],
34
+ key: %i[bold],
35
+ value: %i[green],
36
+ string: %i[yellow],
37
+ hash: %i[green black!],
38
+ array: %i[blue black!],
39
+ number: %i[magenta],
40
+ undefined: %i[red italic]
41
+ },
42
+ logger: {
43
+ unknown: %i[cyan],
44
+ fatal: %i[white bold red!],
45
+ error: %i[red bold],
46
+ warn: %i[yellow bold],
47
+ info: %i[blue],
48
+ debug: %i[green]
49
+ }
50
+ }
37
51
  }.compare_by_identity
38
52
  private_constant :VAR
39
53
 
40
- def get!(key)
54
+ def __get__(key)
41
55
  VAR[key.is_a?(::String) ? key.to_sym : key]
42
56
  end
43
57
 
44
- def set!(key, val)
58
+ def __set__(key, val)
45
59
  return if VAR.frozen?
46
60
 
47
61
  VAR[key.is_a?(::String) ? key.to_sym : key] = val
@@ -49,6 +63,7 @@ module Squared
49
63
 
50
64
  def finalize!
51
65
  VAR.each_value(&:freeze)
66
+ VAR[:theme].each_value(&:freeze)
52
67
  VAR.freeze
53
68
  end
54
69
 
@@ -1,70 +1,78 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'json'
4
+
3
5
  module Squared
4
6
  module Config
5
7
  class Viewer
6
- include Common::Format
8
+ include Common
9
+ include Format
7
10
  include Task
8
11
  include ::Rake::DSL
9
12
 
10
13
  class << self
11
- attr_reader :styles
12
-
13
- def style(name, *args)
14
- styles[name.to_sym]&.clear&.concat(args)
15
- end
16
-
17
14
  def to_s
18
15
  /[^:]+$/.match(super.to_s)[0]
19
16
  end
20
17
  end
21
18
 
22
- @styles = {
23
- banner: %i[blue],
24
- key: %i[bold],
25
- value: %i[green],
26
- string: %i[yellow],
27
- hash: %i[green black!],
28
- array: %i[blue black!],
29
- number: %i[magenta],
30
- undefined: %i[red italic]
31
- }.freeze
19
+ attr_reader :name, :main, :project, :theme
32
20
 
33
- attr_reader :main, :project, :name
34
-
35
- def initialize(main = 'package', project: nil, name: nil)
21
+ def initialize(main, name = nil, project: nil, dump: nil, opts: {}, auto: true, common: true)
36
22
  if project
37
- @project = get!(:project)[project.to_sym]
23
+ main = @project.base_path(main).to_s if (@project = __get__(:project)[project.to_sym])
38
24
  @required = true
39
25
  end
40
- @name = (name || @project&.name)&.to_s
41
- unless @name
42
- msg, hint = project ? [project, 'not found'] : %w[name missing]
43
- warn log_message(:warn, msg, subject: self.class, hint: hint, color: !pipe?)
44
- @required = true
26
+ @name = name&.to_s || @project&.name
27
+ @ext = File.extname(main)
28
+ @dump = dump
29
+ @mime = {}
30
+ @theme = common ? __get__(:theme)[:viewer] : {}
31
+ if exist?
32
+ @main = main.chomp(@ext)
33
+ @name = @main unless @name || @required
34
+ if auto
35
+ case @ext
36
+ when '.json', '.js'
37
+ add('json', command: File.basename(@main), opts: opts)
38
+ when '.yaml', '.yml'
39
+ add('yaml', command: File.basename(@main), opts: opts)
40
+ end
41
+ end
42
+ else
43
+ @main = main
45
44
  end
46
- @main = main
47
- @include = {}
45
+ return unless warning? && ((missing = exist? && !File.exist?(main)) || !@name)
46
+
47
+ msg, hint = if missing
48
+ ['path not found', realpath]
49
+ else
50
+ @required = true
51
+ project ? [project, 'not found'] : %w[name missing]
52
+ end
53
+ warn log_message(:warn, msg, subject: self.class, hint: hint, color: !pipe?)
48
54
  end
49
55
 
50
56
  def build
51
57
  return unless enabled?
52
58
 
59
+ params = ->(args) { exist? ? [realpath, [args.keys] + args.extras] : [args.keys, args.extras] }
60
+
53
61
  namespace name do
54
- namespace :view do
55
- if @include['json'] && !::Rake::Task.task_defined?("#{name}:view:json")
56
- desc format_desc('json')
62
+ view = @command && @command != name ? @command : 'view'
63
+ namespace view do
64
+ if @mime['json'] && (exist? || !::Rake::Task.task_defined?("#{name}:#{view}:json"))
65
+ desc format_desc(view, %w[json])
57
66
  task :json, [:keys] do |_, args|
58
- require 'json'
59
- read_keys JSON, 'json', args.keys, args.extras
67
+ read_keys(JSON, 'json', *params.(args))
60
68
  end
61
69
  end
62
70
 
63
- if @include['yaml'] && !::Rake::Task.task_defined?("#{name}:view:yaml")
64
- desc format_desc('yaml', 'yml')
71
+ if @mime['yaml'] && (exist? || !::Rake::Task.task_defined?("#{name}:#{view}:yaml"))
72
+ desc format_desc(view, %w[yaml yml])
65
73
  task :yaml, [:keys] do |_, args|
66
74
  require 'yaml'
67
- read_keys YAML, 'yaml', args.keys, args.extras, 'yml', 'yaml'
75
+ read_keys(YAML, 'yaml', *params.(args), ext: %w[yml yaml])
68
76
  end
69
77
  end
70
78
  end
@@ -73,20 +81,23 @@ module Squared
73
81
  yield self if block_given?
74
82
  end
75
83
 
76
- def add(type, gem: nil, parse: nil, ext: [], opts: {}, command: nil, file: nil)
84
+ def add(type, gem: nil, parse: nil, ext: nil, opts: {}, command: 'view', file: nil, exist: nil)
85
+ return self if @mime.frozen?
86
+
77
87
  type = type.to_s
78
88
  if parse && enabled?
79
89
  require(gem || type)
80
90
  obj = eval(parse)
81
- ext = as_a(ext)
91
+ ext << type if (ext = as_a(ext)).empty?
92
+ file = realpath if file.nil? && exist?
82
93
  namespace name do
83
- desc format_desc(ext.first || type, command: command)
84
- namespace(command || :view) do
94
+ desc format_desc(command, ext, exist: exist)
95
+ namespace command do
85
96
  task type, [:keys] do |_, args|
86
97
  if file
87
- read_keys obj, type, file.to_s, collect_args(args, :keys), *ext
98
+ read_keys(obj, type, file.to_s, collect_args(args, :keys), ext: ext)
88
99
  else
89
- read_keys obj, type, args.keys, args.extras, *ext
100
+ read_keys(obj, type, args.keys, args.extras, ext: ext)
90
101
  end
91
102
  end
92
103
  end
@@ -95,16 +106,19 @@ module Squared
95
106
  rescue LoadError, NameError
96
107
  self
97
108
  else
98
- @include[type] = opts
109
+ @mime[type] = opts
110
+ if exist?
111
+ @command = command
112
+ @mime.freeze
113
+ end
99
114
  self
100
115
  end
101
116
 
102
117
  def also(path, type = nil, name: nil, gem: nil, parse: nil, opts: {})
103
- return self unless (file = base_path(path)).exist?
118
+ return self if @mime.frozen? || !(file = base_path(path)).exist?
104
119
 
105
- ext = chop_extname(file).downcase
106
- name ||= file.basename.to_s.chomp(".#{ext}")
107
- type = (type || ext).to_s
120
+ ext = mime_type(file)
121
+ type = type&.to_s || ext
108
122
  if !parse
109
123
  case type
110
124
  when 'json'
@@ -114,49 +128,59 @@ module Squared
114
128
  parse = 'YAML'
115
129
  end
116
130
  end
117
- add(type, gem: gem, parse: parse, ext: ext, opts: opts, command: name, file: file)
131
+ name ||= file.basename.to_s.chomp(File.extname(file))
132
+ add(type, gem: gem, parse: parse, ext: ext, opts: opts, command: name, file: file, exist: true)
133
+ end
134
+
135
+ def style(name, *args)
136
+ apply_style(theme, name, *args)
137
+ self
138
+ end
139
+
140
+ def extensions
141
+ exist? ? [@ext.sub('.', '')] : @mime.keys
118
142
  end
119
143
 
120
144
  def to_s
121
- @include.keys.map { |ext| "#{main}.#{ext}" }.join(',')
145
+ realpath if exist?
146
+
147
+ @mime.keys.map { |ext| "#{main}.#{ext}" }.join(',')
122
148
  end
123
149
 
124
150
  def inspect
125
- "#<#{self.class}: #{name} => #{main} {#{@include.keys.join(', ')}}>"
151
+ "#<#{self.class}: #{name} => #{exist? ? realpath : "#{main} {#{extensions.join(', ')}}"}>"
126
152
  end
127
153
 
128
154
  def enabled?
129
- !@required || !!project&.enabled?
155
+ return File.exist?(realpath) if exist?
156
+
157
+ !@required || (!project.nil? && project.enabled?)
130
158
  end
131
159
 
132
160
  protected
133
161
 
134
- def read_keys(reader, type, file, keys, *ext)
135
- path = base_path(file)
136
- fmt = chop_extname(file)
137
- ext << type if ext.empty?
138
- if path.exist? && path.basename.to_s.include?('.')
139
- raise ArgumentError, message(file, fmt, hint: 'invalid') unless ext.include?(fmt)
162
+ def read_keys(reader, type, file, keys, ext: [type])
163
+ if (mime = mime_type(file)) && base_path(file).exist?
164
+ raise ArgumentError, message(file, mime, hint: 'invalid') unless ext.include?(mime)
140
165
  else
141
- if ext.include?(fmt)
166
+ if ext.include?(mime)
142
167
  alt = file
143
168
  file = nil
144
- ext[0] = fmt
169
+ ext[0] = mime
145
170
  else
146
171
  keys.unshift(file)
147
- alt = "#{main}.{#{ext.join(',')}}"
148
- alt = project.base_path(alt) if project
172
+ alt = base_path("#{main}.{#{ext.join(',')}}")
149
173
  file = Dir[alt].first
150
174
  end
151
- if !file
175
+ unless file
152
176
  raise ArgumentError, message(reader.name, "#{File.basename(alt, '.*')}.#{ext.first}", hint: 'not found')
153
177
  end
154
178
  end
155
179
  project&.info "#{Viewer}(#{type}) => #{file} {#{keys.join(', ')}}"
156
180
  doc = if reader.respond_to?(:load_file)
157
- reader.load_file(file, **@include[type])
181
+ reader.load_file(file, **@mime[type])
158
182
  else
159
- reader.parse(File.read(file), **@include[type])
183
+ reader.parse(File.read(file), **@mime[type])
160
184
  end
161
185
  lines = print_keys(type, doc, keys, file: file)
162
186
  return unless lines
@@ -168,15 +192,16 @@ module Squared
168
192
  sub = if pipe?
169
193
  nil
170
194
  else
195
+ styles = theme
171
196
  [
172
- { pat: /^([^:]+|(?<! ):(?! ))+$/, styles: Viewer.styles[:banner] },
173
- { pat: /^(.*?)(<[^>]+>)(.+)$/m, styles: Viewer.styles[:undefined], index: 2 },
174
- { pat: /^(.+)( : (?!undefined).+)$/m, styles: Viewer.styles[:key] },
175
- { pat: /^(.+ : )(-?[\d.]+)(\s*)$/m, styles: Viewer.styles[:number], index: 2 },
176
- { pat: /^(.+ : ")(.+)("\s*)$/m, styles: Viewer.styles[:string], index: 2 },
177
- { pat: /^(.+ : \{)(.+)(\}\s*)$/m, styles: Viewer.styles[:hash], index: 2 },
178
- { pat: /^(.+ : \[)(.+)(\]\s*)$/m, styles: Viewer.styles[:array], index: 2 },
179
- { pat: /^(.+ : (?!undefined))([^"\[{].*)$/m, styles: Viewer.styles[:value], index: 2 }
197
+ { pat: /^((?:[^:]|(?<! ):(?! ))+)$/, styles: styles[:banner] },
198
+ { pat: /^(.*?)(<[^>]+>)(.+)$/m, styles: styles[:undefined], index: 2 },
199
+ { pat: /^(.+)( : (?!undefined).+)$/m, styles: styles[:key] },
200
+ { pat: /^(.+ : )(-?[\d.]+)(\s*)$/m, styles: styles[:number], index: 2 },
201
+ { pat: /^(.+ : ")(.+)("\s*)$/m, styles: styles[:string], index: 2 },
202
+ { pat: /^(.+ : \{)(.+)(\}\s*)$/m, styles: styles[:hash], index: 2 },
203
+ { pat: /^(.+ : \[)(.+)(\]\s*)$/m, styles: styles[:array], index: 2 },
204
+ { pat: /^(.+ : (?!undefined))([^"\[{].*)$/m, styles: styles[:value], index: 2 }
180
205
  ]
181
206
  end
182
207
  emphasize(lines, title: title, sub: sub)
@@ -185,7 +210,7 @@ module Squared
185
210
  def print_keys(type, data, keys, file: nil)
186
211
  out = []
187
212
  pad = 0
188
- symbolize = @include[type][:symbolize_names]
213
+ symbolize = @mime[type][:symbolize_names]
189
214
  keys.each do |key|
190
215
  begin
191
216
  items = key.split('.')
@@ -210,20 +235,16 @@ module Squared
210
235
  $2 ? ".#{s}" : "#{s}."
211
236
  end
212
237
  end
213
- out << [key, 'undefined']
238
+ out << [key, pipe? ? JSON.dump(nil) : 'undefined']
214
239
  else
215
- out << [key, val.inspect]
240
+ out << [key, @dump == 'json' || pipe? ? JSON.dump(val) : val.inspect]
216
241
  end
217
- pad = key.size if key.size > pad
242
+ pad = [pad, key.size].max
218
243
  end
219
244
  if pipe?
220
- out = out.map do |item|
221
- val = item.last
222
- val.start_with?('"') && val.end_with?('"') ? val[1..-2] : val
223
- end
224
- puts out.join("\n")
245
+ puts out.map(&:last).join("\n")
225
246
  else
226
- out.map { |item| "#{item.first.ljust(pad)} : #{item.last}" }
247
+ out.map { |item| "#{item[0].ljust(pad)} : #{item[1]}" }
227
248
  end
228
249
  end
229
250
 
@@ -231,12 +252,28 @@ module Squared
231
252
  project ? project.base_path(file) : Pathname.new(file).realdirpath
232
253
  end
233
254
 
234
- def format_desc(type, alt = nil, command: nil)
235
- message(name, command || 'view', "#{type}[#{command.nil? ? "file?=#{main}.#{alt || type}," : ''}keys*]")
255
+ def mime_type(file)
256
+ case (ret = File.extname(file).sub('.', '').downcase)
257
+ when 'yml'
258
+ 'yaml'
259
+ when 'js'
260
+ 'json'
261
+ else
262
+ ret.empty? ? nil : ret
263
+ end
264
+ end
265
+
266
+ def format_desc(command, ext, exist: exist?)
267
+ message(name, command, "#{ext.first}[#{exist ? '' : "file?=#{File.basename(main)}.#{ext.last},"}keys*]")
236
268
  end
237
269
 
238
- def chop_extname(file)
239
- File.extname(file).sub('.', '')
270
+ def realpath
271
+ file = main + @ext
272
+ Pathname.new(file).realdirpath.to_s rescue file
273
+ end
274
+
275
+ def exist?
276
+ !@ext.empty? && (!@required || !project.nil?)
240
277
  end
241
278
 
242
279
  def pipe?
@@ -245,6 +282,10 @@ module Squared
245
282
  val = ENV['PIPE_OUT']
246
283
  !val.nil? && !val.empty? && val != '0'
247
284
  end
285
+
286
+ def warning?
287
+ project ? project.warning : true
288
+ end
248
289
  end
249
290
  end
250
291
  end
@@ -7,7 +7,8 @@ module Squared
7
7
  module Repo
8
8
  module Project
9
9
  class Base
10
- include Common::System
10
+ include Common
11
+ include System
11
12
  include Shell
12
13
  include Task
13
14
  include ::Rake::DSL
@@ -17,11 +18,17 @@ module Squared
17
18
  include Common::Task
18
19
  include ::Rake::DSL
19
20
 
21
+ def populate(*); end
22
+
20
23
  def tasks
21
24
  [].freeze
22
25
  end
23
26
 
24
- def populate(*); end
27
+ def as_path(val)
28
+ return val if val.is_a?(::Pathname)
29
+
30
+ val.is_a?(::String) ? Pathname.new(val) : nil
31
+ end
25
32
 
26
33
  def to_s
27
34
  /[^:]+$/.match(super.to_s)[0]
@@ -35,25 +42,33 @@ module Squared
35
42
  @@print_order = 0
36
43
  @@tasks = {}
37
44
 
38
- attr_reader :name, :project, :workspace, :group, :path, :logger
45
+ alias __warn__ warn
46
+
47
+ attr_reader :name, :project, :workspace, :group, :path, :logger, :theme
48
+ attr_accessor :warning
39
49
 
40
50
  protected :logger
41
51
 
42
52
  def_delegators :logger, :log, :<<, :debug, :info, :warn, :error, :fatal, :unknown
43
53
 
44
- def initialize(name, project, workspace, **kwargs)
54
+ def initialize(name, path, workspace, *, group: nil, log: nil, common: true, **kwargs)
45
55
  @name = name.to_s
46
- @path = workspace.root_path(project.to_s)
56
+ @path = workspace.root_path(path.to_s)
47
57
  @project = @path.basename.to_s
48
58
  @workspace = workspace
49
- @group = kwargs[:group]&.to_s
59
+ @group = group&.to_s
50
60
  @depend = kwargs[:depend]
51
61
  @doc = kwargs[:doc]
52
62
  @test = kwargs[:test]
53
63
  @output = [kwargs[:run], nil]
54
64
  @copy = kwargs[:copy]
55
65
  @clean = kwargs[:clean]
56
- log = kwargs[:log]
66
+ @theme = if common
67
+ workspace.theme
68
+ else
69
+ __get__(:theme)[:project][to_sym] ||= {}
70
+ end
71
+ @warning = workspace.warning
57
72
  log = { file: log } unless log.is_a?(::Hash)
58
73
  if (logfile = env('LOG_FILE')).nil? && (auto = env('LOG_AUTO'))
59
74
  logfile = case auto
@@ -72,7 +87,7 @@ module Squared
72
87
  logfile.realdirpath
73
88
  rescue StandardError => e
74
89
  logfile = nil
75
- Warning.warn e
90
+ __warn__ e if @warning
76
91
  end
77
92
  end
78
93
  @logger = Logger.new(logfile, progname: @name, level: env('LOG_LEVEL') || log[:level] || Logger::INFO)
@@ -162,6 +177,10 @@ module Squared
162
177
  run(@depend, exception: workspace.exception) if @depend
163
178
  end
164
179
 
180
+ def copy(*)
181
+ run_s @copy
182
+ end
183
+
165
184
  def doc
166
185
  build @doc if @doc
167
186
  end
@@ -170,10 +189,6 @@ module Squared
170
189
  build @test if @test
171
190
  end
172
191
 
173
- def copy(*)
174
- run_s @copy
175
- end
176
-
177
192
  def clean
178
193
  return unless @clean
179
194
 
@@ -194,7 +209,7 @@ module Squared
194
209
  begin
195
210
  File.delete(file) if File.file?(file)
196
211
  rescue StandardError => e
197
- warn e
212
+ error e
198
213
  end
199
214
  end
200
215
  end
@@ -202,10 +217,6 @@ module Squared
202
217
  end
203
218
  end
204
219
 
205
- def styles
206
- workspace.styles
207
- end
208
-
209
220
  def base_path(*args)
210
221
  path.join(*args)
211
222
  end
@@ -349,7 +360,7 @@ module Squared
349
360
 
350
361
  if verbose?
351
362
  pad = 0
352
- if (args = styles[:banner])
363
+ if (args = theme[:banner])
353
364
  if args.any? { |s| s.to_s.end_with?('!') }
354
365
  pad = 1
355
366
  elsif args.size <= 1
@@ -4,7 +4,7 @@ module Squared
4
4
  module Repo
5
5
  module Project
6
6
  class Git < Base
7
- include Common::Format
7
+ include Format
8
8
 
9
9
  REF = :git
10
10
  private_constant :REF
@@ -35,7 +35,7 @@ module Squared
35
35
  end
36
36
 
37
37
  def is_a?(val)
38
- if val.is_a?(::Pathname) || (val.is_a?(::String) && (val = Pathname.new(val)))
38
+ if (val = as_path(val))
39
39
  val.join('.git').directory?
40
40
  else
41
41
  super
@@ -516,7 +516,7 @@ module Squared
516
516
  return unless verbose?
517
517
 
518
518
  if size > 0
519
- args = styles[:banner]&.reject { |s| s.to_s.end_with?('!') } || []
519
+ args = theme[:banner]&.reject { |s| s.to_s.end_with?('!') } || []
520
520
  args << :bold if args.size <= 1
521
521
  puts print_footer "#{sub_style(size, *args)} #{size == 1 ? type.sub(/s$/, '') : type}"
522
522
  else
@@ -19,7 +19,7 @@ module Squared
19
19
  end
20
20
 
21
21
  def is_a?(val)
22
- if val.is_a?(::Pathname) || (val.is_a?(::String) && (val = Pathname.new(val)))
22
+ if (val = as_path(val))
23
23
  val.join('package.json').exist?
24
24
  else
25
25
  super
@@ -33,7 +33,7 @@ module Squared
33
33
  run: nil
34
34
  }.freeze
35
35
 
36
- def initialize(name, project, workspace, **kwargs)
36
+ def initialize(name, path, workspace, *, **kwargs)
37
37
  super
38
38
  initialize_script(REF)
39
39
  if (opts = env('BUILD', strict: true))
@@ -71,7 +71,7 @@ module Squared
71
71
  when :install
72
72
  desc format_desc(action, flag)
73
73
  task flag do
74
- install flag
74
+ depend(flag, override: true)
75
75
  end
76
76
  when :outdated
77
77
  desc format_desc(action, flag, %w[prune dry-run], req: 'opts?')
@@ -134,10 +134,10 @@ module Squared
134
134
  end
135
135
  end
136
136
 
137
- def depend(flag = nil)
138
- if @depend
137
+ def depend(flag = nil, override: false)
138
+ if @depend && !override
139
139
  super
140
- else
140
+ elsif outdated?
141
141
  frozen = flag == :frozen
142
142
  force = flag == :force
143
143
  dedupe = flag == :dedupe
@@ -206,8 +206,7 @@ module Squared
206
206
  info cmd
207
207
  data = `#{cmd} --json --loglevel=error`
208
208
  Dir.chdir(pwd)
209
- doc = File.read(package)
210
- json = JSON.parse(doc)
209
+ json = JSON.parse(doc = package.read)
211
210
  pat = /^(\d+)(\.)(\d+)(\.)(\d+)$/
212
211
  dep1 = json['dependencies'] || {}
213
212
  dep2 = json['devDependencies'] || {}
@@ -451,11 +450,11 @@ module Squared
451
450
  elsif pnpm?
452
451
  if silent
453
452
  cmd << '--reporter=silent'
454
- else
455
- case level
456
- when 'debug', 'info', 'warn', 'error'
457
- cmd << "--loglevel=#{level}"
458
- end
453
+ level ||= 'error'
454
+ end
455
+ case level
456
+ when 'debug', 'info', 'warn', 'error'
457
+ cmd << "--loglevel=#{level}"
459
458
  end
460
459
  elsif silent
461
460
  cmd << '--loglevel=silent'
@@ -21,7 +21,7 @@ module Squared
21
21
  end
22
22
 
23
23
  def is_a?(val)
24
- if val.is_a?(::Pathname) || (val.is_a?(::String) && (val = Pathname.new(val)))
24
+ if (val = as_path(val))
25
25
  REQUIREMENTS.any? { |file| val.join(file).exist? }
26
26
  else
27
27
  super
@@ -29,7 +29,7 @@ module Squared
29
29
  end
30
30
  end
31
31
 
32
- def initialize(name, project, workspace, **kwargs)
32
+ def initialize(name, path, workspace, *, **kwargs)
33
33
  super
34
34
  initialize_build(REF, **kwargs)
35
35
  end
@@ -59,7 +59,7 @@ module Squared
59
59
  desc options.()
60
60
  end
61
61
  task flag do |_, args|
62
- install(flag, opts: collect_args(args, :opts))
62
+ depend(flag, opts: collect_args(args, :opts), override: true)
63
63
  end
64
64
  end
65
65
  end
@@ -68,8 +68,8 @@ module Squared
68
68
  end
69
69
  end
70
70
 
71
- def depend(flag = nil, opts: [])
72
- if @depend
71
+ def depend(flag = nil, opts: [], override: false)
72
+ if @depend && !override
73
73
  super
74
74
  elsif outdated?
75
75
  case install_type
@@ -97,7 +97,7 @@ module Squared
97
97
 
98
98
  def outdated(*); end
99
99
 
100
- def install_type
100
+ def install_type(*)
101
101
  return @requirements if @requirements
102
102
 
103
103
  ret = REQUIREMENTS.index { |file| base_path(file).exist? }
@@ -7,7 +7,7 @@ module Squared
7
7
  REF = :ruby
8
8
  GEMFILE = %w[Gemfile Gemfile.lock gem.deps.rb Isolate].freeze
9
9
  OPT_INSTALL = %w[no-cache force quiet verbose].freeze
10
- OPT_UPDATE = %w[redownload local strict conservative quiet verbose].freeze
10
+ OPT_UPDATE = %w[redownload local strict conservative group=s quiet verbose].freeze
11
11
  private_constant :REF, :GEMFILE, :OPT_INSTALL, :OPT_UPDATE
12
12
 
13
13
  class << self
@@ -18,7 +18,7 @@ module Squared
18
18
  end
19
19
 
20
20
  def is_a?(val)
21
- if val.is_a?(::Pathname) || (val.is_a?(::String) && (val = Pathname.new(val)))
21
+ if (val = as_path(val))
22
22
  [*GEMFILE, *::Rake::Application::DEFAULT_RAKEFILES, 'README.rdoc'].any? { |file| val.join(file).exist? }
23
23
  else
24
24
  super
@@ -33,7 +33,7 @@ module Squared
33
33
  rake: nil
34
34
  }.freeze
35
35
 
36
- def initialize(name, project, workspace, **kwargs)
36
+ def initialize(name, path, workspace, *, **kwargs)
37
37
  super
38
38
  initialize_build(REF, **kwargs)
39
39
  @version = env('BUILD', suffix: 'VERSION', strict: true) || kwargs.delete(:version)
@@ -51,7 +51,7 @@ module Squared
51
51
  break
52
52
  end
53
53
  rescue StandardError => e
54
- warn e
54
+ error e
55
55
  end
56
56
  end
57
57
 
@@ -80,12 +80,12 @@ module Squared
80
80
  when :'with-g', :'without-g'
81
81
  desc format_desc(action, flag, 'group+')
82
82
  task flag, [:group] do |_, args|
83
- install(flag, group: collect_args(args, :group))
83
+ depend(flag, group: collect_args(args, :group), override: true)
84
84
  end
85
85
  else
86
86
  desc format_desc(action, flag, OPT_INSTALL)
87
87
  task flag, [:opts] do |_, args|
88
- install(flag, opts: collect_args(args, :opts))
88
+ depend(flag, opts: collect_args(args, :opts), override: true)
89
89
  end
90
90
  end
91
91
  when :update
@@ -106,10 +106,10 @@ module Squared
106
106
  end
107
107
  end
108
108
 
109
- def depend(flag = nil, opts: [], group: [])
110
- if @depend
109
+ def depend(flag = nil, opts: [], group: [], override: false)
110
+ if @depend && !override
111
111
  super
112
- else
112
+ elsif outdated?
113
113
  case flag
114
114
  when :redownload, :local, :'prefer-local'
115
115
  cmd = bundle_session 'install'
@@ -213,11 +213,11 @@ module Squared
213
213
  end
214
214
  return false unless @autodetect
215
215
 
216
- error = ->(hint) { raise ArgumentError, message('failed to parse', hint: hint) }
216
+ quit = ->(hint) { raise ArgumentError, message('failed to parse', hint: hint) }
217
217
  begin
218
218
  out = `gem -C #{shell_quote(path)} list --local -d #{project}`
219
219
  data = /#{Regexp.escape(project)} \(([^)]+)\)/.match(out)
220
- error.('version') unless data
220
+ quit.('version') unless data
221
221
  ver = data[1].split(/\s*,\s*/)
222
222
  if @version
223
223
  ver.unshift(@version)
@@ -231,10 +231,10 @@ module Squared
231
231
  @version = v
232
232
  break
233
233
  end
234
- error.('path') unless data
234
+ quit.('path') unless data
235
235
  @gemdir = Pathname.new(data[1].strip).join(gempath.())
236
236
  rescue StandardError => e
237
- warn e
237
+ error e
238
238
  @version = nil
239
239
  @gemdir = nil
240
240
  @autodetect = false
@@ -248,7 +248,9 @@ module Squared
248
248
  end
249
249
 
250
250
  def outdated?
251
- GEMFILE.any? { |file| base_path(file).exist? }
251
+ return @outdated unless @outdated.nil?
252
+
253
+ @outdated = GEMFILE.any? { |file| base_path(file).exist? }
252
254
  end
253
255
 
254
256
  def dev?
@@ -261,7 +263,13 @@ module Squared
261
263
  if (val = env('BUNDLE_JOBS')).to_i > 0
262
264
  @session << "-j#{val}"
263
265
  end
264
- list.each { |flag| @session << "--#{flag}" if opts.include?(flag) }
266
+ list.each do |flag|
267
+ if opts.include?(flag)
268
+ @session << "--#{flag}"
269
+ elsif /^g(?:roup)?=(.+)$/.match(flag)
270
+ @session << "--group=#{$1}"
271
+ end
272
+ end
265
273
  end
266
274
 
267
275
  def gem_session(*cmd)
@@ -3,7 +3,8 @@
3
3
  module Squared
4
4
  module Repo
5
5
  class Workspace
6
- include Common::Format
6
+ include Common
7
+ include Format
7
8
  include System
8
9
  include Task
9
10
  include ::Rake::DSL
@@ -51,10 +52,10 @@ module Squared
51
52
 
52
53
  @project_kind = []
53
54
 
54
- attr_reader :main, :root, :home, :series
55
- attr_accessor :manifest, :manifest_url, :exception, :styles, :pipe, :verbose
55
+ attr_reader :main, :root, :home, :series, :theme
56
+ attr_accessor :manifest, :manifest_url, :exception, :pipe, :verbose, :warning
56
57
 
57
- def initialize(main)
58
+ def initialize(main, *, common: true, **)
58
59
  @main = main.to_s
59
60
  @home = if (val = env('REPO_HOME'))
60
61
  home = Pathname.new(val)
@@ -90,7 +91,7 @@ module Squared
90
91
  end
91
92
  @root ||= @home.parent
92
93
  @series = TASK_NAME.dup
93
- @styles = {}
94
+ @theme = common ? __get__(:theme)[:workspace] : {}
94
95
  @project = {}
95
96
  @script = {
96
97
  group: {},
@@ -102,9 +103,12 @@ module Squared
102
103
  @exception = !env('PIPE_FAIL', ignore: '0').nil?
103
104
  @pipe = !env('PIPE_OUT', ignore: '0').nil?
104
105
  @verbose = !@pipe
106
+ @warning = !empty?(@root, init: false)
105
107
  end
106
108
 
107
109
  def build(**kwargs)
110
+ return unless enabled?
111
+
108
112
  default = kwargs[:default]
109
113
  parallel = env('REPO_SYNC', ignore: '0') ? [] : (kwargs[:parallel] || []).map!(&:to_sym)
110
114
 
@@ -140,9 +144,9 @@ module Squared
140
144
  end
141
145
  series.merge!(parent) if incl.uniq.size > 1
142
146
  series.merge!(group)
143
- series[:refresh].clear if series[:refresh].all? { |target| target.to_s.end_with?(':build') }
147
+ series[:refresh].clear if series[:refresh].all? { |target| target.end_with?(':build') }
144
148
 
145
- if manifest_url && (empty?(root) || @override)
149
+ if repo?
146
150
  branch = env('REPO_MANIFEST') || read_manifest
147
151
  target = branch || manifest
148
152
  stage = nil
@@ -250,27 +254,35 @@ module Squared
250
254
  yield self if block_given?
251
255
  end
252
256
 
253
- def repo(url, manifest = 'latest')
257
+ def repo(url, manifest = 'latest', run: nil, dev: nil, prod: nil)
254
258
  @manifest_url = url
255
259
  @manifest = manifest
256
- self
260
+ script = case (val = env('REPO_BUILD'))
261
+ when 'verbose'
262
+ run ? "#{run}:verbose" : nil
263
+ when 'silent'
264
+ @verbose = false
265
+ @warning = false
266
+ run
267
+ else
268
+ val || run
269
+ end
270
+ case env('REPO_WARN')
271
+ when '0'
272
+ @warning = false
273
+ when '1'
274
+ @warning = true
275
+ end
276
+ script ? run(script, dev: bool_match(env('REPO_DEV'), dev), prod: bool_match(env('REPO_DEV'), prod)) : self
257
277
  end
258
278
 
259
279
  def run(script, group: nil, ref: nil, **kwargs)
260
280
  if group || ref
261
281
  script_command :run, script, group, ref
262
282
  else
263
- @script[:build] = case (val = env('REPO_BUILD'))
264
- when 'verbose'
265
- "#{script}:verbose"
266
- when 'silent'
267
- @verbose = false
268
- script
269
- else
270
- val || script
271
- end
272
- @script[:dev] = bool_match(env('REPO_DEV'), kwargs[:dev])
273
- @script[:prod] = bool_match(env('REPO_PROD'), kwargs[:prod])
283
+ @script[:build] = script
284
+ @script[:dev] = kwargs[:dev]
285
+ @script[:prod] = kwargs[:prod]
274
286
  self
275
287
  end
276
288
  end
@@ -291,17 +303,17 @@ module Squared
291
303
  script_command :test, script, group, ref
292
304
  end
293
305
 
294
- def add(name, dir = nil, **kwargs)
295
- path = (dir || name).to_s
306
+ def add(name, path = nil, **kwargs)
307
+ path = root_path((path || name).to_s)
296
308
  ref = kwargs[:ref]
297
309
  project = if !ref.is_a?(::Class)
298
- Workspace.find(path: root_path(path), ref: ref)
310
+ Workspace.find(path: path, ref: ref)
299
311
  elsif ref < Project::Base
300
312
  ref
301
313
  end
302
314
  instance = (project || Project::Base).new(name, path, self, **kwargs)
303
315
  @project[n = name.to_sym] = instance
304
- get!(:project)[n] = instance
316
+ __get__(:project)[n] = instance unless kwargs[:private]
305
317
  self
306
318
  end
307
319
 
@@ -315,13 +327,19 @@ module Squared
315
327
  self
316
328
  end
317
329
 
318
- def style(name, *args)
319
- set = ->(k, v) { styles[k.to_sym] = check_style(v, empty: false) }
320
- if name.is_a?(Hash)
321
- name.each { |k, v| set.(k, v || args.flatten) }
322
- else
323
- set.(name, args.flatten)
330
+ def style(name, *args, target: nil, empty: false)
331
+ data = nil
332
+ if target
333
+ as_a(target).each_with_index do |val, i|
334
+ if i == 0
335
+ break unless (data = __get__(:theme)[val.to_sym])
336
+ else
337
+ data = data[val.to_sym] ||= {}
338
+ end
339
+ end
340
+ return unless data
324
341
  end
342
+ apply_style(data || theme, name, *args, empty: empty)
325
343
  self
326
344
  end
327
345
 
@@ -340,12 +358,12 @@ module Squared
340
358
  ret.empty? || as_a(ignore).any? { |val| ret == val.to_s } ? nil : ret
341
359
  end
342
360
 
343
- def read_manifest
361
+ def read_manifest(*)
344
362
  require 'rexml/document'
345
363
  file = root_path('.repo/manifest.xml')
346
364
  return unless file.exist?
347
365
 
348
- doc = REXML::Document.new(File.read(file))
366
+ doc = REXML::Document.new(file.read)
349
367
  doc.elements['manifest/include'].attributes['name']&.sub('.xml', '')
350
368
  end
351
369
 
@@ -382,13 +400,12 @@ module Squared
382
400
  "#<#{self.class}: #{main} => #{self}>"
383
401
  end
384
402
 
385
- def empty?(dir)
386
- return true if dir.empty? || dir.join('.repo').directory?
387
- return true if dir.children.size == 1 && dir.join(dir.children.first).to_s == __FILE__
403
+ def enabled?
404
+ repo? || @project.any? { |_, proj| proj.enabled? }
405
+ end
388
406
 
389
- dir == root && !env('REPO_ROOT').nil? && root.children.none? do |path|
390
- path.directory? && !path.basename.to_s.start_with?('.') && path.to_s != home.to_s
391
- end
407
+ def repo?
408
+ !manifest_url.nil? && (empty?(root) || @override)
392
409
  end
393
410
 
394
411
  def multitask?
@@ -399,6 +416,15 @@ module Squared
399
416
  end
400
417
  end
401
418
 
419
+ def empty?(dir, init: true)
420
+ return true if dir.empty? || (init && dir.join('.repo').directory?)
421
+ return true if dir.children.size == 1 && dir.join(dir.children.first).to_s == __FILE__
422
+
423
+ dir == root && !env('REPO_ROOT').nil? && root.children.none? do |path|
424
+ path.directory? && !path.basename.to_s.start_with?('.') && path.to_s != home.to_s
425
+ end
426
+ end
427
+
402
428
  def task_defined?(obj, key)
403
429
  obj.is_a?(TASK_BASE[key])
404
430
  end
data/lib/squared/repo.rb CHANGED
@@ -9,7 +9,7 @@ module Squared
9
9
  project id
10
10
  else
11
11
  (id = Pathname.new(id).realdirpath.to_s) rescue nil if id.is_a?(::String)
12
- get!(:project).find { |_, val| val.path.to_s == id.to_s }
12
+ __get__(:project).find { |_, val| val.path.to_s == id.to_s }
13
13
  end
14
14
  end
15
15
  ret.size == 1 ? ret.first : ret
@@ -19,7 +19,7 @@ module Squared
19
19
  ret = project(name)
20
20
  return ret if ret&.path&.directory?
21
21
 
22
- raise NoMethodError, message('project is not initialized', name)
22
+ raise NoMethodError, "project is not initialized (#{name})"
23
23
  end
24
24
 
25
25
  def project?(name)
@@ -29,7 +29,7 @@ module Squared
29
29
  private
30
30
 
31
31
  def project(name)
32
- get!(:project)[name.to_sym]
32
+ __get__(:project)[name.to_sym]
33
33
  end
34
34
  end
35
35
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.0.2'
4
+ VERSION = '0.0.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squared
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - An Pham
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-01 00:00:00.000000000 Z
11
+ date: 2024-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake