code-ruby-parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.overcommit.yml +4 -0
  4. data/Gemfile +5 -0
  5. data/Gemfile.lock +32 -0
  6. data/bin/code-parser +27 -0
  7. data/bin/format +3 -0
  8. data/bin/template-parser +27 -0
  9. data/docs/class.code +9 -0
  10. data/docs/meetup.code +14 -0
  11. data/docs/rain.code +23 -0
  12. data/docs/slack.code +17 -0
  13. data/docs/stripe.code +7 -0
  14. data/docs/twitter.code +7 -0
  15. data/lib/code/parser/addition.rb +13 -0
  16. data/lib/code/parser/and_operator.rb +13 -0
  17. data/lib/code/parser/bitwise_and.rb +13 -0
  18. data/lib/code/parser/bitwise_or.rb +13 -0
  19. data/lib/code/parser/boolean.rb +13 -0
  20. data/lib/code/parser/call.rb +174 -0
  21. data/lib/code/parser/chained_call.rb +41 -0
  22. data/lib/code/parser/class.rb +56 -0
  23. data/lib/code/parser/code.rb +20 -0
  24. data/lib/code/parser/comments.rb +46 -0
  25. data/lib/code/parser/dictionnary.rb +48 -0
  26. data/lib/code/parser/equal.rb +39 -0
  27. data/lib/code/parser/equality.rb +20 -0
  28. data/lib/code/parser/error/syntax_error.rb +36 -0
  29. data/lib/code/parser/error.rb +6 -0
  30. data/lib/code/parser/function.rb +109 -0
  31. data/lib/code/parser/greater_than.rb +13 -0
  32. data/lib/code/parser/group.rb +15 -0
  33. data/lib/code/parser/identifier.rb +54 -0
  34. data/lib/code/parser/if.rb +81 -0
  35. data/lib/code/parser/if_modifier.rb +39 -0
  36. data/lib/code/parser/list.rb +20 -0
  37. data/lib/code/parser/multiplication.rb +13 -0
  38. data/lib/code/parser/negation.rb +18 -0
  39. data/lib/code/parser/not_keyword.rb +24 -0
  40. data/lib/code/parser/nothing.rb +13 -0
  41. data/lib/code/parser/number.rb +39 -0
  42. data/lib/code/parser/operation.rb +44 -0
  43. data/lib/code/parser/or_keyword.rb +13 -0
  44. data/lib/code/parser/or_operator.rb +13 -0
  45. data/lib/code/parser/power.rb +33 -0
  46. data/lib/code/parser/range.rb +13 -0
  47. data/lib/code/parser/rescue.rb +38 -0
  48. data/lib/code/parser/shift.rb +13 -0
  49. data/lib/code/parser/statement.rb +9 -0
  50. data/lib/code/parser/string.rb +61 -0
  51. data/lib/code/parser/ternary.rb +73 -0
  52. data/lib/code/parser/unary_minus.rb +23 -0
  53. data/lib/code/parser/while.rb +36 -0
  54. data/lib/code/parser.rb +237 -0
  55. data/lib/code-ruby-parser.rb +7 -0
  56. data/lib/code.rb +2 -0
  57. data/lib/template/parser.rb +32 -0
  58. data/lib/template-ruby-parser.rb +7 -0
  59. data/lib/template.rb +2 -0
  60. data/spec/code/parser/addition_spec.rb +26 -0
  61. data/spec/code/parser/and_operator_spec.rb +26 -0
  62. data/spec/code/parser/bitwise_and_spec.rb +26 -0
  63. data/spec/code/parser/bitwise_or_spec.rb +26 -0
  64. data/spec/code/parser/boolean_spec.rb +13 -0
  65. data/spec/code/parser/call_spec.rb +52 -0
  66. data/spec/code/parser/chained_call_spec.rb +33 -0
  67. data/spec/code/parser/class_spec.rb +32 -0
  68. data/spec/code/parser/code_spec.rb +13 -0
  69. data/spec/code/parser/dictionnary_spec.rb +40 -0
  70. data/spec/code/parser/equal_spec.rb +42 -0
  71. data/spec/code/parser/equality_spec.rb +26 -0
  72. data/spec/code/parser/function_spec.rb +43 -0
  73. data/spec/code/parser/greater_than_spec.rb +26 -0
  74. data/spec/code/parser/group_spec.rb +13 -0
  75. data/spec/code/parser/if_modifier_spec.rb +26 -0
  76. data/spec/code/parser/if_spec.rb +39 -0
  77. data/spec/code/parser/list_spec.rb +27 -0
  78. data/spec/code/parser/multiplication_spec.rb +26 -0
  79. data/spec/code/parser/negation_spec.rb +13 -0
  80. data/spec/code/parser/not_keyword_spec.rb +21 -0
  81. data/spec/code/parser/nothing_spec.rb +20 -0
  82. data/spec/code/parser/number_spec.rb +24 -0
  83. data/spec/code/parser/or_keyword_spec.rb +26 -0
  84. data/spec/code/parser/or_operator_spec.rb +26 -0
  85. data/spec/code/parser/power_spec.rb +21 -0
  86. data/spec/code/parser/range_spec.rb +21 -0
  87. data/spec/code/parser/rescue_spec.rb +26 -0
  88. data/spec/code/parser/shift_spec.rb +26 -0
  89. data/spec/code/parser/string_spec.rb +27 -0
  90. data/spec/code/parser/ternary_spec.rb +26 -0
  91. data/spec/code/parser/unary_minus_spec.rb +21 -0
  92. data/spec/code/parser/while_spec.rb +32 -0
  93. data/spec/spec_helper.rb +6 -0
  94. data/spec/template/parser_spec.rb +13 -0
  95. data/template-ruby-parser.gemspec +16 -0
  96. metadata +171 -0
@@ -0,0 +1,38 @@
1
+ class Code
2
+ class Parser
3
+ class Rescue < ::Code::Parser
4
+ def parse
5
+ left = parse_subclass(::Code::Parser::Ternary)
6
+
7
+ previous_cursor = cursor
8
+
9
+ comments_before = parse_comments
10
+
11
+ if match(RESCUE_KEYWORD)
12
+ previous_cursor = cursor
13
+ comments_after = parse_comments
14
+ right = parse_subclass(::Code::Parser::Rescue)
15
+
16
+ if right
17
+ {
18
+ rescue: {
19
+ left: left,
20
+ right: right,
21
+ comments_before: comments_before,
22
+ comments_after: comments_after
23
+ }.compact
24
+ }
25
+ else
26
+ @cursor = previous_cursor
27
+ buffer!
28
+ { rescue: { left: left, comments_before: comments_before }.compact }
29
+ end
30
+ else
31
+ @cursor = previous_cursor
32
+ buffer!
33
+ left
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ class Code
2
+ class Parser
3
+ class Shift < ::Code::Parser
4
+ def parse
5
+ parse_subclass(
6
+ ::Code::Parser::Operation,
7
+ operators: [GREATER + GREATER, LESSER + LESSER],
8
+ subclass: ::Code::Parser::Addition
9
+ )
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ class Code
2
+ class Parser
3
+ class Statement < ::Code::Parser
4
+ def parse
5
+ parse_subclass(::Code::Parser::Class)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,61 @@
1
+ class Code
2
+ class Parser
3
+ class String < ::Code::Parser
4
+ def parse
5
+ if match(SINGLE_QUOTE)
6
+ parse_string(SINGLE_QUOTE)
7
+ elsif match(DOUBLE_QUOTE)
8
+ parse_string(DOUBLE_QUOTE)
9
+ elsif match(COLON) && !next?(SPECIAL)
10
+ buffer!
11
+ consume while !next?(SPECIAL) && !end_of_input?
12
+ { string: buffer }
13
+ else
14
+ parse_subclass(::Code::Parser::Number)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def parse_string(quote)
21
+ buffer!
22
+ output = []
23
+
24
+ while !next?(quote) && !end_of_input?
25
+ c = consume
26
+
27
+ if c == BACKSLASH
28
+ match(OPENING_CURLY_BRACKET) || match(quote)
29
+ elsif c == OPENING_CURLY_BRACKET
30
+ output << { text: escape_string(buffer![..-2]) } if buffer?
31
+
32
+ output << { code: parse_code }
33
+
34
+ match(CLOSING_CURLY_BRACKET)
35
+ buffer!
36
+ end
37
+ end
38
+
39
+ output << { text: escape_string(buffer) } if buffer?
40
+
41
+ match(quote)
42
+
43
+ if output.empty?
44
+ { string: EMPTY_STRING }
45
+ elsif output.one? && output.first.key?(:text)
46
+ { string: output.first[:text] }
47
+ else
48
+ { string: output }
49
+ end
50
+ end
51
+
52
+ def escape_string(string)
53
+ string
54
+ .gsub(SPECIAL_NEWLINE, SPECIAL_NEWLINE_ESCAPED)
55
+ .gsub(BACKSLASH + OPENING_CURLY_BRACKET, OPENING_CURLY_BRACKET)
56
+ .gsub(BACKSLASH + SINGLE_QUOTE, SINGLE_QUOTE)
57
+ .gsub(BACKSLASH + DOUBLE_QUOTE, DOUBLE_QUOTE)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,73 @@
1
+ class Code
2
+ class Parser
3
+ class Ternary < ::Code::Parser
4
+ def parse
5
+ left = parse_subclass(::Code::Parser::Range)
6
+
7
+ previous_cursor = cursor
8
+ return left if !match(WHITESPACE) && !(first_comments = parse_comments)
9
+ first_comments ||= parse_comments
10
+
11
+ if match(QUESTION_MARK)
12
+ second_comments = parse_comments
13
+
14
+ middle = parse_subclass(::Code::Parser::Ternary)
15
+
16
+ if middle
17
+ previous_cursor = cursor
18
+ third_comments = parse_comments
19
+
20
+ if match(COLON)
21
+ fourth_comments = parse_comments
22
+ right = parse_subclass(::Code::Parser::Ternary)
23
+
24
+ if right
25
+ {
26
+ ternary: {
27
+ left: left,
28
+ middle: middle,
29
+ right: right,
30
+ first_comments: first_comments,
31
+ second_comments: second_comments,
32
+ third_comments: third_comments,
33
+ fourth_comments: fourth_comments
34
+ }.compact
35
+ }
36
+ else
37
+ @cursor = previous_cursor
38
+ buffer!
39
+ {
40
+ ternary: {
41
+ left: left,
42
+ middle: middle,
43
+ first_comments: first_comments,
44
+ second_comments: second_comments
45
+ }.compact
46
+ }
47
+ end
48
+ else
49
+ @cursor = previous_cursor
50
+ buffer!
51
+ {
52
+ ternary: {
53
+ left: left,
54
+ middle: middle,
55
+ first_comments: first_comments,
56
+ second_comments: second_comments
57
+ }.compact
58
+ }
59
+ end
60
+ else
61
+ @cursor = previous_cursor
62
+ buffer!
63
+ left
64
+ end
65
+ else
66
+ @cursor = previous_cursor
67
+ buffer!
68
+ left
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,23 @@
1
+ class Code
2
+ class Parser
3
+ class UnaryMinus < ::Code::Parser
4
+ def parse
5
+ if match(MINUS)
6
+ previous_cursor = cursor
7
+ comments = parse_comments
8
+ right = parse_subclass(::Code::Parser::UnaryMinus)
9
+
10
+ if right
11
+ { unary_minus: { right: right, comments: comments }.compact }
12
+ else
13
+ @cursor = previous_cursor
14
+ buffer!
15
+ parse_subclass(::Code::Parser::Power)
16
+ end
17
+ else
18
+ parse_subclass(::Code::Parser::Power)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ class Code
2
+ class Parser
3
+ class While < ::Code::Parser
4
+ def parse
5
+ if operator = match([WHILE_KEYWORD, UNTIL_KEYWORD])
6
+ previous_cursor = cursor
7
+
8
+ comments = parse_comments
9
+
10
+ condition = parse_subclass(::Code::Parser::While)
11
+
12
+ if condition
13
+ body = parse_code
14
+
15
+ match(END_KEYWORD)
16
+
17
+ {
18
+ while: {
19
+ operator: operator,
20
+ comments: comments,
21
+ condition: condition,
22
+ body: body
23
+ }.compact
24
+ }
25
+ else
26
+ @cursor = previous_cursor
27
+ buffer!
28
+ parse_subclass(::Code::Parser::If)
29
+ end
30
+ else
31
+ parse_subclass(::Code::Parser::If)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,237 @@
1
+ class Code
2
+ class Parser
3
+ attr_accessor :input, :cursor, :buffer
4
+
5
+ EMPTY_STRING = ""
6
+
7
+ DIGITS = %w[0 1 2 3 4 5 6 7 8 9]
8
+ NON_ZERO_DIGITS = %w[1 2 3 4 5 6 7 8 9]
9
+
10
+ X = "x"
11
+ O = "o"
12
+ B = "b"
13
+
14
+ SINGLE_QUOTE = "'"
15
+ DOUBLE_QUOTE = '"'
16
+ OPENING_CURLY_BRACKET = "{"
17
+ CLOSING_CURLY_BRACKET = "}"
18
+ OPENING_SQUARE_BRACKET = "["
19
+ CLOSING_SQUARE_BRACKET = "]"
20
+ OPENING_PARENTHESIS = "("
21
+ CLOSING_PARENTHESIS = ")"
22
+ DOT = "."
23
+ BACKSLASH = "\\"
24
+ COMMA = ","
25
+ SPACE = " "
26
+ SLASH = "/"
27
+ ASTERISK = "*"
28
+ NEWLINE = "\n"
29
+ HASH = "#"
30
+ COLON = ":"
31
+ EQUAL = "="
32
+ GREATER = ">"
33
+ LESSER = "<"
34
+ AMPERSAND = "&"
35
+ PIPE = "|"
36
+ UNDERSCORE = "_"
37
+ EXCLAMATION_POINT = "!"
38
+ QUESTION_MARK = "?"
39
+ MINUS = "-"
40
+ PLUS = "+"
41
+ PERCENT = "%"
42
+ CARET = "^"
43
+ TILDE = "~"
44
+
45
+ EQUALS = [
46
+ EQUAL,
47
+ PLUS + EQUAL,
48
+ MINUS + EQUAL,
49
+ ASTERISK + EQUAL,
50
+ SLASH + EQUAL,
51
+ PERCENT + EQUAL,
52
+ GREATER + GREATER + EQUAL,
53
+ LESSER + LESSER + EQUAL,
54
+ AMPERSAND + EQUAL,
55
+ PIPE + EQUAL,
56
+ CARET + EQUAL,
57
+ PIPE + PIPE + EQUAL,
58
+ AMPERSAND + AMPERSAND + EQUAL
59
+ ]
60
+
61
+ WHITESPACE = [SPACE, NEWLINE]
62
+
63
+ SPECIAL_NEWLINE = "\\n"
64
+ SPECIAL_NEWLINE_ESCAPED = "\n"
65
+
66
+ NOTHING_KEYWORD = "nothing"
67
+ NULL_KEYWORD = "null"
68
+ NIL_KEYWORD = "nil"
69
+ TRUE_KEYWORD = "true"
70
+ FALSE_KEYWORD = "false"
71
+ DO_KEYWORD = "do"
72
+ END_KEYWORD = "end"
73
+ RESCUE_KEYWORD = "rescue"
74
+ NOT_KEYWORD = "not"
75
+ OR_KEYWORD = "or"
76
+ AND_KEYWORD = "and"
77
+ IF_KEYWORD = "if"
78
+ UNLESS_KEYWORD = "unless"
79
+ ELSE_KEYWORD = "else"
80
+ ELSIF_KEYWORD = "elsif"
81
+ ELSUNLESS_KEYWORD = "elsunless"
82
+ WHILE_KEYWORD = "while"
83
+ UNTIL_KEYWORD = "until"
84
+ CLASS_KEYWORD = "class"
85
+
86
+ NOTHING_KEYWORDS = [NOTHING_KEYWORD, NULL_KEYWORD, NIL_KEYWORD]
87
+ BOOLEAN_KEYWORDS = [TRUE_KEYWORD, FALSE_KEYWORD]
88
+ KEYWORDS =
89
+ NOTHING_KEYWORDS + BOOLEAN_KEYWORDS +
90
+ [
91
+ DO_KEYWORD, END_KEYWORD, RESCUE_KEYWORD, NOT_KEYWORD, OR_KEYWORD,
92
+ AND_KEYWORD, IF_KEYWORD, UNLESS_KEYWORD, ELSE_KEYWORD, ELSIF_KEYWORD,
93
+ ELSUNLESS_KEYWORD, WHILE_KEYWORD, UNTIL_KEYWORD, CLASS_KEYWORD
94
+ ]
95
+
96
+ SPECIAL = [
97
+ SINGLE_QUOTE, DOUBLE_QUOTE, OPENING_CURLY_BRACKET, CLOSING_CURLY_BRACKET,
98
+ OPENING_SQUARE_BRACKET, CLOSING_SQUARE_BRACKET, BACKSLASH, DOT, COMMA,
99
+ SPACE, SLASH, ASTERISK, NEWLINE, HASH, COLON, EQUAL, GREATER, LESSER,
100
+ OPENING_PARENTHESIS, CLOSING_PARENTHESIS, AMPERSAND, PIPE,
101
+ EXCLAMATION_POINT, QUESTION_MARK, MINUS, PLUS, TILDE
102
+ ]
103
+
104
+ def initialize(
105
+ input,
106
+ cursor: 0,
107
+ buffer: EMPTY_STRING,
108
+ check_end_of_input: true
109
+ )
110
+ @input = input
111
+ @cursor = cursor
112
+ @buffer = buffer
113
+ @check_end_of_input = check_end_of_input
114
+ end
115
+
116
+ def self.parse(input)
117
+ new(input).parse
118
+ end
119
+
120
+ def parse
121
+ output = parse_subclass(::Code::Parser::Code)
122
+
123
+ if check_end_of_input && cursor != input.size
124
+ syntax_error("Unexpected end of input")
125
+ end
126
+
127
+ output
128
+ end
129
+
130
+ private
131
+
132
+ attr_reader :check_end_of_input
133
+
134
+ def syntax_error(message)
135
+ raise(
136
+ ::Code::Parser::Error::SyntaxError.new(
137
+ message,
138
+ input: input,
139
+ line: line,
140
+ column: column,
141
+ offset_lines: offset_lines,
142
+ offset_columns: offset_columns
143
+ )
144
+ )
145
+ end
146
+
147
+ def line
148
+ input[0...cursor].count("\n")
149
+ end
150
+
151
+ def column
152
+ cursor - input.lines[0...line].map(&:size).sum
153
+ end
154
+
155
+ def offset_lines
156
+ buffer.count("\n")
157
+ end
158
+
159
+ def offset_columns
160
+ buffer.size + 1
161
+ end
162
+
163
+ def consume(n = 1)
164
+ if cursor + n <= input.size
165
+ consumed = input[cursor, n]
166
+ @buffer += input[cursor, n]
167
+ @cursor += n
168
+ consumed
169
+ else
170
+ syntax_error("Unexpected end of input")
171
+ end
172
+ end
173
+
174
+ def add(output)
175
+ @output << output if output
176
+ output
177
+ end
178
+
179
+ def next?(expected)
180
+ if expected.is_a?(Array)
181
+ expected.any? { |e| input[cursor, e.size] == e }
182
+ else
183
+ input[cursor, expected.size] == expected
184
+ end
185
+ end
186
+
187
+ def next_next?(expected)
188
+ if expected.is_a?(Array)
189
+ expected.any? { |e| next_next?(e) }
190
+ else
191
+ input[cursor + 1, expected.size] == expected
192
+ end
193
+ end
194
+
195
+ def match(expected)
196
+ if expected.is_a?(Array)
197
+ expected.detect { |e| match(e) }
198
+ else
199
+ if input[cursor, expected.size] == expected
200
+ @buffer += expected
201
+ @cursor += expected.size
202
+ expected
203
+ else
204
+ false
205
+ end
206
+ end
207
+ end
208
+
209
+ def parse_subclass(subclass, **kargs)
210
+ parser =
211
+ subclass.new(input, cursor: cursor, check_end_of_input: false, **kargs)
212
+ output = parser.parse
213
+ @cursor = parser.cursor
214
+ output
215
+ end
216
+
217
+ def parse_code
218
+ parse_subclass(::Code::Parser::Code)
219
+ end
220
+
221
+ def parse_comments(whitespace: WHITESPACE)
222
+ parse_subclass(::Code::Parser::Comments, whitespace: whitespace)
223
+ end
224
+
225
+ def end_of_input?
226
+ cursor >= input.size
227
+ end
228
+
229
+ def buffer?
230
+ buffer != EMPTY_STRING
231
+ end
232
+
233
+ def buffer!
234
+ buffer.tap { @buffer = EMPTY_STRING }
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,7 @@
1
+ require "zeitwerk"
2
+ require "forwardable"
3
+
4
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
5
+ loader.ignore("#{__dir__}/template-ruby-parser.rb")
6
+ loader.ignore("#{__dir__}/code-ruby-parser.rb")
7
+ loader.setup
data/lib/code.rb ADDED
@@ -0,0 +1,2 @@
1
+ class Code
2
+ end
@@ -0,0 +1,32 @@
1
+ class Template
2
+ class Parser < ::Code::Parser
3
+ Version = Gem::Version.new("0.1.0")
4
+
5
+ def parse
6
+ parts = []
7
+
8
+ while !end_of_input?
9
+ c = consume
10
+
11
+ if c == OPENING_CURLY_BRACKET
12
+ parts << { text: escape(buffer!) } if buffer?
13
+ parts << { code: parse_code }
14
+ match(CLOSING_CURLY_BRACKET)
15
+ buffer!
16
+ elsif c == BACKSLASH
17
+ match(OPENING_CURLY_BRACKET)
18
+ end
19
+ end
20
+
21
+ parts << { text: escape(buffer!) } if buffer?
22
+
23
+ parts
24
+ end
25
+
26
+ private
27
+
28
+ def escape(text)
29
+ text.gsub(BACKSLASH + OPENING_CURLY_BRACKET, OPENING_CURLY_BRACKET)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ require "zeitwerk"
2
+ require "forwardable"
3
+
4
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
5
+ loader.ignore("#{__dir__}/template-ruby-parser.rb")
6
+ loader.ignore("#{__dir__}/code-ruby-parser.rb")
7
+ loader.setup
data/lib/template.rb ADDED
@@ -0,0 +1,2 @@
1
+ class Template
2
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe ::Code::Parser do
4
+ subject { ::Code::Parser.parse(input) }
5
+
6
+ ["a + b", "a - b", "(a - b) + c", "a - (b + c)"].each do |input|
7
+ context input do
8
+ let!(:input) { input }
9
+
10
+ it { expect { subject }.to_not raise_error }
11
+ end
12
+ end
13
+
14
+ [
15
+ "a /* cool */ * b",
16
+ "a + /* cool */ b",
17
+ "a + b - c /* cool */",
18
+ "a + b - /* cool */ c"
19
+ ].each do |input|
20
+ context input do
21
+ let!(:input) { input }
22
+
23
+ it { expect(subject.to_json).to include("cool") }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe ::Code::Parser do
4
+ subject { ::Code::Parser.parse(input) }
5
+
6
+ ["a && b", "a && b && c"].each do |input|
7
+ context input do
8
+ let!(:input) { input }
9
+
10
+ it { expect { subject }.to_not raise_error }
11
+ end
12
+ end
13
+
14
+ [
15
+ "a /* cool */ && b",
16
+ "a && /* cool */ b",
17
+ "a && b && c /* cool */",
18
+ "a && b && /* cool */ c"
19
+ ].each do |input|
20
+ context input do
21
+ let!(:input) { input }
22
+
23
+ it { expect(subject.to_json).to include("cool") }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe ::Code::Parser do
4
+ subject { ::Code::Parser.parse(input) }
5
+
6
+ ["a & b", "a & b & c"].each do |input|
7
+ context input do
8
+ let!(:input) { input }
9
+
10
+ it { expect { subject }.to_not raise_error }
11
+ end
12
+ end
13
+
14
+ [
15
+ "a /* cool */ & b",
16
+ "a & /* cool */ b",
17
+ "a & b & c /* cool */",
18
+ "a & b & /* cool */ c"
19
+ ].each do |input|
20
+ context input do
21
+ let!(:input) { input }
22
+
23
+ it { expect(subject.to_json).to include("cool") }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe ::Code::Parser do
4
+ subject { ::Code::Parser.parse(input) }
5
+
6
+ ["a | b", "a | b | c"].each do |input|
7
+ context input do
8
+ let!(:input) { input }
9
+
10
+ it { expect { subject }.to_not raise_error }
11
+ end
12
+ end
13
+
14
+ [
15
+ "a /* cool */ | b",
16
+ "a | /* cool */ b",
17
+ "a | b | c /* cool */",
18
+ "a | b | /* cool */ c"
19
+ ].each do |input|
20
+ context input do
21
+ let!(:input) { input }
22
+
23
+ it { expect(subject.to_json).to include("cool") }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe ::Code::Parser do
4
+ subject { ::Code::Parser.parse(input) }
5
+
6
+ %w[true false].each do |input|
7
+ context input do
8
+ let!(:input) { input }
9
+
10
+ it { expect { subject }.to_not raise_error }
11
+ end
12
+ end
13
+ end