squared 0.4.36 → 0.5.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.
@@ -63,7 +63,6 @@ module Squared
63
63
  hash: %i[green black!],
64
64
  array: %i[blue black!],
65
65
  number: [:magenta],
66
- boolean: [:magenta],
67
66
  undefined: %i[red italic]
68
67
  },
69
68
  logger: {
@@ -94,28 +93,28 @@ module Squared
94
93
  PATH.freeze
95
94
  ARG.freeze
96
95
  VAR.each_value(&:freeze)
97
- VAR[:theme].each_value { |val| val.freeze.each_value(&:freeze) }
96
+ VAR[:theme].each_value(&:freeze)
98
97
  VAR.freeze
99
98
  end
100
99
 
101
100
  module_function
102
101
 
103
- def as_a(obj, meth = nil, flat: nil, compact: false, &blk)
102
+ def as_a(obj, *meth, flat: nil, compact: false, &blk)
104
103
  return [] if obj.nil?
105
104
 
106
105
  unless obj.is_a?(::Array)
107
- obj = if obj.respond_to?(:to_ary)
108
- obj.to_ary
109
- elsif obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
106
+ obj = if obj.respond_to?(:to_a) && !obj.is_a?(::Hash) && (val = obj.to_a).is_a?(::Array)
110
107
  val
111
108
  else
112
109
  [obj]
113
110
  end
114
111
  end
115
- obj = flat.is_a?(::Numeric) ? obj.flatten(flat) : obj.flatten if flat
112
+ obj = obj.flatten(flat.is_a?(::Numeric) ? flat : nil) if flat
116
113
  obj = obj.compact if compact
117
- obj = obj.map(&meth) if meth
118
- block_given? ? obj.select(&blk) : obj
114
+ obj = obj.map(&meth.shift) until meth.empty?
115
+ return obj unless block_given?
116
+
117
+ obj.select(&blk)
119
118
  end
120
119
  end
121
120
  end
@@ -29,19 +29,13 @@ module Squared
29
29
  bright_white!: '107'
30
30
  }.freeze
31
31
  BOX_GRAPH = ['│', '─', '├', '└', '┬'].freeze
32
- BOX_BORDER = ['│', '─', '', '', '', '', '├', '┤', '┬', '┴'].tap do |val|
33
- if ENV['TERM']&.end_with?('256color')
34
- val.slice!(2, 4)
35
- val.insert(2, '╭', '╮', '╯', '╰')
36
- end
37
- val.freeze
38
- end
32
+ BOX_BORDER = ['│', '─', '', '', '', '', '├', '┤', '┬', '┴'].freeze
39
33
  TEXT_STYLE = [:bold, :dim, :italic, :underline, :blinking, nil, :inverse, :hidden, :strikethrough].freeze
40
34
  private_constant :AIX_TERM, :BOX_GRAPH, :BOX_BORDER, :TEXT_STYLE
41
35
 
42
36
  def enable_aixterm
43
37
  unless (colors = __get__(:colors)).frozen?
44
- colors.merge!(AIX_TERM)
38
+ colors.update(AIX_TERM)
45
39
  end
46
40
  self
47
41
  end
@@ -67,8 +61,7 @@ module Squared
67
61
  end
68
62
  wrap = ->(s, n) { "\x1B[#{n.join(';')}m#{s}\x1B[0m" }
69
63
  code = []
70
- args.clear if args.size == 1 && args.first.nil?
71
- args.concat(Array(styles)).flatten.each_with_index do |type, i|
64
+ args.concat(as_a(styles)).flatten.each_with_index do |type, i|
72
65
  next unless type
73
66
 
74
67
  if index == -1
@@ -109,7 +102,7 @@ module Squared
109
102
  ret = wrap.call(ret, code) unless code.empty?
110
103
  return ret unless data
111
104
 
112
- out = +''
105
+ out = ''.dup
113
106
  data.to_a.each_with_index do |group, i|
114
107
  next if i == 0
115
108
 
@@ -142,11 +135,11 @@ module Squared
142
135
  def apply_style(data, key, args, empty: true)
143
136
  return if data.is_a?(::Symbol) && (data = __get__(:theme)[data]).nil?
144
137
 
145
- set = ->(k, v) { data[k.to_sym] = check_style(v, empty: empty) }
138
+ set = ->(k, v) { data[k] = check_style(v, empty: empty) }
146
139
  if key.is_a?(::Hash)
147
140
  key.each { |k, v| set.call(k, v || args) }
148
141
  else
149
- set.call(key, args)
142
+ set.call(key.to_sym, args)
150
143
  end
151
144
  end
152
145
 
@@ -158,8 +151,7 @@ module Squared
158
151
  when Logger::WARN then :warn
159
152
  when Logger::ERROR then :error
160
153
  when Logger::FATAL then :fatal
161
- else :unknown
162
- end
154
+ else :unknown end
163
155
  else
164
156
  level.to_s.downcase.to_sym
165
157
  end
@@ -180,30 +172,26 @@ module Squared
180
172
  if level.is_a?(::Numeric)
181
173
  if append && respond_to?(:log)
182
174
  ref = log rescue nil
183
- ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(::Logger)
175
+ ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(Logger)
184
176
  end
185
- return false unless pass || level >= ARG[:LEVEL]
177
+ return false if !pass && level < ARG[:LEVEL]
186
178
  end
187
- if hint.nil? ? args.size > 1 : !hint
179
+ if (args.size > 1 && !hint) || hint == false
188
180
  title = log_title(level, color: false)
189
- if color
190
- sub = [{ pat: /\A(#{Regexp.escape(title)})(.*)\z/m, styles: __get__(:theme)[:logger][log_sym(level)] }]
191
- end
181
+ sub = [pat: /\A(#{Regexp.escape(title)})(.*)\z/m, styles: __get__(:theme)[:logger][log_sym(level)]] if color
192
182
  emphasize(args, title: title + (subject ? " #{subject}" : ''), sub: sub, pipe: -1)
193
183
  else
194
184
  msg = [log_title(level, color: color)]
195
- if subject
196
- msg << (color ? sub_style(subject.to_s, (@theme.is_a?(::Hash) && @theme[:subject]) || :bold) : subject)
197
- end
185
+ msg << (color ? sub_style(subject, styles: (@theme && @theme[:subject]) || :bold) : subject) if subject
198
186
  msg << args.shift if msg.size == 1
199
187
  message(msg.join(' '), *args, hint: hint)
200
188
  end
201
189
  end
202
190
 
203
- def log_console(*args, pipe: 1)
191
+ def puts_oe(*args, pipe: 1)
204
192
  return if args.first == false && args.size == 1
205
193
 
206
- if pipe.is_a?(::Pathname)
194
+ if pipe.is_a?(Pathname)
207
195
  begin
208
196
  File.open(pipe, 'a') do |f|
209
197
  br = File::SEPARATOR == '\\' ? "\r\n" : "\n"
@@ -217,30 +205,29 @@ module Squared
217
205
  (pipe == 2 ? $stderr : $stdout).puts(*args)
218
206
  end
219
207
 
220
- alias puts_oe log_console
221
-
222
208
  module_function
223
209
 
224
210
  def message(*args, hint: nil, empty: false, space: ARG[:SPACE])
225
- (empty ? args.reject { |val| val.nil? || (val.respond_to?(:empty?) && val.empty?) } : args)
226
- .join(space) + (hint ? " (#{hint})" : '')
211
+ (empty ? args.reject { |val| val.nil? || val.empty? } : args).join(space) + (hint ? " (#{hint})" : '')
227
212
  end
228
213
 
229
214
  def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, pipe: nil,
230
- border: @theme.is_a?(::Hash) && @theme[:border])
215
+ border: @theme && @theme[:border])
231
216
  n = 0
232
- max = ->(a) { n = [n, a.max_by(&:size).size].max }
233
- set = ->(s) { Array(s).map(&:to_s).tap { |a| max.call(a) } }
217
+ max = ->(v) { n = [n, v.max_by(&:size).size].max }
218
+ set = lambda do |v|
219
+ ret = as_a(v, :to_s)
220
+ max.call(ret)
221
+ ret
222
+ end
234
223
  title &&= set.call(title)
235
224
  footer &&= set.call(footer)
236
225
  if val.is_a?(::Array)
237
226
  lines = val.map(&:to_s)
238
227
  else
239
228
  lines = val.to_s.lines(chomp: true)
240
- lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(::StandardError))
229
+ lines[0] = "#{val.class}: #{lines.first}" if (err = val.is_a?(StandardError))
241
230
  end
242
- return if lines.empty?
243
-
244
231
  n = cols || max.call(lines)
245
232
  if $stdout.tty?
246
233
  require 'io/console'
@@ -259,8 +246,8 @@ module Squared
259
246
  sub.each { |h| s = sub_style(s, **h) }
260
247
  s = "#{b0} #{s} #{b0}"
261
248
  if border
262
- s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/om, styles: border)
263
- s = sub_style(s, pat: /\A(.+)(#{Regexp.escape(b0)})\z/om, styles: border, index: 2)
249
+ s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/m, styles: border)
250
+ s = sub_style(s, pat: /\A(.+)(#{Regexp.escape(b0)})\z/m, styles: border, index: 2)
264
251
  end
265
252
  s
266
253
  end
@@ -294,7 +281,7 @@ module Squared
294
281
  else
295
282
  pipe = $stdout unless pipe.respond_to?(:puts)
296
283
  end
297
- pipe.puts(out)
284
+ pipe.puts out
298
285
  else
299
286
  err ? warn(out) : puts(out)
300
287
  end
@@ -11,24 +11,22 @@ module Squared
11
11
  agree = /^#{Regexp.escape(agree)}$/i if agree.is_a?(::String)
12
12
  cancel = /^#{Regexp.escape(cancel)}$/i if cancel.is_a?(::String)
13
13
  Timeout.timeout(timeout) do
14
- begin
15
- while (ch = Readline.readline(msg))
16
- ch = ch.chomp
17
- case (ch.empty? ? default : ch)
18
- when agree
19
- return true
20
- when cancel
21
- return false
22
- end
23
- attempts -= 1
24
- exit 1 unless attempts > 0
14
+ while (ch = Readline.readline(msg))
15
+ ch = ch.chomp
16
+ case (ch.empty? ? default : ch)
17
+ when agree
18
+ return true
19
+ when cancel
20
+ return false
25
21
  end
26
- rescue Interrupt
27
- puts
28
- exit 0
29
- else
30
- false
22
+ attempts -= 1
23
+ exit 1 unless attempts > 0
31
24
  end
25
+ rescue Interrupt
26
+ puts
27
+ exit 0
28
+ else
29
+ false
32
30
  end
33
31
  end
34
32
 
@@ -37,49 +35,50 @@ module Squared
37
35
  require 'readline'
38
36
  require 'timeout'
39
37
  if list
40
- grep &&= Array(grep).map { |val| Regexp.new(val) }
38
+ grep &&= (grep.is_a?(::Enumerable) ? grep : [grep]).map { |val| Regexp.new(val) }
41
39
  items = []
42
40
  list.each do |val|
43
41
  next if grep&.none? { |pat| pat.match?(line) }
44
42
 
45
- items << val.to_s.chomp
43
+ items << val.chomp
46
44
  puts "#{items.size.to_s.rjust(2)}. #{val}"
47
45
  end
48
46
  max = items.size
49
47
  raise_error 'empty selection list' if max == 0
50
- min = grep ? 1 : [min, max].min
48
+ min = [min, max].min
51
49
  if auto
52
- msg = "#{msg}: [#{min}-#{max}#{if multiple
53
- "|,#{multiple.is_a?(::Numeric) ? "{#{multiple}}" : ''}"
54
- end}] "
50
+ msg = "#{msg}: [1-#{max}#{if multiple
51
+ "|,#{multiple.is_a?(Numeric) ? "{#{multiple}}" : ''}"
52
+ end}] "
55
53
  end
56
54
  end
57
55
  valid = ->(s) { s.match?(/^-?\d+$/) && s.to_i.between?(min, max) }
58
56
  Timeout.timeout(timeout) do
59
- begin
60
- while (ch = Readline.readline(msg))
61
- unless (ch = ch.strip).empty?
62
- if multiple
63
- a = ch.split(',').map!(&:strip)
64
- b = a.select { |s| valid.call(s) }.map!(&:to_i).sort
65
- next unless a.size == b.size
66
- return items ? b.map! { |i| items[i - 1] } : b unless multiple.is_a?(::Numeric) && multiple != b.size
67
- elsif valid.call(ch)
68
- return items ? items[ch.to_i - 1] : ch.to_i
69
- end
70
- end
71
- attempts -= 1
72
- next if attempts > 0
57
+ while (ch = Readline.readline(msg))
58
+ unless (ch = ch.strip).empty?
59
+ if multiple
60
+ a = ch.split(/\s*,\s*/)
61
+ b = a.select { |s| valid.call(s) }.map!(&:to_i).sort
62
+ next unless a.size == b.size
63
+ return b unless items
64
+ next if multiple.is_a?(::Numeric) && multiple != b.size
73
65
 
74
- exit 1 if force
75
- break
66
+ return b.map! { |i| items[i - 1] }
67
+ elsif valid.call(ch)
68
+ return items ? items[ch.to_i - 1] : ch.to_i
69
+ end
76
70
  end
77
- rescue Interrupt
78
- puts
79
- exit 0
80
- else
81
- multiple ? [] : nil
71
+ attempts -= 1
72
+ next if attempts > 0
73
+ break unless force
74
+
75
+ exit 1
82
76
  end
77
+ rescue Interrupt
78
+ puts
79
+ exit 0
80
+ else
81
+ multiple ? [] : nil
83
82
  end
84
83
  end
85
84
 
@@ -94,23 +93,19 @@ module Squared
94
93
  elsif block_given?
95
94
  Readline.readmultiline(msg, history, &blk)
96
95
  else
97
- Readline.readmultiline(msg, history) do |line|
98
- next if line.strip.empty?
99
-
100
- multiline.any? { |val| line.split.last.end_with?(val.to_s) }
101
- end
96
+ Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val) } }
102
97
  end
103
98
  end
104
99
  case force
105
100
  when ::TrueClass, ::FalseClass
106
101
  msg = "#{msg} %s " % if multiline
107
- multiline.is_a?(::Enumerable) ? "{#{multiline.to_a.join('|')}}" : multiline
102
+ multiline.is_a?(::Enumerable) ? "{#{multiline.join('|')}}" : multiline
108
103
  else
109
104
  "(#{force ? 'required' : 'optional'}):"
110
105
  end
111
106
  ret = (prompt.call || '').strip
112
- multiline.each { |val| break if ret.delete_suffix!(val.to_s) } if multiline.is_a?(::Enumerable)
113
- exit 1 if force && ret.empty?
107
+ multiline.each { |val| break if ret.delete_suffix!(val) } if multiline.is_a?(::Enumerable)
108
+ raise_error 'user cancelled' if force && ret.empty?
114
109
  ret
115
110
  else
116
111
  prompt.call
@@ -6,31 +6,28 @@ require 'rake'
6
6
  module Squared
7
7
  module Common
8
8
  module Shell
9
- QUOTE_VALUE = /\A(["'])(.*)\1\z/m.freeze
10
- private_constant :QUOTE_VALUE
11
-
12
9
  module_function
13
10
 
14
11
  def shell_escape(val, quote: false, force: false, double: false, option: false, override: false)
15
- if (r = /\A(--?)([^=\s]+)((=|\s+)(["'])?(?(5)(.*)\5|(.*)))?\z/m.match(val = val.to_s))
16
- if (data = r[2].match(QUOTE_VALUE))
12
+ if (r = /\A(--?)([^= ]+)((=|\s+)(["'])?(?(5)(.*)\5|(.*)))?\z/m.match(val = val.to_s))
13
+ if (data = r[2].match(/\A(["'])(.+)\1\z/))
17
14
  double = data[1] == '"'
18
15
  override = true
19
16
  elsif !r[3] || r[6]
20
17
  return val
21
18
  end
22
- opt = if r[7].match?(/\A["']/)
23
- "#{r[7]}#{r[7][0]}"
24
- elsif r[7].match?(/["']\z/)
25
- "#{r[7][-1]}#{r[7]}"
26
- else
27
- return val unless r[7].match?(/\s/)
28
-
29
- r[7]
30
- end
31
- r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, force: force, double: double, override: override)
32
- elsif option && val =~ /\A(-{0,2}[^=\s-][^=\s]*)=(.+)\z/m
33
- return val if $2.match?(QUOTE_VALUE)
19
+ if r[7].match?(/\A["']/)
20
+ opt = "#{r[7]}#{r[7][0]}"
21
+ elsif r[7].match?(/["']\z/)
22
+ opt = "#{r[7][-1]}#{r[7]}"
23
+ else
24
+ return val unless r[7].match?(/\s/)
25
+
26
+ opt = r[7]
27
+ end
28
+ r[1] + (data ? data[2] : r[2]) + r[4] + shell_quote(opt, double: double, force: force, override: override)
29
+ elsif option && val =~ /\A([^=]+)=(.+)\z/m
30
+ return val if $2.match?(/\A(["']).+\1\z/m)
34
31
 
35
32
  "#{$1}=%s" % if $2.include?(' ')
36
33
  shell_quote($2, option: false)
@@ -38,98 +35,81 @@ module Squared
38
35
  Rake::Win32.windows? ? $2 : Shellwords.escape($2)
39
36
  end
40
37
  elsif Rake::Win32.windows?
41
- quote ? shell_quote(val, force: force, double: double) : val
42
- elsif val.empty?
43
- ''
38
+ quote ? shell_quote(val, double: double, force: force) : val
44
39
  else
45
- Shellwords.escape(val)
40
+ val.empty? ? '' : Shellwords.escape(val)
46
41
  end
47
42
  end
48
43
 
49
- def shell_quote(val, option: true, force: true, double: false, preserve: true, override: false)
44
+ def shell_quote(val, option: true, force: true, double: false, override: false)
50
45
  val = val.to_s
51
46
  return val if (!force && !val.include?(' ')) || val.empty?
52
47
 
53
- if option
54
- pat = /\A(?:-[^=\s-](?:=|\s+)?|(--)?[^=\s-][^=\s]*(?(1)(?:=|\s+)|=))(["']).+\2\z/m
55
- return val if val.match?(pat)
48
+ if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/m)
49
+ return val
56
50
  end
57
- q = ->(s) { s.gsub("'\\\\''", "'") }
58
- if val =~ QUOTE_VALUE
59
- return val if $1 == '"' && Rake::Win32.windows? && val.match?(/(?:[#{File::SEPARATOR} ]|\\")/o)
60
51
 
61
- base = $2 unless preserve
62
- end
63
52
  if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
64
- "\"#{q.call(base || val).gsub(/(?<!\\)"/, '\\"')}\""
53
+ "\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
65
54
  else
66
- base ? val : "'#{q.call(val).gsub("'", "'\\\\''")}'"
55
+ "'#{val.gsub("'", "'\\\\''")}'"
67
56
  end
68
57
  end
69
58
 
70
59
  def shell_option(flag, val = nil, escape: true, quote: true, option: true, force: true, double: false,
71
60
  merge: false, override: false)
72
61
  flag = flag.to_s
73
- if flag =~ QUOTE_VALUE
62
+ if flag =~ /\A(["'])(.+)\1\z/
74
63
  double = $1 == '"'
75
64
  flag = $2
76
65
  escape = false
77
66
  override = true
78
67
  end
79
- sep = unless flag.empty?
80
- if flag[0] == '-'
81
- if flag[1] == '-'
82
- '='
83
- else
84
- merge ? '' : ' '
85
- end
86
- elsif flag.size == 1
87
- pre = '-'
88
- merge ? '' : ' '
89
- else
90
- pre = '--'
91
- '='
92
- end
93
- end
94
- "#{pre}#{flag}#{unless val.nil?
95
- "#{sep}#{if escape
96
- shell_escape(val, quote: quote, double: double, override: override)
97
- elsif quote
98
- shell_quote(val, option: option, force: force, double: double, override: override)
99
- else
100
- val
101
- end}"
102
- end}"
68
+ if flag[0] == '-'
69
+ b = flag[1] == '-' ? '=' : ' '
70
+ elsif flag.size == 1
71
+ a = '-'
72
+ b = merge ? '' : ' '
73
+ else
74
+ a = '--'
75
+ b = '='
76
+ end
77
+ "#{a}#{flag}#{if val
78
+ "#{b}#{if escape
79
+ shell_escape(val, quote: quote, double: double, override: override)
80
+ elsif quote
81
+ shell_quote(val, option: option, force: force, double: double, override: override)
82
+ else
83
+ val
84
+ end}"
85
+ end}"
103
86
  end
104
87
 
105
- def shell_split(val, quote: false, force: false, join: nil)
106
- ret = val.shellsplit.map! { |opt| shell_escape(opt, quote: quote, force: force, double: true, option: true) }
88
+ def shell_split(val, join: nil, **kwargs)
89
+ ret = val.shellsplit
90
+ ret.map! { |opt| shell_escape(opt, double: true, option: true, **kwargs) }
107
91
  return ret unless join
108
92
 
109
93
  ret.join(join.is_a?(::String) ? join : ' ')
110
94
  end
111
95
 
112
- def shell_bin(name, env: true)
113
- require_relative 'base'
114
- key = name.to_s.upcase
115
- key = File.basename(key, '.*') if Rake::Win32.windows?
116
- shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
117
- option: false, force: false, double: true)
96
+ def line_width(lines)
97
+ ret = [lines.max_by(&:size).size, 80].max
98
+ [ret, Rake.application.terminal_width].min
118
99
  end
119
100
 
120
101
  def fill_option(val, **kwargs)
121
- return val unless val.is_a?(::String)
122
102
  return "-#{val}" if val.match?(/\A(?:[a-z]\d*|\d)\z/i)
123
103
 
124
104
  shell_escape(val.start_with?('-') ? val : "--#{val}", **kwargs)
125
105
  end
126
106
 
127
- def quote_option(flag, val, option: true, double: false, merge: false)
128
- shell_option(flag, val, escape: false, option: option, double: double, merge: merge)
107
+ def quote_option(flag, val, **kwargs)
108
+ shell_option(flag, val, escape: false, **kwargs)
129
109
  end
130
110
 
131
- def basic_option(flag, val, merge: false)
132
- shell_option(flag, val, escape: false, force: false, merge: merge)
111
+ def basic_option(flag, val, **kwargs)
112
+ shell_option(flag, val, escape: false, force: false, **kwargs)
133
113
  end
134
114
  end
135
115
  end
@@ -1,55 +1,49 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'pathname'
4
- require 'rake'
4
+ require 'fileutils'
5
5
 
6
6
  module Squared
7
7
  module Common
8
8
  module System
9
9
  module_function
10
10
 
11
- def shell(*args, name: :system, **kwargs)
12
- if RUBY_ENGINE == 'jruby' && Rake::Win32.windows?
13
- e = kwargs[:exception]
14
- if (dir = kwargs[:chdir]) && ((pwd = Dir.pwd) != dir)
15
- Dir.chdir dir
16
- ret = Kernel.send(name, *args)
17
- Dir.chdir pwd
18
- else
19
- ret = Kernel.send(name, *args)
20
- end
21
- elsif RUBY_VERSION < '2.6'
22
- e = kwargs.delete(:exception)
23
- ret = Kernel.send(name, *args, **kwargs)
11
+ def shell(*args, **kwargs)
12
+ if RUBY_VERSION < '2.6'
13
+ exception = kwargs.delete(:exception)
14
+ ret = Kernel.system(*args, **kwargs)
15
+ return ret if ret || !exception
16
+
17
+ raise $?.to_s
24
18
  else
25
- return Kernel.send(name, *args, **kwargs)
19
+ Kernel.system(*args, **kwargs)
26
20
  end
27
- return ret unless e && !ret && name == :system
28
-
29
- raise $?.to_s
30
21
  end
31
22
 
32
- def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil, verbose: true)
33
- src = Pathname.new(src)
34
- dest = Pathname.new(dest)
35
- raise "#{dest.cleanpath} (not found)" if !create && !dest.parent.exist?
23
+ def copy_dir(src, dest, glob = ['**/*'], create: false, link: nil, force: false, pass: nil, hidden: false,
24
+ verbose: true)
25
+ base = Pathname.new(src)
26
+ target = Pathname.new(dest)
27
+ raise "#{target.cleanpath} (not found)" if !create && !target.parent.exist?
36
28
 
37
29
  subdir = {}
38
- dest.mkpath if create
30
+ target.mkpath if create
31
+ flags = hidden ? [File::FNM_DOTMATCH] : []
39
32
  if pass
40
33
  exclude = []
41
- Array(pass).each { |val| exclude.concat(Dir.glob(src + val)) }
34
+ pass = [pass] unless pass.is_a?(::Array)
35
+ pass.each { |val| exclude.concat(Dir.glob(val, *flags, base: base)) }
42
36
  end
43
- Array(glob).each do |val|
44
- Dir.glob(src + val) do |path|
45
- next if exclude&.include?(path) || (path = Pathname.new(path)).directory?
37
+ (glob.is_a?(::Enumerable) ? glob : [glob]).each do |val|
38
+ Dir.glob(val, *flags, base: base) do |file|
39
+ next if exclude&.include?(file) || (entry = base + file).directory?
46
40
 
47
- dir = dest.join(path.relative_path_from(src)).dirname
41
+ dir = target.join(file).dirname
48
42
  if (data = subdir[dir.to_s])
49
- data << path
43
+ data << entry
50
44
  else
51
45
  dir.mkpath
52
- subdir[dir.to_s] = [path]
46
+ subdir[dir.to_s] = [entry]
53
47
  end
54
48
  end
55
49
  end
@@ -57,13 +51,14 @@ module Squared
57
51
  soft = 0
58
52
  subdir.each do |dir, files|
59
53
  if link
60
- files.dup.tap do |items|
54
+ files.dup.yield_self do |items|
61
55
  files.clear
62
56
  items.each do |file|
63
57
  if file.exist?
64
- if !file.symlink?
58
+ if file.symlink?
59
+ next unless force
60
+ else
65
61
  files << file
66
- elsif !force
67
62
  next
68
63
  end
69
64
  end
@@ -81,15 +76,17 @@ module Squared
81
76
  out = FileUtils.cp(files, dir, verbose: false)
82
77
  count += out.size
83
78
  end
84
- puts [dest.realpath, subdir.size, soft > 0 ? "#{count}+#{soft}" : count].join(' => ') if verbose
79
+ puts [target.realpath, subdir.size, soft > 0 ? "#{count}+#{soft}" : count].join(' => ') if verbose
85
80
  end
86
81
 
87
82
  def copy_guard(src, dest, link: nil, force: false, verbose: true)
88
83
  unless force
89
- if (path = Pathname.new(dest)).directory?
90
- src = Array(src).reject { |val| path.join(File.basename(val)).exist? }
84
+ target = Pathname.new(dest)
85
+ if target.directory?
86
+ src = [src] unless src.is_a?(::Enumerable)
87
+ src = src.reject { |val| target.join(File.basename(val)).exist? }
91
88
  return if src.empty?
92
- elsif path.exist?
89
+ elsif target.exist?
93
90
  return
94
91
  end
95
92
  end