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
|
require 'spec_helper'
RSpec.describe('Group parsing') do
include_examples 'parse', /(?=abc)(?!def)/,
0 => [:assertion, :lookahead, Assertion::Lookahead],
1 => [:assertion, :nlookahead, Assertion::NegativeLookahead]
include_examples 'parse', /(?<=abc)(?<!def)/,
0 => [:assertion, :lookbehind, Assertion::Lookbehind],
1 => [:assertion, :nlookbehind, Assertion::NegativeLookbehind]
include_examples 'parse', /a(?# is for apple)b(?# for boy)c(?# cat)/,
1 => [:group, :comment, Group::Comment],
3 => [:group, :comment, Group::Comment],
5 => [:group, :comment, Group::Comment]
if ruby_version_at_least('2.4.1')
include_examples 'parse', 'a(?~b)c(?~d)e',
1 => [:group, :absence, Group::Absence],
3 => [:group, :absence, Group::Absence]
end
include_examples 'parse', /(?m:a)/,
0 => [:group, :options, Group::Options, options: { m: true }, option_changes: { m: true }]
# self-defeating group option
include_examples 'parse', /(?m-m:a)/,
0 => [:group, :options, Group::Options, options: {}, option_changes: { m: false }]
# activate one option in nested group
include_examples 'parse', /(?x-mi:a(?m:b))/,
0 => [:group, :options, Group::Options, options: { x: true }, option_changes: { i: false, m: false, x: true }],
[0, 1] => [:group, :options, Group::Options, options: { m: true, x: true }, option_changes: { m: true }]
# deactivate one option in nested group
include_examples 'parse', /(?ix-m:a(?-i:b))/,
0 => [:group, :options, Group::Options, options: { i: true, x: true }, option_changes: { i: true, m: false, x: true }],
[0, 1] => [:group, :options, Group::Options, options: { x: true }, option_changes: { i: false }]
# invert all options in nested group
include_examples 'parse', /(?xi-m:a(?m-ix:b))/,
0 => [:group, :options, Group::Options, options: { i: true, x: true }, option_changes: { i: true, m: false, x: true }],
[0, 1] => [:group, :options, Group::Options, options: { m: true }, option_changes: { i: false, m: true, x: false }]
# nested options affect literal subexpressions
include_examples 'parse', /(?x-mi:a(?m:b))/,
[0, 0] => [:literal, :literal, Literal, text: 'a', options: { x: true }],
[0, 1, 0] => [:literal, :literal, Literal, text: 'b', options: { m: true, x: true }]
# option switching group
include_examples 'parse', /a(?i-m)b/m,
0 => [:literal, :literal, Literal, text: 'a', options: { m: true }],
1 => [:group, :options_switch, Group::Options, options: { i: true }, option_changes: { i: true, m: false }],
2 => [:literal, :literal, Literal, text: 'b', options: { i: true }]
# option switch in group
include_examples 'parse', /(a(?i-m)b)c/m,
0 => [:group, :capture, Group::Capture, options: { m: true }],
[0, 0] => [:literal, :literal, Literal, text: 'a', options: { m: true }],
[0, 1] => [:group, :options_switch, Group::Options, options: { i: true }, option_changes: { i: true, m: false }],
[0, 2] => [:literal, :literal, Literal, text: 'b', options: { i: true }],
1 => [:literal, :literal, Literal, text: 'c', options: { m: true }]
# nested option switch in group
include_examples 'parse', /((?i-m)(a(?-i)b))/m,
[0, 1] => [:group, :capture, Group::Capture, options: { i: true }],
[0, 1, 0] => [:literal, :literal, Literal, text: 'a', options: { i: true }],
[0, 1, 1] => [:group, :options_switch, Group::Options, options: {}, option_changes: { i: false }],
[0, 1, 2] => [:literal, :literal, Literal, text: 'b', options: {}]
# options dau
include_examples 'parse', /(?dua:abc)/,
0 => [:group, :options, Group::Options, options: { a: true }, option_changes: { a: true }]
# nested options dau
include_examples 'parse', /(?u:a(?d:b))/,
0 => [:group, :options, Group::Options, options: { u: true }, option_changes: { u: true }],
[0, 1] => [:group, :options, Group::Options, options: { d: true }, option_changes: { d: true, u: false }],
[0, 1, 0] => [:literal, :literal, Literal, text: 'b', options: { d: true }]
# nested options da
include_examples 'parse', /(?di-xm:a(?da-x:b))/,
0 => [:group, :options, Group::Options, options: { d: true, i:true }],
[0, 1] => [:group, :options, Group::Options, options: { a: true, i: true }, option_changes: { a: true, d: false, x: false}],
[0, 1, 0] => [:literal, :literal, Literal, text: 'b', options: { a: true, i: true }]
specify('parse group number') do
root = RP.parse(/(a)(?=b)((?:c)(d|(e)))/)
expect(root.dig(0).number).to eq 1
expect(root.dig(1)).not_to respond_to(:number)
expect(root.dig(2).number).to eq 2
expect(root.dig(2, 0)).not_to respond_to(:number)
expect(root.dig(2, 1).number).to eq 3
expect(root.dig(2, 1, 0, 1, 0).number).to eq 4
end
specify('parse group number at level') do
root = RP.parse(/(a)(?=b)((?:c)(d|(e)))/)
expect(root.dig(0).number_at_level).to eq 1
expect(root.dig(1)).not_to respond_to(:number_at_level)
expect(root.dig(2).number_at_level).to eq 2
expect(root.dig(2, 0)).not_to respond_to(:number_at_level)
expect(root.dig(2, 1).number_at_level).to eq 1
expect(root.dig(2, 1, 0, 1, 0).number_at_level).to eq 1
end
specify('parse invalid option switch quantification') do
expect { RP.parse('a(?i)+') }.to raise_error(/Can not quantify/)
expect { RP.parse('a(?i)*') }.to raise_error(/Can not quantify/)
expect { RP.parse('a(?i)?') }.to raise_error(/Can not quantify/)
expect { RP.parse('a(?i){5}') }.to raise_error(/Can not quantify/)
end
end
|