squared 0.4.30 → 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,7 +61,7 @@ module Squared
67
61
  end
68
62
  wrap = ->(s, n) { "\x1B[#{n.join(';')}m#{s}\x1B[0m" }
69
63
  code = []
70
- args.concat(Array(styles)).flatten.each_with_index do |type, i|
64
+ args.concat(as_a(styles)).flatten.each_with_index do |type, i|
71
65
  next unless type
72
66
 
73
67
  if index == -1
@@ -108,7 +102,7 @@ module Squared
108
102
  ret = wrap.call(ret, code) unless code.empty?
109
103
  return ret unless data
110
104
 
111
- out = +''
105
+ out = ''.dup
112
106
  data.to_a.each_with_index do |group, i|
113
107
  next if i == 0
114
108
 
@@ -141,11 +135,11 @@ module Squared
141
135
  def apply_style(data, key, args, empty: true)
142
136
  return if data.is_a?(::Symbol) && (data = __get__(:theme)[data]).nil?
143
137
 
144
- set = ->(k, v) { data[k.to_sym] = check_style(v, empty: empty) }
138
+ set = ->(k, v) { data[k] = check_style(v, empty: empty) }
145
139
  if key.is_a?(::Hash)
146
140
  key.each { |k, v| set.call(k, v || args) }
147
141
  else
148
- set.call(key, args)
142
+ set.call(key.to_sym, args)
149
143
  end
150
144
  end
151
145
 
@@ -157,8 +151,7 @@ module Squared
157
151
  when Logger::WARN then :warn
158
152
  when Logger::ERROR then :error
159
153
  when Logger::FATAL then :fatal
160
- else :unknown
161
- end
154
+ else :unknown end
162
155
  else
163
156
  level.to_s.downcase.to_sym
164
157
  end
@@ -178,9 +171,8 @@ module Squared
178
171
  args = args.map(&:to_s)
179
172
  if level.is_a?(::Numeric)
180
173
  if append && respond_to?(:log)
181
- (log rescue nil).tap do |ref|
182
- ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(::Logger)
183
- end
174
+ ref = log rescue nil
175
+ ref.add(level, message(subject, *args, hint: hint, space: ', ')) if ref.is_a?(Logger)
184
176
  end
185
177
  return false if !pass && level < ARG[:LEVEL]
186
178
  end
@@ -190,16 +182,16 @@ module Squared
190
182
  emphasize(args, title: title + (subject ? " #{subject}" : ''), sub: sub, pipe: -1)
191
183
  else
192
184
  msg = [log_title(level, color: color)]
193
- msg << (color ? sub_style(subject.to_s, styles: (@theme && @theme[:subject]) || :bold) : subject) if subject
185
+ msg << (color ? sub_style(subject, styles: (@theme && @theme[:subject]) || :bold) : subject) if subject
194
186
  msg << args.shift if msg.size == 1
195
187
  message(msg.join(' '), *args, hint: hint)
196
188
  end
197
189
  end
198
190
 
199
- def log_console(*args, pipe: 1)
191
+ def puts_oe(*args, pipe: 1)
200
192
  return if args.first == false && args.size == 1
201
193
 
202
- if pipe.is_a?(::Pathname)
194
+ if pipe.is_a?(Pathname)
203
195
  begin
204
196
  File.open(pipe, 'a') do |f|
205
197
  br = File::SEPARATOR == '\\' ? "\r\n" : "\n"
@@ -213,27 +205,28 @@ module Squared
213
205
  (pipe == 2 ? $stderr : $stdout).puts(*args)
214
206
  end
215
207
 
216
- alias puts_oe log_console
217
-
218
208
  module_function
219
209
 
220
210
  def message(*args, hint: nil, empty: false, space: ARG[:SPACE])
221
- (empty ? args.reject { |val| val.nil? || (val.respond_to?(:empty?) && val.empty?) } : args)
222
- .join(space) + (hint ? " (#{hint})" : '')
211
+ (empty ? args.reject { |val| val.nil? || val.empty? } : args).join(space) + (hint ? " (#{hint})" : '')
223
212
  end
224
213
 
225
214
  def emphasize(val, title: nil, footer: nil, right: false, cols: nil, sub: nil, pipe: nil,
226
- border: @theme.is_a?(::Hash) && @theme[:border])
215
+ border: @theme && @theme[:border])
227
216
  n = 0
228
- max = ->(a) { n = [n, a.max_by(&:size).size].max }
229
- 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
230
223
  title &&= set.call(title)
231
224
  footer &&= set.call(footer)
232
225
  if val.is_a?(::Array)
233
226
  lines = val.map(&:to_s)
234
227
  else
235
228
  lines = val.to_s.lines(chomp: true)
236
- 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))
237
230
  end
238
231
  n = cols || max.call(lines)
239
232
  if $stdout.tty?
@@ -253,8 +246,8 @@ module Squared
253
246
  sub.each { |h| s = sub_style(s, **h) }
254
247
  s = "#{b0} #{s} #{b0}"
255
248
  if border
256
- s = sub_style(s, pat: /\A(#{Regexp.escape(b0)})(.+)\z/om, styles: border)
257
- 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)
258
251
  end
259
252
  s
260
253
  end
@@ -288,7 +281,7 @@ module Squared
288
281
  else
289
282
  pipe = $stdout unless pipe.respond_to?(:puts)
290
283
  end
291
- pipe.puts(out)
284
+ pipe.puts out
292
285
  else
293
286
  err ? warn(out) : puts(out)
294
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(/\s*,\s*/)
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,19 +93,19 @@ module Squared
94
93
  elsif block_given?
95
94
  Readline.readmultiline(msg, history, &blk)
96
95
  else
97
- Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val.to_s) } }
96
+ Readline.readmultiline(msg, history) { |line| multiline.any? { |val| line.split.last.end_with?(val) } }
98
97
  end
99
98
  end
100
99
  case force
101
100
  when ::TrueClass, ::FalseClass
102
101
  msg = "#{msg} %s " % if multiline
103
- multiline.is_a?(::Enumerable) ? "{#{multiline.to_a.join('|')}}" : multiline
102
+ multiline.is_a?(::Enumerable) ? "{#{multiline.join('|')}}" : multiline
104
103
  else
105
104
  "(#{force ? 'required' : 'optional'}):"
106
105
  end
107
106
  ret = (prompt.call || '').strip
108
- multiline.each { |val| break if ret.delete_suffix!(val.to_s) } if multiline.is_a?(::Enumerable)
109
- 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?
110
109
  ret
111
110
  else
112
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,92 +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
- flag[1] == '-' ? '=' : ' '
82
- elsif flag.size == 1
83
- pre = '-'
84
- merge ? '' : ' '
85
- else
86
- pre = '--'
87
- '='
88
- end
89
- end
90
- "#{pre}#{flag}#{unless val.nil?
91
- "#{sep}#{if escape
92
- shell_escape(val, quote: quote, double: double, override: override)
93
- elsif quote
94
- shell_quote(val, option: option, force: force, double: double, override: override)
95
- else
96
- val
97
- end}"
98
- 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}"
99
86
  end
100
87
 
101
- def shell_split(val, quote: false, force: false, join: nil)
102
- 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) }
103
91
  return ret unless join
104
92
 
105
93
  ret.join(join.is_a?(::String) ? join : ' ')
106
94
  end
107
95
 
108
- def shell_bin(name, env: true)
109
- key = name.upcase
110
- shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
111
- 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
112
99
  end
113
100
 
114
101
  def fill_option(val, **kwargs)
115
- return val unless val.is_a?(::String)
116
102
  return "-#{val}" if val.match?(/\A(?:[a-z]\d*|\d)\z/i)
117
103
 
118
104
  shell_escape(val.start_with?('-') ? val : "--#{val}", **kwargs)
119
105
  end
120
106
 
121
- def quote_option(flag, val, option: true, double: false, merge: false)
122
- 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)
123
109
  end
124
110
 
125
- def basic_option(flag, val, merge: false)
126
- 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)
127
113
  end
128
114
  end
129
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