squared 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,82 +9,94 @@ module Squared
9
9
  include ::Rake::DSL
10
10
 
11
11
  class << self
12
- include Common::Format
13
-
14
- attr_reader :styles
15
-
16
- def style(name, *args)
17
- args = check_style(args)
18
- styles[name.to_sym]&.clear&.concat(args)
12
+ def to_s
13
+ /[^:]+$/.match(super.to_s)[0]
19
14
  end
20
15
  end
21
16
 
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
17
+ attr_reader :name, :main, :project, :theme
32
18
 
33
- attr_reader :main, :project, :name
34
-
35
- def initialize(main = 'package', project: nil, name: nil)
19
+ def initialize(main, name = nil, project: nil, opts: {}, auto: true, common: true)
36
20
  if project
37
- @project = get(:project)[project.to_sym]
21
+ main = @project.base_path(main).to_s if (@project = __get__(:project)[project.to_sym])
38
22
  @required = true
39
23
  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: 'Config::Viewer', hint: hint, color: !pipe?)
44
- @required = true
24
+ @name = name&.to_s || @project&.name
25
+ @ext = File.extname(main)
26
+ @mime = {}
27
+ @theme = common ? __get__(:theme)[:viewer] : {}
28
+ if exist?
29
+ @main = main.chomp(@ext)
30
+ @name = @main unless @name || @required
31
+ if auto
32
+ case @ext
33
+ when '.json', '.js'
34
+ add('json', command: File.basename(@main), opts: opts)
35
+ when '.yaml', '.yml'
36
+ add('yaml', command: File.basename(@main), opts: opts)
37
+ end
38
+ end
39
+ else
40
+ @main = main
45
41
  end
46
- @main = main
47
- @include = {}
42
+ return unless warning? && ((missing = exist? && !File.exist?(main)) || !@name)
43
+
44
+ msg, hint = if missing
45
+ ['path not found', realpath]
46
+ else
47
+ @required = true
48
+ project ? [project, 'not found'] : %w[name missing]
49
+ end
50
+ warn log_message(:warn, msg, subject: self.class, hint: hint, color: !pipe?)
48
51
  end
49
52
 
50
53
  def build
51
54
  return unless enabled?
52
55
 
53
- namespace @name do
54
- namespace :view do
55
- if @include['json'] && !::Rake::Task.task_defined?("#{@name}:view:json")
56
- desc format_desc('json')
56
+ params = ->(args) { exist? ? [realpath, [args.keys] + args.extras] : [args.keys, args.extras] }
57
+
58
+ namespace name do
59
+ view = @command && @command != name ? @command : 'view'
60
+ namespace view do
61
+ if @mime['json'] && (exist? || !::Rake::Task.task_defined?("#{name}:#{view}:json"))
62
+ desc format_desc(view, %w[json])
57
63
  task :json, [:keys] do |_, args|
58
64
  require 'json'
59
- read_keys JSON, 'json', args.keys, args.extras
65
+ read_keys(JSON, 'json', *params.(args))
60
66
  end
61
67
  end
62
68
 
63
- if @include['yaml'] && !::Rake::Task.task_defined?("#{@name}:view:yaml")
64
- desc format_desc('yaml', 'yml')
69
+ if @mime['yaml'] && (exist? || !::Rake::Task.task_defined?("#{name}:#{view}:yaml"))
70
+ desc format_desc(view, %w[yaml yml])
65
71
  task :yaml, [:keys] do |_, args|
66
72
  require 'yaml'
67
- read_keys YAML, 'yaml', args.keys, args.extras, 'yml', 'yaml'
73
+ read_keys(YAML, 'yaml', *params.(args), ext: %w[yml yaml])
68
74
  end
69
75
  end
70
76
  end
71
77
  end
78
+
79
+ yield self if block_given?
72
80
  end
73
81
 
74
- def add(type, gem: nil, parse: nil, ext: [], opts: {}, command: nil, file: nil)
82
+ def add(type, gem: nil, parse: nil, ext: [], opts: {}, command: 'view', file: nil)
83
+ return self if @mime.frozen?
84
+
75
85
  type = type.to_s
76
86
  if parse && enabled?
77
87
  require(gem || type)
78
88
  obj = eval(parse)
79
89
  ext = as_a(ext)
80
- namespace @name do
81
- desc format_desc(ext.first || type, command: command)
82
- namespace(command || :view) do
90
+ ext << type if ext.empty?
91
+ file = realpath if file.nil? && exist?
92
+ namespace name do
93
+ desc format_desc(command, ext)
94
+ namespace command do
83
95
  task type, [:keys] do |_, args|
84
96
  if file
85
- read_keys obj, type, file.to_s, collect_args(args, :keys), *ext
97
+ read_keys(obj, type, file.to_s, collect_args(args, :keys), ext: ext)
86
98
  else
87
- read_keys obj, type, args.keys, args.extras, *ext
99
+ read_keys(obj, type, args.keys, args.extras, ext: ext)
88
100
  end
89
101
  end
90
102
  end
@@ -93,16 +105,19 @@ module Squared
93
105
  rescue LoadError, NameError
94
106
  self
95
107
  else
96
- @include[type] = opts
108
+ @mime[type] = opts
109
+ if exist?
110
+ @command = command
111
+ @mime.freeze
112
+ end
97
113
  self
98
114
  end
99
115
 
100
116
  def also(path, type = nil, name: nil, gem: nil, parse: nil, opts: {})
101
- return self unless (file = base_path(path)).exist?
117
+ return self if @mime.frozen? || !(file = base_path(path)).exist?
102
118
 
103
- ext = chop_extname(file).downcase
104
- name ||= file.basename.to_s.chomp(".#{ext}")
105
- type = (type || ext).to_s
119
+ ext = mime_type(file)
120
+ type = type&.to_s || ext
106
121
  if !parse
107
122
  case type
108
123
  when 'json'
@@ -112,42 +127,61 @@ module Squared
112
127
  parse = 'YAML'
113
128
  end
114
129
  end
130
+ name ||= file.basename.to_s.chomp(File.extname(file))
115
131
  add(type, gem: gem, parse: parse, ext: ext, opts: opts, command: name, file: file)
116
132
  end
117
133
 
134
+ def style(name, *args)
135
+ apply_style(theme, name, *args)
136
+ self
137
+ end
138
+
139
+ def extensions
140
+ exist? ? [@ext.sub('.', '')] : @mime.keys
141
+ end
142
+
143
+ def to_s
144
+ realpath if exist?
145
+
146
+ @mime.keys.map { |ext| "#{main}.#{ext}" }.join(',')
147
+ end
148
+
149
+ def inspect
150
+ "#<#{self.class}: #{name} => #{exist? ? realpath : "#{main} {#{extensions.join(', ')}}"}>"
151
+ end
152
+
118
153
  def enabled?
119
- !@required || !!@project&.enabled?
154
+ return File.exist?(realpath) if exist?
155
+
156
+ !@required || (!project.nil? && project.enabled?)
120
157
  end
121
158
 
122
159
  protected
123
160
 
124
- def read_keys(reader, type, file, keys, *ext)
125
- path = base_path(file)
126
- fmt = chop_extname(file)
127
- ext << type if ext.empty?
128
- if path.exist? && path.basename.to_s.include?('.')
129
- raise ArgumentError, message(file, fmt, hint: 'invalid') unless ext.include?(fmt)
161
+ def read_keys(reader, type, file, keys, ext: [type])
162
+ if (mime = mime_type(file)) && base_path(file).exist?
163
+ raise ArgumentError, message(file, mime, hint: 'invalid') unless ext.include?(mime)
130
164
  else
131
- if ext.include?(fmt)
165
+ if ext.include?(mime)
132
166
  alt = file
133
167
  file = nil
134
- ext[0] = fmt
168
+ ext[0] = mime
135
169
  else
136
170
  keys.unshift(file)
137
- alt = "#{@main}.{#{ext.join(',')}}"
138
- alt = @project.base_path(alt) if @project
171
+ alt = base_path("#{main}.{#{ext.join(',')}}")
139
172
  file = Dir[alt].first
140
173
  end
141
- if !file
174
+ unless file
142
175
  raise ArgumentError, message(reader.name, "#{File.basename(alt, '.*')}.#{ext.first}", hint: 'not found')
143
176
  end
144
177
  end
178
+ project&.info "#{Viewer}(#{type}) => #{file} {#{keys.join(', ')}}"
145
179
  doc = if reader.respond_to?(:load_file)
146
- reader.load_file(file, **@include[type])
180
+ reader.load_file(file, **@mime[type])
147
181
  else
148
- reader.parse(File.read(file), **@include[type])
182
+ reader.parse(File.read(file), **@mime[type])
149
183
  end
150
- lines = print_keys(type, doc, keys)
184
+ lines = print_keys(type, doc, keys, file: file)
151
185
  return unless lines
152
186
 
153
187
  title = Pathname.new(file)
@@ -157,24 +191,25 @@ module Squared
157
191
  sub = if pipe?
158
192
  nil
159
193
  else
194
+ styles = theme
160
195
  [
161
- { pat: /^([^:]+|(?<! ):(?! ))+$/, styles: Viewer.styles[:banner] },
162
- { pat: /^(.*?)(<[^>]+>)(.+)$/m, styles: Viewer.styles[:undefined], index: 2 },
163
- { pat: /^(.+)( : (?!undefined))(.+)$/m, styles: Viewer.styles[:key] },
164
- { pat: /^(.+)( : )(-?[\d.]+)(\s*)$/m, styles: Viewer.styles[:number], index: 3 },
165
- { pat: /^(.+)( : ")(.+)("\s*)$/m, styles: Viewer.styles[:string], index: 3 },
166
- { pat: /^(.+)( : \{)(.+)(\}\s*)$/m, styles: Viewer.styles[:hash], index: 3 },
167
- { pat: /^(.+)( : \[)(.+)(\]\s*)$/m, styles: Viewer.styles[:array], index: 3 },
168
- { pat: /^(.+)( : (?!undefined))([^"\[{].*)$/m, styles: Viewer.styles[:value], index: 3 }
196
+ { pat: /^((?:[^:]|(?<! ):(?! ))+)$/, styles: styles[:banner] },
197
+ { pat: /^(.*?)(<[^>]+>)(.+)$/m, styles: styles[:undefined], index: 2 },
198
+ { pat: /^(.+)( : (?!undefined).+)$/m, styles: styles[:key] },
199
+ { pat: /^(.+ : )(-?[\d.]+)(\s*)$/m, styles: styles[:number], index: 2 },
200
+ { pat: /^(.+ : ")(.+)("\s*)$/m, styles: styles[:string], index: 2 },
201
+ { pat: /^(.+ : \{)(.+)(\}\s*)$/m, styles: styles[:hash], index: 2 },
202
+ { pat: /^(.+ : \[)(.+)(\]\s*)$/m, styles: styles[:array], index: 2 },
203
+ { pat: /^(.+ : (?!undefined))([^"\[{].*)$/m, styles: styles[:value], index: 2 }
169
204
  ]
170
205
  end
171
206
  emphasize(lines, title: title, sub: sub)
172
207
  end
173
208
 
174
- def print_keys(type, data, keys)
209
+ def print_keys(type, data, keys, file: nil)
175
210
  out = []
176
211
  pad = 0
177
- symbolize = @include[type][:symbolize_names]
212
+ symbolize = @mime[type][:symbolize_names]
178
213
  keys.each do |key|
179
214
  begin
180
215
  items = key.split('.')
@@ -189,6 +224,7 @@ module Squared
189
224
  end
190
225
  end
191
226
  rescue StandardError
227
+ project&.warn "#{Viewer}(#{type}) => #{file ? "#{file} " : ''}{#{key}: undefined}"
192
228
  val = Regexp.escape($!.message)
193
229
  key = key.sub(/(#{val})\.|\.(#{val})|(#{val})/) do
194
230
  s = "<#{$3 || $2 || $1}>"
@@ -198,41 +234,59 @@ module Squared
198
234
  $2 ? ".#{s}" : "#{s}."
199
235
  end
200
236
  end
201
- out << [key, 'undefined']
237
+ out << [key, pipe? ? nil : 'undefined']
202
238
  else
203
- out << [key, val.inspect]
239
+ out << [key, pipe? ? val : val.inspect]
204
240
  end
205
241
  pad = key.size if key.size > pad
206
242
  end
207
243
  if pipe?
208
- out = out.map do |item|
209
- val = item.last
210
- val.start_with?('"') && val.end_with?('"') ? val[1..-2] : val
211
- end
244
+ require 'json'
245
+ out = out.map { |item| JSON.dump(item[1]) }
212
246
  puts out.join("\n")
213
247
  else
214
- out.map { |item| "#{item.first.ljust(pad)} : #{item.last}" }
248
+ out.map { |item| "#{item[0].ljust(pad)} : #{item[1]}" }
215
249
  end
216
250
  end
217
251
 
218
252
  def base_path(file)
219
- @project ? @project.base_path(file) : Pathname.new(file).realdirpath
253
+ project ? project.base_path(file) : Pathname.new(file).realdirpath
220
254
  end
221
255
 
222
- def format_desc(type, alt = nil, command: nil)
223
- message(@name, command || 'view', "#{type}[#{command.nil? ? "file?=#{@main}.#{alt || type}," : ''}keys*]")
256
+ def mime_type(file)
257
+ case (ret = File.extname(file).sub('.', '').downcase)
258
+ when 'yml'
259
+ 'yaml'
260
+ when 'js'
261
+ 'json'
262
+ else
263
+ ret.empty? ? nil : ret
264
+ end
265
+ end
266
+
267
+ def format_desc(command, ext)
268
+ message(name, command, "#{ext.first}[#{exist? ? '' : "file?=#{File.basename(main)}.#{ext.last},"}keys*]")
224
269
  end
225
270
 
226
- def chop_extname(file)
227
- File.extname(file).sub('.', '')
271
+ def realpath
272
+ file = main + @ext
273
+ Pathname.new(file).realdirpath.to_s rescue file
274
+ end
275
+
276
+ def exist?
277
+ !@ext.empty? && (!@required || !project.nil?)
228
278
  end
229
279
 
230
280
  def pipe?
231
- return @project.workspace.pipe? if @project
281
+ return project.workspace.pipe if project
232
282
 
233
283
  val = ENV['PIPE_OUT']
234
284
  !val.nil? && !val.empty? && val != '0'
235
285
  end
286
+
287
+ def warning?
288
+ project ? project.warning : true
289
+ end
236
290
  end
237
291
  end
238
292
  end