rip-parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +15 -0
  3. data/.gitignore +9 -0
  4. data/.rspec +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +3 -0
  7. data/LICENSE.md +9 -0
  8. data/README.md +13 -0
  9. data/Rakefile +1 -0
  10. data/bin/console +8 -0
  11. data/bin/setup +8 -0
  12. data/legacy/normalizer.rb +279 -0
  13. data/legacy/parser_spec.rb +999 -0
  14. data/legacy/rules.rb +250 -0
  15. data/legacy/rules_spec.rb +1700 -0
  16. data/rip-parser.gemspec +20 -0
  17. data/source/rip/parser/about.rb +9 -0
  18. data/source/rip/parser/error.rb +36 -0
  19. data/source/rip/parser/grammar.rb +23 -0
  20. data/source/rip/parser/keywords.rb +84 -0
  21. data/source/rip/parser/location.rb +47 -0
  22. data/source/rip/parser/node.rb +115 -0
  23. data/source/rip/parser/rules/assignment.rb +23 -0
  24. data/source/rip/parser/rules/binary_condition.rb +24 -0
  25. data/source/rip/parser/rules/character.rb +40 -0
  26. data/source/rip/parser/rules/class.rb +60 -0
  27. data/source/rip/parser/rules/common.rb +47 -0
  28. data/source/rip/parser/rules/date_time.rb +31 -0
  29. data/source/rip/parser/rules/expression.rb +122 -0
  30. data/source/rip/parser/rules/import.rb +23 -0
  31. data/source/rip/parser/rules/invocation.rb +15 -0
  32. data/source/rip/parser/rules/invocation_index.rb +15 -0
  33. data/source/rip/parser/rules/keyword.rb +12 -0
  34. data/source/rip/parser/rules/lambda.rb +45 -0
  35. data/source/rip/parser/rules/list.rb +18 -0
  36. data/source/rip/parser/rules/map.rb +15 -0
  37. data/source/rip/parser/rules/module.rb +29 -0
  38. data/source/rip/parser/rules/number.rb +21 -0
  39. data/source/rip/parser/rules/pair.rb +13 -0
  40. data/source/rip/parser/rules/property.rb +33 -0
  41. data/source/rip/parser/rules/range.rb +15 -0
  42. data/source/rip/parser/rules/reference.rb +16 -0
  43. data/source/rip/parser/rules/string.rb +41 -0
  44. data/source/rip/parser/rules/unit.rb +17 -0
  45. data/source/rip/parser/rules.rb +7 -0
  46. data/source/rip/parser/utilities/normalizer.rb +638 -0
  47. data/source/rip/parser.rb +24 -0
  48. data/source/rip-parser.rb +1 -0
  49. data/spec/fixtures/syntax_sample.rip +96 -0
  50. data/spec/spec_helper.rb +20 -0
  51. data/spec/support/helpers.rb +57 -0
  52. data/spec/support/parslet.rb +1 -0
  53. data/spec/support/shared_examples.rb +9 -0
  54. data/spec/unit/rip/parser/grammar_spec.rb +8 -0
  55. data/spec/unit/rip/parser/location_spec.rb +89 -0
  56. data/spec/unit/rip/parser/node_spec.rb +157 -0
  57. data/spec/unit/rip/parser/rules/assignment_spec.rb +59 -0
  58. data/spec/unit/rip/parser/rules/binary_condition_spec.rb +41 -0
  59. data/spec/unit/rip/parser/rules/character_spec.rb +29 -0
  60. data/spec/unit/rip/parser/rules/class_spec.rb +181 -0
  61. data/spec/unit/rip/parser/rules/common_spec.rb +88 -0
  62. data/spec/unit/rip/parser/rules/date_time_spec.rb +61 -0
  63. data/spec/unit/rip/parser/rules/expression_spec.rb +95 -0
  64. data/spec/unit/rip/parser/rules/import_spec.rb +64 -0
  65. data/spec/unit/rip/parser/rules/invocation_index_spec.rb +46 -0
  66. data/spec/unit/rip/parser/rules/invocation_spec.rb +46 -0
  67. data/spec/unit/rip/parser/rules/keyword_spec.rb +17 -0
  68. data/spec/unit/rip/parser/rules/lambda_spec.rb +174 -0
  69. data/spec/unit/rip/parser/rules/list_spec.rb +45 -0
  70. data/spec/unit/rip/parser/rules/map_spec.rb +36 -0
  71. data/spec/unit/rip/parser/rules/module_spec.rb +63 -0
  72. data/spec/unit/rip/parser/rules/number_spec.rb +40 -0
  73. data/spec/unit/rip/parser/rules/pair_spec.rb +25 -0
  74. data/spec/unit/rip/parser/rules/property_spec.rb +27 -0
  75. data/spec/unit/rip/parser/rules/range_spec.rb +37 -0
  76. data/spec/unit/rip/parser/rules/reference_spec.rb +43 -0
  77. data/spec/unit/rip/parser/rules/string_spec.rb +166 -0
  78. data/spec/unit/rip/parser/rules/unit_spec.rb +17 -0
  79. data/spec/unit/rip/parser_spec.rb +106 -0
  80. metadata +192 -0
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Lambda do
4
+ class LambdaParser
5
+ include Rip::Parser::Rules::Lambda
6
+ include Rip::Parser::Rules::Module
7
+ end
8
+
9
+ let(:parser) { LambdaParser.new }
10
+
11
+ describe '#lambda_block' do
12
+ subject { parser.lambda_block }
13
+
14
+ it do
15
+ should parse('=> { -> { 42 } }').as(
16
+ fat_rocket: '=>',
17
+ overloads: [
18
+ {
19
+ dash_rocket: '->',
20
+ body: { expression_chain: { integer: '42' } }
21
+ }
22
+ ]
23
+ )
24
+ end
25
+
26
+ it do
27
+ should parse('=> { -> { 42 } (foo) -> { foo } }').as(
28
+ fat_rocket: '=>',
29
+ overloads: [
30
+ {
31
+ dash_rocket: '->',
32
+ body: { expression_chain: { integer: '42' } }
33
+ },
34
+ {
35
+ dash_rocket: '->',
36
+ parameters: [ { parameter: 'foo' } ],
37
+ body: { expression_chain: { reference: 'foo' } }
38
+ }
39
+ ]
40
+ )
41
+ end
42
+
43
+ it { should_not parse('=> { }') }
44
+ end
45
+
46
+ describe '#overload_block' do
47
+ subject { parser.overload_block }
48
+
49
+ it do
50
+ should parse('-> { 42 }').as(
51
+ dash_rocket: '->',
52
+ body: { expression_chain: { integer: '42' } }
53
+ )
54
+ end
55
+
56
+ it do
57
+ should parse('() -> { 42 }').as(
58
+ dash_rocket: '->',
59
+ parameters: [],
60
+ body: { expression_chain: { integer: '42' } }
61
+ )
62
+ end
63
+
64
+ it { should_not parse('-> {}') }
65
+ end
66
+
67
+ describe '#parameters' do
68
+ subject { parser.parameters }
69
+
70
+ it { should parse('()').as(parameters: []) }
71
+
72
+ it do
73
+ should parse('(foo)').as(
74
+ parameters: [
75
+ { parameter: 'foo' }
76
+ ]
77
+ )
78
+ end
79
+
80
+ it do
81
+ should parse('(foo<integer>, bar)').as(
82
+ parameters: [
83
+ { parameter: 'foo', type_argument: { reference: 'integer' } },
84
+ { parameter: 'bar' }
85
+ ]
86
+ )
87
+ end
88
+
89
+ it do
90
+ should parse('(foo<integer> = 42)').as(
91
+ parameters: [
92
+ { parameter: 'foo', default: { expression_chain: { integer: '42' } }, type_argument: { reference: 'integer' } }
93
+ ]
94
+ )
95
+ end
96
+
97
+ it do
98
+ should parse('(foo, bar<integer>, baz = 42)').as(
99
+ parameters: [
100
+ { parameter: 'foo' },
101
+ { parameter: 'bar', type_argument: { reference: 'integer' } },
102
+ { parameter: 'baz', default: { expression_chain: { integer: '42' } } }
103
+ ]
104
+ )
105
+ end
106
+ end
107
+
108
+ describe '#required_parameter' do
109
+ subject { parser.required_parameter }
110
+
111
+ it { should parse('foo').as(parameter: 'foo') }
112
+
113
+ it do
114
+ should parse('foo<bar>').as(
115
+ parameter: 'foo',
116
+ type_argument: { reference: 'bar' }
117
+ )
118
+ end
119
+ end
120
+
121
+ describe '#optional_parameter' do
122
+ subject { parser.optional_parameter }
123
+
124
+ it do
125
+ should parse('foo = 42').as(
126
+ parameter: 'foo',
127
+ default: { expression_chain: { integer: '42' } }
128
+ )
129
+ end
130
+
131
+ it do
132
+ should parse('foo<bar> = 42').as(
133
+ parameter: 'foo',
134
+ default: { expression_chain: { integer: '42' } },
135
+ type_argument: { reference: 'bar' }
136
+ )
137
+ end
138
+ end
139
+
140
+ describe '#parameter_type_argument' do
141
+ subject { parser.parameter_type_argument }
142
+
143
+ it { should parse('<foo>').as(type_argument: { reference: 'foo' }) }
144
+ end
145
+
146
+ describe '#block_body' do
147
+ subject { parser.block_body }
148
+
149
+ it do
150
+ should parse('{ :one }').as(
151
+ body: { expression_chain: { location: ':', string: [
152
+ { character: 'o' },
153
+ { character: 'n' },
154
+ { character: 'e' }
155
+ ] } }
156
+ )
157
+ end
158
+
159
+ it do
160
+ should parse('{ 42; :cat }').as(
161
+ body: [
162
+ { expression_chain: { integer: '42' } },
163
+ { expression_chain: { location: ':', string: [
164
+ { character: 'c' },
165
+ { character: 'a' },
166
+ { character: 't' }
167
+ ] } }
168
+ ]
169
+ )
170
+ end
171
+
172
+ it { should_not parse('{}') }
173
+ end
174
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::List do
4
+ class ListParser
5
+ include Parslet
6
+
7
+ include Rip::Parser::Rules::List
8
+ include Rip::Parser::Rules::Number
9
+ include Rip::Parser::Rules::String
10
+
11
+ rule(:expression) { number | string | list }
12
+ end
13
+
14
+ let(:parser) { ListParser.new }
15
+
16
+ describe '#list' do
17
+ subject { parser.list }
18
+
19
+ it { should parse('[]').as(location: '[', list: []) }
20
+
21
+ it do
22
+ should parse('[ 1, 2, 3.14 ]').as(location: '[', list: [
23
+ { integer: '1' },
24
+ { integer: '2' },
25
+ { integer: '3', decimal: '14' }
26
+ ])
27
+ end
28
+
29
+ it do
30
+ should parse('[ "nested", [] ]').as(location: '[', list: [
31
+ {
32
+ location: '"', string: [
33
+ { character: 'n' },
34
+ { character: 'e' },
35
+ { character: 's' },
36
+ { character: 't' },
37
+ { character: 'e' },
38
+ { character: 'd' }
39
+ ]
40
+ },
41
+ { location: '[', list: [] }
42
+ ])
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Map do
4
+ class MapParser
5
+ include Parslet
6
+
7
+ include Rip::Parser::Rules::Map
8
+ include Rip::Parser::Rules::Reference
9
+ include Rip::Parser::Rules::String
10
+
11
+ rule(:expression) { reference | string | map }
12
+ end
13
+
14
+ let(:parser) { MapParser.new }
15
+
16
+ describe '#map' do
17
+ subject { parser.map }
18
+
19
+ it { should parse('{}').as(location: '{', map: []) }
20
+
21
+ it do
22
+ should parse('{ a, b, c }').as(location: '{', map: [
23
+ { reference: 'a' },
24
+ { reference: 'b' },
25
+ { reference: 'c' }
26
+ ])
27
+ end
28
+
29
+ it do
30
+ should parse('{ nested, {} }').as(location: '{', map: [
31
+ { reference: 'nested' },
32
+ { location: '{', map: [] }
33
+ ])
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Module do
4
+ class ModuleParser
5
+ include Parslet
6
+
7
+ include Rip::Parser::Rules::Module
8
+ include Rip::Parser::Rules::Number
9
+ include Rip::Parser::Rules::String
10
+
11
+ rule(:expression) { number | string | list }
12
+ end
13
+
14
+ let(:parser) { ModuleParser.new }
15
+
16
+ describe '#module' do
17
+ subject { parser.module }
18
+
19
+ it do
20
+ should parse('42;3.14').as(module: [
21
+ { integer: '42' },
22
+ { integer: '3', decimal: '14' }
23
+ ])
24
+ end
25
+
26
+ it do
27
+ should parse(":foo\n:bar\n:baz").as(module: [
28
+ {
29
+ location: ':',
30
+ string: [
31
+ { character: 'f' },
32
+ { character: 'o' },
33
+ { character: 'o' }
34
+ ]
35
+ },
36
+ {
37
+ location: ':',
38
+ string: [
39
+ { character: 'b' },
40
+ { character: 'a' },
41
+ { character: 'r' }
42
+ ]
43
+ },
44
+ {
45
+ location: ':',
46
+ string: [
47
+ { character: 'b' },
48
+ { character: 'a' },
49
+ { character: 'z' }
50
+ ]
51
+ }
52
+ ])
53
+ end
54
+
55
+ it { should_not parse('') }
56
+
57
+ it { should_not parse('# comment') }
58
+
59
+ it { should_not parse('42 3.14') }
60
+
61
+ it { should_not parse(':aaa :bbb') }
62
+ end
63
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Number do
4
+ class NumberParser
5
+ include Rip::Parser::Rules::Number
6
+ end
7
+
8
+ let(:parser) { NumberParser.new }
9
+
10
+ describe '#integer' do
11
+ subject { parser.integer }
12
+
13
+ it { should parse('42').as(integer: '42') }
14
+ end
15
+
16
+ describe '#decimal' do
17
+ subject { parser.decimal }
18
+
19
+ it { should parse('3.14').as(integer: '3', decimal: '14') }
20
+ end
21
+
22
+ describe '#number' do
23
+ subject { parser.number }
24
+
25
+ it { should parse('42').as(integer: '42') }
26
+ it { should parse('+42').as(integer: '42', sign: '+') }
27
+ it { should parse('-3.14').as(integer: '3', decimal: '14', sign: '-') }
28
+ end
29
+
30
+ describe '#digits' do
31
+ subject { parser.digits }
32
+
33
+ it { should parse('0') }
34
+ it { should parse('1_234_567_890') }
35
+
36
+ it { should_not parse('_1') }
37
+ it { should_not parse('2_') }
38
+ it { should_not parse('3__4') }
39
+ end
40
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Pair do
4
+ class PairParser
5
+ include ::Parslet
6
+
7
+ include Rip::Parser::Rules::Module
8
+ include Rip::Parser::Rules::Pair
9
+ end
10
+
11
+ let(:parser) { PairParser.new }
12
+
13
+ describe '#pair_value' do
14
+ subject { parser.pair_value }
15
+
16
+ it do
17
+ should parse(': value').as(
18
+ location: ':',
19
+ value: {
20
+ expression_chain: { reference: 'value' }
21
+ }
22
+ )
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Property do
4
+ class PropertyParser
5
+ include Rip::Parser::Rules::Property
6
+ end
7
+
8
+ let(:parser) { PropertyParser.new }
9
+
10
+ describe '#property' do
11
+ subject { parser.property }
12
+
13
+ it { should parse('.code').as(location: '.', property_name: 'code') }
14
+ it { should parse("\n.code").as(location: '.', property_name: 'code') }
15
+ it { should parse(".\ncode").as(location: '.', property_name: 'code') }
16
+ end
17
+
18
+ describe '#property_name' do
19
+ subject { parser.property_name }
20
+
21
+ Rip::Parser::Rules::Property::SPECIAL_NAMES.each do |name|
22
+ it { should parse(name) }
23
+ end
24
+
25
+ it { should_not parse('>~<') }
26
+ end
27
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Range do
4
+ class RangeParser
5
+ include ::Parslet
6
+
7
+ include Rip::Parser::Rules::Module
8
+ include Rip::Parser::Rules::Range
9
+ end
10
+
11
+ let(:parser) { RangeParser.new }
12
+
13
+ describe '#range_end' do
14
+ subject { parser.range_end }
15
+
16
+ it do
17
+ should parse('..`z').as(
18
+ location: '..',
19
+ end: {
20
+ expression_chain: { character: 'z', location: '`' }
21
+ }
22
+ )
23
+ end
24
+
25
+ it do
26
+ should parse('..5.to_float').as(
27
+ location: '..',
28
+ end: {
29
+ expression_chain: [
30
+ { integer: '5' },
31
+ { property_name: 'to_float', location: '.' }
32
+ ]
33
+ }
34
+ )
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Reference do
4
+ class ReferenceParser
5
+ include Rip::Parser::Rules::Reference
6
+ end
7
+
8
+ let(:parser) { ReferenceParser.new }
9
+
10
+ describe '#reference' do
11
+ subject { parser.reference }
12
+
13
+ [
14
+ 'name',
15
+ 'Person',
16
+ '==',
17
+ 'save!',
18
+ 'valid?',
19
+ 'long_ref-name',
20
+ '*-+&$~%',
21
+ 'one_9',
22
+ 'ɹÇʇɹoÔ€uÉl∀™',
23
+ 'nilly',
24
+ 'nil',
25
+ 'true',
26
+ 'false',
27
+ 'System',
28
+ 'returner'
29
+ ].each do |word|
30
+ it { should parse(word).as(reference: word) }
31
+ end
32
+
33
+ [
34
+ 'one.two',
35
+ '999',
36
+ '6teen',
37
+ 'rip rocks',
38
+ 'key:value'
39
+ ].each do |word|
40
+ it { should_not parse(word) }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,166 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::String do
4
+ class StringParser
5
+ include ::Parslet
6
+
7
+ include Rip::Parser::Rules::Reference
8
+ include Rip::Parser::Rules::String
9
+
10
+ rule(:expression) { reference }
11
+ end
12
+
13
+ let(:parser) { StringParser.new }
14
+
15
+ describe '#string' do
16
+ subject { parser.string }
17
+
18
+ it { should parse(':rip') }
19
+ it { should parse('""') }
20
+ it { should parse('"foo-bar-baz"') }
21
+
22
+ it do
23
+ should parse(strip_heredoc(<<-RIP))
24
+ <<DOC
25
+ foo
26
+ bar
27
+ baz
28
+ DOC
29
+ RIP
30
+ end
31
+ end
32
+
33
+ describe '#string_symbol' do
34
+ subject { parser.string_symbol }
35
+
36
+ it do
37
+ should parse(':cat').as(location: ':', string: [
38
+ { character: 'c' },
39
+ { character: 'a' },
40
+ { character: 't' }
41
+ ])
42
+ end
43
+
44
+ it do
45
+ should parse(':7').as(location: ':', string: [
46
+ { character: '7' }
47
+ ])
48
+ end
49
+
50
+ it { should_not parse(':foo#{bar}baz') }
51
+ end
52
+
53
+ describe '#string_double' do
54
+ subject { parser.string_double }
55
+
56
+ it do
57
+ should parse('"dog"').as(location: '"', string: [
58
+ { character: 'd' },
59
+ { character: 'o' },
60
+ { character: 'g' }
61
+ ])
62
+ end
63
+
64
+ it do
65
+ should parse('"a\nb"').as(location: '"', string: [
66
+ { character: 'a' },
67
+ { escape_location: '\\', escape_special: 'n' },
68
+ { character: 'b' }
69
+ ])
70
+ end
71
+
72
+ it do
73
+ should parse('"foo#{bar}baz"').as(location: '"', string: [
74
+ { character: 'f' },
75
+ { character: 'o' },
76
+ { character: 'o' },
77
+ { location: '#{', interpolation: { reference: 'bar' } },
78
+ { character: 'b' },
79
+ { character: 'a' },
80
+ { character: 'z' }
81
+ ])
82
+ end
83
+ end
84
+
85
+ describe '#regular_expression' do
86
+ subject { parser.regular_expression }
87
+
88
+ it do
89
+ should parse('/r\.p/').as(location: '/', regular_expression: [
90
+ { character: 'r' },
91
+ { escape_location: '\\', escape_any: '.' },
92
+ { character: 'p' }
93
+ ])
94
+ end
95
+
96
+ it do
97
+ should parse('/f#{bar}b/').as(location: '/', regular_expression: [
98
+ { character: 'f' },
99
+ { location: '#{', interpolation: { reference: 'bar' } },
100
+ { character: 'b' }
101
+ ])
102
+ end
103
+ end
104
+
105
+ describe '#heredoc' do
106
+ subject { parser.heredoc }
107
+
108
+ context 'normal' do
109
+ let(:rip) do
110
+ strip_heredoc(<<-RIP)
111
+ <<BLOCK
112
+ multi-line
113
+ string
114
+ BLOCK
115
+ RIP
116
+ end
117
+
118
+ it do
119
+ should parse(rip).as(location: '<<', label: 'BLOCK', string: [
120
+ { character: 'm' }, { character: 'u' }, { character: 'l' }, { character: 't' },
121
+ { character: 'i' }, { character: '-' }, { character: 'l' }, { character: 'i' },
122
+ { character: 'n' }, { character: 'e' }, { character: "\n" }, { character: 's' },
123
+ { character: 't' }, { character: 'r' }, { character: 'i' }, { character: 'n' },
124
+ { character: 'g' }, { character: "\n" }
125
+ ])
126
+ end
127
+ end
128
+
129
+ context 'interpolation' do
130
+ let(:rip) do
131
+ strip_heredoc(<<-RIP)
132
+ <<BLOCK
133
+ \#{answer}
134
+ BLOCK
135
+ RIP
136
+ end
137
+
138
+ it do
139
+ should parse(rip).as(location: '<<', label: 'BLOCK', string: [
140
+ { location: '#{', interpolation: { reference: 'answer' } },
141
+ { character: "\n" }
142
+ ])
143
+ end
144
+ end
145
+
146
+ context 'pathelogical' do
147
+ let(:rip) do
148
+ strip_heredoc(<<-RIP)
149
+ <<BLOCK
150
+
151
+ \\tfoo
152
+
153
+ BLOCK
154
+ RIP
155
+ end
156
+
157
+ it do
158
+ should parse(rip).as(location: '<<', label: 'BLOCK', string: [
159
+ { character: "\n" },
160
+ { escape_location: '\\', escape_special: 't' }, { character: 'f' }, { character: 'o' }, { character: 'o' }, { character: "\n" },
161
+ { character: "\n" }
162
+ ])
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Rip::Parser::Rules::Unit do
4
+ class UnitParser
5
+ include Rip::Parser::Rules::Unit
6
+ end
7
+
8
+ let(:parser) { UnitParser.new }
9
+
10
+ describe '#unit' do
11
+ subject { parser.unit }
12
+
13
+ it { should parse('-42°').as(magnitude: { sign: '-', integer: '42' }, label: '°') }
14
+
15
+ it { should parse('6.28circle').as(magnitude: { integer: '6', decimal: '28' }, label: 'circle') }
16
+ end
17
+ end