Module: Howzit::StringUtils
- Included in:
- String
- Defined in:
- lib/howzit/stringutils.rb
Overview
String Extensions
Instance Method Summary collapse
-
#available? ⇒ Boolean
Test if an executable is available on the system.
-
#build_note? ⇒ Boolean
Test if the filename matches the conditions to be a build note.
-
#c ⇒ String
Shortcut for calling Color.template.
-
#comp_distance(term) ⇒ Float
Compare strings and return a distance.
-
#contains_count(chars) ⇒ Object
Number of matching characters the string contains.
-
#distance(chars) ⇒ Number
Determine the minimum distance between characters that they all still fall within.
-
#extract_metadata ⇒ Hash
Split the content at the first top-level header and assume everything before it is metadata.
-
#format_header(opts = {}) ⇒ String
Make a fancy title line for the topic.
-
#in_distance?(chars, distance) ⇒ Boolean
Determine if a series of characters are all within a given distance of each other in the String.
-
#in_order(chars) ⇒ Boolean
Determine if characters are in order.
-
#iterm_marker ⇒ String
Output an iTerm marker.
-
#metadata ⇒ Hash
Examine text for multimarkdown-style metadata and return key/value pairs.
-
#normalize_metadata(meta) ⇒ Hash
Autocorrect some keys.
-
#note_title(file, truncate = 0) ⇒ Object
Get the title of the build note (top level header).
-
#preserve_escapes ⇒ String
Replace slash escaped characters in a string with a zero-width space that will prevent a shell from interpreting them when output to console.
-
#render_arguments ⇒ String
Render $X placeholders based on positional arguments.
- #render_named_placeholders ⇒ Object
- #render_numeric_placeholders ⇒ Object
-
#render_template(vars) ⇒ String
Render [%variable] placeholders in a templated string.
-
#render_template!(vars) ⇒ Object
Render [%variable] placeholders in place.
-
#should_mark_iterm? ⇒ Boolean
Test if iTerm markers should be output.
-
#split_line(width, indent = '') ⇒ Object
Splits a line at nearest word break.
-
#to_config_value(orig_value = nil) ⇒ Object
Convert a string to a valid YAML value.
-
#to_rx ⇒ Regexp
Convert a string to a regex object based on matching settings.
-
#trunc(len) ⇒ Object
Truncate string to nearest word.
-
#trunc!(len) ⇒ Object
Truncate string in place (destructive).
-
#uncolor ⇒ Object
Just strip out color codes when requested.
-
#wrap(width) ⇒ String
Wrap text at a specified width.
-
#wrap!(width) ⇒ Object
Wrap string in place (destructive).
Instance Method Details
#available? ⇒ Boolean
Test if an executable is available on the system
289 290 291 |
# File 'lib/howzit/stringutils.rb', line 289 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 |
#c ⇒ String
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_metadata ⇒ Hash
Split the content at the first top-level header and assume everything before it is metadata. Passes to
metadata for processing
357 358 359 360 361 362 363 364 |
# File 'lib/howzit/stringutils.rb', line 357 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
431 432 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 |
# File 'lib/howzit/stringutils.rb', line 431 def format_header(opts = {}) title = dup = { hr: "\u{254C}", color: '{bg}', border: '{x}', mark: should_mark_iterm? } .merge!(opts) case Howzit.[:header_format] when :block Color.template("\n\n#{[:color]}\u{258C}#{title}#{should_mark_iterm? && [:mark] ? iterm_marker : ''}{x}") else cols = TTY::Screen.columns cols = Howzit.[:wrap] if Howzit.[:wrap].positive? && cols > Howzit.[:wrap] title = Color.template("#{[:border]}#{[:hr] * 2}( #{[:color]}#{title}#{[:border]} )") tail = if should_mark_iterm? "#{[:hr] * (cols - title.uncolor.length - 15)}#{[:mark] ? iterm_marker : ''}" else [: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_marker ⇒ String
Output an iTerm marker
421 422 423 |
# File 'lib/howzit/stringutils.rb', line 421 def iterm_marker "\e]1337;SetMark\a" if should_mark_iterm? end |
#metadata ⇒ Hash
Examine text for multimarkdown-style metadata and return key/value pairs
371 372 373 374 375 376 377 378 379 380 |
# File 'lib/howzit/stringutils.rb', line 371 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
389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/howzit/stringutils.rb', line 389 def () data = {} .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_escapes ⇒ String
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_arguments ⇒ String
Render $X placeholders based on positional arguments
327 328 329 330 331 332 |
# File 'lib/howzit/stringutils.rb', line 327 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_placeholders ⇒ Object
334 335 336 337 338 339 340 |
# File 'lib/howzit/stringutils.rb', line 334 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_placeholders ⇒ Object
342 343 344 345 346 347 348 |
# File 'lib/howzit/stringutils.rb', line 342 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
301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/howzit/stringutils.rb', line 301 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
318 319 320 |
# File 'lib/howzit/stringutils.rb', line 318 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
411 412 413 |
# File 'lib/howzit/stringutils.rb', line 411 def should_mark_iterm? ENV['TERM_PROGRAM'] =~ /^iTerm/ && !Howzit.[:run] && !Howzit.[:paginate] end |
#split_line(width, indent = '') ⇒ Object
Splits a line at nearest word break
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 |
# File 'lib/howzit/stringutils.rb', line 267 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_rx ⇒ Regexp
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.[: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
244 245 246 247 248 249 250 |
# File 'lib/howzit/stringutils.rb', line 244 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)
257 258 259 |
# File 'lib/howzit/stringutils.rb', line 257 def trunc!(len) replace trunc(len) end |
#uncolor ⇒ Object
Just strip out color codes when requested
185 186 187 |
# File 'lib/howzit/stringutils.rb', line 185 def uncolor gsub(/\e\[[\d;]+m/, '').gsub(/\e\]1337;SetMark/, '') end |
#wrap(width) ⇒ String
Wrap text at a specified width.
Adapted from https://github.com/pazdera/word_wrap/, copyright (c) 2014, 2015 Radek Pazdera Distributed under the MIT License
200 201 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 |
# File 'lib/howzit/stringutils.rb', line 200 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)
236 237 238 |
# File 'lib/howzit/stringutils.rb', line 236 def wrap!(width) replace(wrap(width)) end |