plurimath-parslet 3.0.0

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 (148) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.txt +284 -0
  3. data/LICENSE +23 -0
  4. data/README.adoc +454 -0
  5. data/Rakefile +71 -0
  6. data/lib/parslet/accelerator/application.rb +62 -0
  7. data/lib/parslet/accelerator/engine.rb +112 -0
  8. data/lib/parslet/accelerator.rb +162 -0
  9. data/lib/parslet/atoms/alternative.rb +53 -0
  10. data/lib/parslet/atoms/base.rb +157 -0
  11. data/lib/parslet/atoms/can_flatten.rb +137 -0
  12. data/lib/parslet/atoms/capture.rb +38 -0
  13. data/lib/parslet/atoms/context.rb +103 -0
  14. data/lib/parslet/atoms/dsl.rb +112 -0
  15. data/lib/parslet/atoms/dynamic.rb +32 -0
  16. data/lib/parslet/atoms/entity.rb +45 -0
  17. data/lib/parslet/atoms/ignored.rb +26 -0
  18. data/lib/parslet/atoms/infix.rb +115 -0
  19. data/lib/parslet/atoms/lookahead.rb +52 -0
  20. data/lib/parslet/atoms/named.rb +32 -0
  21. data/lib/parslet/atoms/re.rb +41 -0
  22. data/lib/parslet/atoms/repetition.rb +87 -0
  23. data/lib/parslet/atoms/scope.rb +26 -0
  24. data/lib/parslet/atoms/sequence.rb +48 -0
  25. data/lib/parslet/atoms/str.rb +42 -0
  26. data/lib/parslet/atoms/visitor.rb +89 -0
  27. data/lib/parslet/atoms.rb +34 -0
  28. data/lib/parslet/cause.rb +101 -0
  29. data/lib/parslet/context.rb +21 -0
  30. data/lib/parslet/convenience.rb +33 -0
  31. data/lib/parslet/error_reporter/contextual.rb +120 -0
  32. data/lib/parslet/error_reporter/deepest.rb +100 -0
  33. data/lib/parslet/error_reporter/tree.rb +63 -0
  34. data/lib/parslet/error_reporter.rb +8 -0
  35. data/lib/parslet/export.rb +163 -0
  36. data/lib/parslet/expression/treetop.rb +92 -0
  37. data/lib/parslet/expression.rb +51 -0
  38. data/lib/parslet/graphviz.rb +97 -0
  39. data/lib/parslet/parser.rb +68 -0
  40. data/lib/parslet/pattern/binding.rb +49 -0
  41. data/lib/parslet/pattern.rb +113 -0
  42. data/lib/parslet/position.rb +21 -0
  43. data/lib/parslet/rig/rspec.rb +52 -0
  44. data/lib/parslet/scope.rb +42 -0
  45. data/lib/parslet/slice.rb +105 -0
  46. data/lib/parslet/source/line_cache.rb +99 -0
  47. data/lib/parslet/source.rb +96 -0
  48. data/lib/parslet/transform.rb +265 -0
  49. data/lib/parslet/version.rb +5 -0
  50. data/lib/parslet.rb +314 -0
  51. data/plurimath-parslet.gemspec +42 -0
  52. data/spec/acceptance/infix_parser_spec.rb +145 -0
  53. data/spec/acceptance/mixing_parsers_spec.rb +74 -0
  54. data/spec/acceptance/regression_spec.rb +329 -0
  55. data/spec/acceptance/repetition_and_maybe_spec.rb +44 -0
  56. data/spec/acceptance/unconsumed_input_spec.rb +21 -0
  57. data/spec/examples/boolean_algebra_spec.rb +257 -0
  58. data/spec/examples/calc_spec.rb +278 -0
  59. data/spec/examples/capture_spec.rb +137 -0
  60. data/spec/examples/comments_spec.rb +186 -0
  61. data/spec/examples/deepest_errors_spec.rb +420 -0
  62. data/spec/examples/documentation_spec.rb +205 -0
  63. data/spec/examples/email_parser_spec.rb +275 -0
  64. data/spec/examples/empty_spec.rb +37 -0
  65. data/spec/examples/erb_spec.rb +482 -0
  66. data/spec/examples/ip_address_spec.rb +153 -0
  67. data/spec/examples/json_spec.rb +413 -0
  68. data/spec/examples/local_spec.rb +302 -0
  69. data/spec/examples/mathn_spec.rb +151 -0
  70. data/spec/examples/minilisp_spec.rb +492 -0
  71. data/spec/examples/modularity_spec.rb +340 -0
  72. data/spec/examples/nested_errors_spec.rb +322 -0
  73. data/spec/examples/optimized_erb_spec.rb +299 -0
  74. data/spec/examples/parens_spec.rb +239 -0
  75. data/spec/examples/prec_calc_spec.rb +525 -0
  76. data/spec/examples/readme_spec.rb +228 -0
  77. data/spec/examples/scopes_spec.rb +187 -0
  78. data/spec/examples/seasons_spec.rb +196 -0
  79. data/spec/examples/sentence_spec.rb +119 -0
  80. data/spec/examples/simple_xml_spec.rb +250 -0
  81. data/spec/examples/string_parser_spec.rb +407 -0
  82. data/spec/fixtures/examples/boolean_algebra.rb +62 -0
  83. data/spec/fixtures/examples/calc.rb +86 -0
  84. data/spec/fixtures/examples/capture.rb +36 -0
  85. data/spec/fixtures/examples/comments.rb +22 -0
  86. data/spec/fixtures/examples/deepest_errors.rb +99 -0
  87. data/spec/fixtures/examples/documentation.rb +32 -0
  88. data/spec/fixtures/examples/email_parser.rb +42 -0
  89. data/spec/fixtures/examples/empty.rb +10 -0
  90. data/spec/fixtures/examples/erb.rb +39 -0
  91. data/spec/fixtures/examples/ip_address.rb +103 -0
  92. data/spec/fixtures/examples/json.rb +107 -0
  93. data/spec/fixtures/examples/local.rb +60 -0
  94. data/spec/fixtures/examples/mathn.rb +47 -0
  95. data/spec/fixtures/examples/minilisp.rb +75 -0
  96. data/spec/fixtures/examples/modularity.rb +60 -0
  97. data/spec/fixtures/examples/nested_errors.rb +95 -0
  98. data/spec/fixtures/examples/optimized_erb.rb +105 -0
  99. data/spec/fixtures/examples/parens.rb +25 -0
  100. data/spec/fixtures/examples/prec_calc.rb +71 -0
  101. data/spec/fixtures/examples/readme.rb +59 -0
  102. data/spec/fixtures/examples/scopes.rb +43 -0
  103. data/spec/fixtures/examples/seasons.rb +40 -0
  104. data/spec/fixtures/examples/sentence.rb +18 -0
  105. data/spec/fixtures/examples/simple_xml.rb +51 -0
  106. data/spec/fixtures/examples/string_parser.rb +77 -0
  107. data/spec/parslet/atom_results_spec.rb +39 -0
  108. data/spec/parslet/atoms/alternative_spec.rb +26 -0
  109. data/spec/parslet/atoms/base_spec.rb +127 -0
  110. data/spec/parslet/atoms/capture_spec.rb +21 -0
  111. data/spec/parslet/atoms/combinations_spec.rb +5 -0
  112. data/spec/parslet/atoms/dsl_spec.rb +7 -0
  113. data/spec/parslet/atoms/entity_spec.rb +77 -0
  114. data/spec/parslet/atoms/ignored_spec.rb +15 -0
  115. data/spec/parslet/atoms/infix_spec.rb +5 -0
  116. data/spec/parslet/atoms/lookahead_spec.rb +22 -0
  117. data/spec/parslet/atoms/named_spec.rb +4 -0
  118. data/spec/parslet/atoms/re_spec.rb +14 -0
  119. data/spec/parslet/atoms/repetition_spec.rb +24 -0
  120. data/spec/parslet/atoms/scope_spec.rb +26 -0
  121. data/spec/parslet/atoms/sequence_spec.rb +28 -0
  122. data/spec/parslet/atoms/str_spec.rb +15 -0
  123. data/spec/parslet/atoms/visitor_spec.rb +101 -0
  124. data/spec/parslet/atoms_spec.rb +488 -0
  125. data/spec/parslet/convenience_spec.rb +54 -0
  126. data/spec/parslet/error_reporter/contextual_spec.rb +118 -0
  127. data/spec/parslet/error_reporter/deepest_spec.rb +82 -0
  128. data/spec/parslet/error_reporter/tree_spec.rb +7 -0
  129. data/spec/parslet/export_spec.rb +40 -0
  130. data/spec/parslet/expression/treetop_spec.rb +74 -0
  131. data/spec/parslet/minilisp.citrus +29 -0
  132. data/spec/parslet/minilisp.tt +29 -0
  133. data/spec/parslet/parser_spec.rb +36 -0
  134. data/spec/parslet/parslet_spec.rb +38 -0
  135. data/spec/parslet/pattern_spec.rb +272 -0
  136. data/spec/parslet/position_spec.rb +14 -0
  137. data/spec/parslet/rig/rspec_spec.rb +54 -0
  138. data/spec/parslet/scope_spec.rb +45 -0
  139. data/spec/parslet/slice_spec.rb +186 -0
  140. data/spec/parslet/source/line_cache_spec.rb +74 -0
  141. data/spec/parslet/source_spec.rb +210 -0
  142. data/spec/parslet/transform/context_spec.rb +56 -0
  143. data/spec/parslet/transform_spec.rb +183 -0
  144. data/spec/spec_helper.rb +74 -0
  145. data/spec/support/opal.rb +8 -0
  146. data/spec/support/opal.rb.erb +14 -0
  147. data/spec/support/parslet_matchers.rb +96 -0
  148. metadata +240 -0
@@ -0,0 +1,275 @@
1
+ require 'spec_helper'
2
+ require_relative '../fixtures/examples/email_parser'
3
+
4
+ RSpec.describe 'Email Parser Example' do
5
+ let(:parser) { EmailParser.new }
6
+ let(:sanitizer) { EmailSanitizer.new }
7
+
8
+ describe EmailParser do
9
+ describe '#word' do
10
+ it 'parses simple words' do
11
+ result = parser.word.parse('hello')
12
+ expect(result).to parse_as({ word: 'hello' })
13
+ end
14
+
15
+ it 'parses words with numbers' do
16
+ result = parser.word.parse('test123')
17
+ expect(result).to parse_as({ word: 'test123' })
18
+ end
19
+
20
+ it 'handles trailing space' do
21
+ result = parser.word.parse('word ')
22
+ expect(result).to parse_as({ word: 'word' })
23
+ end
24
+ end
25
+
26
+ describe '#at' do
27
+ it 'parses @ symbol' do
28
+ result = parser.at.parse('@')
29
+ expect(result).to eq('@')
30
+ end
31
+
32
+ it 'parses "at" word' do
33
+ result = parser.at.parse('at')
34
+ expect(result).to eq('at')
35
+ end
36
+
37
+ it 'parses "AT" word' do
38
+ result = parser.at.parse('AT')
39
+ expect(result).to eq('AT')
40
+ end
41
+
42
+ it 'parses "at" with dashes' do
43
+ result = parser.at.parse('-at-')
44
+ expect(result).to eq('-at-')
45
+ end
46
+
47
+ it 'parses "AT" with underscores' do
48
+ result = parser.at.parse('_AT_')
49
+ expect(result).to eq('_AT_')
50
+ end
51
+ end
52
+
53
+ describe '#dot' do
54
+ it 'parses . symbol' do
55
+ result = parser.dot.parse('.')
56
+ expect(result).to eq('.')
57
+ end
58
+
59
+ it 'parses "dot" word' do
60
+ result = parser.dot.parse('dot')
61
+ expect(result).to eq('dot')
62
+ end
63
+
64
+ it 'parses "DOT" word' do
65
+ result = parser.dot.parse('DOT')
66
+ expect(result).to eq('DOT')
67
+ end
68
+
69
+ it 'parses "dot" with dashes' do
70
+ result = parser.dot.parse('-dot-')
71
+ expect(result).to eq('-dot-')
72
+ end
73
+
74
+ it 'parses "DOT" with underscores' do
75
+ result = parser.dot.parse('_DOT_')
76
+ expect(result).to eq('_DOT_')
77
+ end
78
+ end
79
+
80
+ describe '#separator' do
81
+ it 'parses dot as separator' do
82
+ result = parser.separator.parse('.')
83
+ expect(result).to parse_as({ dot: '.' })
84
+ end
85
+
86
+ it 'parses space as separator' do
87
+ result = parser.separator.parse(' ')
88
+ expect(result).to eq(' ')
89
+ end
90
+
91
+ it 'parses "dot" word as separator' do
92
+ result = parser.separator.parse('dot')
93
+ expect(result).to parse_as({ dot: 'dot' })
94
+ end
95
+ end
96
+
97
+ describe '#words' do
98
+ it 'parses single word' do
99
+ result = parser.words.parse('hello')
100
+ expected = { word: 'hello' }
101
+ expect(result).to parse_as(expected)
102
+ end
103
+
104
+ it 'parses words separated by dots' do
105
+ result = parser.words.parse('a.b.c')
106
+ expected = [
107
+ { word: 'a' },
108
+ { dot: '.', word: 'b' },
109
+ { dot: '.', word: 'c' }
110
+ ]
111
+ expect(result).to parse_as(expected)
112
+ end
113
+
114
+ it 'parses words separated by spaces' do
115
+ # This actually fails because space separator requires a following word
116
+ # Let's test a simpler case
117
+ result = parser.words.parse('hello')
118
+ expected = { word: 'hello' }
119
+ expect(result).to parse_as(expected)
120
+ end
121
+
122
+ it 'parses words with dot separators' do
123
+ result = parser.words.parse('test.example')
124
+ expected = [
125
+ { word: 'test' },
126
+ { dot: '.', word: 'example' }
127
+ ]
128
+ expect(result).to parse_as(expected)
129
+ end
130
+ end
131
+
132
+ describe '#email (root)' do
133
+ it 'parses simple email addresses' do
134
+ result = parser.parse('user@domain.com')
135
+ expected = {
136
+ email: [
137
+ { username: { word: 'user' } },
138
+ { word: 'domain' },
139
+ { dot: '.', word: 'com' }
140
+ ]
141
+ }
142
+ expect(result).to parse_as(expected)
143
+ end
144
+
145
+ it 'parses the main example: a.b.c.d@gmail.com' do
146
+ result = parser.parse('a.b.c.d@gmail.com')
147
+ expected = {
148
+ email: [
149
+ {
150
+ username: [
151
+ { word: 'a' },
152
+ { dot: '.', word: 'b' },
153
+ { dot: '.', word: 'c' },
154
+ { dot: '.', word: 'd' }
155
+ ]
156
+ },
157
+ { word: 'gmail' },
158
+ { dot: '.', word: 'com' }
159
+ ]
160
+ }
161
+ expect(result).to parse_as(expected)
162
+ end
163
+
164
+ it 'parses emails with word-based @ and dots' do
165
+ result = parser.parse('user dot name at domain dot com')
166
+ expected = {
167
+ email: [
168
+ {
169
+ username: [
170
+ { word: 'user' },
171
+ { dot: 'dot', word: 'name' }
172
+ ]
173
+ },
174
+ { word: 'domain' },
175
+ { dot: 'dot', word: 'com' }
176
+ ]
177
+ }
178
+ expect(result).to parse_as(expected)
179
+ end
180
+
181
+ it 'handles simple email structure' do
182
+ result = parser.parse('test@example.org')
183
+ expected = {
184
+ email: [
185
+ { username: { word: 'test' } },
186
+ { word: 'example' },
187
+ { dot: '.', word: 'org' }
188
+ ]
189
+ }
190
+ expect(result).to parse_as(expected)
191
+ end
192
+ end
193
+ end
194
+
195
+ describe EmailSanitizer do
196
+ describe 'transformation rules' do
197
+ it 'transforms dot + word combinations' do
198
+ input = { dot: '.', word: Parslet::Slice.new(Parslet::Position.new('test', 0), 'test') }
199
+ result = sanitizer.apply(input)
200
+ expect(result).to eq('.test')
201
+ end
202
+
203
+ it 'transforms standalone words' do
204
+ input = { word: Parslet::Slice.new(Parslet::Position.new('hello', 0), 'hello') }
205
+ result = sanitizer.apply(input)
206
+ expect(result).to eq('hello')
207
+ end
208
+
209
+ it 'transforms username sequences' do
210
+ input = { username: ['user', '.', 'name'] }
211
+ result = sanitizer.apply(input)
212
+ expect(result).to eq('user.name@')
213
+ end
214
+
215
+ it 'transforms simple usernames' do
216
+ input = { username: 'user' }
217
+ result = sanitizer.apply(input)
218
+ expect(result).to eq('user@')
219
+ end
220
+
221
+ it 'transforms email sequences' do
222
+ input = { email: ['user@', 'domain', '.', 'com'] }
223
+ result = sanitizer.apply(input)
224
+ expect(result).to eq('user@domain.com')
225
+ end
226
+ end
227
+ end
228
+
229
+ describe 'integration test' do
230
+ it 'processes the main example correctly: a.b.c.d@gmail.com' do
231
+ input = 'a.b.c.d@gmail.com'
232
+ tree = parser.parse(input)
233
+ result = sanitizer.apply(tree)
234
+
235
+ # Expected result from the example file
236
+ expect(result).to eq('a.b.c.d@gmail.com')
237
+ end
238
+
239
+ it 'handles simple email addresses' do
240
+ input = 'user@domain.com'
241
+ tree = parser.parse(input)
242
+ result = sanitizer.apply(tree)
243
+ expect(result).to eq('user@domain.com')
244
+ end
245
+
246
+ it 'sanitizes word-based email notation' do
247
+ input = 'user dot name at domain dot com'
248
+ tree = parser.parse(input)
249
+ result = sanitizer.apply(tree)
250
+ expect(result).to eq('user.name@domain.com')
251
+ end
252
+
253
+ it 'handles mixed notation' do
254
+ input = 'test.user at example dot org'
255
+ tree = parser.parse(input)
256
+ result = sanitizer.apply(tree)
257
+ expect(result).to eq('test.user@example.org')
258
+ end
259
+
260
+ it 'handles complex email structures' do
261
+ input = 'test@example.org'
262
+ tree = parser.parse(input)
263
+ result = sanitizer.apply(tree)
264
+ expect(result).to eq('test@example.org')
265
+ end
266
+
267
+ it 'produces the expected output from the example file' do
268
+ # This matches the exact output shown in the example file
269
+ input = 'a.b.c.d@gmail.com'
270
+ tree = parser.parse(input)
271
+ result = sanitizer.apply(tree)
272
+ expect(result).to eq('a.b.c.d@gmail.com')
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require_relative '../fixtures/examples/empty'
3
+
4
+ RSpec.describe 'Empty Parser Example' do
5
+ let(:parser) { EmptyExample::MyParser.new }
6
+
7
+ describe EmptyExample::MyParser do
8
+ describe '#empty' do
9
+ it 'raises NotImplementedError when called' do
10
+ expect { parser.empty.parslet }.to raise_error(NotImplementedError)
11
+ end
12
+
13
+ it 'demonstrates empty rule behavior' do
14
+ # The empty rule has no implementation, so accessing its parslet should fail
15
+ expect { parser.empty.parslet }.to raise_error(NotImplementedError, /rule.*empty.*not.*implemented/i)
16
+ end
17
+ end
18
+ end
19
+
20
+ describe 'integration test' do
21
+ it 'reproduces the behavior from the example file' do
22
+ # The example file calls MyParser.new.empty.parslet which should raise NotImplementedError
23
+ expect { EmptyExample::MyParser.new.empty.parslet }.to raise_error(NotImplementedError)
24
+ end
25
+
26
+ it 'shows that empty rules can be used for quick parser specification' do
27
+ # This demonstrates the concept mentioned in the comment:
28
+ # "A way to quickly spec out your parser rules?"
29
+
30
+ # You can define the rule structure without implementation
31
+ expect(parser).to respond_to(:empty)
32
+
33
+ # But trying to use it will remind you to implement it
34
+ expect { parser.empty.parslet }.to raise_error(NotImplementedError)
35
+ end
36
+ end
37
+ end