Module: Howzit::StringUtils

Included in:
String
Defined in:
lib/howzit/stringutils.rb

Overview

String Extensions

Instance Method Summary collapse

Instance Method Details

#available?Boolean

Test if an executable is available on the system



291
292
293
# File 'lib/howzit/stringutils.rb', line 291

def available?
  Util.valid_command?(self)
end

#build_note?Boolean

Test if the filename matches the conditions to be a build note



91
92
93
94
95
96
97
# File 'lib/howzit/stringutils.rb', line 91

def build_note?
  return false if downcase !~ /^(howzit[^.]*|build[^.]+)/

  return false if Howzit.config.should_ignore(self)

  true
end

#cString

Shortcut for calling Color.template



162
163
164
# File 'lib/howzit/stringutils.rb', line 162

def c
  Color.template(self)
end

#comp_distance(term) ⇒ Float

Compare strings and return a distance



12
13
14
15
# File 'lib/howzit/stringutils.rb', line 12

def comp_distance(term)
  chars = term.split(//)
  contains_count(chars) + distance(chars)
end

#contains_count(chars) ⇒ Object

Number of matching characters the string contains



22
23
24
25
26
27
# File 'lib/howzit/stringutils.rb', line 22

def contains_count(chars)
  chars = chars.split(//) if chars.is_a?(String)
  count = 0
  chars.each { |char| count += 1 if self =~ /#{char}/i }
  count
end

#distance(chars) ⇒ Number

Determine the minimum distance between characters that they all still fall within



73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/howzit/stringutils.rb', line 73

def distance(chars)
  distance = 0
  max = self.length - chars.length
  return max unless in_order(chars) == chars.length

  while distance < max
    return distance if in_distance?(chars, distance)

    distance += 1
  end
  distance
end

#extract_metadataHash

Split the content at the first top-level header and assume everything before it is metadata. Passes to #metadata for processing



359
360
361
362
363
364
365
366
# File 'lib/howzit/stringutils.rb', line 359

def 
  if File.exist?(self)
    leader = Util.read_file(self).split(/^#/)[0].strip
    leader.length.positive? ? leader. : {}
  else
    {}
  end
end

#format_header(opts = {}) ⇒ String

Make a fancy title line for the topic



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/howzit/stringutils.rb', line 433

def format_header(opts = {})
  title = dup
  options = {
    hr: "\u{254C}",
    color: '{bg}',
    border: '{x}',
    mark: should_mark_iterm?
  }

  options.merge!(opts)

  case Howzit.options[:header_format]
  when :block
    Color.template("\n\n#{options[:color]}\u{258C}#{title}#{should_mark_iterm? && options[:mark] ? iterm_marker : ''}{x}")
  else
    cols = TTY::Screen.columns

    cols = Howzit.options[:wrap] if Howzit.options[:wrap].positive? && cols > Howzit.options[:wrap]
    title = Color.template("#{options[:border]}#{options[:hr] * 2}( #{options[:color]}#{title}#{options[:border]} )")

    tail = if should_mark_iterm?
             "#{options[:hr] * (cols - title.uncolor.length - 15)}#{options[:mark] ? iterm_marker : ''}"
           else
             options[:hr] * (cols - title.uncolor.length)
           end
    Color.template("\n\n#{title}#{tail}{x}\n\n")
  end
end

#in_distance?(chars, distance) ⇒ Boolean

Determine if a series of characters are all within a given distance of each other in the String



59
60
61
62
63
# File 'lib/howzit/stringutils.rb', line 59

def in_distance?(chars, distance)
  chars = chars.split(//) if chars.is_a?(String)
  rx = Regexp.new(chars.join(".{,#{distance}}"), 'i')
  self =~ rx ? true : false
end

#in_order(chars) ⇒ Boolean

Determine if characters are in order



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/howzit/stringutils.rb', line 36

def in_order(chars)
  chars = chars.split(//) if chars.is_a?(String)
  position = 0
  in_order = 0
  chars.each do |char|
    new_pos = self[position..-1] =~ /#{char}/i
    if new_pos
      position += new_pos
      in_order += 1
    end
  end
  in_order
end

#iterm_markerString

Output an iTerm marker



423
424
425
# File 'lib/howzit/stringutils.rb', line 423

def iterm_marker
  "\e]1337;SetMark\a" if should_mark_iterm?
end

#metadataHash

Examine text for multimarkdown-style metadata and return key/value pairs



373
374
375
376
377
378
379
380
381
382
# File 'lib/howzit/stringutils.rb', line 373

def 
  data = {}
  scan(/(?mi)^(\S[\s\S]+?): ([\s\S]*?)(?=\n\S[\s\S]*?:|\Z)/).each do |m|
    data[m[0].strip.downcase] = m[1]
  end
  out = (data)
  Howzit.named_arguments ||= {}
  Howzit.named_arguments = out.merge(Howzit.named_arguments)
  out
end

#normalize_metadata(meta) ⇒ Hash

Autocorrect some keys



391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/howzit/stringutils.rb', line 391

def (meta)
  data = {}
  meta.each do |k, v|
    case k
    when /^te?m?pl(ate)?s?$/
      data['template'] = v
    when /^req\w*$/
      data['required'] = v
    else
      data[k] = v
    end
  end
  data
end

#note_title(file, truncate = 0) ⇒ Object

Get the title of the build note (top level header)



104
105
106
107
108
109
110
111
112
113
# File 'lib/howzit/stringutils.rb', line 104

def note_title(file, truncate = 0)
  title = match(/(?:^(\S.*?)(?=\n==)|^# ?(.*?)$)/)
  title = if title
            title[1].nil? ? title[2] : title[1]
          else
            file.sub(/(\.\w+)?$/, '')
          end

  title && truncate.positive? ? title.trunc(truncate) : title
end

#preserve_escapesString

Replace slash escaped characters in a string with a zero-width space that will prevent a shell from interpreting them when output to console



122
123
124
# File 'lib/howzit/stringutils.rb', line 122

def preserve_escapes
  gsub(/\\([a-z])/, '\​\1')
end

#render_argumentsString

Render $X placeholders based on positional arguments



329
330
331
332
333
334
# File 'lib/howzit/stringutils.rb', line 329

def render_arguments
  str = dup
  str.render_named_placeholders
  str.render_numeric_placeholders
  Howzit.arguments.nil? ? str : str.gsub(/\$[@*]/, Shellwords.join(Howzit.arguments))
end

#render_named_placeholdersObject



336
337
338
339
340
341
342
# File 'lib/howzit/stringutils.rb', line 336

def render_named_placeholders
  gsub!(/\$\{(?<name>[A-Z0-9_]+(?::.*?)?)\}/i) do
    m = Regexp.last_match
    arg, default = m['name'].split(/:/).map(&:strip)
    Howzit.named_arguments.key?(arg) && !Howzit.named_arguments[arg].nil? ? Howzit.named_arguments[arg] : default
  end
end

#render_numeric_placeholdersObject



344
345
346
347
348
349
350
# File 'lib/howzit/stringutils.rb', line 344

def render_numeric_placeholders
  gsub!(/\$\{?(\d+)\}?/) do
    arg, default = Regexp.last_match(1).split(/:/)
    idx = arg.to_i - 1
    Howzit.arguments.length > idx ? Howzit.arguments[idx] : default || Regexp.last_match(0)
  end
end

#render_template(vars) ⇒ String

Render [%variable] placeholders in a templated string



303
304
305
306
307
308
309
310
311
312
313
# File 'lib/howzit/stringutils.rb', line 303

def render_template(vars)
  vars.each do |k, v|
    gsub!(/\[%#{k}(:.*?)?\]/, v)
  end

  # Replace empty variables with default
  gsub!(/\[%([^\]]+?):(.*?)\]/, '\2')

  # Remove remaining empty variables
  gsub(/\[%.*?\]/, '')
end

#render_template!(vars) ⇒ Object

Render [%variable] placeholders in place



320
321
322
# File 'lib/howzit/stringutils.rb', line 320

def render_template!(vars)
  replace render_template(vars)
end

#should_mark_iterm?Boolean

Test if iTerm markers should be output. Requires that the $TERM_PROGRAM be iTerm and howzit is not running directives or paginating output



413
414
415
# File 'lib/howzit/stringutils.rb', line 413

def should_mark_iterm?
  ENV['TERM_PROGRAM'] =~ /^iTerm/ && !Howzit.options[:run] && !Howzit.options[:paginate]
end

#split_line(width, indent = '') ⇒ Object

Splits a line at nearest word break



269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/howzit/stringutils.rb', line 269

def split_line(width, indent = '')
  line = dup
  at = line.index(/\s/)
  last_at = at

  while !at.nil? && at < width
    last_at = at
    at = line.index(/\s/, last_at + 1)
  end

  if last_at.nil?
    [indent + line[0, width], line[width, line.length]]
  else
    [indent + line[0, last_at], line[last_at + 1, line.length]]
  end
end

#to_config_value(orig_value = nil) ⇒ Object

Convert a string to a valid YAML value



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/howzit/stringutils.rb', line 133

def to_config_value(orig_value = nil)
  if orig_value
    case orig_value.class.to_s
    when /Integer/
      to_i
    when /(True|False)Class/
      self =~ /^(t(rue)?|y(es)?|1)$/i ? true : false
    else
      self
    end
  else
    case self
    when /^[0-9]+$/
      to_i
    when /^(t(rue)?|y(es)?)$/i
      true
    when /^(f(alse)?|n(o)?)$/i
      false
    else
      self
    end
  end
end

#to_rxRegexp

Convert a string to a regex object based on matching settings



171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/howzit/stringutils.rb', line 171

def to_rx
  case Howzit.options[:matching]
  when 'exact'
    /^#{self}$/i
  when 'beginswith'
    /^#{self}/i
  when 'fuzzy'
    /#{split(//).join('.{0,3}?')}/i
  else
    /#{self}/i
  end
end

#trunc(len) ⇒ Object

Truncate string to nearest word



246
247
248
249
250
251
252
# File 'lib/howzit/stringutils.rb', line 246

def trunc(len)
  split(/ /).each_with_object([]) do |x, ob|
    break ob unless ob.join(' ').length + ' '.length + x.length <= len

    ob.push(x)
  end.join(' ').strip
end

#trunc!(len) ⇒ Object

Truncate string in place (destructive)



259
260
261
# File 'lib/howzit/stringutils.rb', line 259

def trunc!(len)
  replace trunc(len)
end

#uncolorObject

Just strip out color codes when requested



185
186
187
188
189
# File 'lib/howzit/stringutils.rb', line 185

def uncolor
  # force UTF-8 and remove invalid characters, then remove color codes
  # and iTerm markers
  gsub(Howzit::Color::COLORED_REGEXP, "").gsub(/\e\]1337;SetMark/, "")
end

#wrap(width) ⇒ String

Wrap text at a specified width.

Adapted from github.com/pazdera/word_wrap/, copyright © 2014, 2015 Radek Pazdera Distributed under the MIT License



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/howzit/stringutils.rb', line 202

def wrap(width)
  width ||= 80
  output = []
  indent = ''

  text = gsub(/\t/, '  ')

  text.lines do |line|
    line.chomp! "\n"
    if line.length > width
      indent = if line.uncolor =~ /^(\s*(?:[+\-*]|\d+\.) )/
                 ' ' * Regexp.last_match[1].length
               else
                 ''
               end
      new_lines = line.split_line(width)

      while new_lines.length > 1 && new_lines[1].length + indent.length > width
        output.push new_lines[0]

        new_lines = new_lines[1].split_line(width, indent)
      end
      output += [new_lines[0], indent + new_lines[1]]
    else
      output.push line
    end
  end
  output.map!(&:rstrip)
  output.join("\n")
end

#wrap!(width) ⇒ Object

Wrap string in place (destructive)



238
239
240
# File 'lib/howzit/stringutils.rb', line 238

def wrap!(width)
  replace(wrap(width))
end