squared 0.5.11 → 0.6.0

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.
@@ -49,19 +49,17 @@ module Squared
49
49
  val = val.to_s
50
50
  return val if (!force && !val.include?(' ')) || val.empty?
51
51
 
52
- if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/m)
53
- return val
54
- end
55
-
56
- if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
52
+ if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/mo)
53
+ val
54
+ elsif double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
57
55
  "\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
58
56
  else
59
57
  "'#{val.gsub("'", "'\\\\''")}'"
60
58
  end
61
59
  end
62
60
 
63
- def shell_option(flag, val = nil, escape: true, quote: true, option: true, force: true, double: false,
64
- merge: false, override: false)
61
+ def shell_option(flag, val = nil, sep: '=', escape: true, quote: true, force: true, double: false, merge: false,
62
+ override: false)
65
63
  flag = flag.to_s
66
64
  if flag =~ /\A(["'])(.+)\1\z/
67
65
  double = $1 == '"'
@@ -70,19 +68,19 @@ module Squared
70
68
  override = true
71
69
  end
72
70
  b = if flag[0] == '-'
73
- flag[1] == '-' ? '=' : ' '
71
+ flag[1] == '-' ? sep : ' '
74
72
  elsif flag.size == 1
75
73
  a = '-'
76
74
  merge ? '' : ' '
77
75
  else
78
76
  a = '--'
79
- '='
77
+ sep
80
78
  end
81
79
  "#{a}#{flag}#{unless val.nil?
82
80
  "#{b}#{if escape
83
81
  shell_escape(val, quote: quote, double: double, override: override)
84
82
  elsif quote
85
- shell_quote(val, option: option, force: force, double: double, override: override)
83
+ shell_quote(val, option: false, force: force, double: double, override: override)
86
84
  else
87
85
  val
88
86
  end}"
@@ -96,6 +94,41 @@ module Squared
96
94
  ret.join(join.is_a?(::String) ? join : ' ')
97
95
  end
98
96
 
97
+ def shell_parse(val, escape: false, force: true, **kwargs)
98
+ a = []
99
+ b = []
100
+ c = []
101
+ d = []
102
+ e = [a, b]
103
+ j = -1
104
+ val.shellsplit.each_with_index do |opt, i|
105
+ if opt == '--'
106
+ e = [c, d]
107
+ elsif opt =~ /\A--?[^=]+(=|\z)/
108
+ j = $1 == '=' ? -1 : i
109
+ e[0] << [opt]
110
+ elsif j >= 0
111
+ e[0][j] << opt
112
+ else
113
+ e[1] << shell_quote(opt, option: false, force: force)
114
+ end
115
+ end
116
+ ret = [[a, b], [], [c, d]].flat_map do |e, f|
117
+ next '--' unless e
118
+
119
+ e.flat_map do |item|
120
+ if item.size == 1
121
+ fill_option(item.first)
122
+ else
123
+ flag = item.shift
124
+ item.map! { |s| shell_option(flag, s, escape: escape, force: force, **kwargs) }
125
+ end
126
+ end.concat(f)
127
+ end
128
+ ret.pop if ret.last == '--'
129
+ ret
130
+ end
131
+
99
132
  def shell_bin(name, env: true)
100
133
  key = name.upcase
101
134
  shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name, option: false, force: false,
@@ -103,7 +136,7 @@ module Squared
103
136
  end
104
137
 
105
138
  def line_width(lines)
106
- ret = [lines.max_by(&:size).size, 80].max
139
+ ret = [lines.empty? ? 0 : lines.max_by(&:size).size, 80].max
107
140
  [ret, Rake.application.terminal_width].min
108
141
  end
109
142
 
@@ -6,6 +6,25 @@ require 'rake'
6
6
  module Squared
7
7
  module Common
8
8
  module System
9
+ class << self
10
+ private
11
+
12
+ def parse_link(val)
13
+ case val
14
+ when ::TrueClass, 's'
15
+ 1
16
+ when 'r'
17
+ 2
18
+ when 'h'
19
+ 3
20
+ else
21
+ raise ArgumentError, "unrecognized 'link' flag: #{val}" if val
22
+
23
+ 0
24
+ end
25
+ end
26
+ end
27
+
9
28
  module_function
10
29
 
11
30
  def shell(*args, name: :system, **kwargs)
@@ -29,11 +48,11 @@ module Squared
29
48
  raise $?.to_s
30
49
  end
31
50
 
32
- def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil, hidden: false,
33
- verbose: true)
51
+ def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, preserve: nil, force: false, verbose: true,
52
+ pass: nil, hidden: false)
34
53
  base = Pathname.new(src)
35
54
  target = Pathname.new(dest)
36
- raise "#{target.cleanpath} (not found)" if !create && !target.parent.exist?
55
+ raise Errno::ENOENT, dest.cleanpath.to_s unless create || target.parent.exist?
37
56
 
38
57
  subdir = {}
39
58
  target.mkpath if create
@@ -57,53 +76,67 @@ module Squared
57
76
  end
58
77
  count = 0
59
78
  soft = 0
79
+ type = System.send :parse_link, link
60
80
  subdir.each do |dir, files|
61
- if link
62
- files.dup.tap do |items|
63
- files.clear
64
- items.each do |file|
65
- if file.exist?
66
- if !file.symlink?
67
- files << file
68
- elsif !force
69
- next
70
- end
71
- end
72
- if link == 'hard'
73
- FileUtils.ln(file, dir, force: force, verbose: false)
74
- else
75
- FileUtils.ln_s(file, dir, force: force, verbose: false)
81
+ unless type == 0
82
+ items = files.dup
83
+ files.clear
84
+ items.each do |file|
85
+ if file.exist?
86
+ if !file.symlink?
87
+ files << file
88
+ elsif !force
89
+ next
76
90
  end
77
- soft += 1
78
91
  end
92
+ case type
93
+ when 1
94
+ FileUtils.ln_s(file, dir, force: force, verbose: false)
95
+ when 2
96
+ FileUtils.ln_s(file.relative_path_from(dir), dir, force: force, verbose: false)
97
+ else
98
+ FileUtils.ln(file, dir, force: force, verbose: false)
99
+ end
100
+ soft += 1
79
101
  end
80
102
  end
81
103
  next if files.empty?
82
104
 
83
- out = FileUtils.cp(files, dir, verbose: false)
105
+ out = FileUtils.cp(files, dir, preserve: preserve, verbose: false)
84
106
  count += out.size
85
107
  end
86
108
  puts [target.realpath, subdir.size, soft > 0 ? "#{count}+#{soft}" : count].join(' => ') if verbose
87
109
  end
88
110
 
89
- def copy_guard(src, dest, link: nil, force: false, verbose: true)
90
- unless force
91
- target = Pathname.new(dest)
92
- if target.directory?
93
- src = Array(src).reject { |val| target.join(File.basename(val)).exist? }
94
- return if src.empty?
95
- elsif target.exist?
96
- return
111
+ def copy_guard(*src, dest, base: '.', create: false, link: nil, preserve: nil, force: false, verbose: true)
112
+ src = src.compact.flatten
113
+ dest = Pathname.new(dest).realdirpath
114
+ base = Pathname.new(base).realpath
115
+ dir = if dest.directory?
116
+ true
117
+ elsif src.size > 1
118
+ raise Errno::ENOENT, dest.cleanpath.to_s unless create && !dest.exist?
119
+
120
+ dest.mkpath
121
+ true
122
+ end
123
+ targets = src.map! { |file| [base + file, dir ? dest + File.basename(file) : dest] }
124
+ return if !force && (targets = targets.reject { |to| to[1].exist? }).empty?
125
+
126
+ type = System.send :parse_link, link
127
+ targets.each do |file, to|
128
+ case type
129
+ when 0
130
+ FileUtils.cp(file, to, preserve: preserve, verbose: verbose)
131
+ when 1
132
+ FileUtils.ln_s(file, to, force: force, verbose: verbose)
133
+ when 2
134
+ FileUtils.ln_s(file.relative_path_from(dir ? to.dirname : to), to, force: force, verbose: verbose)
135
+ else
136
+ FileUtils.ln(file, to, force: force, verbose: verbose)
97
137
  end
98
138
  end
99
- case link
100
- when 'hard', 1
101
- FileUtils.ln(src, dest, force: force, verbose: verbose)
102
- when ::TrueClass, 'soft', 0
103
- FileUtils.ln_s(src, dest, force: force, verbose: verbose)
104
- else
105
- FileUtils.cp(src, dest, verbose: verbose)
106
- end
139
+ nil
107
140
  end
108
141
  end
109
142
  end
@@ -9,21 +9,44 @@ module Squared
9
9
  module Utils
10
10
  module_function
11
11
 
12
- def split_escape(val, char: ',')
13
- val.split(/\s*(?<!\\)#{char}\s*/)
12
+ def as_a(obj, *meth, flat: nil, compact: false, &blk)
13
+ return [] if obj.nil?
14
+
15
+ unless obj.is_a?(::Array)
16
+ obj = if obj.respond_to?(:to_ary)
17
+ obj.to_ary
18
+ elsif obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
19
+ val
20
+ else
21
+ [obj]
22
+ end
23
+ end
24
+ obj = flat.is_a?(::Numeric) ? obj.flatten(flat) : obj.flatten if flat
25
+ obj = obj.compact if compact
26
+ obj = obj.map(&meth.shift) until meth.empty?
27
+ return obj unless block_given?
28
+
29
+ obj.select(&blk)
30
+ end
31
+
32
+ def split_escape(val, char: ',', &blk)
33
+ ret = val.split(/\s*(?<!\\)#{char}\s*/)
34
+ return ret unless block_given?
35
+
36
+ ret.each(&blk)
14
37
  end
15
38
 
16
39
  def split_option(val)
17
40
  val = val.strip
18
41
  return [val, '', ''] unless (i = val.index('='))
19
42
 
20
- last = val[(i + 1)..-1].strip
43
+ last = val[i.succ..-1].strip
21
44
  quote = ''
22
45
  if last =~ /\A(["'])(.+)\1\z/
23
46
  last = $2
24
47
  quote = $1
25
48
  end
26
- [val[0..(i - 1)], last, quote]
49
+ [val[0..i.pred], last, quote]
27
50
  end
28
51
 
29
52
  def task_invoke(*cmd, args: [], exception: true, warning: true)
@@ -105,9 +128,9 @@ module Squared
105
128
  end
106
129
  end
107
130
 
108
- def env(key, default = nil, suffix: nil, strict: false, equals: nil, ignore: nil)
131
+ def env(key, default = nil, suffix: nil, strict: false, equals: nil, ignore: nil, **)
109
132
  ret = env_value(key, suffix: suffix, strict: strict)
110
- return ret == equals.to_s unless equals.nil?
133
+ return Array(equals).any? { |val| val.to_s == ret } unless equals.nil?
111
134
 
112
135
  ret.empty? || (ignore && Array(ignore).any? { |val| val.to_s == ret }) ? default : ret
113
136
  end
@@ -86,7 +86,7 @@ module Squared
86
86
  ['path not found', realpath]
87
87
  else
88
88
  @required = true
89
- project ? [project, 'not found'] : %w[name missing]
89
+ project ? [project, 'missing'] : %w[name missing]
90
90
  end
91
91
  warn log_message(Logger::WARN, msg, subject: self.class, hint: hint)
92
92
  end
@@ -106,7 +106,7 @@ module Squared
106
106
  next unless (data = Viewer.parse(type, type.upcase, ext))
107
107
  end
108
108
  obj, ext = data
109
- target = file || target? ? file || realpath : nil
109
+ target = file || (realpath if target?)
110
110
 
111
111
  task_desc(command, *ext, target: target)
112
112
  task type, [:keys] do |_, args|
@@ -205,14 +205,14 @@ module Squared
205
205
 
206
206
  def read_keys(reader, type, file, keys, ext: [type], opts: {})
207
207
  if file && (mime = mimetype(file)) && basepath(file).exist?
208
- raise_error(file, mime, hint: 'invalid') unless ext.include?(mime)
208
+ raise_error file, mime, hint: 'invalid' unless ext.include?(mime)
209
209
  else
210
210
  if ext.include?(mime)
211
211
  alt = file
212
212
  file = nil
213
213
  ext[0] = mime
214
214
  elsif file
215
- keys.prepend(file)
215
+ keys.unshift(file)
216
216
  alt = basepath "#{main}.{#{ext.join(',')}}"
217
217
  file = Dir[alt].first
218
218
  else
@@ -220,7 +220,7 @@ module Squared
220
220
  args = { hint: 'no keys' }
221
221
  end
222
222
  unless file
223
- args ||= { hint: 'not found', kind: LoadError }
223
+ args ||= { kind: Errno::ENOENT }
224
224
  raise_error(reader.name, "#{File.basename(alt, '.*')}.#{ext.first}", **args)
225
225
  end
226
226
  end
@@ -237,22 +237,18 @@ module Squared
237
237
  title = Pathname.new(file)
238
238
  .realpath
239
239
  .to_s
240
- .sub(/\A#{Regexp.escape(File.join(Dir.pwd, ''))}/, '')
240
+ .sub(/^#{Regexp.escape(File.join(Dir.pwd, ''))}/, '')
241
241
  emphasize(lines, title: title, sub: unless stdin?
242
242
  [
243
- { pat: /\A((?:[^:]|(?<! ):(?! ))+)\z/, styles: theme[:banner] },
244
- { pat: /\A(.*?)(<[^>]+>)(.+)\z/m, styles: theme[:undefined], index: 2 },
245
- { pat: /\A((?~ : ))( : (?!undefined).+)\z/m, styles: theme[:key] },
246
- { pat: /\A((?~: ): )(-?[\d.]+)(\s*)\z/m, styles: theme[:number],
247
- index: 2 },
248
- { pat: /\A((?~: ): ")(.+)("\s*)\z/m, styles: theme[:string], index: 2 },
249
- { pat: /\A((?~: ): \{)(.+)(\}\s*)\z/m, styles: theme[:hash], index: 2 },
250
- { pat: /\A((?~: ): \[)(.+)(\]\s*)\z/m, styles: theme[:array],
251
- index: 2 },
252
- { pat: /\A((?~: ): )(true|false)(\s*)\z/m, styles: theme[:boolean],
253
- index: 2 },
254
- { pat: /\A((?~: ): (?!undefined))([^"\[{].*)\z/m, styles: theme[:value],
255
- index: 2 }
243
+ opt_style(theme[:banner], /\A((?:[^:]|(?<! ):(?! ))+)\z/),
244
+ opt_style(theme[:undefined], /\A(.*?)(<[^>]+>)(.+)\z/m, 2),
245
+ opt_style(theme[:key], /\A((?~ : ))( : (?!undefined).+)\z/m),
246
+ opt_style(theme[:number], /\A((?~: ): )(-?[\d.]+)(\s*)\z/m, 2),
247
+ opt_style(theme[:string], /\A((?~: ): ")(.+)("\s*)\z/m, 2),
248
+ opt_style(theme[:hash], /\A((?~: ): \{)(.+)(\}\s*)\z/m, 2),
249
+ opt_style(theme[:array], /\A((?~: ): \[)(.+)(\]\s*)\z/m, 2),
250
+ opt_style(theme[:boolean], /\A((?~: ): )(true|false)(\s*)\z/m, 2),
251
+ opt_style(theme[:value], /\A((?~: ): (?!undefined))([^"\[{].*)\z/m, 2)
256
252
  ]
257
253
  end, border: theme[:border])
258
254
  end
@@ -309,8 +305,8 @@ module Squared
309
305
  def task_desc(command, *ext, target: nil)
310
306
  return unless Rake::TaskManager.record_task_metadata
311
307
 
312
- val = "#{ext.first}[#{target ? '' : "file?=#{File.basename(main)}.#{ext.last},"}keys+]"
313
- args = *name.split(':').append(command, val)
308
+ val = "#{ext.first}[#{"file?=#{File.basename(main)}.#{ext.last}," if target}keys+]"
309
+ args = *name.split(':').push(command, val)
314
310
  if project
315
311
  project.workspace.task_desc(*args)
316
312
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Squared
4
- VERSION = '0.5.11'
4
+ VERSION = '0.6.0'
5
5
  end