rip-parser 0.1.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 (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