srl_ruby 0.4.13 → 0.4.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +17 -0
- data/CHANGELOG.md +6 -0
- data/bin/srl2ruby +1 -1
- data/lib/srl_ruby/tokenizer.rb +10 -10
- data/lib/srl_ruby/version.rb +1 -1
- data/spec/acceptance/srl_test_suite_spec.rb +17 -17
- data/spec/acceptance/support/rule_file_tokenizer.rb +1 -1
- data/spec/regex/atomic_expression_spec.rb +13 -13
- data/spec/regex/character_spec.rb +39 -39
- data/spec/regex/match_option_spec.rb +10 -9
- data/spec/regex/monadic_expression_spec.rb +14 -13
- data/spec/regex/multiplicity_spec.rb +10 -10
- data/spec/regex/repetition_spec.rb +10 -9
- data/spec/srl_ruby/srl_ruby_spec.rb +1 -1
- data/spec/srl_ruby/tokenizer_spec.rb +45 -45
- data/spec/srl_ruby_spec.rb +129 -129
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa7a9699a1a4f26e820e1523d4f6d3fa186cd814afeb5b41e164ea191df7303b
|
4
|
+
data.tar.gz: 0f4b1c7de0da2ed0a1acf1f2a700271d35afc383b5d9eeec0d790993f9d8928b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 972f392c2817101f0bffcc688b867060f19da7c258e5b0bd2fb2061a602df6d0c8f00df85be855bc6bb2cc24b8bd1c1994fac00d06a7ca9b1fe353277acbd21f
|
7
|
+
data.tar.gz: 7b8e2065d771a5ae84051bc7633d09ea6ed7dcb781b277fd47118b3796cf5a2f7f4d1fe44e29b5acf65303902e8c9a1b9b4f7692b8c9b4079c47115258450870
|
data/.rubocop.yml
CHANGED
@@ -184,3 +184,20 @@ Style/TernaryParentheses:
|
|
184
184
|
|
185
185
|
Style/UnlessElse:
|
186
186
|
Enabled: false
|
187
|
+
|
188
|
+
#RSpec/ContextWording:
|
189
|
+
# Enabled: false
|
190
|
+
#
|
191
|
+
#RSpec/ExampleLength:
|
192
|
+
# Max: 40
|
193
|
+
#
|
194
|
+
#RSpec/MultipleExpectations:
|
195
|
+
# Max: 15
|
196
|
+
#
|
197
|
+
#RSpec/NoExpectationExample:
|
198
|
+
# Enabled: false
|
199
|
+
#
|
200
|
+
#RSpec/RepeatedDescription:
|
201
|
+
# Enabled: false
|
202
|
+
|
203
|
+
|
data/CHANGELOG.md
CHANGED
data/bin/srl2ruby
CHANGED
data/lib/srl_ruby/tokenizer.rb
CHANGED
@@ -17,15 +17,15 @@ module SrlRuby
|
|
17
17
|
# Delimiters: parentheses '(' and ')'
|
18
18
|
# Separators: comma (optional)
|
19
19
|
class Tokenizer
|
20
|
-
PATT_CHAR_CLASS = /[^,"\s]{2,}
|
21
|
-
PATT_DIGIT_LIT = /[0-9]((?=\s|,|\))|$)
|
22
|
-
PATT_IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_]
|
23
|
-
PATT_INTEGER = /[0-9]{2,}((?=\s|,|\))|$)
|
24
|
-
PATT_LETTER_LIT = /[a-zA-Z]((?=\s|,|\))|$)
|
25
|
-
PATT_NEWLINE = /(?:\r\n)|\r|\n
|
26
|
-
PATT_STR_DBL_QUOTE = /"(?:\\"|[^"])*"
|
27
|
-
PATT_STR_SNGL_QUOTE = /'(?:\\'|[^'])*'
|
28
|
-
PATT_WHITESPACE = /[ \t\f]
|
20
|
+
PATT_CHAR_CLASS = /[^,"\s]{2,}/
|
21
|
+
PATT_DIGIT_LIT = /[0-9]((?=\s|,|\))|$)/
|
22
|
+
PATT_IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_]+/
|
23
|
+
PATT_INTEGER = /[0-9]{2,}((?=\s|,|\))|$)/ # An integer has 2..* digits
|
24
|
+
PATT_LETTER_LIT = /[a-zA-Z]((?=\s|,|\))|$)/
|
25
|
+
PATT_NEWLINE = /(?:\r\n)|\r|\n/
|
26
|
+
PATT_STR_DBL_QUOTE = /"(?:\\"|[^"])*"/ # Double quotes literal?
|
27
|
+
PATT_STR_SNGL_QUOTE = /'(?:\\'|[^'])*'/ # Single quotes literal?
|
28
|
+
PATT_WHITESPACE = /[ \t\f]+/
|
29
29
|
|
30
30
|
# @return [StringScanner]
|
31
31
|
attr_reader(:scanner)
|
@@ -100,7 +100,7 @@ module SrlRuby
|
|
100
100
|
WHITESPACE
|
101
101
|
WITH
|
102
102
|
WORD
|
103
|
-
].
|
103
|
+
].to_h { |x| [x, x] }
|
104
104
|
|
105
105
|
class ScanError < StandardError; end
|
106
106
|
|
data/lib/srl_ruby/version.rb
CHANGED
@@ -24,7 +24,7 @@ RSpec.describe SrlRuby do
|
|
24
24
|
def test_rule_file(aRuleFileRepr)
|
25
25
|
regex = SrlRuby::parse(aRuleFileRepr.srl.value)
|
26
26
|
# puts regex.source
|
27
|
-
expect(regex).to
|
27
|
+
expect(regex).to be_a(Regexp)
|
28
28
|
|
29
29
|
aRuleFileRepr.match_tests.each do |test|
|
30
30
|
expect(test.test_string.value).to match(regex)
|
@@ -47,7 +47,7 @@ RSpec.describe SrlRuby do
|
|
47
47
|
cp_test.expectations.each do |expec|
|
48
48
|
expected_name = expec.var_name.value.to_s
|
49
49
|
unless actual_names.empty?
|
50
|
-
expect(actual_names).to
|
50
|
+
expect(actual_names).to include(expected_name)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -68,77 +68,77 @@ RSpec.describe SrlRuby do
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
it '
|
71
|
+
it 'matches a backslash' do
|
72
72
|
rule_file_repr = load_file('backslash.rule')
|
73
73
|
test_rule_file(rule_file_repr)
|
74
74
|
end
|
75
75
|
|
76
|
-
it '
|
76
|
+
it 'supports named capture group' do
|
77
77
|
rule_file_repr = load_file('basename_capture_group.rule')
|
78
78
|
test_rule_file(rule_file_repr)
|
79
79
|
end
|
80
80
|
|
81
|
-
it '
|
81
|
+
it 'matches uppercase letter(s)' do
|
82
82
|
rule_file_repr = load_file('issue_17_uppercase_letter.rule')
|
83
83
|
test_rule_file(rule_file_repr)
|
84
84
|
end
|
85
85
|
|
86
|
-
it '
|
86
|
+
it "doesn't trim literal strings" do
|
87
87
|
rule_file_repr = load_file('literally_spaces.rule')
|
88
88
|
test_rule_file(rule_file_repr)
|
89
89
|
end
|
90
90
|
|
91
|
-
it '
|
91
|
+
it 'supports non word boundary' do
|
92
92
|
rule_file_repr = load_file('no_word.rule')
|
93
93
|
test_rule_file(rule_file_repr)
|
94
94
|
end
|
95
95
|
|
96
|
-
it '
|
96
|
+
it 'matches non digit pattern' do
|
97
97
|
rule_file_repr = load_file('nondigit.rule')
|
98
98
|
test_rule_file(rule_file_repr)
|
99
99
|
end
|
100
100
|
|
101
|
-
it '
|
101
|
+
it 'supports negative character class' do
|
102
102
|
rule_file_repr = load_file('none_of.rule')
|
103
103
|
test_rule_file(rule_file_repr)
|
104
104
|
end
|
105
105
|
|
106
|
-
it '
|
106
|
+
it 'supports negative character class' do
|
107
107
|
rule_file_repr = load_file('sample_capture.rule')
|
108
108
|
test_rule_file(rule_file_repr)
|
109
109
|
end
|
110
110
|
|
111
|
-
it '
|
111
|
+
it 'matches a tab' do
|
112
112
|
rule_file_repr = load_file('tab.rule')
|
113
113
|
test_rule_file(rule_file_repr)
|
114
114
|
end
|
115
115
|
|
116
|
-
it '
|
116
|
+
it 'matches mail address' do
|
117
117
|
rule_file_repr = load_file('website_example_email.rule')
|
118
118
|
test_rule_file(rule_file_repr)
|
119
119
|
end
|
120
120
|
|
121
|
-
it '
|
121
|
+
it 'matches mail address' do
|
122
122
|
rule_file_repr = load_file('website_example_email_capture.rule')
|
123
123
|
test_rule_file(rule_file_repr)
|
124
124
|
end
|
125
125
|
|
126
|
-
it '
|
126
|
+
it 'supports lookahead' do
|
127
127
|
rule_file_repr = load_file('website_example_lookahead.rule')
|
128
128
|
test_rule_file(rule_file_repr)
|
129
129
|
end
|
130
130
|
|
131
|
-
it '
|
131
|
+
it "doesn't trim literal strings" do
|
132
132
|
rule_file_repr = load_file('website_example_password.rule')
|
133
133
|
test_rule_file(rule_file_repr)
|
134
134
|
end
|
135
135
|
|
136
|
-
it '
|
136
|
+
it 'processes an URL' do
|
137
137
|
rule_file_repr = load_file('website_example_url.rule')
|
138
138
|
test_rule_file(rule_file_repr)
|
139
139
|
end
|
140
140
|
|
141
|
-
it '
|
141
|
+
it 'matches a word boundary' do
|
142
142
|
rule_file_repr = load_file('word.rule')
|
143
143
|
test_rule_file(rule_file_repr)
|
144
144
|
end
|
@@ -7,30 +7,30 @@ require_relative '../../lib/regex/atomic_expression'
|
|
7
7
|
# Reopen the module, in order to get rid of fully qualified names
|
8
8
|
module Regex # This module is used as a namespace
|
9
9
|
describe AtomicExpression do
|
10
|
-
subject {
|
10
|
+
subject(:atomic_expr) { described_class.new }
|
11
11
|
|
12
12
|
context 'Creation & initialisation' do
|
13
|
-
it '
|
14
|
-
expect {
|
13
|
+
it 'is created without argument' do
|
14
|
+
expect { described_class.new }.not_to raise_error
|
15
15
|
end
|
16
16
|
|
17
|
-
it '
|
18
|
-
expect(
|
17
|
+
it 'knows that it is atomic' do
|
18
|
+
expect(atomic_expr).to be_atomic
|
19
19
|
end
|
20
20
|
end # context
|
21
21
|
|
22
22
|
context 'Provided services' do
|
23
|
-
it '
|
24
|
-
pre_snapshot = Marshal.dump(
|
25
|
-
expect {
|
26
|
-
post_snapshot = Marshal.dump(
|
23
|
+
it 'is unchanged by a done! notification' do
|
24
|
+
pre_snapshot = Marshal.dump(atomic_expr)
|
25
|
+
expect { atomic_expr.done! }.not_to raise_error
|
26
|
+
post_snapshot = Marshal.dump(atomic_expr)
|
27
27
|
expect(post_snapshot).to eq(pre_snapshot)
|
28
28
|
end
|
29
29
|
|
30
|
-
it '
|
31
|
-
pre_snapshot = Marshal.dump(
|
32
|
-
expect {
|
33
|
-
post_snapshot = Marshal.dump(
|
30
|
+
it 'is unchanged by a lazy! notification' do
|
31
|
+
pre_snapshot = Marshal.dump(atomic_expr)
|
32
|
+
expect { atomic_expr.lazy! }.not_to raise_error
|
33
|
+
post_snapshot = Marshal.dump(atomic_expr)
|
34
34
|
expect(post_snapshot).to eq(pre_snapshot)
|
35
35
|
end
|
36
36
|
end # context
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# File:
|
3
|
+
# File: described_class_spec.rb
|
4
4
|
require_relative '../spec_helper' # Use the RSpec test framework
|
5
5
|
require_relative '../../lib/regex/character'
|
6
6
|
|
@@ -8,13 +8,13 @@ module Regex # Open this namespace, to get rid of scope qualifiers
|
|
8
8
|
describe Character do
|
9
9
|
# rubocop: disable Lint/ConstantDefinitionInBlock
|
10
10
|
|
11
|
-
# This constant holds an arbitrary selection of
|
11
|
+
# This constant holds an arbitrary selection of described_classs
|
12
12
|
SampleChars = [?a, ?\0, ?\u0107].freeze
|
13
13
|
|
14
|
-
# This constant holds the codepoints of the
|
14
|
+
# This constant holds the codepoints of the described_class selection
|
15
15
|
SampleInts = [0x61, 0, 0x0107].freeze
|
16
16
|
|
17
|
-
# This constant holds an arbitrary selection of two
|
17
|
+
# This constant holds an arbitrary selection of two described_classs (digrams)
|
18
18
|
# escape sequences
|
19
19
|
SampleDigrams = %w[\n \e \0 \6 \k].freeze
|
20
20
|
|
@@ -28,63 +28,63 @@ module Regex # Open this namespace, to get rid of scope qualifiers
|
|
28
28
|
end
|
29
29
|
|
30
30
|
context 'Creation & initialization' do
|
31
|
-
it '
|
31
|
+
it 'is created with a with an integer value (codepoint) or...' do
|
32
32
|
SampleInts.each do |codepoint|
|
33
|
-
expect {
|
33
|
+
expect { described_class.new(codepoint) }.not_to raise_error
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
it '...
|
37
|
+
it '... is created with a single described_class String or...' do
|
38
38
|
SampleChars.each do |ch|
|
39
|
-
expect {
|
39
|
+
expect { described_class.new(ch) }.not_to raise_error
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
it '...
|
43
|
+
it '... is created with an escape sequence' do
|
44
44
|
# Case 1: escape sequence is a digram
|
45
45
|
SampleDigrams.each do |escape_seq|
|
46
|
-
expect {
|
46
|
+
expect { described_class.new(escape_seq) }.not_to raise_error
|
47
47
|
end
|
48
48
|
|
49
49
|
# Case 2: escape sequence is an escaped octal or hexadecimal literal
|
50
50
|
SampleNumEscs.each do |escape_seq|
|
51
|
-
expect {
|
51
|
+
expect { described_class.new(escape_seq) }.not_to raise_error
|
52
52
|
end
|
53
53
|
end
|
54
54
|
end # context
|
55
55
|
|
56
56
|
# rubocop: disable Style/DocumentDynamicEvalDefinition
|
57
57
|
context 'Provided services' do
|
58
|
-
it '
|
59
|
-
# Lexeme is defined when the
|
58
|
+
it 'knows its lexeme if created from a string' do
|
59
|
+
# Lexeme is defined when the described_class was initialised from a text
|
60
60
|
SampleChars.each do |ch|
|
61
|
-
ch =
|
61
|
+
ch = described_class.new(ch)
|
62
62
|
expect(ch.lexeme).to eq(ch)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
it '
|
66
|
+
it 'does not know its lexeme representation from a codepoint' do
|
67
67
|
SampleInts.each do |ch|
|
68
|
-
ch =
|
68
|
+
ch = described_class.new(ch)
|
69
69
|
expect(ch.lexeme).to be_nil
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
it '
|
74
|
-
# Try for one
|
75
|
-
newOne =
|
73
|
+
it 'knows its String representation' do
|
74
|
+
# Try for one described_class
|
75
|
+
newOne = described_class.new(?\u03a3)
|
76
76
|
expect(newOne.char).to eq('Σ')
|
77
77
|
expect(newOne.to_str).to eq("\u03A3")
|
78
78
|
|
79
79
|
# Try with our chars sample
|
80
80
|
SampleChars.each do |ch|
|
81
|
-
new_ch =
|
81
|
+
new_ch = described_class.new(ch).to_str
|
82
82
|
new_ch == ch
|
83
83
|
end
|
84
84
|
|
85
85
|
# Try with our codepoint sample
|
86
86
|
mapped_chars = SampleInts.map do |codepoint|
|
87
|
-
|
87
|
+
described_class.new(codepoint).char
|
88
88
|
end
|
89
89
|
expect(mapped_chars).to eq(SampleChars)
|
90
90
|
|
@@ -92,32 +92,32 @@ module Regex # Open this namespace, to get rid of scope qualifiers
|
|
92
92
|
(SampleDigrams + SampleNumEscs).each do |escape_seq|
|
93
93
|
# Build a string from escape sequence literal
|
94
94
|
expectation = String.class_eval(%Q|"#{escape_seq}"|, __FILE__, __LINE__)
|
95
|
-
new_ch =
|
95
|
+
new_ch = described_class.new(escape_seq).to_str
|
96
96
|
new_ch == expectation
|
97
97
|
end
|
98
98
|
end
|
99
99
|
|
100
|
-
it '
|
101
|
-
# Try for one
|
102
|
-
newOne =
|
100
|
+
it 'knows its codepoint' do
|
101
|
+
# Try for one described_class
|
102
|
+
newOne = described_class.new(?\u03a3)
|
103
103
|
expect(newOne.codepoint).to eq(0x03a3)
|
104
104
|
|
105
105
|
# Try with our chars sample
|
106
106
|
allCodepoints = SampleChars.map do |ch|
|
107
|
-
|
107
|
+
described_class.new(ch).codepoint
|
108
108
|
end
|
109
109
|
expect(allCodepoints).to eq(SampleInts)
|
110
110
|
|
111
111
|
# Try with our codepoint sample
|
112
112
|
SampleInts.each do |codepoint|
|
113
|
-
expect(
|
113
|
+
expect(described_class.new(codepoint).codepoint).to eq(codepoint)
|
114
114
|
end
|
115
115
|
|
116
116
|
# Try with our escape sequence samples
|
117
117
|
(SampleDigrams + SampleNumEscs).each do |escape_seq|
|
118
118
|
# Get ordinal value of given escape sequence
|
119
119
|
expectation = String.class_eval(%Q|"#{escape_seq}".ord()|, __FILE__, __LINE__)
|
120
|
-
expect(
|
120
|
+
expect(described_class.new(escape_seq).codepoint).to eq(expectation)
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
@@ -128,26 +128,26 @@ module Regex # Open this namespace, to get rid of scope qualifiers
|
|
128
128
|
end
|
129
129
|
end # module
|
130
130
|
|
131
|
-
it '
|
132
|
-
newOne =
|
131
|
+
it 'knows whether it is equal to another Object' do
|
132
|
+
newOne = described_class.new(?\u03a3)
|
133
133
|
|
134
134
|
# Case 1: test equality with itself
|
135
135
|
expect(newOne).to eq(newOne)
|
136
136
|
|
137
|
-
# Case 2: test equality with another
|
138
|
-
expect(newOne).to eq(
|
139
|
-
expect(newOne).not_to eq(
|
137
|
+
# Case 2: test equality with another described_class
|
138
|
+
expect(newOne).to eq(described_class.new(?\u03a3))
|
139
|
+
expect(newOne).not_to eq(described_class.new(?\u0333))
|
140
140
|
|
141
141
|
# Case 3: test equality with an integer value
|
142
142
|
# (equality based on codepoint value)
|
143
143
|
expect(newOne).to eq(0x03a3)
|
144
144
|
expect(newOne).not_to eq(0x0333)
|
145
145
|
|
146
|
-
# Case 4: test equality with a single-
|
146
|
+
# Case 4: test equality with a single-described_class String
|
147
147
|
expect(newOne).to eq(?\u03a3)
|
148
148
|
expect(newOne).not_to eq(?\u0333)
|
149
149
|
|
150
|
-
# Case 5: test fails with multiple
|
150
|
+
# Case 5: test fails with multiple described_class strings
|
151
151
|
expect(newOne).not_to eq('03a3')
|
152
152
|
|
153
153
|
# Case 6: equality testing with arbitrary object
|
@@ -156,7 +156,7 @@ module Regex # Open this namespace, to get rid of scope qualifiers
|
|
156
156
|
|
157
157
|
# In case 6, equality is based on to_s method.
|
158
158
|
simulator = double('fake')
|
159
|
-
|
159
|
+
allow(simulator).to receive(:to_s).and_return(?\u03a3)
|
160
160
|
expect(newOne).to eq(simulator)
|
161
161
|
|
162
162
|
weird = Object.new
|
@@ -164,11 +164,11 @@ module Regex # Open this namespace, to get rid of scope qualifiers
|
|
164
164
|
expect(newOne).to eq(weird)
|
165
165
|
end
|
166
166
|
|
167
|
-
it '
|
168
|
-
ch1 =
|
167
|
+
it 'knows its readable description' do
|
168
|
+
ch1 = described_class.new('a')
|
169
169
|
expect(ch1.explain).to eq("the character 'a'")
|
170
170
|
|
171
|
-
ch2 =
|
171
|
+
ch2 = described_class.new(?\u03a3)
|
172
172
|
expect(ch2.explain).to eq("the character '\u03a3'")
|
173
173
|
end
|
174
174
|
end # context
|
@@ -9,25 +9,26 @@ require_relative '../../lib/regex/match_option'
|
|
9
9
|
module Regex # This module is used as a namespace
|
10
10
|
describe MatchOption do
|
11
11
|
let(:sample_child) { double('fake-child') }
|
12
|
-
|
12
|
+
|
13
|
+
subject(:option) { described_class.new(sample_child, [Regexp::MULTILINE, Regexp::IGNORECASE]) }
|
13
14
|
|
14
15
|
context 'Creation & initialisation' do
|
15
|
-
it '
|
16
|
-
expect {
|
16
|
+
it 'is created with a child and flags' do
|
17
|
+
expect { described_class.new(sample_child, []) }.not_to raise_error
|
17
18
|
end
|
18
19
|
|
19
|
-
it '
|
20
|
-
expect(
|
20
|
+
it 'Knows its child' do
|
21
|
+
expect(option.child).to eq(sample_child)
|
21
22
|
end
|
22
23
|
|
23
|
-
it '
|
24
|
-
expect(
|
24
|
+
it 'Knows its flags' do
|
25
|
+
expect(option.flags).to eq([Regexp::MULTILINE, Regexp::IGNORECASE])
|
25
26
|
end
|
26
27
|
end # context
|
27
28
|
|
28
29
|
context 'Provided services' do
|
29
|
-
it '
|
30
|
-
expect(
|
30
|
+
it 'Combines the flag bits' do
|
31
|
+
expect(option.combine_opts).to eq(Regexp::MULTILINE | Regexp::IGNORECASE)
|
31
32
|
end
|
32
33
|
end # context
|
33
34
|
end # describe
|
@@ -8,31 +8,32 @@ require_relative '../../lib/regex/monadic_expression'
|
|
8
8
|
module Regex # This module is used as a namespace
|
9
9
|
describe MonadicExpression do
|
10
10
|
let(:sample_child) { double('fake_regex') }
|
11
|
-
|
11
|
+
|
12
|
+
subject(:monadic_expr) { described_class.new(sample_child) }
|
12
13
|
|
13
14
|
context 'Creation & initialisation' do
|
14
|
-
it '
|
15
|
-
expect {
|
15
|
+
it 'is created with a child expression' do
|
16
|
+
expect { described_class.new(sample_child) }.not_to raise_error
|
16
17
|
end
|
17
18
|
|
18
|
-
it '
|
19
|
-
expect(
|
19
|
+
it 'Knows its child' do
|
20
|
+
expect(monadic_expr.child).to eq(sample_child)
|
20
21
|
end
|
21
22
|
|
22
|
-
it '
|
23
|
-
expect(
|
23
|
+
it 'Know that it is not atomic' do
|
24
|
+
expect(monadic_expr).not_to be_atomic
|
24
25
|
end
|
25
26
|
end # context
|
26
27
|
|
27
28
|
context 'Provided services' do
|
28
|
-
it '
|
29
|
-
|
30
|
-
expect {
|
29
|
+
it 'Propagates done! notification' do
|
30
|
+
allow(sample_child).to receive(:done!)
|
31
|
+
expect { monadic_expr.done! }.not_to raise_error
|
31
32
|
end
|
32
33
|
|
33
|
-
it '
|
34
|
-
|
35
|
-
expect {
|
34
|
+
it 'is unchanged by a lazy! notification' do
|
35
|
+
allow(sample_child).to receive(:lazy!)
|
36
|
+
expect { monadic_expr.lazy! }.not_to raise_error
|
36
37
|
end
|
37
38
|
end # context
|
38
39
|
end # describe
|
@@ -9,39 +9,39 @@ require_relative '../../lib/regex/multiplicity'
|
|
9
9
|
module Regex # This module is used as a namespace
|
10
10
|
describe Multiplicity do
|
11
11
|
context 'Creation & initialisation' do
|
12
|
-
it '
|
12
|
+
it 'is created with 3 arguments' do
|
13
13
|
# Valid cases: initialized with two integer values and a policy symbol
|
14
14
|
%i[greedy lazy possessive].each do |policy|
|
15
|
-
expect {
|
15
|
+
expect { described_class.new(0, 1, policy) }.not_to raise_error
|
16
16
|
end
|
17
17
|
|
18
18
|
# Invalid case: initialized with invalid policy value
|
19
19
|
err = StandardError
|
20
20
|
msg = "Invalid repetition policy 'KO'."
|
21
|
-
expect {
|
21
|
+
expect { described_class.new(0, :more, 'KO') }.to raise_error(err, msg)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
25
|
context 'Provided services' do
|
26
26
|
# rubocop: disable Style/CombinableLoops
|
27
|
-
it '
|
27
|
+
it 'Knows its text representation' do
|
28
28
|
policy2text = { greedy: '', lazy: '?', possessive: '+' }
|
29
29
|
|
30
30
|
# Case: zero or one
|
31
31
|
policy2text.each_key do |policy|
|
32
|
-
multi =
|
32
|
+
multi = described_class.new(0, 1, policy)
|
33
33
|
expect(multi.to_str).to eq("?#{policy2text[policy]}")
|
34
34
|
end
|
35
35
|
|
36
36
|
# Case: zero or more
|
37
37
|
policy2text.each_key do |policy|
|
38
|
-
multi =
|
38
|
+
multi = described_class.new(0, :more, policy)
|
39
39
|
expect(multi.to_str).to eq("*#{policy2text[policy]}")
|
40
40
|
end
|
41
41
|
|
42
42
|
# Case: one or more
|
43
43
|
policy2text.each_key do |policy|
|
44
|
-
multi =
|
44
|
+
multi = described_class.new(1, :more, policy)
|
45
45
|
expect(multi.to_str).to eq("+#{policy2text[policy]}")
|
46
46
|
end
|
47
47
|
|
@@ -49,7 +49,7 @@ module Regex # This module is used as a namespace
|
|
49
49
|
policy2text.each_key do |policy|
|
50
50
|
samples = [1, 2, 5, 100]
|
51
51
|
samples.each do |count|
|
52
|
-
multi =
|
52
|
+
multi = described_class.new(count, count, policy)
|
53
53
|
expect(multi.to_str).to eq("{#{count}}#{policy2text[policy]}")
|
54
54
|
end
|
55
55
|
end
|
@@ -59,7 +59,7 @@ module Regex # This module is used as a namespace
|
|
59
59
|
samples = [1, 2, 5, 100]
|
60
60
|
samples.each do |count|
|
61
61
|
upper = count + 1 + rand(20)
|
62
|
-
multi =
|
62
|
+
multi = described_class.new(count, upper, policy)
|
63
63
|
expectation = "{#{count},#{upper}}#{policy2text[policy]}"
|
64
64
|
expect(multi.to_str).to eq(expectation)
|
65
65
|
end
|
@@ -69,7 +69,7 @@ module Regex # This module is used as a namespace
|
|
69
69
|
policy2text.each_key do |policy|
|
70
70
|
samples = [2, 3, 5, 100]
|
71
71
|
samples.each do |count|
|
72
|
-
multi =
|
72
|
+
multi = described_class.new(count, :more, policy)
|
73
73
|
expect(multi.to_str).to eq("{#{count},}#{policy2text[policy]}")
|
74
74
|
end
|
75
75
|
end
|
@@ -9,23 +9,24 @@ module Regex # This module is used as a namespace
|
|
9
9
|
describe Repetition do
|
10
10
|
let(:optional) { Multiplicity.new(0, 1, :possessive) }
|
11
11
|
let(:sample_child) { double('fake_regex') }
|
12
|
-
|
12
|
+
|
13
|
+
subject(:repetition) { described_class.new(sample_child, optional) }
|
13
14
|
|
14
15
|
context 'Creation & initialisation' do
|
15
|
-
it '
|
16
|
-
expect {
|
16
|
+
it 'is created with a child expression and a multiplicity' do
|
17
|
+
expect { described_class.new(sample_child, optional) }.not_to raise_error
|
17
18
|
end
|
18
19
|
|
19
|
-
it '
|
20
|
-
expect(
|
20
|
+
it 'Knows its multiplicity' do
|
21
|
+
expect(repetition.multiplicity).to eq(optional)
|
21
22
|
end
|
22
23
|
end # context
|
23
24
|
|
24
25
|
context 'Provided services' do
|
25
|
-
it '
|
26
|
-
|
27
|
-
expect {
|
28
|
-
expect(
|
26
|
+
it 'Changes its policy with lazy! notification' do
|
27
|
+
allow(sample_child).to receive(:lazy!)
|
28
|
+
expect { repetition.lazy! }.not_to raise_error
|
29
|
+
expect(repetition.multiplicity.policy).to eq(:lazy)
|
29
30
|
end
|
30
31
|
end # context
|
31
32
|
end # describe
|