# File lib/asciidoctor/substitutors.rb, line 84
  def apply_subs source, subs = NORMAL_SUBS, expand = nil
    if source.empty? || !subs
      return source
    elsif expand
      if ::Symbol === subs
        subs = SUB_GROUPS[subs] || [subs]
      else
        effective_subs = []
        subs.each do |key|
          if (sub_group = SUB_GROUPS[key])
            effective_subs += sub_group unless sub_group.empty?
          else
            effective_subs << key
          end
        end

        if (subs = effective_subs).empty?
          return source
        end
      end
    elsif subs.empty?
      return source
    end

    text = (multiline = ::Array === source) ? source * LF : source

    if (has_passthroughs = subs.include? :macros)
      text = extract_passthroughs text
      has_passthroughs = false if @passthroughs.empty?
    end

    subs.each do |type|
      case type
      when :specialcharacters
        text = sub_specialchars text
      when :quotes
        text = sub_quotes text
      when :attributes
        text = sub_attributes(text.split LF, -1) * LF if text.include? ATTR_REF_HEAD
      when :replacements
        text = sub_replacements text
      when :macros
        text = sub_macros text
      when :highlight
        text = highlight_source text, (subs.include? :callouts)
      when :callouts
        text = sub_callouts text unless subs.include? :highlight
      when :post_replacements
        text = sub_post_replacements text
      else
        warn %(asciidoctor: WARNING: unknown substitution type #{type})
      end
    end
    text = restore_passthroughs text if has_passthroughs

    multiline ? (text.split LF, -1) : text
  end