module Doing::StringTags

Handling of @tags in strings

Public Instance Methods

add_at() click to toggle source

Add @ prefix to string if needed, maintains +/- prefix

@return [String] @string

# File lib/doing/string/tags.rb, line 11
def add_at
  strip.sub(/^([+-]*)@?/, '\1@')
end
add_tags(tags, remove: false) click to toggle source

Adds tags to a string

@param tags [String or Array] List of tags to add. @ symbol optional @param remove [Boolean] remove tags instead of adding

@return [String] the tagged string

# File lib/doing/string/tags.rb, line 59
def add_tags(tags, remove: false)
  title = dup
  tags = tags.to_tags
  tags.each { |tag| title.tag!(tag, remove: remove) }
  title
end
add_tags!(tags, remove: false) click to toggle source

@see add_tags

# File lib/doing/string/tags.rb, line 67
def add_tags!(tags, remove: false)
  replace add_tags(tags, remove: remove)
end
dedup_tags() click to toggle source

Remove duplicate tags, leaving only first occurrence

@return Deduplicated string

# File lib/doing/string/tags.rb, line 159
def dedup_tags
  title = dup
  tags = title.scan(/(?<=\A| )(@(\S+?)(\([^)]+\))?)(?= |\Z)/).uniq
  tags.each do |tag|
    found = false
    title.gsub!(/( |^)#{Regexp.escape(tag[1])}(\([^)]+\))?(?= |$)/) do |m|
      if found
        ''
      else
        found = true
        m
      end
    end
  end
  title
end
dedup_tags!() click to toggle source

@see dedup_tags

# File lib/doing/string/tags.rb, line 177
def dedup_tags!
  replace dedup_tags
end
remove_at() click to toggle source

Removes @ prefix if needed, maintains +/- prefix

@return [String] string without @ prefix

# File lib/doing/string/tags.rb, line 20
def remove_at
  strip.sub(/^([+-]*)@?/, '\1')
end
split_tags() click to toggle source

Split a string of tags, remove @ symbols, with or without @ symbols, with or without parenthetical values

@return [Array] array of tags without @ symbols

# File lib/doing/string/tags.rb, line 31
def split_tags
  gsub(/ *, */, ' ').scan(/(@?(?:\S+(?:\(.+\)))|@?(?:\S+))/).map(&:first).map(&:remove_at).sort.uniq
end
tag(tag, value: nil, remove: false, rename_to: nil, regex: false, single: false, force: false) click to toggle source

Add, rename, or remove a tag

@param tag The tag @param value [String] Value for tag (@tag(value)) @param remove [Boolean] Remove the tag instead of adding @param rename_to [String] Replace tag with this tag @param regex [Boolean] Tag is regular expression @param single [Boolean] Operating on a single item (for logging) @param force [Boolean] With rename_to, add tag if it doesn’t exist

@return [String] The string with modified tags

# File lib/doing/string/tags.rb, line 93
def tag(tag, value: nil, remove: false, rename_to: nil, regex: false, single: false, force: false)
  log_level = single ? :info : :debug
  title = dup
  title.chomp!
  tag = tag.sub(/^@?/, '')
  case_sensitive = tag !~ /[A-Z]/

  rx_tag = if regex
             tag.gsub(/\./, '\S')
           else
             tag.gsub(/\?/, '.').gsub(/\*/, '\S*?')
           end

  if remove || rename_to
    rx = Regexp.new("(?<=^| )@#{rx_tag}(?<parens>\\((?<value>[^)]*)\\))?(?= |$)", case_sensitive)
    m = title.match(rx)

    if m.nil? && rename_to && force
      title.tag!(rename_to, value: value, single: single)
    elsif m
      title.gsub!(rx) do
        rename_to ? "@#{rename_to}#{value.nil? ? m['parens'] : "(#{value})"}" : ''
      end

      title.dedup_tags!
      title.chomp!

      if rename_to
        f = "@#{tag}".cyan
        t = "@#{rename_to}".cyan
        Doing.logger.write(log_level, 'Tag:', %(renamed #{f} to #{t} in "#{title}"))
      else
        f = "@#{tag}".cyan
        Doing.logger.write(log_level, 'Tag:', %(removed #{f} from "#{title}"))
      end
    else
      Doing.logger.debug('Skipped:', "not tagged #{"@#{tag}".cyan}")
    end
  elsif title =~ /@#{tag}(?=[ (]|$)/ && !value.good?
    Doing.logger.debug('Skipped:', "already tagged #{"@#{tag}".cyan}")
    return title
  else
    add = tag
    add += "(#{value})" unless value.nil?

    title.chomp!

    if value && title =~ /@#{tag}(?=[ (]|$)/
      title.sub!(/@#{tag}(\(.*?\))?/, "@#{add}")
    else
      title += " @#{add}"
    end

    title.dedup_tags!
    title.chomp!
    Doing.logger.write(log_level, 'Tag:', %(added #{('@' + tag).cyan} to "#{title}"))
  end

  title.gsub(/ +/, ' ')
end
tag!(tag, **options) click to toggle source

Add, rename, or remove a tag in place

@see tag

# File lib/doing/string/tags.rb, line 76
def tag!(tag, **options)
  replace tag(tag, **options)
end
to_tags() { |arr| ... } click to toggle source

Convert a list of tags to an array. Tags can be with or without @ symbols, separated by any character, and can include parenthetical values (with spaces)

@return [Array] array of tags including @ symbols

# File lib/doing/string/tags.rb, line 42
def to_tags
  arr = split_tags.map(&:add_at)
  if block_given?
    yield arr
  else
    arr
  end
end