# Copyright (c) 2020 Jerome Arbez-Gindre # frozen_string_literal: true # :nocov: require('asciidoctor/extensions') unless RUBY_ENGINE == 'opal' # :nocov: # An extension that allow to define applicable definitions # # Usage # :tag-mylabel-color: yellow # :tag-otherlabel-color: red # # # [define, requirement, TOTO-0001, [mylabel, otherlabel]] # -- # The system shall allow to do lots of things. # -- # # or # # [define, requirement, TOTO-0001] # This shall be nice. # require('asciidoctor/defmastership/regexp_dispatcher') require('defmastership/constants') require('defmastership/parsing_state') module Asciidoctor # Module to host DefMastership preprocessor module DefMastership # Preprocessor to replace adoc statements # This class smells of :reek:InstanceVariableAssumption. # Not an issue because process is the only method used by Asciidoctor class Preprocessor < Asciidoctor::Extensions::Preprocessor REGEXPS = { eref_config: ::DefMastership::DMRegexp::EREF_CONFIG, definition: ::DefMastership::DMRegexp::DEFINITION, eref_def: ::DefMastership::DMRegexp::EREF_DEF, iref_def: ::DefMastership::DMRegexp::IREF_DEF, attr_set: ::DefMastership::DMRegexp::ATTR_SET, variable_def: ::DefMastership::DMRegexp::VARIABLE_DEF }.freeze private_constant :REGEXPS def initialize(config = {}) super @has_url = Set.new @variables = {} @parsing_state = ::DefMastership::ParsingState.new end def process(_document, reader) return reader if reader.eof? reader.unshift_lines(parse_and_replace(reader.read_lines)) end def build_definition(_line, matches) Helper::DefinitionStringBuilder.new(matches, show_explicit_checksum(matches)).str end def variable_set(line, matches) @variables.merge!(Helper.variable_hash(matches)) [line] end def set_eref_url_if_any(line, matches) @has_url.add(matches[:reference]) if Helper.valid_eref_url?(matches) [line] end def build_external_ref(_line, matches) return [] unless show_ext_ref(matches) extrefs = matches[:extrefs].split(/\s*,\s*/) extref_line = extrefs.map { |ref| build_link(ref, matches) } ["[.external_reference]\#{eref-#{matches[:reference]}-prefix} #{extref_line.join(', ')}.#"] end # This method smells of :reek:UtilityFunction def build_internal_ref(line, _matches) [ line.gsub(REGEXPS.fetch(:iref_def)) do intref = Regexp.last_match[:intref] "<<#{intref},#{intref}>>" end ] end # This method smells of :reek:UtilityFunction def attribute_setting(_line, matches) [ '[.attribute]', "{attr-#{matches[:attr]}-prefix} #{matches[:value]}." ] end private def build_subs subs = RegexpDispatcher.new(self) subs .add_rule(REGEXPS.fetch(:eref_config), :set_eref_url_if_any) .add_rule(REGEXPS.fetch(:definition), :build_definition) .add_rule(REGEXPS.fetch(:eref_def), :build_external_ref) .add_rule(REGEXPS.fetch(:iref_def), :build_internal_ref) .add_rule(REGEXPS.fetch(:attr_set), :attribute_setting) .add_rule(REGEXPS.fetch(:variable_def), :variable_set) end def parse_and_replace(lines) subs = build_subs lines.reduce([]) do |new_lines, line| next new_lines + [line] unless @parsing_state.enabled?(line) next new_lines + subs.replace(line) end end def show_explicit_checksum(matches) matches[:explicit_checksum] && !@variables['show-explicit-checksum'].eql?('disable') && !@variables["show-#{matches[:type]}-explicit-checksum"].eql?('disable') end def build_link(ref, matches) refname = matches[:reference] return ref unless @has_url.include?(refname) ref_pattern = @variables["eref-#{refname}-ref-pattern"] || '#%s' ref_str = format(ref_pattern, ref) "link:{eref-#{refname}-url}#{ref_str}[#{ref}]" end def show_ext_ref(matches) !@variables['show-ext-ref'].eql?('disable') && !@variables["show-#{matches[:reference]}-ext-ref"].eql?('disable') end end # Proepocessors class Helpers class Preprocessor # Helpers for Preprocessor class module Helper # Isolate the definition macro class DefinitionStringBuilder def initialize(matches, show_explicit_checksum) @matches = matches @show_explicit_checksum = show_explicit_checksum end def str explicit_checksum_str = " [.checksum]#(#{@matches[:explicit_checksum]})#" if @show_explicit_checksum explicit_version_str = Helper.build_explicit_version_str(@matches[:explicit_version]) labels_str = Helper.build_labels_str(@matches[:labels]) reference = @matches[:reference] [ ".#{reference}#{explicit_version_str}#{explicit_checksum_str}#{labels_str}", "[##{reference}.define.#{@matches[:type]}]" ] end end def self.valid_eref_url?(match) match[:symb] == 'url' && !match[:value].eql?('none') end def self.build_labels_str(labels) return unless labels labels_strings = labels.split(/\s*,\s*/).reduce([]) do |acc, label| acc << "[.tag.{tag-#{label}-color}]##{label}#" end " #{labels_strings.join(' ')}" end def self.build_explicit_version_str(explicit_version) " [.version]#(#{explicit_version})#" if explicit_version end def self.variable_hash(match) { match[:varname] => match[:value] } end end end end end