Module: PointBlank::Parsing::LinkSharedMethods

Included in:
ImageInline, LinkInline, LinkReferenceOverlay
Defined in:
lib/mmmd/blankshell.rb

Overview

Shared methods for parsing links

Instance Method Summary collapse

Instance Method Details

#balanced?(text) ⇒ Boolean

Check if brackets are balanced

Parameters:

  • text (String)

Returns:

  • (Boolean)


144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/mmmd/blankshell.rb', line 144

def balanced?(text)
  bracketcount = 0
  text.split(/(?<!\\)([()])/).each do |part|
    if part == '('
      bracketcount += 1
    elsif part == ')'
      bracketcount -= 1
      return false if bracketcount.negative?
    end
  end
  bracketcount.zero?
end

#find_balanced_end(text) ⇒ Integer?

Find index at which balanced part of a bracket closes

Parameters:

  • text (String)

Returns:

  • (Integer, nil)


160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/mmmd/blankshell.rb', line 160

def find_balanced_end(text)
  bracketcount = 0
  index = 0
  text.split(/(?<!\\)([()])/).each do |part|
    if part == '('
      bracketcount += 1
    elsif part == ')'
      bracketcount -= 1
      return index if bracketcount <= 0
    end
    index += part.length
  end
  nil
end

#normalize_label(string) ⇒ String

Normalize a label

Parameters:

  • string (String)

Returns:

  • (String)


15
16
17
18
19
20
# File 'lib/mmmd/blankshell.rb', line 15

def normalize_label(string)
  string = string.downcase(:fold).strip.gsub(/\s+/, " ")
  return nil if string.empty?

  string
end

#process_destination(string) ⇒ String

Process destination string

Parameters:

  • string (String)

Returns:

  • (String)


178
179
180
181
182
183
184
185
# File 'lib/mmmd/blankshell.rb', line 178

def process_destination(string)
  string = string.gsub(/\\([!"\#$%&'()*+,\-.\/:;<=>?@\[\\\]\^_`{|}~])/,
                       '\\1')
  string = string.gsub("\n", " ")
  MMMD::EntityUtils.encode_uri(
    MMMD::EntityUtils.decode_entities(string)
  )
end

#process_title(string) ⇒ String

Process title string

Parameters:

  • string (String)

Returns:

  • (String)


190
191
192
193
194
195
# File 'lib/mmmd/blankshell.rb', line 190

def process_title(string)
  string = string.gsub(/\\([!"\#$%&'()*+,\-.\/:;<=>?@\[\\\]\^_`{|}~])/,
                       '\\1')
  string = string.gsub("\n", " ")
  MMMD::EntityUtils.decode_entities(string)
end

#read_destination(text) ⇒ Array(<String, nil>, String)

Read link destination (URI). Returns matched label or nil, and remainder of the string

Parameters:

  • text (String)

Returns:

  • (Array(<String, nil>, String))


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/mmmd/blankshell.rb', line 76

def read_destination(text)
  if (result = text.match(/\A<.*?(?<![^\\]\\)>/m)) &&
     !result[0][1..].match?(/(?<![^\\]\\)</)
    [process_destination(result[0].gsub(/\\(?=[><])/, '')[1..-2]),
     text.delete_prefix(result[0]).lstrip]
  elsif (result = text.match(/\A\S+/)) &&
        (lnk = result[0]) &&
        !lnk.start_with?('<') &&
        (lnk = (ix = find_balanced_end(lnk)) ? lnk[..ix - 1] : lnk) &&
        balanced?(lnk)
    [process_destination(lnk),
     text.delete_prefix(lnk).lstrip]
  else
    [nil, text]
  end
end

#read_label(text) ⇒ Array(<String, nil>, String)

Read link label. Returns matched label or nil, and remainder of the string

Parameters:

  • text (String)

Returns:

  • (Array(<String, nil>, String))


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/mmmd/blankshell.rb', line 52

def read_label(text)
  prev = text
  label = ""
  return nil, text unless text.start_with?('[')

  bracketcount = 0
  text.split(/(?<!\\)([\[\]])/).each do |part|
    if part == '['
      bracketcount += 1
    elsif part == ']'
      bracketcount -= 1
      break (label += part) if bracketcount.zero?
    end
    label += part
  end
  text = text.delete_prefix(label)
  label = normalize_label(label[1..-2])
  text.start_with?(':') && label ? [label, text[1..].lstrip] : [nil, prev]
end

#read_properties(text) ⇒ Array([Hash, nil], String)

Read link properties. Returns matched parameters as hash or nil, and remainder of the string

Parameters:

  • text (String)

Returns:

  • (Array([Hash, nil], String))


119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/mmmd/blankshell.rb', line 119

def read_properties(text)
  properties = {}
  remaining = text
  if text.start_with? '[' # link label
    properties[:label], remaining = read_return_label(remaining)
    close_bracket = false
  elsif text.start_with? '(' # link properties
    destination, remaining = read_destination(remaining[1..])
    return [nil, text] unless destination

    title, remaining = read_title(remaining.lstrip)
    properties[:uri] = destination
    properties[:title] = title
    close_bracket = true
  end
  if properties.empty? || (close_bracket && !remaining.start_with?(')'))
    [nil, text]
  else
    [properties, close_bracket ? remaining[1..] : remaining]
  end
end

#read_return_label(text) ⇒ Array(<String, nil>, String)

Read link label. Returns matched label or nil, and remainder of the string

Parameters:

  • text (String)

Returns:

  • (Array(<String, nil>, String))


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/mmmd/blankshell.rb', line 26

def read_return_label(text)
  prev = text
  label = ""
  return nil, text unless text.start_with?('[')

  bracketcount = 0
  text.split(/(?<!\\)([\[\]])/).each do |part|
    if part == '['
      bracketcount += 1
    elsif part == ']'
      bracketcount -= 1
      break (label += part) if bracketcount.zero?
    end
    label += part
  end
  return [nil, text] unless bracketcount.zero?

  text = text.delete_prefix(label)
  label = normalize_label(label[1..-2])
  label ? [label, text] : [nil, prev]
end

#read_title(text) ⇒ Array(<String, nil>, String)

Read link title. Returns matched label or nil, and remainder of the string

Parameters:

  • text (String)

Returns:

  • (Array(<String, nil>, String))


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/mmmd/blankshell.rb', line 97

def read_title(text)
  if text.start_with?("'") &&
     (result = text.match(/\A'.*?(?<!\\)'/m))
    [process_title(result[0][1..-2]),
     text.delete_prefix(result[0]).lstrip]
  elsif text.start_with?('"') &&
        (result = text.match(/\A".*?(?<!\\)"/m))
    [process_title(result[0][1..-2]),
     text.delete_prefix(result[0]).lstrip]
  elsif text.start_with?('(') &&
        (result = find_balanced_end(text))
    [process_title(text[1..(result - 1)]),
     text.delete_prefix(text[..result]).lstrip]
  else
    [nil, text]
  end
end