kramdown-rfc2629 1.5.22 → 1.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.