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
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 |
#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
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 = { hr: "\u{254C}", color: '{bg}', border: '{x}', mark: should_mark_iterm? } .merge!(opts) case Howzit.[: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.[:wrap] if Howzit.[:wrap].positive? && cols > Howzit.[: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 [: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
423 424 425 |
# File 'lib/howzit/stringutils.rb', line 423 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
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 () 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
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_placeholders ⇒ Object
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_placeholders ⇒ Object
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.[:run] && !Howzit.[: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_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
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 |
#uncolor ⇒ Object
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 |