# File lib/asciidoctor/reader.rb, line 695
  def preprocess_conditional_inclusion directive, target, delimiter, text
    # must have a target before brackets if ifdef or ifndef
    # must not have text between brackets if endif
    # don't honor match if it doesn't meet this criteria
    # QUESTION should we warn for these bogus declarations?
    if ((directive == 'ifdef' || directive == 'ifndef') && target.empty?) ||
        (directive == 'endif' && text)
      return false
    end

    # attributes are case insensitive
    target = target.downcase

    if directive == 'endif'
      stack_size = @conditional_stack.size
      if stack_size > 0
        pair = @conditional_stack[-1]
        if target.empty? || target == pair[: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
      else
        warn %(asciidoctor: ERROR: #{line_info}: unmatched macro: endif::#{target}[])
      end
      return true
    end

    skip = false
    unless @skipping
      # QUESTION any way to wrap ifdef & ifndef logic up together?
      case directive
      when 'ifdef'
        case delimiter
        when nil
          # if the attribute is undefined, then skip
          skip = !@document.attributes.has_key?(target)
        when ','
          # if any attribute is defined, then don't skip
          skip = !target.split(',').detect {|name| @document.attributes.has_key? name }
        when '+'
          # if any attribute is undefined, then skip
          skip = target.split('+').detect {|name| !@document.attributes.has_key? name }
        end
      when 'ifndef'
        case delimiter
        when nil
          # if the attribute is defined, then skip
          skip = @document.attributes.has_key?(target)
        when ','
          # if any attribute is undefined, then don't skip
          skip = !target.split(',').detect {|name| !@document.attributes.has_key? name }
        when '+'
          # if any attribute is defined, then skip
          skip = target.split('+').detect {|name| @document.attributes.has_key? name }
        end
      when 'ifeval'
        # the text in brackets must match an expression
        # don't honor match if it doesn't meet this criteria
        if !target.empty? || !(expr_match = EvalExpressionRx.match(text.strip))
          return false
        end

        lhs = resolve_expr_val expr_match[1]
        rhs = resolve_expr_val expr_match[3]

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

    # conditional inclusion block
    if directive == 'ifeval' || !text
      @skipping = true if skip
      @conditional_stack << {:target => target, :skip => skip, :skipping => @skipping}
    # single line conditional inclusion
    else
      unless @skipping || skip
        # FIXME slight hack to skip past conditional line
        # but keep our synthetic line marked as processed
        # QUESTION can we use read_line true and unshift twice instead?
        conditional_line = peek_line true
        replace_next_line text.rstrip
        unshift conditional_line
        return true
      end
    end

    true
  end