yap-shell-parser 0.2.2 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,16 +3,297 @@ require 'yap/shell/parser/lexer'
3
3
 
4
4
  describe Yap::Shell::Parser::Lexer do
5
5
  subject { described_class.new.tokenize(str) }
6
+ let(:str){ self.class.description }
6
7
 
7
8
  def t(tag, val, lineno:0, attrs:{})
8
9
  [tag, Yap::Shell::Parser::Lexer::Token.new(tag, val, lineno:lineno, attrs:attrs)]
9
10
  end
10
11
 
12
+ describe "block expressions" do
13
+ describe "can follow any command" do
14
+ describe "ls { this_is_a_block }" do
15
+ it { should eq [
16
+ t(:Command, "ls", lineno:0),
17
+ t(:BlockBegin, '{', lineno: 0),
18
+ t(:Command, "this_is_a_block", lineno:0),
19
+ t(:BlockEnd, '}', lineno: 0)
20
+ ]}
21
+ end
22
+
23
+ describe "whitespace before/after the range doesn't matter" do
24
+ describe " ls { this_is_a_block } " do
25
+ it { should eq [
26
+ t(:Command, "ls", lineno:0),
27
+ t(:BlockBegin, '{', lineno: 0),
28
+ t(:Command, "this_is_a_block", lineno:0),
29
+ t(:BlockEnd, '}', lineno: 0)
30
+ ]}
31
+ end
32
+
33
+ describe "ls {echo n}" do
34
+ it { should eq [
35
+ t(:Command, "ls", lineno:0),
36
+ t(:BlockBegin, '{', lineno: 0),
37
+ t(:Command, "echo", lineno:0),
38
+ t(:Argument, "n", lineno:0),
39
+ t(:BlockEnd, '}', lineno: 0)
40
+ ]}
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "can take block params" do
46
+ describe "ls { |a| this_is_a_block }" do
47
+ it { should eq [
48
+ t(:Command, "ls", lineno:0),
49
+ t(:BlockBegin, '{', lineno: 0),
50
+ t(:BlockParams, ['a'], lineno: 0),
51
+ t(:Command, "this_is_a_block", lineno:0),
52
+ t(:BlockEnd, '}', lineno: 0)
53
+ ]}
54
+ end
55
+
56
+ describe "ls { |a,b| this_is_a_block }" do
57
+ it { should eq [
58
+ t(:Command, "ls", lineno:0),
59
+ t(:BlockBegin, '{', lineno: 0),
60
+ t(:BlockParams, ['a', 'b'], lineno: 0),
61
+ t(:Command, "this_is_a_block", lineno:0),
62
+ t(:BlockEnd, '}', lineno: 0)
63
+ ]}
64
+ end
65
+
66
+ describe "ls { |a, b, c| this_is_a_block }" do
67
+ it { should eq [
68
+ t(:Command, "ls", lineno:0),
69
+ t(:BlockBegin, '{', lineno: 0),
70
+ t(:BlockParams, ['a', 'b', 'c'], lineno: 0),
71
+ t(:Command, "this_is_a_block", lineno:0),
72
+ t(:BlockEnd, '}', lineno: 0)
73
+ ]}
74
+ end
75
+ end
76
+
77
+ describe "can contain multiple statements" do
78
+ describe "ls { |a| ls ; ls2 || ls3 && ls4 ; ls5 }" do
79
+ it { should eq [
80
+ t(:Command, "ls", lineno:0),
81
+ t(:BlockBegin, '{', lineno: 0),
82
+ t(:BlockParams, ['a'], lineno: 0),
83
+ t(:Command, 'ls', lineno: 0),
84
+ t(:Separator, ';', lineno: 0),
85
+ t(:Command, 'ls2', lineno: 0),
86
+ t(:Conditional, '||', lineno: 0),
87
+ t(:Command, 'ls3', lineno: 0),
88
+ t(:Conditional, '&&', lineno: 0),
89
+ t(:Command, 'ls4', lineno: 0),
90
+ t(:Separator, ';', lineno: 0),
91
+ t(:Command, 'ls5', lineno: 0),
92
+ t(:BlockEnd, '}', lineno: 0)
93
+ ]}
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "looping constructs" do
99
+ describe "standalone" do
100
+ describe "(1..100)" do
101
+ it { should eq [
102
+ t(:Range, (1..100), lineno:0),
103
+ ]}
104
+ end
105
+ end
106
+
107
+ describe "start of line" do
108
+ describe "numerical range (no reference variable)" do
109
+ describe "(0..3): echo hi" do
110
+ it { should eq [
111
+ t(:Range, (0..3), lineno:0),
112
+ t(:BlockBegin, '{', lineno: 0),
113
+ t(:Command, "echo", lineno:0),
114
+ t(:Argument, "hi", lineno:0),
115
+ t(:BlockEnd, '}', lineno: 0)
116
+ ]}
117
+ end
118
+
119
+ describe "whitespace before/after the range doesn't matter" do
120
+ describe " (0..3) : echo hi" do
121
+ it { should eq [
122
+ t(:Range, (0..3), lineno:0),
123
+ t(:BlockBegin, '{', lineno: 0),
124
+ t(:Command, "echo", lineno:0),
125
+ t(:Argument, "hi", lineno:0),
126
+ t(:BlockEnd, '}', lineno: 0)
127
+ ]}
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "numerical range $n (reference variable)" do
133
+ describe "(0..3) as n: echo $n" do
134
+ it { should eq [
135
+ t(:Range, (0..3), lineno:0),
136
+ t(:BlockBegin, '{', lineno: 0),
137
+ t(:BlockParams, ['n'], lineno: 0),
138
+ t(:Command, "echo", lineno:0),
139
+ t(:Argument, "$n", lineno:0),
140
+ t(:BlockEnd, '}', lineno:0)
141
+ ]}
142
+ end
143
+
144
+ describe "whitespace before/after the range/reference doesn't matter" do
145
+ describe " (0..3) as n : echo $n" do
146
+ it { should eq [
147
+ t(:Range, (0..3), lineno:0),
148
+ t(:BlockBegin, '{', lineno: 0),
149
+ t(:BlockParams, ['n'], lineno: 0),
150
+ t(:Command, "echo", lineno:0),
151
+ t(:Argument, "$n", lineno:0),
152
+ t(:BlockEnd, '}', lineno:0)
153
+ ]}
154
+ end
155
+ end
156
+ end
157
+
158
+ describe "<number>.times w/block" do
159
+ describe "3.times { |n| echo hi }" do
160
+ it { should eq [
161
+ t(:Range, (1..3), lineno:0),
162
+ t(:BlockBegin, '{', lineno: 0),
163
+ t(:BlockParams, ['n'], lineno: 0),
164
+ t(:Command, "echo", lineno:0),
165
+ t(:Argument, "hi", lineno:0),
166
+ t(:BlockEnd, '}', lineno:0)
167
+ ]}
168
+ end
169
+
170
+ describe "3.times { |a, b,c| echo hi }" do
171
+ it { should eq [
172
+ t(:Range, (1..3), lineno:0),
173
+ t(:BlockBegin, '{', lineno: 0),
174
+ t(:BlockParams, ['a', 'b', 'c'], lineno: 0),
175
+ t(:Command, "echo", lineno:0),
176
+ t(:Argument, "hi", lineno:0),
177
+ t(:BlockEnd, '}', lineno:0)
178
+ ]}
179
+ end
180
+ end
181
+
182
+ describe "<number>.times (no reference variable)" do
183
+ describe "3.times: echo hi" do
184
+ it { should eq [
185
+ t(:Range, (1..3), lineno:0),
186
+ t(:BlockBegin, '{', lineno: 0),
187
+ t(:Command, "echo", lineno:0),
188
+ t(:Argument, "hi", lineno:0),
189
+ t(:BlockEnd, '}', lineno:0)
190
+ ]}
191
+ end
192
+
193
+ describe "whitespace before/after the range doesn't matter" do
194
+ describe " 3.times : echo hi" do
195
+ it { should eq [
196
+ t(:Range, (1..3), lineno:0),
197
+ t(:BlockBegin, '{', lineno: 0),
198
+ t(:Command, "echo", lineno:0),
199
+ t(:Argument, "hi", lineno:0),
200
+ t(:BlockEnd, '}', lineno:0)
201
+ ]}
202
+ end
203
+ end
204
+ end
205
+
206
+ describe "<number>.times $n (w/reference variable)" do
207
+ describe "3.times as n: echo $n" do
208
+ it { should eq [
209
+ t(:Range, (1..3), lineno:0),
210
+ t(:BlockBegin, '{', lineno: 0),
211
+ t(:BlockParams, ['n'], lineno: 0),
212
+ t(:Command, "echo", lineno:0),
213
+ t(:Argument, "$n", lineno:0),
214
+ t(:BlockEnd, '}', lineno:0)
215
+ ]}
216
+ end
217
+
218
+ describe "whitespace before/after the range/reference doesn't matter" do
219
+ describe " 3.times as n : echo $n" do
220
+ it { should eq [
221
+ t(:Range, (1..3), lineno:0),
222
+ t(:BlockBegin, '{', lineno: 0),
223
+ t(:BlockParams, ['n'], lineno: 0),
224
+ t(:Command, "echo", lineno:0),
225
+ t(:Argument, "$n", lineno:0),
226
+ t(:BlockEnd, '}', lineno:0)
227
+ ]}
228
+ end
229
+ end
230
+ end
231
+ end
232
+
233
+ describe "statement mixed with other statements" do
234
+ describe "numerical range (no reference variable)" do
235
+ describe "foo { echo foo }" do
236
+ it { should eq [
237
+ t(:Command, "foo", lineno:0),
238
+ t(:BlockBegin, '{', lineno:0),
239
+ t(:Command, "echo", lineno:0),
240
+ t(:Argument, "foo", lineno:0),
241
+ t(:BlockEnd, '}', lineno:0),
242
+ ]}
243
+ end
244
+
245
+ describe "foo { |n| echo foo }" do
246
+ it { should eq [
247
+ t(:Command, "foo", lineno:0),
248
+ t(:BlockBegin, '{', lineno:0),
249
+ t(:BlockParams, ['n'], lineno:0),
250
+ t(:Command, "echo", lineno:0),
251
+ t(:Argument, "foo", lineno:0),
252
+ t(:BlockEnd, '}', lineno:0),
253
+ ]}
254
+ end
255
+
256
+ describe "(0..3).each { echo foo }" do
257
+ it { should eq [
258
+ t(:Range, (0..3), lineno:0),
259
+ t(:BlockBegin, '{', lineno:0),
260
+ t(:Command, "echo", lineno:0),
261
+ t(:Argument, "foo", lineno:0),
262
+ t(:BlockEnd, '}', lineno:0),
263
+ ]}
264
+ end
265
+
266
+ describe "whitespace before/after the range doesn't matter" do
267
+ describe " (0..3).each { echo foo } " do
268
+ it { should eq [
269
+ t(:Range, (0..3), lineno:0),
270
+ t(:BlockBegin, '{', lineno:0),
271
+ t(:Command, "echo", lineno:0),
272
+ t(:Argument, "foo", lineno:0),
273
+ t(:BlockEnd, '}', lineno:0),
274
+ ]}
275
+ end
276
+ end
277
+ end
278
+ end
279
+ end
280
+
11
281
  describe "empty string" do
12
282
  let(:str){ "" }
13
283
  it { should eq [] }
14
284
  end
15
285
 
286
+ describe "string with newlines" do
287
+ let(:str){ "ls \n\nlib:\ntasks\nyap\nyap.rb" }
288
+ it { should eq [
289
+ t(:Command, "ls", lineno:0),
290
+ t(:Argument, "lib:", lineno:0),
291
+ t(:Argument, "tasks", lineno:0),
292
+ t(:Argument, "yap", lineno:0),
293
+ t(:Argument, "yap.rb", lineno:0)
294
+ ]}
295
+ end
296
+
16
297
  describe "env variables" do
17
298
  let(:str){ "foo $baz" }
18
299
  it { should eq [
@@ -354,12 +635,26 @@ describe Yap::Shell::Parser::Lexer do
354
635
  ]}
355
636
  end
356
637
 
357
- describe "the ending line cannot have non-whitespace characters beyond the delimiter" do
358
- let(:str){ "foo <<L337\nhere\nwe\ngo\n this is bad L337"}
638
+ describe <<-DESCRIPTION do
639
+ the delimiter doesn't have to be on its own line, just be the last thing.
640
+ It also will ignore any whitespace leading up to the delimiter.
641
+ DESCRIPTION
642
+ let(:str){ "foo <<L337\nhere\nwe\ngo\n this is great L337"}
643
+ it { should eq [
644
+ t(:Command, "foo", lineno:0),
645
+ t(:Heredoc, "here\nwe\ngo\n this is great", lineno:0)
646
+ ]}
647
+ end
648
+
649
+ describe "when there is no matching end delimiter found" do
650
+ let(:str){ "foo <<L337\nhere\nwe\ngo"}
359
651
  it "raises an error" do
360
- expect{ subject }.to raise_error
652
+ expect do
653
+ subject
654
+ end.to raise_error(Yap::Shell::Parser::Lexer::HeredocMissingEndDelimiter)
361
655
  end
362
656
  end
657
+
363
658
  end
364
659
 
365
660
  context "internal evaluations" do
@@ -980,7 +1275,5 @@ describe Yap::Shell::Parser::Lexer do
980
1275
  )
981
1276
  end
982
1277
  end
983
-
984
1278
  end
985
-
986
1279
  end
@@ -1,28 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'yap/shell/parser'
3
3
  require 'pry'
4
-
5
4
  describe Yap::Shell::Parser do
6
5
  subject(:parser){ Yap::Shell::Parser }
7
6
 
8
- def self.it_parses(str)
9
- context "#{str.inspect}" do
10
- it "parses" do
11
- expect { parser.parse(str) }.to_not raise_error
12
- end
13
- end
14
- end
15
-
16
- def self.it_errors(str)
17
- context "#{str.inspect}" do
18
- it "raises a Yap::Shell::Parser::ParseError" do
19
- expect {
20
- parser.parse(str)
21
- }.to raise_error(Yap::Shell::Parser::ParseError)
22
- end
23
- end
24
- end
25
-
26
7
  describe '.each_command_substitution_for' do
27
8
  let(:str){ "echo `echo hi`" }
28
9
 
@@ -33,41 +14,47 @@ describe Yap::Shell::Parser do
33
14
  end
34
15
  end
35
16
 
36
- it_parses "ls"
37
- it_parses "echo foo"
38
- it_parses "echo foo ; echo bar baz yep"
39
- it_parses "echo foo && echo bar baz yep"
40
- it_parses "echo foo && echo bar && ls foo && ls bar"
41
- it_parses "echo foo ; echo bar baz yep ; ls foo"
42
- it_parses "echo foo && echo bar ; ls baz"
43
- it_parses "echo foo && echo bar ; ls baz ; echo zach || echo gretchen"
44
- it_parses "echo foo | bar"
45
- it_parses "echo foo | bar && foo | bar"
46
- it_parses "foo && bar ; word || baz ; yep | grep -v foo"
47
- it_parses "( foo )"
48
- it_parses "( foo a b && bar c d )"
49
- it_parses "( foo a b && (bar c d | baz e f))"
50
- it_parses "((((foo))))"
51
- it_parses "foo -b -c ; (this ;that ;the; other ;thing) && yep"
52
- it_parses "foo -b -c ; (this ;that && other ;thing) && yep"
53
- it_parses "4 + 5"
54
- it_parses "!'hello' ; 4 - 4 && 10 + 3"
55
- it_parses "\\foo <<-EOT\nbar\nEOT"
56
- it_parses "ls | grep md | grep WISH"
57
- it_parses "(!upcase)"
58
- it_parses "echo foo > bar.txt"
59
- it_parses "ls -l > a.txt ; echo f 2> b.txt ; cat b &> c.txt ; du -sh 1>&2 1>hey.txt"
60
- it_parses "!Dir.chdir('..')"
61
- it_parses "FOO=123"
62
- it_parses "FOO=123 BAR=345"
63
- it_parses "FOO=abc bar=2314 car=14ab ls -l"
64
- it_parses "FOO=abc BAR='hello world' ls -l ; CAR=f echo foo && say hi"
65
- it_parses "`git cbranch`"
66
- it_parses "`git cbranch`.bak"
67
- it_parses "echo `echo hi`"
68
- it_parses "echo `echo hi` foo"
69
- it_parses "`hi``bye` `what`"
70
- it_parses "echo && `what` && where is `that`thing | `you know`"
17
+ it { is_expected.to parse "ls" }
18
+ it { is_expected.to parse "echo foo" }
19
+ it { is_expected.to parse "echo foo ; echo bar baz yep" }
20
+ it { is_expected.to parse "echo foo && echo bar baz yep" }
21
+ it { is_expected.to parse "echo foo && echo bar && ls foo && ls bar" }
22
+ it { is_expected.to parse "echo foo ; echo bar baz yep ; ls foo" }
23
+ it { is_expected.to parse "echo foo && echo bar ; ls baz" }
24
+ it { is_expected.to parse "echo foo && echo bar ; ls baz ; echo zach || echo gretchen" }
25
+ it { is_expected.to parse "echo foo | bar" }
26
+ it { is_expected.to parse "echo foo | bar && foo | bar" }
27
+ it { is_expected.to parse "foo && bar ; word || baz ; yep | grep -v foo" }
28
+ it { is_expected.to parse "( foo )" }
29
+ it { is_expected.to parse "( foo a b && bar c d )" }
30
+ it { is_expected.to parse "( foo a b && (bar c d | baz e f))" }
31
+ it { is_expected.to parse "((((foo))))" }
32
+ it { is_expected.to parse "foo -b -c ; (this ;that ;the; other ;thing) && yep" }
33
+ it { is_expected.to parse "foo -b -c ; (this ;that && other ;thing) && yep" }
34
+ it { is_expected.to parse "4 + 5" }
35
+ it { is_expected.to parse "!'hello' ; 4 - 4 && 10 + 3" }
36
+ it { is_expected.to parse "\\foo <<-EOT\nbar\nEOT" }
37
+ it { is_expected.to parse "ls | grep md | grep WISH" }
38
+ it { is_expected.to parse "(!upcase)" }
39
+ it { is_expected.to parse "echo foo > bar.txt" }
40
+ it { is_expected.to parse "ls -l > a.txt ; echo f 2> b.txt ; cat b &> c.txt ; du -sh 1>&2 1>hey.txt" }
41
+ it { is_expected.to parse "!Dir.chdir('..')" }
42
+ it { is_expected.to parse "FOO=123" }
43
+ it { is_expected.to parse "FOO=123 BAR=345" }
44
+ it { is_expected.to parse "FOO=abc bar=2314 car=14ab ls -l" }
45
+ it { is_expected.to parse "FOO=abc BAR='hello world' ls -l ; CAR=f echo foo && say hi" }
46
+ it { is_expected.to parse "`git cbranch`" }
47
+ it { is_expected.to parse "`git cbranch`.bak" }
48
+ it { is_expected.to parse "echo `echo hi`" }
49
+ it { is_expected.to parse "echo `echo hi` foo" }
50
+ it { is_expected.to parse "`hi``bye` `what`" }
51
+ it { is_expected.to parse "echo && `what` && where is `that`thing | `you know`" }
52
+ it { is_expected.to parse "(0..3)" }
53
+ it { is_expected.to parse "(0..3): echo hi" }
54
+ it { is_expected.to parse "(0..3) as n: echo hi $n" }
55
+ it { is_expected.to parse "echo hi ; (0..3) {echo hi $n}" }
56
+ it { is_expected.to parse "echo hi ; (0..3) { echo hi $n } ; echo bye" }
57
+ it { is_expected.to parse "ls *.rb { |f,g,h| echo $f && echo $h && echo $i }" }
71
58
 
72
- it_errors "ls ()"
59
+ it { is_expected.to fail_parsing "ls ()" }
73
60
  end
@@ -22,5 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency "bundler", "~> 1.7"
23
23
  spec.add_development_dependency "rake", "~> 10.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.2"
25
- spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "pry-byebug"
26
26
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yap-shell-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Dennis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-13 00:00:00.000000000 Z
11
+ date: 2016-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.2'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry
56
+ name: pry-byebug
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -75,6 +75,7 @@ extra_rdoc_files: []
75
75
  files:
76
76
  - ".gitignore"
77
77
  - ".rspec"
78
+ - ".ruby-version"
78
79
  - ".travis.yml"
79
80
  - Gemfile
80
81
  - LICENSE.txt
@@ -113,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  version: '0'
114
115
  requirements: []
115
116
  rubyforge_project:
116
- rubygems_version: 2.4.6
117
+ rubygems_version: 2.4.5.1
117
118
  signing_key:
118
119
  specification_version: 4
119
120
  summary: The parser for the yap shell