srl_ruby 0.4.13 → 0.4.15
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 +11 -0
- data/bin/srl2ruby +1 -1
- data/lib/regex/character.rb +9 -9
- data/lib/regex/multiplicity.rb +1 -0
- data/lib/srl_ruby/ast_builder.rb +12 -0
- data/lib/srl_ruby/grammar.rb +1 -1
- data/lib/srl_ruby/tokenizer.rb +37 -10
- data/lib/srl_ruby/version.rb +2 -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
- data/srl_ruby.gemspec +5 -5
- metadata +33 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af00786c71ac6736bb80041630395c02bf7e86a8a15c4601b3010edefadc7d21
|
4
|
+
data.tar.gz: ac70e3dc3bdd7ce80e84e9d2c5c72b3f45d4664fb1d47d4e12e85d57b24c3aa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42229711b0814750b89ed47ff893defbc51ae40463613f85c3c3d82afff577984452eb8039439ebec6813708f892cf657ed338df6170d0ab0acc411a96cc471f
|
7
|
+
data.tar.gz: dd628a6cdd006763a00a5c82950bc5721bf4f9ee6a065b88f29f0dda9a0161bd7e5613dc3379f30479b3866fbca77b454afe2919084a633cc326a5195b3082f4
|
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
@@ -1,3 +1,14 @@
|
|
1
|
+
## [0.4.15] - 2025-03-20
|
2
|
+
- Tested against rley 0.9.02 and rubocop 1.74.0
|
3
|
+
### Changed
|
4
|
+
- File `srl_ruby.gemspec`: make dependencies more lenient
|
5
|
+
|
6
|
+
## [0.4.14] - 2025-02-22
|
7
|
+
- Tested against rubocop-rspec 3.5.0
|
8
|
+
|
9
|
+
### Fixed
|
10
|
+
- Fixed most "offences" reported by rubocop-rspec
|
11
|
+
|
1
12
|
## [0.4.13] - 2025-02-22
|
2
13
|
- Tested against MRI Ruby 3.4.1
|
3
14
|
|
data/bin/srl2ruby
CHANGED
data/lib/regex/character.rb
CHANGED
@@ -41,13 +41,13 @@ module Regex # This module is used as a namespace
|
|
41
41
|
# codepoint value.
|
42
42
|
# Examples:
|
43
43
|
# Initializing with codepoint value...
|
44
|
-
#
|
44
|
+
# Regex::Character.new(0x3a3) # Represents: Σ
|
45
45
|
# (Unicode GREEK CAPITAL LETTER SIGMA)
|
46
|
-
#
|
46
|
+
# Regex::Character.new(931) # Also represents: Σ (931 dec == 3a3 hex)
|
47
47
|
#
|
48
48
|
# Initializing with a single character string
|
49
|
-
#
|
50
|
-
#
|
49
|
+
# Regex::Character.new(?\u03a3) # Also represents: Σ
|
50
|
+
# Regex::Character.new('Σ') # Obviously, represents a Σ
|
51
51
|
#
|
52
52
|
# Initializing with an escape sequence string
|
53
53
|
# Recognized escaped characters are: \a (alarm, 0x07), \n (newline, 0xA),
|
@@ -56,8 +56,8 @@ module Regex # This module is used as a namespace
|
|
56
56
|
# \uXXXX where XXXX is a 4 hex digits integer value, \u{X...}, \ooo (octal)
|
57
57
|
# \xXX (hex)
|
58
58
|
# Any other escaped character will be treated as a literal character
|
59
|
-
#
|
60
|
-
#
|
59
|
+
# Regex::Character.new('\n') # Represents a newline
|
60
|
+
# Regex::Character.new('\u03a3') # Represents a Σ
|
61
61
|
def initialize(aValue)
|
62
62
|
super()
|
63
63
|
case aValue
|
@@ -80,7 +80,7 @@ module Regex # This module is used as a namespace
|
|
80
80
|
|
81
81
|
# Convertion method that returns a character given a codepoint (integer) value.
|
82
82
|
# Example:
|
83
|
-
#
|
83
|
+
# Regex::Character::codepoint2char(0x3a3) # Returns: Σ (
|
84
84
|
# The Unicode GREEK CAPITAL LETTER SIGMA)
|
85
85
|
def self.codepoint2char(aCodepoint)
|
86
86
|
[aCodepoint].pack('U') # Remark: chr() fails with codepoints > 256
|
@@ -88,7 +88,7 @@ module Regex # This module is used as a namespace
|
|
88
88
|
|
89
89
|
# Convertion method that returns the codepoint for the given single character.
|
90
90
|
# Example:
|
91
|
-
#
|
91
|
+
# Regex::Character::char2codepoint('Σ') # Returns: 0x3a3
|
92
92
|
def self.char2codepoint(aChar)
|
93
93
|
aChar.ord
|
94
94
|
end
|
@@ -102,7 +102,7 @@ module Regex # This module is used as a namespace
|
|
102
102
|
# \xXX (hex)
|
103
103
|
# Any other escaped character will be treated as a literal character
|
104
104
|
# Example:
|
105
|
-
#
|
105
|
+
# Regex::Character::esc2codepoint('\n') # Returns: 0xd
|
106
106
|
def self.esc2codepoint(esc_seq)
|
107
107
|
msg = "Escape sequence #{esc_seq} does not begin with a backslash (\\)."
|
108
108
|
raise StandardError, msg unless esc_seq[0] == '\\'
|
data/lib/regex/multiplicity.rb
CHANGED
@@ -70,6 +70,7 @@ module Regex # This module is used as a namespace
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# Validation method. Return the validated lower bound value
|
73
|
+
# @param anUpperBound [Integer, Symbol] integer or :more symbol
|
73
74
|
def valid_upper_bound(anUpperBound)
|
74
75
|
err_msg = "Invalid upper bound of repetition count #{anUpperBound}"
|
75
76
|
unless anUpperBound.kind_of?(Integer) || (anUpperBound == :more)
|
data/lib/srl_ruby/ast_builder.rb
CHANGED
@@ -12,8 +12,10 @@ module SrlRuby
|
|
12
12
|
# (say, a parse tree) from simpler objects (terminal and non-terminal
|
13
13
|
# nodes) and using a step by step approach.
|
14
14
|
class ASTBuilder < Rley::ParseRep::ASTBaseBuilder
|
15
|
+
# @return [Hash]
|
15
16
|
Terminal2NodeClass = {}.freeze
|
16
17
|
|
18
|
+
# @return [Array<Symbol>] Options for the regular expression
|
17
19
|
attr_reader :options
|
18
20
|
|
19
21
|
# Create a new AST builder instance.
|
@@ -24,6 +26,7 @@ module SrlRuby
|
|
24
26
|
end
|
25
27
|
|
26
28
|
# Notification that the parse tree construction is complete.
|
29
|
+
# @return [void]
|
27
30
|
def done!
|
28
31
|
apply_options
|
29
32
|
super
|
@@ -31,10 +34,12 @@ module SrlRuby
|
|
31
34
|
|
32
35
|
protected
|
33
36
|
|
37
|
+
# @return [Hash]
|
34
38
|
def terminal2node
|
35
39
|
Terminal2NodeClass
|
36
40
|
end
|
37
41
|
|
42
|
+
# @return [void]
|
38
43
|
def apply_options
|
39
44
|
tree_root = result.root
|
40
45
|
regexp_opts = []
|
@@ -62,12 +67,17 @@ module SrlRuby
|
|
62
67
|
Rley::PTree::TerminalNode.new(aToken, aTokenPosition)
|
63
68
|
end
|
64
69
|
|
70
|
+
# @param lowerBound [Integer]
|
71
|
+
# @param upperBound [Integer, Symbol]
|
72
|
+
# @return [Regex::Multiplicity]
|
65
73
|
def multiplicity(lowerBound, upperBound)
|
66
74
|
Regex::Multiplicity.new(lowerBound, upperBound, :greedy)
|
67
75
|
end
|
68
76
|
|
69
77
|
# rubocop: disable Style/OptionalBooleanParameter
|
70
78
|
|
79
|
+
# @param aString [String]
|
80
|
+
# @param [Array<Regex::Character>, Regex::Concatenation, Regex::Character]
|
71
81
|
def string_literal(aString, to_escape = true)
|
72
82
|
if aString.size > 1
|
73
83
|
chars = []
|
@@ -90,6 +100,8 @@ module SrlRuby
|
|
90
100
|
end
|
91
101
|
# rubocop: enable Style/OptionalBooleanParameter
|
92
102
|
|
103
|
+
# @param lowerBound [Integer]
|
104
|
+
# @param upperBound [Integer]
|
93
105
|
def char_range(lowerBound, upperBound)
|
94
106
|
lower = Regex::Character.new(lowerBound)
|
95
107
|
upper = Regex::Character.new(upperBound)
|
data/lib/srl_ruby/grammar.rb
CHANGED
data/lib/srl_ruby/tokenizer.rb
CHANGED
@@ -17,15 +17,32 @@ module SrlRuby
|
|
17
17
|
# Delimiters: parentheses '(' and ')'
|
18
18
|
# Separators: comma (optional)
|
19
19
|
class Tokenizer
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
# @return [Regexp] Matches a SRL character class
|
21
|
+
PATT_CHAR_CLASS = /[^,"\s]{2,}/
|
22
|
+
|
23
|
+
# @return [Regexp] Matches single digit
|
24
|
+
PATT_DIGIT_LIT = /[0-9]((?=\s|,|\))|$)/
|
25
|
+
|
26
|
+
# @return [Regexp] Matches a SRL identifier
|
27
|
+
PATT_IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_]+/
|
28
|
+
|
29
|
+
# @return [Regexp] Matches a decimal integer. An integer has 2..* digits
|
30
|
+
PATT_INTEGER = /[0-9]{2,}((?=\s|,|\))|$)/
|
31
|
+
|
32
|
+
# @return [Regexp] Matches a single letter.
|
33
|
+
PATT_LETTER_LIT = /[a-zA-Z]((?=\s|,|\))|$)/
|
34
|
+
|
35
|
+
# @return [Regexp] Matches a new line (cross-platform)
|
36
|
+
PATT_NEWLINE = /(?:\r\n)|\r|\n/
|
37
|
+
|
38
|
+
# @return [Regexp] Matches a text enclosed in double quotes
|
39
|
+
PATT_STR_DBL_QUOTE = /"(?:\\"|[^"])*"/
|
40
|
+
|
41
|
+
# @return [Regexp] Matches a text enclosed in single quotes
|
42
|
+
PATT_STR_SNGL_QUOTE = /'(?:\\'|[^'])*'/
|
43
|
+
|
44
|
+
# @return [Regexp] Matches SRL blank(s)
|
45
|
+
PATT_WHITESPACE = /[ \t\f]+/
|
29
46
|
|
30
47
|
# @return [StringScanner]
|
31
48
|
attr_reader(:scanner)
|
@@ -36,6 +53,7 @@ module SrlRuby
|
|
36
53
|
# @return [Integer] offset of start of current line within input
|
37
54
|
attr_reader(:line_start)
|
38
55
|
|
56
|
+
# @return [{String => String}] Mapping special single characters to symbolic names.
|
39
57
|
Lexeme2name = {
|
40
58
|
'(' => 'LPAREN',
|
41
59
|
')' => 'RPAREN',
|
@@ -43,6 +61,7 @@ module SrlRuby
|
|
43
61
|
}.freeze
|
44
62
|
|
45
63
|
# Here are all the SRL keywords (in uppercase)
|
64
|
+
# @return [{String => String}]
|
46
65
|
Keywords = %w[
|
47
66
|
ALL
|
48
67
|
ALREADY
|
@@ -100,8 +119,9 @@ module SrlRuby
|
|
100
119
|
WHITESPACE
|
101
120
|
WITH
|
102
121
|
WORD
|
103
|
-
].
|
122
|
+
].to_h { |x| [x, x] }
|
104
123
|
|
124
|
+
# Exception class for scanner/tokenizer failures.
|
105
125
|
class ScanError < StandardError; end
|
106
126
|
|
107
127
|
# Constructor. Initialize a tokenizer for SRL.
|
@@ -112,6 +132,8 @@ module SrlRuby
|
|
112
132
|
@line_start = 0
|
113
133
|
end
|
114
134
|
|
135
|
+
# Returns the sequence of tokens recognized from the input text given at initialization.
|
136
|
+
# @return [Array<Rley::Lexical::Token>]
|
115
137
|
def tokens
|
116
138
|
tok_sequence = []
|
117
139
|
until @scanner.eos?
|
@@ -124,6 +146,7 @@ module SrlRuby
|
|
124
146
|
|
125
147
|
private
|
126
148
|
|
149
|
+
# @return [Rley::Lexical::Token]
|
127
150
|
def _next_token
|
128
151
|
token = nil
|
129
152
|
|
@@ -170,6 +193,9 @@ module SrlRuby
|
|
170
193
|
token
|
171
194
|
end
|
172
195
|
|
196
|
+
# @param aSymbolName [String]
|
197
|
+
# @param aLexeme [String]
|
198
|
+
# @return [Rley::Lexical::Token]
|
173
199
|
def build_token(aSymbolName, aLexeme)
|
174
200
|
begin
|
175
201
|
col = scanner.pos - aLexeme.size - @line_start + 1
|
@@ -184,6 +210,7 @@ module SrlRuby
|
|
184
210
|
end
|
185
211
|
|
186
212
|
# Event: next line detected.
|
213
|
+
# @return [Integer] Current scanning position (offset)
|
187
214
|
def next_line_scanned
|
188
215
|
@lineno += 1
|
189
216
|
@line_start = scanner.pos
|
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
|