class Object
Constants
- FALLBACK
- FOLD_COLUMNS
- FOLD_MSG
- KDRFC_VERSION
try to get this from gemspec.
- MIN_FOLD_COLUMNS
- NMDTAGS
- NORMINFORM
- RE_IDENT
- RE_NL
- RE_SECTION
- XML_RESOURCE_ORG_PREFIX
- XREF_SECTIONS_RE
- XREF_TXT
- XREF_TXT_SUFFIX
- XSR_PREFIX
- XSR_SUFFIX
Public Instance Methods
add_quote(s)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 23 def add_quote(s) l = s.lines l.map {|li| "> #{li}"}.join end
boilerplate(key)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 77 def boilerplate(key) case key.downcase when /\Abcp14(info)?(\+)?(-tagged)?\z/i ret = '' if $1 ret << <<RFC8174ise Although this document is not an IETF Standards Track publication, it adopts the conventions for normative language to provide clarity of instructions to the implementer. RFC8174ise end ret << <<RFC8174 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 {{!RFC2119}} {{!RFC8174}} when, and only when, they appear in all capitals, as shown here. RFC8174 if $2 ret << <<PLUS These words may also appear in this document in lower case as plain English words, absent their normative meanings. PLUS end if $3 ($options.v3_used ||= []) << "** need --v3 to tag bcp14" ret << <<TAGGED *[MUST]: <bcp14> *[MUST NOT]: <bcp14> *[REQUIRED]: <bcp14> *[SHALL]: <bcp14> *[SHALL NOT]: <bcp14> *[SHOULD]: <bcp14> *[SHOULD NOT]: <bcp14> *[RECOMMENDED]: <bcp14> *[NOT RECOMMENDED]: <bcp14> *[MAY]: <bcp14> *[OPTIONAL]: <bcp14> TAGGED end ret else warn "** Unknwon boilerplate key: #{key}" "{::boilerplate #{key}}" end end
deep_clone()
click to toggle source
# File lib/kramdown-rfc2629.rb, line 25 def deep_clone Marshal.load(Marshal.dump(self)) end
do_the_tls_dance()
click to toggle source
# File lib/kramdown-rfc/command.rb, line 125 def do_the_tls_dance begin require 'openssl' File.open(OpenSSL::X509::DEFAULT_CERT_FILE) do end # This guards against having an unreadable cert file (yes, that appears to happen a lot). rescue if Dir[File.join(OpenSSL::X509::DEFAULT_CERT_DIR, "*.pem")].empty? # This guards against having no certs at all, not against missing the right one for IETF. # Oh well. warn "** Configuration problem with OpenSSL certificate store." warn "** You may want to examine #{OpenSSL::X509::DEFAULT_CERT_FILE}" warn "** and #{OpenSSL::X509::DEFAULT_CERT_DIR}." warn "** Activating suboptimal workaround." warn "** Occasionally run `certified-update` to maintain that workaround." require 'certified' end end end
expand_tabs(s, tab_stops = 8)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 471 def expand_tabs(s, tab_stops = 8) s.gsub(/([^\t\n]*)\t/) do $1 + " " * (tab_stops - ($1.size % tab_stops)) end end
fold8792_1(s, columns = FOLD_COLUMNS, left = false, dry = false)
click to toggle source
# File lib/kramdown-rfc/rfc8792.rb, line 6 def fold8792_1(s, columns = FOLD_COLUMNS, left = false, dry = false) if s.index("\t") warn "*** HT (\"TAB\") in text to be folded. Giving up." return s end if columns < MIN_FOLD_COLUMNS columns = if columns == 0 FOLD_COLUMNS else warn "*** folding to #{MIN_FOLD_COLUMNS}, not #{columns}" MIN_FOLD_COLUMNS end end lines = s.lines.map(&:chomp) did_fold = false ix = 0 while li = lines[ix] col = columns if li[col].nil? if li[-1] == "\\" lines[ix..ix] = [li << "\\", ""] ix += 1 end ix += 1 else did_fold = true min_indent = left || 0 col -= 1 # space for "\\" while li[col] == " " # can't start new line with " " col -= 1 end if col <= min_indent warn "*** Cannot RFC8792-fold1 to #{columns} cols #{"with indent #{left}" if left} |#{li.inspect}|" else if RE_IDENT === li[col] # Don't split IDs col2 = col while col2 > min_indent && RE_IDENT === li[col2-1] col2 -= 1 end if col2 > min_indent col = col2 end end rest = li[col..-1] indent = left || columns - rest.size if !left && li[-1] == "\\" indent -= 1 # leave space for next round end if indent > 0 rest = " " * indent + rest end lines[ix..ix] = [li[0...col] << "\\", rest] end ix += 1 end end if did_fold msg = FOLD_MSG.dup if !dry && columns >= msg.size + 4 delta = columns - msg.size - 2 # 2 spaces half = delta/2 msg = "#{"=" * half} #{msg} #{"=" * (delta - half)}" end lines[0...0] = [msg, ""] lines.map{|x| x << "\n"}.join else s end end
process_chunk(s, nested, dedent, fold, quote)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 28 def process_chunk(s, nested, dedent, fold, quote) process_includes(s) if nested s = remove_indentation(s) if dedent s = fold8792_1(s, *fold) if fold s = add_quote(s) if quote s end
process_includes(input)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 36 def process_includes(input) input.gsub!(/^\{::include((?:-[a-z0-9]+)*)\s+(.*?)\}/) { include_flags = $1 fn = [$2] chunks = false nested = false dedent = false fold = false quote = false include_flags.split("-") do |flag| case flag when "" when "nested" nested = true when "quote" quote = true when "dedent" dedent = true when /\Afold(\d*)(left(\d*))?(dry)?\z/ fold = [$1.to_i, # col 0 for '' ($3.to_i if $2), # left 0 for '', nil if no "left" $4] # dry when "all", "last" fn = fn.flat_map{|n| Dir[n]} fn = [fn.last] if flag == "last" chunks = fn.map{ |f| ret = process_chunk(File.read(f), nested, dedent, fold, quote) nested = false; dedent = false; fold = false; quote = false ret } else warn "** unknown include flag #{flag}" end end chunks = fn.map{|f| File.read(f)} unless chunks # no all/last chunks = chunks.map {|ch| process_chunk(ch, nested, dedent, fold, quote)} chunks.join.chomp } end
process_kramdown_options(coding_override = nil, smart_quotes = nil, typographic_symbols = nil, header_kramdown_options = nil)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 163 def process_kramdown_options(coding_override = nil, smart_quotes = nil, typographic_symbols = nil, header_kramdown_options = nil) ascii_target = coding_override && coding_override =~ /ascii/ suppress_typography = ascii_target || $options.v3 entity_output = ascii_target ? :numeric : :as_char; options = {input: 'RFC2629Kramdown', entity_output: entity_output, link_defs: {}} if smart_quotes.nil? && suppress_typography smart_quotes = false end if smart_quotes == false smart_quotes = ["'".ord, "'".ord, '"'.ord, '"'.ord] end case smart_quotes when Array options[:smart_quotes] = smart_quotes when nil, true # nothin else warn "*** Can't deal with smart_quotes value #{smart_quotes.inspect}" end if typographic_symbols.nil? && suppress_typography typographic_symbols = false end if typographic_symbols == false typographic_symbols = Hash[::Kramdown::Parser::Kramdown::TYPOGRAPHIC_SYMS.map { |k, v| if Symbol === v [v.intern, k] end }.compact] end # warn [:TYPOGRAPHIC_SYMBOLS, typographic_symbols].to_yaml case typographic_symbols when Hash options[:typographic_symbols] = typographic_symbols when nil, true # nothin else warn "*** Can't deal with typographic_symbols value #{typographic_symbols.inspect}" end if header_kramdown_options options.merge! header_kramdown_options end $global_markdown_options = options # For nested calls in bibref annotation processing and xref text options end
read_encodings()
click to toggle source
# File lib/kramdown-rfc/command.rb, line 460 def read_encodings encfilename = File.expand_path '../../../data/encoding-fallbacks.txt', __FILE__ encfile = File.read(encfilename, coding: "UTF-8") Hash[encfile.lines.map{|l| l.chomp!; x, s = l.split(" ", 2) [x.hex.chr(Encoding::UTF_8), s || " "]}] end
remove_indentation(s)
click to toggle source
Note that this doesn't attempt to handle HT characters
# File lib/kramdown-rfc/command.rb, line 17 def remove_indentation(s) l = s.lines indent = l.grep(/\S/).map {|l| l[/^\s*/].size}.min l.map {|li| li.sub(/^ {0,#{indent}}/, "")}.join end
spacify_re(s)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 223 def spacify_re(s) s.gsub(' ', '[\u00A0\s]+') end
xml_from_sections(input)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 227 def xml_from_sections(input) unless ENV["KRAMDOWN_NO_SOURCE"] require 'kramdown-rfc/gzip-clone' require 'base64' compressed_input = Gzip.compress(input) $source = Base64.encode64(compressed_input) end sections = input.scan(RE_SECTION) # resulting in an array; each section is [section-label, nomarkdown-flag, section-text] # the first section is a YAML with front matter parameters (don't put a label here) # We put back the "---" plus gratuitous blank lines to hack the line number in errors yaml_in = input[/---\s*/] << sections.shift[2] ps = KramdownRFC::ParameterSet.new(yaml_load(yaml_in, [Date], [], true)) if v = ps[:v] warn "*** unsupported RFCXML version #{v}" if v != 3 if $options.v2 warn "*** command line --v2 wins over document's 'v: #{v}'" else $options.v3 = true $options.v = 3 ps.default!(:stand_alone, true) ps.default!(:ipr, "trust200902") ps.default!(:pi, {"toc" => true, "sortrefs" => true, "symrefs" => true}) end end coding_override = ps.has(:coding) smart_quotes = ps[:smart_quotes] typographic_symbols = ps[:typographic_symbols] header_kramdown_options = ps[:kramdown_options] kramdown_options = process_kramdown_options(coding_override, smart_quotes, typographic_symbols, header_kramdown_options) # all the other sections are put in a Hash, possibly concatenated from parts there sechash = Hash.new{ |h,k| h[k] = ""} snames = [] # a stack of section names sections.each do |sname, nmdflag, text| # warn [:SNAME, sname, nmdflag, text[0..10]].inspect nmdin, nmdout = { "-" => ["", ""], # stay in nomarkdown "" => NMDTAGS, # pop out temporarily }[nmdflag || ""] if sname snames << sname # "--- label" -> push label (now current) else snames.pop # just "---" -> pop label (previous now current) end sechash[snames.last] << "#{nmdin}#{text}#{nmdout}" end ref_replacements = { } anchor_to_bibref = { } displayref = {} [:ref, :normative, :informative].each do |sn| if refs = ps.has(sn) warn "*** bad section #{sn}: #{refs.inspect}" unless refs.respond_to? :each refs.each do |k, v| if v.respond_to? :to_str if bibtagsys(v) # enable "foo: RFC4711" as a custom anchor definition anchor_to_bibref[k] = v.to_str end ref_replacements[v.to_str] = k end if Hash === v if aliasname = v.delete("-") ref_replacements[aliasname] = k end if bibref = v.delete("=") anchor_to_bibref[k] = bibref end if dr = v.delete("display") displayref[k] = dr end end end end end open_refs = ps[:ref] || { } # consumed norm_ref = { } # convenience replacement of {{-coap}} with {{I-D.ietf-core-coap}} # collect normative/informative tagging {{!RFC2119}} {{?RFC4711}} sechash.each do |k, v| next if k == "fluff" v.gsub!(/{{(#{ spacify_re(XSR_PREFIX) })?(?:([?!])(-)?|(-))([\w._\-]+)(?:=([\w.\/_\-]+))?(#{ XREF_TXT_SUFFIX })?(#{ spacify_re(XSR_SUFFIX) })?}}/) do |match| xsr_prefix = $1 norminform = $2 replacing = $3 || $4 word = $5 bibref = $6 xrt_suffix = $7 xsr_suffix = $8 if replacing if new = ref_replacements[word] word = new else warn "*** no alias replacement for {{-#{word}}}" word = "-#{word}" end end # now, word is the anchor if bibref if old = anchor_to_bibref[word] if bibref != old warn "*** conflicting definitions for xref #{word}: #{old} != #{bibref}" end else anchor_to_bibref[word] = bibref end end # things can be normative in one place and informative in another -> normative # collect norm/inform above and assign it by priority here if norminform norm_ref[word] ||= norminform == '!' # one normative ref is enough end "{{#{xsr_prefix}#{word}#{xrt_suffix}#{xsr_suffix}}}" end end [:normative, :informative].each do |k| ps.rest[k.to_s] ||= { } end norm_ref.each do |k, v| # could check bibtagsys here: needed if open_refs is nil or string target = ps.has(v ? :normative : :informative) warn "*** overwriting #{k}" if target.has_key?(k) target[k] = open_refs[k] # add reference to normative/informative end # note that unused items from ref are considered OK, therefore no check for that here # also should allow norm/inform check of other references # {{?coap}} vs. {{!coap}} vs. {{-coap}} (undecided) # or {{?-coap}} vs. {{!-coap}} vs. {{-coap}} (undecided) # could require all references to be decided by a global flag overlap = [:normative, :informative].map { |s| (ps.has(s) || { }).keys }.reduce(:&) unless overlap.empty? warn "*** #{overlap.join(', ')}: both normative and informative" end stand_alone = ps[:stand_alone] [:normative, :informative].each do |sn| if refs = ps[sn] refs.each do |k, v| href = ::Kramdown::Parser::RFC2629Kramdown.idref_cleanup(k) kramdown_options[:link_defs][k] = ["##{href}", nil] # allow [RFC2119] in addition to {{RFC2119}} bibref = anchor_to_bibref[k] || k bts, url = bibtagsys(bibref, k, stand_alone) if bts && (!v || v == {} || v.respond_to?(:to_str)) if stand_alone a = %{{: anchor="#{k}"}} sechash[sn.to_s] << %{\n#{NMDTAGS[0]}\n#{a}\n#{NMDTAGS[1]}\n} else bts.gsub!('/', '_') (ps.rest["bibxml"] ||= []) << [bts, url] sechash[sn.to_s] << %{&#{bts};\n} # ??? end else unless v && Hash === v warn "*** don't know how to expand ref #{k}" next end if bts && !v.delete("override") warn "*** warning: explicit settings completely override canned bibxml in reference #{k}" end sechash[sn.to_s] << KramdownRFC::ref_to_xml(href, v) end end end end erbfilename = File.expand_path '../../../data/kramdown-rfc2629.erb', __FILE__ erbfile = File.read(erbfilename, coding: "UTF-8") erb = ERB.trim_new(erbfile, '-') # remove redundant nomarkdown pop outs/pop ins as they confuse kramdown input = erb.result(binding).gsub(%r"{::nomarkdown}\s*{:/nomarkdown}"m, "") ps.warn_if_leftovers sechash.delete("fluff") # fluff is a "commented out" section if !sechash.empty? # any sections unused by the ERb file? warn "*** sections left #{sechash.keys.inspect}!" end [input, kramdown_options, coding_override] end
yaml_load(input, *args)
click to toggle source
# File lib/kramdown-rfc/command.rb, line 151 def yaml_load(input, *args) if YAML.respond_to?(:safe_load) begin YAML.safe_load(input, *args) rescue ArgumentError YAML.safe_load(input, permitted_classes: args[0], permitted_symbols: args[1], aliases: args[2]) end else YAML.load(input) end end