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,119 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+ require_relative '../fixtures/examples/sentence'
5
+
6
+ RSpec.describe 'Sentence Parser Example' do
7
+ let(:parser) { SentenceExample::MyParser.new }
8
+ let(:transformer) { SentenceExample::Transformer.new }
9
+
10
+ describe SentenceExample::MyParser do
11
+ describe '#sentence' do
12
+ it 'parses a single sentence ending with 。' do
13
+ result = parser.sentence.parse("テスト。")
14
+ expect(result).to parse_as({ sentence: "テスト。" })
15
+ end
16
+
17
+ it 'parses sentences with complex Unicode characters' do
18
+ result = parser.sentence.parse("RubyKaigi2009のテーマは、「変わる/変える」です。")
19
+ expect(result).to parse_as({ sentence: "RubyKaigi2009のテーマは、「変わる/変える」です。" })
20
+ end
21
+
22
+ it 'fails to parse text without sentence ending' do
23
+ expect { parser.sentence.parse("テスト") }.to raise_error(Parslet::ParseFailed)
24
+ end
25
+ end
26
+
27
+ describe '#sentences' do
28
+ it 'parses multiple sentences' do
29
+ input = "第一。第二。第三。"
30
+ result = parser.sentences.parse(input)
31
+ expected = [
32
+ { sentence: "第一。" },
33
+ { sentence: "第二。" },
34
+ { sentence: "第三。" }
35
+ ]
36
+ expect(result).to parse_as(expected)
37
+ end
38
+
39
+ it 'parses single sentence as array' do
40
+ result = parser.sentences.parse("テスト。")
41
+ expected = [{ sentence: "テスト。" }]
42
+ expect(result).to parse_as(expected)
43
+ end
44
+
45
+ it 'parses empty input as empty array' do
46
+ result = parser.sentences.parse("")
47
+ expect(result).to eq("")
48
+ end
49
+ end
50
+
51
+ describe 'root parser' do
52
+ it 'parses the full example string correctly' do
53
+ string = "RubyKaigi2009のテーマは、「変わる/変える」です。 前回の" +
54
+ "RubyKaigi2008のテーマであった「多様性」の言葉の通り、 " +
55
+ "2008年はRubyそのものに関しても、またRubyの活躍する舞台に関しても、 " +
56
+ "ますます多様化が進みつつあります。RubyKaigi2008は、そのような " +
57
+ "Rubyの生態系をあらためて認識する場となりました。 しかし、" +
58
+ "こうした多様化が進む中、異なる者同士が単純に距離を 置いたままでは、" +
59
+ "その違いを認識したところであまり意味がありません。 異なる実装、" +
60
+ "異なる思想、異なる背景といった、様々な多様性を理解しつつ、 " +
61
+ "すり合わせるべきものをすり合わせ、変えていくべきところを " +
62
+ "変えていくことが、豊かな未来へとつながる道に違いありません。"
63
+
64
+ result = parser.parse(string)
65
+ expected = [
66
+ { sentence: "RubyKaigi2009のテーマは、「変わる/変える」です。" },
67
+ { sentence: " 前回のRubyKaigi2008のテーマであった「多様性」の言葉の通り、 2008年はRubyそのものに関しても、またRubyの活躍する舞台に関しても、 ますます多様化が進みつつあります。" },
68
+ { sentence: "RubyKaigi2008は、そのような Rubyの生態系をあらためて認識する場となりました。" },
69
+ { sentence: " しかし、こうした多様化が進む中、異なる者同士が単純に距離を 置いたままでは、その違いを認識したところであまり意味がありません。" },
70
+ { sentence: " 異なる実装、異なる思想、異なる背景といった、様々な多様性を理解しつつ、 すり合わせるべきものをすり合わせ、変えていくべきところを 変えていくことが、豊かな未来へとつながる道に違いありません。" }
71
+ ]
72
+ expect(result).to parse_as(expected)
73
+ end
74
+ end
75
+ end
76
+
77
+ describe SentenceExample::Transformer do
78
+ it 'transforms sentence slices to strings' do
79
+ input = { sentence: Parslet::Slice.new(Parslet::Position.new("テスト", 0), "テスト") }
80
+ result = transformer.apply(input)
81
+ expect(result).to eq("テスト")
82
+ end
83
+
84
+ it 'transforms array of sentences' do
85
+ input = [
86
+ { sentence: Parslet::Slice.new(Parslet::Position.new("第一第二", 0), "第一") },
87
+ { sentence: Parslet::Slice.new(Parslet::Position.new("第一第二", 2), "第二") }
88
+ ]
89
+ result = transformer.apply(input)
90
+ expect(result).to eq(["第一", "第二"])
91
+ end
92
+ end
93
+
94
+ describe 'integration test' do
95
+ it 'processes the full example correctly' do
96
+ string = "RubyKaigi2009のテーマは、「変わる/変える」です。 前回の" +
97
+ "RubyKaigi2008のテーマであった「多様性」の言葉の通り、 " +
98
+ "2008年はRubyそのものに関しても、またRubyの活躍する舞台に関しても、 " +
99
+ "ますます多様化が進みつつあります。RubyKaigi2008は、そのような " +
100
+ "Rubyの生態系をあらためて認識する場となりました。 しかし、" +
101
+ "こうした多様化が進む中、異なる者同士が単純に距離を 置いたままでは、" +
102
+ "その違いを認識したところであまり意味がありません。 異なる実装、" +
103
+ "異なる思想、異なる背景といった、様々な多様性を理解しつつ、 " +
104
+ "すり合わせるべきものをすり合わせ、変えていくべきところを " +
105
+ "変えていくことが、豊かな未来へとつながる道に違いありません。"
106
+
107
+ tree = parser.parse(string)
108
+ result = transformer.apply(tree)
109
+
110
+ expect(result).to be_an(Array)
111
+ expect(result.length).to eq(5)
112
+ expect(result[0]).to eq("RubyKaigi2009のテーマは、「変わる/変える」です。")
113
+ expect(result[1]).to eq(" 前回のRubyKaigi2008のテーマであった「多様性」の言葉の通り、 2008年はRubyそのものに関しても、またRubyの活躍する舞台に関しても、 ますます多様化が進みつつあります。")
114
+ expect(result[2]).to eq("RubyKaigi2008は、そのような Rubyの生態系をあらためて認識する場となりました。")
115
+ expect(result[3]).to eq(" しかし、こうした多様化が進む中、異なる者同士が単純に距離を 置いたままでは、その違いを認識したところであまり意味がありません。")
116
+ expect(result[4]).to eq(" 異なる実装、異なる思想、異なる背景といった、様々な多様性を理解しつつ、 すり合わせるべきものをすり合わせ、変えていくべきところを 変えていくことが、豊かな未来へとつながる道に違いありません。")
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,250 @@
1
+ require 'spec_helper'
2
+ require_relative '../fixtures/examples/simple_xml'
3
+
4
+ RSpec.describe 'Simple XML Parser Example' do
5
+ let(:parser) { XML.new }
6
+
7
+ describe XML do
8
+ describe '#text' do
9
+ it 'parses empty text' do
10
+ result = parser.text.parse('')
11
+ expect(result).to eq('')
12
+ end
13
+
14
+ it 'parses simple text' do
15
+ result = parser.text.parse('hello world')
16
+ expect(result).to eq('hello world')
17
+ end
18
+
19
+ it 'parses text with spaces and punctuation' do
20
+ result = parser.text.parse('some text in the tags')
21
+ expect(result).to eq('some text in the tags')
22
+ end
23
+
24
+ it 'stops at angle brackets' do
25
+ result = parser.text.parse('text')
26
+ expect(result).to eq('text')
27
+ end
28
+ end
29
+
30
+ describe '#tag method' do
31
+ it 'parses opening tags' do
32
+ result = parser.tag(close: false).parse('<hello>')
33
+ expect(result).to parse_as({ name: 'hello' })
34
+ end
35
+
36
+ it 'parses closing tags' do
37
+ result = parser.tag(close: true).parse('</hello>')
38
+ expect(result).to parse_as({ name: 'hello' })
39
+ end
40
+
41
+ it 'parses single letter tags' do
42
+ result = parser.tag(close: false).parse('<a>')
43
+ expect(result).to parse_as({ name: 'a' })
44
+ end
45
+
46
+ it 'parses multi-letter tags' do
47
+ result = parser.tag(close: false).parse('<body>')
48
+ expect(result).to parse_as({ name: 'body' })
49
+ end
50
+
51
+ it 'parses mixed case tags' do
52
+ result = parser.tag(close: false).parse('<MyTag>')
53
+ expect(result).to parse_as({ name: 'MyTag' })
54
+ end
55
+
56
+ it 'parses closing tags with mixed case' do
57
+ result = parser.tag(close: true).parse('</MyTag>')
58
+ expect(result).to parse_as({ name: 'MyTag' })
59
+ end
60
+ end
61
+
62
+ describe '#document (root)' do
63
+ it 'parses simple text documents' do
64
+ result = parser.parse('hello world')
65
+ expect(result).to eq('hello world')
66
+ end
67
+
68
+ it 'parses empty documents' do
69
+ result = parser.parse('')
70
+ expect(result).to eq('')
71
+ end
72
+
73
+ it 'parses simple tag pairs with text' do
74
+ result = parser.parse('<a>text</a>')
75
+ expected = {
76
+ o: { name: 'a' },
77
+ i: 'text',
78
+ c: { name: 'a' }
79
+ }
80
+ expect(result).to parse_as(expected)
81
+ end
82
+
83
+ it 'parses nested tags' do
84
+ result = parser.parse('<a><b>text</b></a>')
85
+ expected = {
86
+ o: { name: 'a' },
87
+ i: {
88
+ o: { name: 'b' },
89
+ i: 'text',
90
+ c: { name: 'b' }
91
+ },
92
+ c: { name: 'a' }
93
+ }
94
+ expect(result).to parse_as(expected)
95
+ end
96
+
97
+ it 'parses the main example: <a><b>some text in the tags</b></a>' do
98
+ result = parser.parse('<a><b>some text in the tags</b></a>')
99
+ expected = {
100
+ o: { name: 'a' },
101
+ i: {
102
+ o: { name: 'b' },
103
+ i: 'some text in the tags',
104
+ c: { name: 'b' }
105
+ },
106
+ c: { name: 'a' }
107
+ }
108
+ expect(result).to parse_as(expected)
109
+ end
110
+
111
+ it 'parses mismatched tags (parser allows this)' do
112
+ result = parser.parse('<b><b>some text in the tags</b></a>')
113
+ expected = {
114
+ o: { name: 'b' },
115
+ i: {
116
+ o: { name: 'b' },
117
+ i: 'some text in the tags',
118
+ c: { name: 'b' }
119
+ },
120
+ c: { name: 'a' }
121
+ }
122
+ expect(result).to parse_as(expected)
123
+ end
124
+
125
+ it 'parses tags with empty content' do
126
+ result = parser.parse('<tag></tag>')
127
+ expected = {
128
+ o: { name: 'tag' },
129
+ i: [],
130
+ c: { name: 'tag' }
131
+ }
132
+ expect(result).to parse_as(expected)
133
+ end
134
+
135
+ it 'parses multiple levels of nesting' do
136
+ result = parser.parse('<a><b><c>deep</c></b></a>')
137
+ expected = {
138
+ o: { name: 'a' },
139
+ i: {
140
+ o: { name: 'b' },
141
+ i: {
142
+ o: { name: 'c' },
143
+ i: 'deep',
144
+ c: { name: 'c' }
145
+ },
146
+ c: { name: 'b' }
147
+ },
148
+ c: { name: 'a' }
149
+ }
150
+ expect(result).to parse_as(expected)
151
+ end
152
+ end
153
+ end
154
+
155
+ describe 'check function' do
156
+ it 'validates matching tag pairs' do
157
+ result = check('<a><b>some text in the tags</b></a>')
158
+ expect(result).to eq('verified')
159
+ end
160
+
161
+ it 'handles mismatched tags by showing the structure' do
162
+ result = check('<b><b>some text in the tags</b></a>')
163
+ expected = {
164
+ o: { name: 'b' },
165
+ i: 'verified',
166
+ c: { name: 'a' }
167
+ }
168
+ expect(result).to eq(expected)
169
+ end
170
+
171
+ it 'validates simple tag pairs' do
172
+ result = check('<tag>content</tag>')
173
+ expect(result).to eq('verified')
174
+ end
175
+
176
+ it 'validates nested matching tags' do
177
+ result = check('<outer><inner>text</inner></outer>')
178
+ expect(result).to eq('verified')
179
+ end
180
+
181
+ it 'shows structure for partially matching tags' do
182
+ result = check('<a><b>text</b></c>')
183
+ expected = {
184
+ o: { name: 'a' },
185
+ i: 'verified',
186
+ c: { name: 'c' }
187
+ }
188
+ expect(result).to eq(expected)
189
+ end
190
+
191
+ it 'handles empty tags' do
192
+ result = check('<empty></empty>')
193
+ # Empty content results in an array, which doesn't match the transform rule
194
+ expected = {
195
+ o: { name: 'empty' },
196
+ i: [],
197
+ c: { name: 'empty' }
198
+ }
199
+ expect(result).to eq(expected)
200
+ end
201
+ end
202
+
203
+ describe 'integration test' do
204
+ it 'processes the first example correctly: <a><b>some text in the tags</b></a>' do
205
+ # This should validate to "verified"
206
+ result = check('<a><b>some text in the tags</b></a>')
207
+ expect(result).to eq('verified')
208
+ end
209
+
210
+ it 'processes the second example correctly: <b><b>some text in the tags</b></a>' do
211
+ # This should show the mismatched structure
212
+ result = check('<b><b>some text in the tags</b></a>')
213
+ expected = {
214
+ o: { name: 'b' },
215
+ i: 'verified',
216
+ c: { name: 'a' }
217
+ }
218
+ expect(result).to eq(expected)
219
+ end
220
+
221
+ it 'produces the expected outputs from the example file' do
222
+ # First example should verify
223
+ result1 = check('<a><b>some text in the tags</b></a>')
224
+ expect(result1).to eq('verified')
225
+
226
+ # Second example should show mismatch structure
227
+ result2 = check('<b><b>some text in the tags</b></a>')
228
+ expected2 = {
229
+ o: { name: 'b' },
230
+ i: 'verified',
231
+ c: { name: 'a' }
232
+ }
233
+ expect(result2).to eq(expected2)
234
+ end
235
+
236
+ it 'demonstrates the validation concept' do
237
+ # Valid XML reduces to "verified"
238
+ valid_xml = '<root><child>content</child></root>'
239
+ expect(check(valid_xml)).to eq('verified')
240
+
241
+ # Invalid XML shows the structure with mismatches
242
+ invalid_xml = '<root><child>content</wrong></root>'
243
+ result = check(invalid_xml)
244
+ expect(result).to be_a(Hash)
245
+ expect(result).to have_key(:o)
246
+ expect(result).to have_key(:i)
247
+ expect(result).to have_key(:c)
248
+ end
249
+ end
250
+ end