Module: Doing::StringTags

Included in:
String
Defined in:
lib/doing/string/tags.rb

Overview

Handling of @tags in strings

Instance Method Summary collapse

Instance Method Details

#add_atString

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

Returns:



11
12
13
# File 'lib/doing/string/tags.rb', line 11

def add_at
  strip.sub(/^([+-]*)@?/, '\1@')
end

#add_tags(tags, remove: false) ⇒ String

Adds tags to a string

Parameters:

  • tags (String or Array)

    List of tags to add. @ symbol optional

  • remove (Boolean) (defaults to: false)

    remove tags instead of adding

Returns:

  • (String)

    the tagged string



59
60
61
62
63
64
# 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) ⇒ Object

See Also:



67
68
69
# File 'lib/doing/string/tags.rb', line 67

def add_tags!(tags, remove: false)
  replace add_tags(tags, remove: remove)
end

#dedup_tagsObject

Remove duplicate tags, leaving only first occurrence

Returns:

  • Deduplicated string



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# 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!Object

See Also:



177
178
179
# File 'lib/doing/string/tags.rb', line 177

def dedup_tags!
  replace dedup_tags
end

#remove_atString

Removes @ prefix if needed, maintains +/- prefix

Returns:

  • (String)

    string without @ prefix



20
21
22
# File 'lib/doing/string/tags.rb', line 20

def remove_at
  strip.sub(/^([+-]*)@?/, '\1')
end

#split_tagsArray

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

Returns:

  • (Array)

    array of tags without @ symbols



31
32
33
# 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) ⇒ String

Add, rename, or remove a tag

Parameters:

  • tag

    The tag

  • value (String) (defaults to: nil)

    Value for tag (@tag(value))

  • remove (Boolean) (defaults to: false)

    Remove the tag instead of adding

  • rename_to (String) (defaults to: nil)

    Replace tag with this tag

  • regex (Boolean) (defaults to: false)

    Tag is regular expression

  • single (Boolean) (defaults to: false)

    Operating on a single item (for logging)

  • force (Boolean) (defaults to: false)

    With rename_to, add tag if it doesn't exist

Returns:

  • (String)

    The string with modified tags



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# 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) ⇒ Object

Add, rename, or remove a tag in place

See Also:



76
77
78
# File 'lib/doing/string/tags.rb', line 76

def tag!(tag, **options)
  replace tag(tag, **options)
end

#to_tagsArray

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)

Returns:

  • (Array)

    array of tags including @ symbols



42
43
44
45
46
47
48
49
# 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