1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
require 'spec_helper'
RSpec.describe('Expression::Base#options') do
it 'returns a hash of options/flags that affect the expression' do
exp = RP.parse(/a/ix)[0]
expect(exp).to be_a Literal
expect(exp.options).to eq(i: true, x: true)
end
it 'includes options that are locally enabled via special groups' do
exp = RP.parse(/(?x)(?m:a)/i)[1][0]
expect(exp).to be_a Literal
expect(exp.options).to eq(i: true, m: true, x: true)
end
it 'excludes locally disabled options' do
exp = RP.parse(/(?x)(?-im:a)/i)[1][0]
expect(exp).to be_a Literal
expect(exp.options).to eq(x: true)
end
it 'gives correct precedence to negative options' do
# Negative options have precedence. E.g. /(?i-i)a/ is case-sensitive.
regexp = /(?i-i:a)/
expect(regexp).to match 'a'
expect(regexp).not_to match 'A'
exp = RP.parse(regexp)[0][0]
expect(exp).to be_a Literal
expect(exp.options).to eq({})
end
it 'correctly handles multiple negative option parts' do
regexp = /(?--m--mx--) . /mx
expect(regexp).to match ' . '
expect(regexp).not_to match '.'
expect(regexp).not_to match "\n"
exp = RP.parse(regexp)[2]
expect(exp.options).to eq({})
end
it 'gives correct precedence when encountering multiple encoding flags' do
# Any encoding flag overrides all previous encoding flags. If there are
# multiple encoding flags in an options string, the last one wins.
# E.g. /(?dau)\w/ matches UTF8 chars but /(?dua)\w/ only ASCII chars.
regexp1 = /(?dau)\w/
regexp2 = /(?dua)\w/
expect(regexp1).to match 'ü'
expect(regexp2).not_to match 'ü'
exp1 = RP.parse(regexp1)[1]
exp2 = RP.parse(regexp2)[1]
expect(exp1.options).to eq(u: true)
expect(exp2.options).to eq(a: true)
end
it 'is accessible via shortcuts' do
exp = Root.construct
expect { exp.options[:i] = true }
.to change { exp.i? }.from(false).to(true)
.and change { exp.ignore_case? }.from(false).to(true)
.and change { exp.case_insensitive? }.from(false).to(true)
expect { exp.options[:m] = true }
.to change { exp.m? }.from(false).to(true)
.and change { exp.multiline? }.from(false).to(true)
expect { exp.options[:x] = true }
.to change { exp.x? }.from(false).to(true)
.and change { exp.extended? }.from(false).to(true)
.and change { exp.free_spacing? }.from(false).to(true)
expect { exp.options[:a] = true }
.to change { exp.a? }.from(false).to(true)
.and change { exp.ascii_classes? }.from(false).to(true)
expect { exp.options[:d] = true }
.to change { exp.d? }.from(false).to(true)
.and change { exp.default_classes? }.from(false).to(true)
expect { exp.options[:u] = true }
.to change { exp.u? }.from(false).to(true)
.and change { exp.unicode_classes? }.from(false).to(true)
end
include_examples 'parse', //i, [] => [:root, i?: true, x?: false]
include_examples 'parse', /a/i, [0] => [:literal, i?: true, x?: false]
include_examples 'parse', /\A/i, [0] => [:bos, i?: true, x?: false]
include_examples 'parse', /\d/i, [0] => [:digit, i?: true, x?: false]
include_examples 'parse', /\n/i, [0] => [:newline, i?: true, x?: false]
include_examples 'parse', /\K/i, [0] => [:mark, i?: true, x?: false]
include_examples 'parse', /./i, [0] => [:dot, i?: true, x?: false]
include_examples 'parse', /(a)/i, [0] => [:capture, i?: true, x?: false]
include_examples 'parse', /(a)/i, [0, 0] => [:literal, i?: true, x?: false]
include_examples 'parse', /(?=a)/i, [0] => [:lookahead, i?: true, x?: false]
include_examples 'parse', /(?=a)/i, [0, 0] => [:literal, i?: true, x?: false]
include_examples 'parse', /(a|b)/i, [0] => [:capture, i?: true, x?: false]
include_examples 'parse', /(a|b)/i, [0, 0] => [:alternation, i?: true, x?: false]
include_examples 'parse', /(a|b)/i, [0, 0, 0] => [:sequence, i?: true, x?: false]
include_examples 'parse', /(a|b)/i, [0, 0, 0, 0] => [:literal, i?: true, x?: false]
include_examples 'parse', /(a)\1/i, [1] => [:number, i?: true, x?: false]
include_examples 'parse', /(a)\k<1>/i, [1] => [:number_ref, i?: true, x?: false]
include_examples 'parse', /(a)\g<1>/i, [1] => [:number_call, i?: true, x?: false]
include_examples 'parse', /[a]/i, [0] => [:character, i?: true, x?: false]
include_examples 'parse', /[a]/i, [0, 0] => [:literal, i?: true, x?: false]
include_examples 'parse', /[a-z]/i, [0, 0] => [:range, i?: true, x?: false]
include_examples 'parse', /[a-z]/i, [0, 0, 0] => [:literal, i?: true, x?: false]
include_examples 'parse', /[a&&z]/i, [0, 0] => [:intersection, i?: true, x?: false]
include_examples 'parse', /[a&&z]/i, [0, 0, 0, 0] => [:literal, i?: true, x?: false]
include_examples 'parse', /[[:ascii:]]/i, [0, 0] => [:ascii, i?: true, x?: false]
include_examples 'parse', /\p{word}/i, [0] => [:word, i?: true, x?: false]
include_examples 'parse', /(a)(?(1)b|c)/i, [1] => [:open, i?: true, x?: false]
include_examples 'parse', /(a)(?(1)b|c)/i, [1, 0] => [:condition, i?: true, x?: false]
include_examples 'parse', /(a)(?(1)b|c)/i, [1, 1] => [:sequence, i?: true, x?: false]
include_examples 'parse', /(a)(?(1)b|c)/i, [1, 1, 0] => [:literal, i?: true, x?: false]
end
|