yap-shell-parser 0.2.2 → 0.3.1

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.
@@ -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