squared 0.4.40 → 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: {
@@ -90,39 +89,32 @@ module Squared
90
89
  VAR[key.is_a?(::String) ? key.to_sym : key] = val
91
90
  end
92
91
 
93
- def __arg__(key, name = nil, &blk)
94
- ret = ARG[key.to_sym]
95
- return ret unless name && ret.is_a?(::Hash)
96
-
97
- ret[name = name.downcase] || (block_given? ? ret.fetch(name.to_sym, &blk) : ret[name.to_sym])
98
- end
99
-
100
92
  def __freeze__
101
93
  PATH.freeze
102
94
  ARG.freeze
103
95
  VAR.each_value(&:freeze)
104
- VAR[:theme].each_value { |val| val.freeze.each_value(&:freeze) }
96
+ VAR[:theme].each_value(&:freeze)
105
97
  VAR.freeze
106
98
  end
107
99
 
108
100
  module_function
109
101
 
110
- def as_a(obj, meth = nil, flat: nil, compact: false, &blk)
102
+ def as_a(obj, *meth, flat: nil, compact: false, &blk)
111
103
  return [] if obj.nil?
112
104
 
113
105
  unless obj.is_a?(::Array)
114
- obj = if obj.respond_to?(:to_ary)
115
- obj.to_ary
116
- 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)
117
107
  val
118
108
  else
119
109
  [obj]
120
110
  end
121
111
  end
122
- obj = flat.is_a?(::Numeric) ? obj.flatten(flat) : obj.flatten if flat
112
+ obj = obj.flatten(flat.is_a?(::Numeric) ? flat : nil) if flat
123
113
  obj = obj.compact if compact
124
- obj = obj.map(&meth) if meth
125
- 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)
126
118
  end
127
119
  end
128
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
- valid = ->(s) { s.match?(/^-?\d+$/) && s.to_i.between?(min, max <= min ? Float::INFINITY : max) }
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,105 +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, pass: false, 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
- return val if option && val.match?(/\A(?:-[^=\s-](?:=|\s+)?|(--)?[^=\s-][^=\s]*(?(1)(?:=|\s+)|=))(["']).+\2\z/m)
53
47
 
54
- if val =~ QUOTE_VALUE
55
- if pass == '"' || pass == "'"
56
- return val if pass == $1
57
- elsif pass || ($1 == '"' && Rake::Win32.windows? && val.match?(/(?:[#{File::SEPARATOR} ]|\\")/o))
58
- return val
59
- end
60
- case preserve
61
- when false
62
- base = $2
63
- when '"'
64
- base = $2 if $1 == "'"
65
- when "'"
66
- base = $2 if $1 == '"'
67
- end
48
+ if option && val.match?(/(?:\A|\A[^=\s]+(?:=|\s+)|#{Rake::Win32.windows? ? '[\\\/]' : '\/'})(["']).+\1\z/m)
49
+ return val
68
50
  end
69
- q = -> { (base || val).gsub("'\\\\''", "'") }
51
+
70
52
  if double || Rake::Win32.windows? || (ARG[:QUOTE] == '"' && !override)
71
- "\"#{q.call.gsub(/(?<!\\)"/, '\\"')}\""
53
+ "\"#{val.gsub(/(?<!\\)"/, '\\"')}\""
72
54
  else
73
- "'#{q.call.gsub("'", "'\\\\''")}'"
55
+ "'#{val.gsub("'", "'\\\\''")}'"
74
56
  end
75
57
  end
76
58
 
77
59
  def shell_option(flag, val = nil, escape: true, quote: true, option: true, force: true, double: false,
78
60
  merge: false, override: false)
79
61
  flag = flag.to_s
80
- if flag =~ QUOTE_VALUE
62
+ if flag =~ /\A(["'])(.+)\1\z/
81
63
  double = $1 == '"'
82
64
  flag = $2
83
65
  escape = false
84
66
  override = true
85
67
  end
86
- sep = unless flag.empty?
87
- if flag[0] == '-'
88
- if flag[1] == '-'
89
- '='
90
- else
91
- merge ? '' : ' '
92
- end
93
- elsif flag.size == 1
94
- pre = '-'
95
- merge ? '' : ' '
96
- else
97
- pre = '--'
98
- '='
99
- end
100
- end
101
- "#{pre}#{flag}#{unless val.nil?
102
- "#{sep}#{if escape
103
- shell_escape(val, quote: quote, double: double, override: override)
104
- elsif quote
105
- shell_quote(val, option: option, force: force, double: double, override: override)
106
- else
107
- val
108
- end}"
109
- 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}"
110
86
  end
111
87
 
112
- def shell_split(val, quote: false, force: false, join: nil)
113
- 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) }
114
91
  return ret unless join
115
92
 
116
93
  ret.join(join.is_a?(::String) ? join : ' ')
117
94
  end
118
95
 
119
- def shell_bin(name, env: true)
120
- require_relative 'base'
121
- key = name.to_s.upcase
122
- key = File.basename(key, '.*') if Rake::Win32.windows?
123
- shell_quote((env && ENV["PATH_#{key}"]) || PATH[key] || PATH[key.to_sym] || name,
124
- 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
125
99
  end
126
100
 
127
101
  def fill_option(val, **kwargs)
128
- return val unless val.is_a?(::String)
129
102
  return "-#{val}" if val.match?(/\A(?:[a-z]\d*|\d)\z/i)
130
103
 
131
104
  shell_escape(val.start_with?('-') ? val : "--#{val}", **kwargs)
132
105
  end
133
106
 
134
- def quote_option(flag, val, option: true, double: false, merge: false)
135
- 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)
136
109
  end
137
110
 
138
- def basic_option(flag, val, merge: false)
139
- 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)
140
113
  end
141
114
  end
142
115
  end