kramdown-rfc2629 1.5.22 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,6 +8,12 @@ module KramdownRFC
8
8
  escape_html(str.to_s, :attribute)
9
9
  end
10
10
 
11
+ AUTHOR_ATTRIBUTES = %w{
12
+ initials surname fullname
13
+ asciiInitials asciiSurname asciiFullname
14
+ role
15
+ }
16
+
11
17
  def self.ref_to_xml(k, v)
12
18
  vps = KramdownRFC::ParameterSet.new(v)
13
19
  erb = ERB.trim_new <<-REFERB, '-'
@@ -18,7 +24,7 @@ module KramdownRFC
18
24
  <% vps.arr("author", true, true) do |au|
19
25
  aups = authorps_from_hash(au)
20
26
  -%>
21
- <author <%=aups.attrs("initials", "surname", "fullname=name", "role")%>>
27
+ <author <%=aups.attrs(*AUTHOR_ATTRIBUTES)%>>
22
28
  <%= aups.ele("organization=org", aups.attr("abbrev=orgabbrev"), "") %>
23
29
  </author>
24
30
  <% aups.warn_if_leftovers -%>
@@ -40,19 +46,110 @@ module KramdownRFC
40
46
  ret
41
47
  end
42
48
 
49
+ def self.treat_multi_attribute_member(ps, an)
50
+ value = ps.rest[an]
51
+ if Hash === value
52
+ value.each do |k, v|
53
+ ps.rest[if k == ':'
54
+ an
55
+ else
56
+ Kramdown::Element.attrmangle(k + an) ||
57
+ Kramdown::Element.attrmangle(k) ||
58
+ k
59
+ end] = v
60
+ end
61
+ end
62
+ end
63
+
64
+ def self.initializify(s) # XXX Jean-Pierre
65
+ w = '\p{Lu}\p{Lo}'
66
+ if s =~ /\A[-.#{w}]+[.]/u
67
+ $&
68
+ elsif s =~ /\A([#{w}])[^-]*/u
69
+ ret = "#$1."
70
+ while (s = $') && s =~ /\A(-[\p{L}])[^-]*/u
71
+ ret << "#$1."
72
+ end
73
+ ret
74
+ else
75
+ warn "*** Can't initializify #{s}"
76
+ s
77
+ end
78
+ end
79
+
80
+ def self.looks_like_initial(s)
81
+ s =~ /\A[\p{Lu}\p{Lo}]([-.][\p{Lu}\p{Lo}]?)*\z/u
82
+ end
83
+
84
+ def self.initials_from_parts_and_surname(aups, parts, s)
85
+ ssz = s.size
86
+ nonsurname = parts[0...-ssz]
87
+ if (ns = parts[-ssz..-1]) != s
88
+ warn "*** inconsistent surnames #{ns} and #{s}"
89
+ end
90
+ nonsurname.map{|x| initializify(x)}.join(" ")
91
+ end
92
+
93
+ def self.handle_ins(aups, ins_k, initials_k, surname_k)
94
+ if ins = aups[ins_k]
95
+ parts = ins.split('.').map(&:strip) # split on dots first
96
+ # Coalesce H.-P.
97
+ i = 1; while i < parts.size
98
+ if parts[i][0] == "-"
99
+ parts[i-1..i] = [parts[i-1] + "." + parts[i]]
100
+ else
101
+ i += 1
102
+ end
103
+ end
104
+ # Multiple surnames in ins?
105
+ parts[-1..-1] = parts[-1].split
106
+ s = if surname = aups.rest[surname_k]
107
+ surname.split
108
+ else parts.reverse.take_while{|x| !looks_like_initial(x)}.reverse
109
+ end
110
+ aups.rest[initials_k] = initials_from_parts_and_surname(aups, parts, s)
111
+ aups.rest[surname_k] = s.join(" ")
112
+ end
113
+ end
114
+
115
+ def self.handle_name(aups, fn_k, initials_k, surname_k)
116
+ if name = aups.rest[fn_k]
117
+ names = name.split(/ *\| */, 2) # boundary for given/last name
118
+ if names[1]
119
+ aups.rest[fn_k] = name = names.join(" ") # remove boundary
120
+ if surname = aups.rest[surname_k]
121
+ if surname != names[1]
122
+ warn "*** inconsistent embedded surname #{names[1]} and surname #{surname}"
123
+ end
124
+ end
125
+ aups.rest[surname_k] = names[1]
126
+ end
127
+ parts = name.split
128
+ surname = aups.rest[surname_k] || parts[-1]
129
+ s = surname.split
130
+ aups.rest[initials_k] ||= initials_from_parts_and_surname(aups, parts, s)
131
+ aups.rest[surname_k] = s.join(" ")
132
+ end
133
+ end
134
+
43
135
  def self.authorps_from_hash(au)
44
136
  aups = KramdownRFC::ParameterSet.new(au)
45
- if ins = aups[:ins]
46
- parts = ins.split('.').map(&:strip)
47
- aups.rest["initials"] = parts[0..-2].join('.') << '.'
48
- aups.rest["surname"] = parts[-1]
137
+ if n = aups[:name]
138
+ warn "** both name #{n} and fullname #{fn} are set on one author" if fn = aups.rest["fullname"]
139
+ aups.rest["fullname"] = n
140
+ usename = true
141
+ end
142
+ ["fullname", "ins", "initials", "surname"].each do |an|
143
+ treat_multi_attribute_member(aups, an)
49
144
  end
145
+ handle_ins(aups, :ins, "initials", "surname")
146
+ handle_ins(aups, :asciiIns, "asciiInitials", "asciiSurname")
50
147
  # hack ("heuristic for") initials and surname from name
51
148
  # -- only works for people with exactly one last name and uncomplicated first names
52
- if n = aups.rest["name"]
53
- n = n.split
54
- aups.rest["initials"] ||= n[0..-2].map(&:chr).join('.') << '.'
55
- aups.rest["surname"] ||= n[-1]
149
+ # -- add surname for people with more than one last name
150
+ if usename
151
+ handle_name(aups, "fullname", "initials", "surname")
152
+ handle_name(aups, "asciiFullname", "asciiInitials", "asciiSurname")
56
153
  end
57
154
  aups
58
155
  end
@@ -69,7 +166,7 @@ module KramdownRFC
69
166
  # country: Germany
70
167
 
71
168
  PERSON_ERB = <<~ERB
72
- <<%= element_name%> <%=aups.attrs("initials", "surname", "fullname=name", "role")%>>
169
+ <<%= element_name%> <%=aups.attrs(*AUTHOR_ATTRIBUTES)%>>
73
170
  <%= aups.ele("organization=org", aups.attrs("abbrev=orgabbrev",
74
171
  *[$options.v3 && "ascii=orgascii"]), "") %>
75
172
  <address>
@@ -1,11 +1,22 @@
1
+ FOLD_MSG = "NOTE: '\\' line wrapping per RFC 8792".freeze
2
+ MIN_FOLD_COLUMNS = FOLD_MSG.size
1
3
  FOLD_COLUMNS = 69
2
4
  RE_IDENT = /\A[A-Za-z0-9_]\z/
3
5
 
4
- def fold8792_1(s, columns = FOLD_COLUMNS)
6
+ def fold8792_1(s, columns = FOLD_COLUMNS, left = false, dry = false)
5
7
  if s.index("\t")
6
8
  warn "*** HT (\"TAB\") in text to be folded. Giving up."
7
9
  return s
8
10
  end
11
+ if columns < MIN_FOLD_COLUMNS
12
+ columns =
13
+ if columns == 0
14
+ FOLD_COLUMNS
15
+ else
16
+ warn "*** folding to #{MIN_FOLD_COLUMNS}, not #{columns}"
17
+ MIN_FOLD_COLUMNS
18
+ end
19
+ end
9
20
 
10
21
  lines = s.lines.map(&:chomp)
11
22
  did_fold = false
@@ -20,25 +31,26 @@ def fold8792_1(s, columns = FOLD_COLUMNS)
20
31
  ix += 1
21
32
  else
22
33
  did_fold = true
34
+ min_indent = left || 0
23
35
  col -= 1 # space for "\\"
24
36
  while li[col] == " " # can't start new line with " "
25
37
  col -= 1
26
38
  end
27
- if col <= 0
28
- warn "*** Cannot RFC8792-fold1 #{li.inspect}"
39
+ if col <= min_indent
40
+ warn "*** Cannot RFC8792-fold1 to #{columns} cols #{"with indent #{left}" if left} |#{li.inspect}|"
29
41
  else
30
42
  if RE_IDENT === li[col] # Don't split IDs
31
43
  col2 = col
32
- while col2 > 0 && RE_IDENT === li[col2-1]
44
+ while col2 > min_indent && RE_IDENT === li[col2-1]
33
45
  col2 -= 1
34
46
  end
35
- if col2 > 0
47
+ if col2 > min_indent
36
48
  col = col2
37
49
  end
38
50
  end
39
51
  rest = li[col..-1]
40
- indent = columns - rest.size
41
- if li[-1] == "\\"
52
+ indent = left || columns - rest.size
53
+ if !left && li[-1] == "\\"
42
54
  indent -= 1 # leave space for next round
43
55
  end
44
56
  if indent > 0
@@ -51,7 +63,13 @@ def fold8792_1(s, columns = FOLD_COLUMNS)
51
63
  end
52
64
 
53
65
  if did_fold
54
- lines[0...0] = ["=== NOTE: '\\' line wrapping per RFC 8792 ===", ""]
66
+ msg = FOLD_MSG.dup
67
+ if !dry && columns >= msg.size + 4
68
+ delta = columns - msg.size - 2 # 2 spaces
69
+ half = delta/2
70
+ msg = "#{"=" * half} #{msg} #{"=" * (delta - half)}"
71
+ end
72
+ lines[0...0] = [msg, ""]
55
73
  lines.map{|x| x << "\n"}.join
56
74
  else
57
75
  s
@@ -242,6 +242,14 @@ module Kramdown
242
242
  TRUTHY["false"] = false
243
243
  TRUTHY["no"] = false
244
244
 
245
+ # explicit or automatic studlification
246
+ # note that explicit (including trailing "_") opts out of automatic
247
+ def self.attrmangle(k)
248
+ if (d = k.gsub(/_(.|$)/) { $1.upcase }) != k or d = STUDLY_ATTR_MAP[k]
249
+ d
250
+ end
251
+ end
252
+
245
253
  def rfc2629_fix(opts)
246
254
  if a = attr
247
255
  if anchor = a.delete('id')
@@ -254,7 +262,7 @@ module Kramdown
254
262
  opts = opts.merge(noabbrev: TRUTHY[av]) # updated copy
255
263
  end
256
264
  attr.keys.each do |k|
257
- if (d = k.gsub(/_(.|$)/) { $1.upcase }) != k or d = STUDLY_ATTR_MAP[k]
265
+ if d = self.class.attrmangle(k)
258
266
  a[d] = a.delete(k)
259
267
  end
260
268
  end
@@ -1323,7 +1331,7 @@ COLORS
1323
1331
  if target == "#"
1324
1332
  target = value
1325
1333
  else
1326
- target = target[1..]
1334
+ target = target[1..-1]
1327
1335
  end
1328
1336
  else
1329
1337
  target = nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kramdown-rfc2629
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.22
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carsten Bormann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-13 00:00:00.000000000 Z
11
+ date: 2022-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kramdown
@@ -71,6 +71,7 @@ description: |-
71
71
  "kramdown" markdown parser. Mostly useful for RFC writers.
72
72
  email: cabo@tzi.org
73
73
  executables:
74
+ - kramdown-rfc
74
75
  - kramdown-rfc2629
75
76
  - doilit
76
77
  - kramdown-rfc-extract-markdown
@@ -86,6 +87,7 @@ files:
86
87
  - bin/de-gfm
87
88
  - bin/doilit
88
89
  - bin/kdrfc
90
+ - bin/kramdown-rfc
89
91
  - bin/kramdown-rfc-cache-i-d-bibxml
90
92
  - bin/kramdown-rfc-cache-subseries-bibxml
91
93
  - bin/kramdown-rfc-extract-markdown
@@ -94,6 +96,7 @@ files:
94
96
  - data/kramdown-rfc2629.erb
95
97
  - data/math.json
96
98
  - kramdown-rfc2629.gemspec
99
+ - lib/kramdown-rfc/command.rb
97
100
  - lib/kramdown-rfc/erb.rb
98
101
  - lib/kramdown-rfc/gzip-clone.rb
99
102
  - lib/kramdown-rfc/kdrfc-processor.rb
@@ -120,7 +123,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
123
  - !ruby/object:Gem::Version
121
124
  version: '0'
122
125
  requirements: []
123
- rubygems_version: 3.2.32
126
+ rubygems_version: 3.3.3
124
127
  signing_key:
125
128
  specification_version: 4
126
129
  summary: Kramdown extension for generating RFC 7749 XML.