regexp_parser 1.3.0 → 1.7.1

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.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/Gemfile +3 -3
  4. data/README.md +12 -19
  5. data/Rakefile +3 -4
  6. data/lib/regexp_parser/expression.rb +28 -53
  7. data/lib/regexp_parser/expression/classes/backref.rb +18 -10
  8. data/lib/regexp_parser/expression/classes/conditional.rb +7 -2
  9. data/lib/regexp_parser/expression/classes/escape.rb +0 -4
  10. data/lib/regexp_parser/expression/classes/group.rb +4 -2
  11. data/lib/regexp_parser/expression/classes/keep.rb +1 -3
  12. data/lib/regexp_parser/expression/methods/match.rb +13 -0
  13. data/lib/regexp_parser/expression/methods/match_length.rb +172 -0
  14. data/lib/regexp_parser/expression/methods/options.rb +35 -0
  15. data/lib/regexp_parser/expression/methods/strfregexp.rb +0 -1
  16. data/lib/regexp_parser/expression/methods/tests.rb +6 -15
  17. data/lib/regexp_parser/expression/methods/traverse.rb +3 -1
  18. data/lib/regexp_parser/expression/quantifier.rb +2 -2
  19. data/lib/regexp_parser/expression/sequence.rb +3 -6
  20. data/lib/regexp_parser/expression/sequence_operation.rb +2 -6
  21. data/lib/regexp_parser/expression/subexpression.rb +3 -5
  22. data/lib/regexp_parser/lexer.rb +30 -44
  23. data/lib/regexp_parser/parser.rb +47 -24
  24. data/lib/regexp_parser/scanner.rb +1228 -1367
  25. data/lib/regexp_parser/scanner/char_type.rl +0 -3
  26. data/lib/regexp_parser/scanner/properties/long.yml +34 -1
  27. data/lib/regexp_parser/scanner/properties/short.yml +12 -0
  28. data/lib/regexp_parser/scanner/scanner.rl +101 -194
  29. data/lib/regexp_parser/syntax/tokens.rb +2 -10
  30. data/lib/regexp_parser/syntax/tokens/unicode_property.rb +72 -21
  31. data/lib/regexp_parser/syntax/versions/2.6.0.rb +10 -0
  32. data/lib/regexp_parser/syntax/versions/2.6.2.rb +10 -0
  33. data/lib/regexp_parser/syntax/versions/2.6.3.rb +10 -0
  34. data/lib/regexp_parser/version.rb +1 -1
  35. data/regexp_parser.gemspec +3 -3
  36. data/spec/expression/base_spec.rb +94 -0
  37. data/spec/expression/clone_spec.rb +120 -0
  38. data/spec/expression/conditional_spec.rb +89 -0
  39. data/spec/expression/free_space_spec.rb +27 -0
  40. data/spec/expression/methods/match_length_spec.rb +161 -0
  41. data/spec/expression/methods/match_spec.rb +25 -0
  42. data/spec/expression/methods/strfregexp_spec.rb +224 -0
  43. data/spec/expression/methods/tests_spec.rb +99 -0
  44. data/spec/expression/methods/traverse_spec.rb +161 -0
  45. data/spec/expression/options_spec.rb +128 -0
  46. data/spec/expression/root_spec.rb +9 -0
  47. data/spec/expression/sequence_spec.rb +9 -0
  48. data/spec/expression/subexpression_spec.rb +50 -0
  49. data/spec/expression/to_h_spec.rb +26 -0
  50. data/spec/expression/to_s_spec.rb +100 -0
  51. data/spec/lexer/all_spec.rb +22 -0
  52. data/spec/lexer/conditionals_spec.rb +53 -0
  53. data/spec/lexer/delimiters_spec.rb +68 -0
  54. data/spec/lexer/escapes_spec.rb +14 -0
  55. data/spec/lexer/keep_spec.rb +10 -0
  56. data/spec/lexer/literals_spec.rb +89 -0
  57. data/spec/lexer/nesting_spec.rb +99 -0
  58. data/spec/lexer/refcalls_spec.rb +55 -0
  59. data/spec/parser/all_spec.rb +43 -0
  60. data/spec/parser/alternation_spec.rb +88 -0
  61. data/spec/parser/anchors_spec.rb +17 -0
  62. data/spec/parser/conditionals_spec.rb +179 -0
  63. data/spec/parser/errors_spec.rb +30 -0
  64. data/spec/parser/escapes_spec.rb +121 -0
  65. data/spec/parser/free_space_spec.rb +130 -0
  66. data/spec/parser/groups_spec.rb +108 -0
  67. data/spec/parser/keep_spec.rb +6 -0
  68. data/spec/parser/posix_classes_spec.rb +8 -0
  69. data/spec/parser/properties_spec.rb +115 -0
  70. data/spec/parser/quantifiers_spec.rb +52 -0
  71. data/spec/parser/refcalls_spec.rb +112 -0
  72. data/spec/parser/set/intersections_spec.rb +127 -0
  73. data/spec/parser/set/ranges_spec.rb +111 -0
  74. data/spec/parser/sets_spec.rb +178 -0
  75. data/spec/parser/types_spec.rb +18 -0
  76. data/spec/scanner/all_spec.rb +18 -0
  77. data/spec/scanner/anchors_spec.rb +21 -0
  78. data/spec/scanner/conditionals_spec.rb +128 -0
  79. data/spec/scanner/delimiters_spec.rb +52 -0
  80. data/spec/scanner/errors_spec.rb +67 -0
  81. data/spec/scanner/escapes_spec.rb +53 -0
  82. data/spec/scanner/free_space_spec.rb +133 -0
  83. data/spec/scanner/groups_spec.rb +52 -0
  84. data/spec/scanner/keep_spec.rb +10 -0
  85. data/spec/scanner/literals_spec.rb +49 -0
  86. data/spec/scanner/meta_spec.rb +18 -0
  87. data/spec/scanner/properties_spec.rb +64 -0
  88. data/spec/scanner/quantifiers_spec.rb +20 -0
  89. data/spec/scanner/refcalls_spec.rb +36 -0
  90. data/spec/scanner/sets_spec.rb +102 -0
  91. data/spec/scanner/types_spec.rb +14 -0
  92. data/spec/spec_helper.rb +15 -0
  93. data/{test → spec}/support/runner.rb +9 -8
  94. data/spec/support/shared_examples.rb +77 -0
  95. data/{test → spec}/support/warning_extractor.rb +5 -7
  96. data/spec/syntax/syntax_spec.rb +48 -0
  97. data/spec/syntax/syntax_token_map_spec.rb +23 -0
  98. data/spec/syntax/versions/1.8.6_spec.rb +17 -0
  99. data/spec/syntax/versions/1.9.1_spec.rb +10 -0
  100. data/spec/syntax/versions/1.9.3_spec.rb +9 -0
  101. data/spec/syntax/versions/2.0.0_spec.rb +13 -0
  102. data/spec/syntax/versions/2.2.0_spec.rb +9 -0
  103. data/spec/syntax/versions/aliases_spec.rb +37 -0
  104. data/spec/token/token_spec.rb +85 -0
  105. metadata +151 -146
  106. data/test/expression/test_all.rb +0 -12
  107. data/test/expression/test_base.rb +0 -90
  108. data/test/expression/test_clone.rb +0 -89
  109. data/test/expression/test_conditionals.rb +0 -113
  110. data/test/expression/test_free_space.rb +0 -35
  111. data/test/expression/test_set.rb +0 -84
  112. data/test/expression/test_strfregexp.rb +0 -230
  113. data/test/expression/test_subexpression.rb +0 -58
  114. data/test/expression/test_tests.rb +0 -99
  115. data/test/expression/test_to_h.rb +0 -59
  116. data/test/expression/test_to_s.rb +0 -104
  117. data/test/expression/test_traverse.rb +0 -161
  118. data/test/helpers.rb +0 -10
  119. data/test/lexer/test_all.rb +0 -41
  120. data/test/lexer/test_conditionals.rb +0 -127
  121. data/test/lexer/test_keep.rb +0 -24
  122. data/test/lexer/test_literals.rb +0 -130
  123. data/test/lexer/test_nesting.rb +0 -132
  124. data/test/lexer/test_refcalls.rb +0 -56
  125. data/test/parser/set/test_intersections.rb +0 -127
  126. data/test/parser/set/test_ranges.rb +0 -111
  127. data/test/parser/test_all.rb +0 -64
  128. data/test/parser/test_alternation.rb +0 -92
  129. data/test/parser/test_anchors.rb +0 -34
  130. data/test/parser/test_conditionals.rb +0 -187
  131. data/test/parser/test_errors.rb +0 -63
  132. data/test/parser/test_escapes.rb +0 -134
  133. data/test/parser/test_free_space.rb +0 -139
  134. data/test/parser/test_groups.rb +0 -289
  135. data/test/parser/test_keep.rb +0 -21
  136. data/test/parser/test_posix_classes.rb +0 -27
  137. data/test/parser/test_properties.rb +0 -133
  138. data/test/parser/test_quantifiers.rb +0 -301
  139. data/test/parser/test_refcalls.rb +0 -186
  140. data/test/parser/test_sets.rb +0 -179
  141. data/test/parser/test_types.rb +0 -50
  142. data/test/scanner/test_all.rb +0 -38
  143. data/test/scanner/test_anchors.rb +0 -38
  144. data/test/scanner/test_conditionals.rb +0 -184
  145. data/test/scanner/test_errors.rb +0 -91
  146. data/test/scanner/test_escapes.rb +0 -56
  147. data/test/scanner/test_free_space.rb +0 -200
  148. data/test/scanner/test_groups.rb +0 -79
  149. data/test/scanner/test_keep.rb +0 -35
  150. data/test/scanner/test_literals.rb +0 -89
  151. data/test/scanner/test_meta.rb +0 -40
  152. data/test/scanner/test_properties.rb +0 -312
  153. data/test/scanner/test_quantifiers.rb +0 -37
  154. data/test/scanner/test_refcalls.rb +0 -52
  155. data/test/scanner/test_scripts.rb +0 -53
  156. data/test/scanner/test_sets.rb +0 -119
  157. data/test/scanner/test_types.rb +0 -35
  158. data/test/scanner/test_unicode_blocks.rb +0 -30
  159. data/test/support/disable_autotest.rb +0 -8
  160. data/test/syntax/test_all.rb +0 -6
  161. data/test/syntax/test_syntax.rb +0 -61
  162. data/test/syntax/test_syntax_token_map.rb +0 -25
  163. data/test/syntax/versions/test_1.8.rb +0 -55
  164. data/test/syntax/versions/test_1.9.1.rb +0 -36
  165. data/test/syntax/versions/test_1.9.3.rb +0 -32
  166. data/test/syntax/versions/test_2.0.0.rb +0 -37
  167. data/test/syntax/versions/test_2.2.0.rb +0 -32
  168. data/test/syntax/versions/test_aliases.rb +0 -129
  169. data/test/syntax/versions/test_all.rb +0 -5
  170. data/test/test_all.rb +0 -5
  171. data/test/token/test_all.rb +0 -2
  172. data/test/token/test_token.rb +0 -107
@@ -39,15 +39,7 @@ require 'regexp_parser/syntax/tokens/unicode_property'
39
39
  # into the All and Types constants.
40
40
  module Regexp::Syntax
41
41
  module Token
42
- if RUBY_VERSION >= '1.9'
43
- All = Map.map {|k,v| v}.flatten.uniq.sort
44
- else
45
- All = Map.map {|k,v| v}.flatten.uniq
46
- end
47
-
48
- Types = Map.keys
49
-
50
- All.freeze
51
- Types.freeze
42
+ All = Map.values.flatten.uniq.sort.freeze
43
+ Types = Map.keys.freeze
52
44
  end
53
45
  end
@@ -1,6 +1,8 @@
1
1
  module Regexp::Syntax
2
2
  module Token
3
3
  module UnicodeProperty
4
+ all = proc { |name| constants.grep(/#{name}/).flat_map(&method(:const_get)) }
5
+
4
6
  CharType_V1_9_0 = [:alnum, :alpha, :ascii, :blank, :cntrl, :digit, :graph,
5
7
  :lower, :print, :punct, :space, :upper, :word, :xdigit]
6
8
 
@@ -49,7 +51,13 @@ module Regexp::Syntax
49
51
 
50
52
  Age_V2_5_0 = [:'age=10.0']
51
53
 
52
- Age = Age_V1_9_3 + Age_V2_0_0 + Age_V2_2_0 + Age_V2_3_0 + Age_V2_4_0 + Age_V2_5_0
54
+ Age_V2_6_0 = [:'age=11.0']
55
+
56
+ Age_V2_6_2 = [:'age=12.0']
57
+
58
+ Age_V2_6_3 = [:'age=12.1']
59
+
60
+ Age = all[:Age_V]
53
61
 
54
62
  Derived_V1_9_0 = [
55
63
  :ascii_hex_digit,
@@ -118,7 +126,7 @@ module Regexp::Syntax
118
126
  :regional_indicator
119
127
  ]
120
128
 
121
- Derived = Derived_V1_9_0 + Derived_V2_0_0 + Derived_V2_4_0 + Derived_V2_5_0
129
+ Derived = all[:Derived_V]
122
130
 
123
131
  Script_V1_9_0 = [
124
132
  :arabic,
@@ -283,8 +291,29 @@ module Regexp::Syntax
283
291
  :zanabazar_square,
284
292
  ]
285
293
 
286
- Script = Script_V1_9_0 + Script_V1_9_3 + Script_V2_0_0 +
287
- Script_V2_2_0 + Script_V2_3_0 + Script_V2_4_0 + Script_V2_5_0
294
+ Script_V2_6_0 = [
295
+ :dogra,
296
+ :gunjala_gondi,
297
+ :hanifi_rohingya,
298
+ :makasar,
299
+ :medefaidrin,
300
+ :old_sogdian,
301
+ :sogdian,
302
+ ]
303
+
304
+ Script_V2_6_2 = [
305
+ :egyptian_hieroglyph_format_controls,
306
+ :elymaic,
307
+ :nandinagari,
308
+ :nyiakeng_puachue_hmong,
309
+ :ottoman_siyaq_numbers,
310
+ :small_kana_extension,
311
+ :symbols_and_pictographs_extended_a,
312
+ :tamil_supplement,
313
+ :wancho,
314
+ ]
315
+
316
+ Script = all[:Script_V]
288
317
 
289
318
  UnicodeBlock_V1_9_0 = [
290
319
  :in_alphabetic_presentation_forms,
@@ -585,8 +614,33 @@ module Regexp::Syntax
585
614
  :in_zanabazar_square,
586
615
  ]
587
616
 
588
- UnicodeBlock = UnicodeBlock_V1_9_0 + UnicodeBlock_V2_0_0 + UnicodeBlock_V2_2_0 +
589
- UnicodeBlock_V2_3_0 + UnicodeBlock_V2_4_0 + UnicodeBlock_V2_5_0
617
+ UnicodeBlock_V2_6_0 = [
618
+ :in_chess_symbols,
619
+ :in_dogra,
620
+ :in_georgian_extended,
621
+ :in_gunjala_gondi,
622
+ :in_hanifi_rohingya,
623
+ :in_indic_siyaq_numbers,
624
+ :in_makasar,
625
+ :in_mayan_numerals,
626
+ :in_medefaidrin,
627
+ :in_old_sogdian,
628
+ :in_sogdian,
629
+ ]
630
+
631
+ UnicodeBlock_V2_6_2 = [
632
+ :in_egyptian_hieroglyph_format_controls,
633
+ :in_elymaic,
634
+ :in_nandinagari,
635
+ :in_nyiakeng_puachue_hmong,
636
+ :in_ottoman_siyaq_numbers,
637
+ :in_small_kana_extension,
638
+ :in_symbols_and_pictographs_extended_a,
639
+ :in_tamil_supplement,
640
+ :in_wancho,
641
+ ]
642
+
643
+ UnicodeBlock = all[:UnicodeBlock_V]
590
644
 
591
645
  Emoji_V2_5_0 = [
592
646
  :emoji,
@@ -596,23 +650,20 @@ module Regexp::Syntax
596
650
  :emoji_presentation,
597
651
  ]
598
652
 
599
- Emoji = Emoji_V2_5_0
600
-
601
- V1_9_0 = Category::All + POSIX + CharType_V1_9_0 + Derived_V1_9_0 + Script_V1_9_0 + UnicodeBlock_V1_9_0
602
-
603
- V1_9_3 = Age_V1_9_3 + Script_V1_9_3
604
-
605
- V2_0_0 = Age_V2_0_0 + Derived_V2_0_0 + Script_V2_0_0 + UnicodeBlock_V2_0_0
606
-
607
- V2_2_0 = Age_V2_2_0 + Script_V2_2_0 + UnicodeBlock_V2_2_0
608
-
609
- V2_3_0 = Age_V2_3_0 + Script_V2_3_0 + UnicodeBlock_V2_3_0
610
-
611
- V2_4_0 = Age_V2_4_0 + Derived_V2_4_0 + Script_V2_4_0 + UnicodeBlock_V2_4_0
653
+ Emoji = all[:Emoji_V]
612
654
 
613
- V2_5_0 = Age_V2_5_0 + CharType_V2_5_0 + Derived_V2_5_0 + Emoji_V2_5_0 + Script_V2_5_0 + UnicodeBlock_V2_5_0
655
+ V1_9_0 = Category::All + POSIX + all[:V1_9_0]
656
+ V1_9_3 = all[:V1_9_3]
657
+ V2_0_0 = all[:V2_0_0]
658
+ V2_2_0 = all[:V2_2_0]
659
+ V2_3_0 = all[:V2_3_0]
660
+ V2_4_0 = all[:V2_4_0]
661
+ V2_5_0 = all[:V2_5_0]
662
+ V2_6_0 = all[:V2_6_0]
663
+ V2_6_2 = all[:V2_6_2]
664
+ V2_6_3 = all[:V2_6_3]
614
665
 
615
- All = V1_9_0 + V1_9_3 + V2_0_0 + V2_2_0 + V2_3_0 + V2_4_0 + V2_5_0
666
+ All = all[/^V\d+_\d+_\d+$/]
616
667
 
617
668
  Type = :property
618
669
  NonType = :nonproperty
@@ -0,0 +1,10 @@
1
+ module Regexp::Syntax
2
+ class V2_6_0 < Regexp::Syntax::V2_5
3
+ def initialize
4
+ super
5
+
6
+ implements :property, UnicodeProperty::V2_6_0
7
+ implements :nonproperty, UnicodeProperty::V2_6_0
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Regexp::Syntax
2
+ class V2_6_2 < Regexp::Syntax::V2_6_0
3
+ def initialize
4
+ super
5
+
6
+ implements :property, UnicodeProperty::V2_6_2
7
+ implements :nonproperty, UnicodeProperty::V2_6_2
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Regexp::Syntax
2
+ class V2_6_3 < Regexp::Syntax::V2_6_2
3
+ def initialize
4
+ super
5
+
6
+ implements :property, UnicodeProperty::V2_6_3
7
+ implements :nonproperty, UnicodeProperty::V2_6_3
8
+ end
9
+ end
10
+ end
@@ -1,5 +1,5 @@
1
1
  class Regexp
2
2
  class Parser
3
- VERSION = '1.3.0'
3
+ VERSION = '1.7.1'
4
4
  end
5
5
  end
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
8
8
 
9
9
  gem.summary = "Scanner, lexer, parser for ruby's regular expressions"
10
10
  gem.description = 'A library for tokenizing, lexing, and parsing Ruby regular expressions.'
11
- gem.homepage = 'http://github.com/ammar/regexp_parser'
11
+ gem.homepage = 'https://github.com/ammar/regexp_parser'
12
12
 
13
13
  if gem.respond_to?(:metadata)
14
14
  gem.metadata = { 'issue_tracker' => 'https://github.com/ammar/regexp_parser/issues' }
@@ -21,12 +21,12 @@ Gem::Specification.new do |gem|
21
21
 
22
22
  gem.require_paths = ['lib']
23
23
 
24
- gem.files = Dir.glob('{lib,test}/**/*.rb') +
24
+ gem.files = Dir.glob('{lib,spec}/**/*.rb') +
25
25
  Dir.glob('lib/**/*.rl') +
26
26
  Dir.glob('lib/**/*.yml') +
27
27
  %w(Gemfile Rakefile LICENSE README.md CHANGELOG.md regexp_parser.gemspec)
28
28
 
29
- gem.test_files = Dir.glob('test/**/*.rb')
29
+ gem.test_files = Dir.glob('spec/**/*.rb')
30
30
 
31
31
  gem.rdoc_options = ["--inline-source", "--charset=UTF-8"]
32
32
 
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe(Regexp::Expression::Base) do
4
+ specify('#to_re') do
5
+ re_text = '^a*(b([cde]+))+f?$'
6
+
7
+ re = RP.parse(re_text).to_re
8
+
9
+ expect(re).to be_a(::Regexp)
10
+ expect(re_text).to eq re.source
11
+ end
12
+
13
+ specify('#level') do
14
+ regexp = /^a(b(c(d)))e$/
15
+ root = RP.parse(regexp)
16
+
17
+ ['^', 'a', '(b(c(d)))', 'e', '$'].each_with_index do |t, i|
18
+ expect(root[i].to_s).to eq t
19
+ expect(root[i].level).to eq 0
20
+ end
21
+
22
+ expect(root[2][0].to_s).to eq 'b'
23
+ expect(root[2][0].level).to eq 1
24
+
25
+ expect(root[2][1][0].to_s).to eq 'c'
26
+ expect(root[2][1][0].level).to eq 2
27
+
28
+ expect(root[2][1][1][0].to_s).to eq 'd'
29
+ expect(root[2][1][1][0].level).to eq 3
30
+ end
31
+
32
+ specify('#terminal?') do
33
+ root = RP.parse('^a([b]+)c$')
34
+
35
+ expect(root).not_to be_terminal
36
+
37
+ expect(root[0]).to be_terminal
38
+ expect(root[1]).to be_terminal
39
+ expect(root[2]).not_to be_terminal
40
+ expect(root[2][0]).not_to be_terminal
41
+ expect(root[2][0][0]).to be_terminal
42
+ expect(root[3]).to be_terminal
43
+ expect(root[4]).to be_terminal
44
+ end
45
+
46
+ specify('alt #terminal?') do
47
+ root = RP.parse('^(ab|cd)$')
48
+
49
+ expect(root).not_to be_terminal
50
+
51
+ expect(root[0]).to be_terminal
52
+ expect(root[1]).not_to be_terminal
53
+ expect(root[1][0]).not_to be_terminal
54
+ expect(root[1][0][0]).not_to be_terminal
55
+ expect(root[1][0][0][0]).to be_terminal
56
+ expect(root[1][0][1]).not_to be_terminal
57
+ expect(root[1][0][1][0]).to be_terminal
58
+ end
59
+
60
+ specify('#coded_offset') do
61
+ root = RP.parse('^a*(b+(c?))$')
62
+
63
+ expect(root.coded_offset).to eq '@0+12'
64
+
65
+ [
66
+ ['@0+1', '^'],
67
+ ['@1+2', 'a*'],
68
+ ['@3+8', '(b+(c?))'],
69
+ ['@11+1', '$'],
70
+ ].each_with_index do |check, i|
71
+ against = [root[i].coded_offset, root[i].to_s]
72
+
73
+ expect(against).to eq check
74
+ end
75
+
76
+ expect([root[2][0].coded_offset, root[2][0].to_s]).to eq ['@4+2', 'b+']
77
+ expect([root[2][1].coded_offset, root[2][1].to_s]).to eq ['@6+4', '(c?)']
78
+ expect([root[2][1][0].coded_offset, root[2][1][0].to_s]).to eq ['@7+2', 'c?']
79
+ end
80
+
81
+ specify('#quantity') do
82
+ expect(RP.parse(/aa/)[0].quantity).to eq [nil, nil]
83
+ expect(RP.parse(/a?/)[0].quantity).to eq [0, 1]
84
+ expect(RP.parse(/a*/)[0].quantity).to eq [0, -1]
85
+ expect(RP.parse(/a+/)[0].quantity).to eq [1, -1]
86
+ end
87
+
88
+ specify('#repetitions') do
89
+ expect(RP.parse(/aa/)[0].repetitions).to eq 1..1
90
+ expect(RP.parse(/a?/)[0].repetitions).to eq 0..1
91
+ expect(RP.parse(/a*/)[0].repetitions).to eq 0..(Float::INFINITY)
92
+ expect(RP.parse(/a+/)[0].repetitions).to eq 1..(Float::INFINITY)
93
+ end
94
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('Expression#clone') do
4
+ specify('Base#clone') do
5
+ root = RP.parse(/^(?i:a)b+$/i)
6
+ copy = root.clone
7
+
8
+ expect(copy.to_s).to eq root.to_s
9
+
10
+ expect(root.object_id).not_to eq copy.object_id
11
+ expect(root.text).to eq copy.text
12
+ expect(root.text.object_id).not_to eq copy.text.object_id
13
+
14
+ root_1 = root[1]
15
+ copy_1 = copy[1]
16
+
17
+ expect(root_1.options).to eq copy_1.options
18
+ expect(root_1.options.object_id).not_to eq copy_1.options.object_id
19
+
20
+ root_2 = root[2]
21
+ copy_2 = copy[2]
22
+
23
+ expect(root_2).to be_quantified
24
+ expect(copy_2).to be_quantified
25
+ expect(root_2.quantifier.text).to eq copy_2.quantifier.text
26
+ expect(root_2.quantifier.text.object_id).not_to eq copy_2.quantifier.text.object_id
27
+ expect(root_2.quantifier.object_id).not_to eq copy_2.quantifier.object_id
28
+
29
+ # regression test
30
+ expect { root_2.clone }.not_to change { root_2.quantifier.object_id }
31
+ expect { root_2.clone }.not_to change { root_2.quantifier.text.object_id }
32
+ end
33
+
34
+ specify('Subexpression#clone') do
35
+ root = RP.parse(/^a(b([cde])f)g$/)
36
+ copy = root.clone
37
+
38
+ expect(copy.to_s).to eq root.to_s
39
+
40
+ expect(root).to respond_to(:expressions)
41
+ expect(copy).to respond_to(:expressions)
42
+ expect(root.expressions.object_id).not_to eq copy.expressions.object_id
43
+ copy.expressions.each_with_index do |exp, index|
44
+ expect(root[index].object_id).not_to eq exp.object_id
45
+ end
46
+ copy[2].each_with_index do |exp, index|
47
+ expect(root[2][index].object_id).not_to eq exp.object_id
48
+ end
49
+
50
+ # regression test
51
+ expect { root.clone }.not_to change { root.expressions.object_id }
52
+ end
53
+
54
+ specify('Group::Named#clone') do
55
+ root = RP.parse('^(?<somename>a)+bc$')
56
+ copy = root.clone
57
+
58
+ expect(copy.to_s).to eq root.to_s
59
+
60
+ root_1 = root[1]
61
+ copy_1 = copy[1]
62
+
63
+ expect(root_1.name).to eq copy_1.name
64
+ expect(root_1.name.object_id).not_to eq copy_1.name.object_id
65
+ expect(root_1.text).to eq copy_1.text
66
+ expect(root_1.expressions.object_id).not_to eq copy_1.expressions.object_id
67
+ copy_1.expressions.each_with_index do |exp, index|
68
+ expect(root_1[index].object_id).not_to eq exp.object_id
69
+ end
70
+
71
+ # regression test
72
+ expect { root_1.clone }.not_to change { root_1.name.object_id }
73
+ end
74
+
75
+ specify('Sequence#clone') do
76
+ root = RP.parse(/(a|b)/)
77
+ copy = root.clone
78
+
79
+ # regression test
80
+ expect(copy.to_s).to eq root.to_s
81
+
82
+ root_seq_op = root[0][0]
83
+ copy_seq_op = copy[0][0]
84
+ root_seq_1 = root[0][0][0]
85
+ copy_seq_1 = copy[0][0][0]
86
+
87
+ expect(root_seq_op.object_id).not_to eq copy_seq_op.object_id
88
+ expect(root_seq_1.object_id).not_to eq copy_seq_1.object_id
89
+ copy_seq_1.expressions.each_with_index do |exp, index|
90
+ expect(root_seq_1[index].object_id).not_to eq exp.object_id
91
+ end
92
+ end
93
+
94
+ describe('Base#unquantified_clone') do
95
+ it 'produces a clone' do
96
+ root = RP.parse(/^a(b([cde])f)g$/)
97
+ copy = root.unquantified_clone
98
+
99
+ expect(copy.to_s).to eq root.to_s
100
+
101
+ expect(copy.object_id).not_to eq root.object_id
102
+ end
103
+
104
+ it 'does not carry over the callee quantifier' do
105
+ expect(RP.parse(/a{3}/)[0]).to be_quantified
106
+ expect(RP.parse(/a{3}/)[0].unquantified_clone).not_to be_quantified
107
+
108
+ expect(RP.parse(/[a]{3}/)[0]).to be_quantified
109
+ expect(RP.parse(/[a]{3}/)[0].unquantified_clone).not_to be_quantified
110
+
111
+ expect(RP.parse(/(a|b){3}/)[0]).to be_quantified
112
+ expect(RP.parse(/(a|b){3}/)[0].unquantified_clone).not_to be_quantified
113
+ end
114
+
115
+ it 'keeps quantifiers of callee children' do
116
+ expect(RP.parse(/(a{3}){3}/)[0][0]).to be_quantified
117
+ expect(RP.parse(/(a{3}){3}/)[0].unquantified_clone[0]).to be_quantified
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe(Regexp::Expression::Conditional) do
4
+ let(:root) { RP.parse('^(a(b))(b(?(1)c|(?(2)d|(?(3)e|f)))g)$') }
5
+ let(:cond_1) { root[2][1] }
6
+ let(:cond_2) { root[2][1][2][0] }
7
+ let(:cond_3) { root[2][1][2][0][2][0] }
8
+
9
+ specify('root level') do
10
+ [
11
+ '^',
12
+ '(a(b))',
13
+ '(b(?(1)c|(?(2)d|(?(3)e|f)))g)',
14
+ '$'
15
+ ].each_with_index do |t, i|
16
+ expect(root[i].conditional_level).to eq 0
17
+ expect(root[i].to_s).to eq t
18
+ end
19
+
20
+ expect(root[2][0].to_s).to eq 'b'
21
+ expect(root[2][0].conditional_level).to eq 0
22
+ end
23
+
24
+ specify('level one') do
25
+ condition = cond_1.condition
26
+ branch_1 = cond_1.branches.first
27
+
28
+ expect(condition).to be_a Conditional::Condition
29
+ expect(condition.to_s).to eq '(1)'
30
+ expect(condition.conditional_level).to eq 1
31
+
32
+ expect(branch_1).to be_a Conditional::Branch
33
+ expect(branch_1.to_s).to eq 'c'
34
+ expect(branch_1.conditional_level).to eq 1
35
+
36
+ expect(branch_1.first.to_s).to eq 'c'
37
+ expect(branch_1.first.conditional_level).to eq 1
38
+ end
39
+
40
+ specify('level two') do
41
+ condition = cond_2.condition
42
+ branch_1 = cond_2.branches.first
43
+ branch_2 = cond_2.branches.last
44
+
45
+ expect(cond_2.to_s).to start_with '(?'
46
+ expect(cond_2.conditional_level).to eq 1
47
+
48
+ expect(condition).to be_a Conditional::Condition
49
+ expect(condition.to_s).to eq '(2)'
50
+ expect(condition.conditional_level).to eq 2
51
+
52
+ expect(branch_1).to be_a Conditional::Branch
53
+ expect(branch_1.to_s).to eq 'd'
54
+ expect(branch_1.conditional_level).to eq 2
55
+
56
+ expect(branch_1.first.to_s).to eq 'd'
57
+ expect(branch_1.first.conditional_level).to eq 2
58
+
59
+ expect(branch_2.first.to_s).to start_with '(?'
60
+ expect(branch_2.first.conditional_level).to eq 2
61
+ end
62
+
63
+ specify('level three') do
64
+ condition = cond_3.condition
65
+ branch_1 = cond_3.branches.first
66
+ branch_2 = cond_3.branches.last
67
+
68
+ expect(condition).to be_a Conditional::Condition
69
+ expect(condition.to_s).to eq '(3)'
70
+ expect(condition.conditional_level).to eq 3
71
+
72
+ expect(cond_3.to_s).to eq '(?(3)e|f)'
73
+ expect(cond_3.conditional_level).to eq 2
74
+
75
+ expect(branch_1).to be_a Conditional::Branch
76
+ expect(branch_1.to_s).to eq 'e'
77
+ expect(branch_1.conditional_level).to eq 3
78
+
79
+ expect(branch_1.first.to_s).to eq 'e'
80
+ expect(branch_1.first.conditional_level).to eq 3
81
+
82
+ expect(branch_2).to be_a Conditional::Branch
83
+ expect(branch_2.to_s).to eq 'f'
84
+ expect(branch_2.conditional_level).to eq 3
85
+
86
+ expect(branch_2.first.to_s).to eq 'f'
87
+ expect(branch_2.first.conditional_level).to eq 3
88
+ end
89
+ end