# File lib/asciidoctor/reader.rb, line 713
  def preprocess_conditional_directive keyword, target, delimiter, text
    # attributes are case insensitive
    target = target.downcase unless (no_target = target.empty?)

    # must have a target before brackets if ifdef or ifndef
    # must not have text between brackets if endif
    # skip line if it doesn't meet this criteria
    # QUESTION should we warn for these bogus declarations?
    return false if (no_target && (keyword == 'ifdef' || keyword == 'ifndef')) || (text && keyword == 'endif')

    if keyword == 'endif'
      if @conditional_stack.empty?
        warn %(asciidoctor: ERROR: #{line_info}: unmatched macro: endif::#{target}[])
      elsif no_target || target == (pair = @conditional_stack[-1])[:target]
        @conditional_stack.pop
        @skipping = @conditional_stack.empty? ? false : @conditional_stack[-1][:skipping]
      else
        warn %(asciidoctor: ERROR: #{line_info}: mismatched macro: endif::#{target}[], expected endif::#{pair[:target]}[])
      end
      return true
    end

    if @skipping
      skip = false
    else
      # QUESTION any way to wrap ifdef & ifndef logic up together?
      case keyword
      when 'ifdef'
        case delimiter
        when ','
          # skip if no attribute is defined
          skip = target.split(',', -1).none? {|name| @document.attributes.key? name }
        when '+'
          # skip if any attribute is undefined
          skip = target.split('+', -1).any? {|name| !@document.attributes.key? name }
        else
          # if the attribute is undefined, then skip
          skip = !@document.attributes.key?(target)
        end
      when 'ifndef'
        case delimiter
        when ','
          # skip if any attribute is defined
          skip = target.split(',', -1).any? {|name| @document.attributes.key? name }
        when '+'
          # skip if all attributes are defined
          skip = target.split('+', -1).all? {|name| @document.attributes.key? name }
        else
          # if the attribute is defined, then skip
          skip = @document.attributes.key?(target)
        end
      when 'ifeval'
        # the text in brackets must match an expression
        # don't honor match if it doesn't meet this criteria
        return false unless no_target && EvalExpressionRx =~ text.strip

        # NOTE save values eagerly for Ruby 1.8.7 compat
        lhs, op, rhs = $1, $2, $3
        lhs = resolve_expr_val lhs
        rhs = resolve_expr_val rhs

        # regex enforces a restricted set of math-related operations
        if op == '!='
          skip = lhs.send :==, rhs
        else
          skip = !(lhs.send op.to_sym, rhs)
        end
      end
    end

    # conditional inclusion block
    if keyword == 'ifeval' || !text
      @skipping = true if skip
      @conditional_stack << {:target => target, :skip => skip, :skipping => @skipping}
    # single line conditional inclusion
    else
      unless @skipping || skip
        replace_next_line text.rstrip
        # HACK push dummy line to stand in for the opening conditional directive that's subsequently dropped
        unshift ''
        # NOTE force line to be processed again if it looks like an include directive
        # QUESTION should we just call preprocess_include_directive here?
        @look_ahead -= 1 if text.start_with? 'include::'
      end
    end

    true
  end