OILS / stdlib / ysh / stream.ysh View on Github | oilshell.org

287 lines, 103 significant
1# stream.ysh
2#
3# Usage:
4# source --builtin stream.ysh
5#
6# For reading lines, decoding, extracting, splitting
7
8# make this file a test server
9source $LIB_OSH/byo-server.sh
10
11source $LIB_YSH/args.ysh
12
13proc slurp-by (; num_lines) {
14 var buf = []
15 for line in (io.stdin) {
16 call buf->append(line)
17 if (len(buf) === num_lines) {
18 json write (buf, space=0)
19
20 # TODO:
21 #call buf->clear()
22 setvar buf = []
23 }
24 }
25 if (buf) {
26 json write (buf, space=0)
27 }
28}
29
30proc test-slurp-by {
31 seq 8 | slurp-by (3)
32}
33
34### Awk
35
36# Naming
37#
38# TEXT INPUT
39# each-word # this doesn't go by lines, it does a global regex split or something?
40#
41# LINE INPUT
42# each-line --j8 { echo "-- $_line" } # similar to @()
43# each-line --j8 (^"-- $_line") # is this superfluous?
44#
45# each-split name1 name2
46# (delim=' ')
47# (ifs=' ')
48# (pat=/d+/)
49# # also assign names for each part?
50#
51# each-match # regex match
52# must-match # assert that every line matches
53#
54# TABLE INPUT
55# each-row # TSV and TSV8 input?
56#
57# They all take templates or blocks?
58
59proc each-line (...words; template=null; ; block=null) {
60 # TODO:
61 # parse --j8 --max-jobs flag
62
63 # parse template_str as string
64 # TODO: this is dangerous though ... because you can execute code
65 # I think you need a SAFE version
66
67 # evaluate template string expression - I guess that allows $(echo hi) and so
68 # forth
69
70 # evaluate block with _line binding
71 # block: execute in parallel with --max-jobs
72
73 for line in (stdin) {
74 echo TODO
75 }
76}
77
78proc test-each-line {
79 echo 'TODO: need basic test runner'
80
81 # ysh-tool test stream.ysh
82 #
83 # Col
84}
85
86proc each-row (; ; block) {
87 echo TODO
88}
89
90proc split-by (; delim; ifs=null; block) {
91
92 # TODO: provide the option to bind names? Or is that a separate thing?
93 # The output of this is "ragged"
94
95 for line in (io.stdin) {
96 #pp (line)
97 var parts = line.split(delim)
98 pp (parts)
99
100 # variable number
101 call io->eval(block, dollar0=line, pos_args=parts)
102 }
103}
104
105proc chop () {
106 ### alias for split-by
107 echo TODO
108}
109
110proc test-split-by {
111 var z = 'z' # test out scoping
112 var count = 0 # test out mutation
113
114 # TODO: need split by space
115 # Where the leading and trailing are split
116 # if-split-by(' ') doesn't work well
117
118 line-data | split-by (/s+/) {
119
120 # how do we deal with nonexistent?
121 # should we also bind _parts or _words?
122
123 echo "$z | $0 | $1 | $z"
124
125 setvar count += 1
126 }
127 echo "count = $count"
128}
129
130proc must-split-by (; ; ifs=null; block) {
131 ### like if-split-by
132
133 echo TODO
134}
135
136# Naming: each-match, each-split?
137
138proc if-match (; pattern, template=null; ; block=null) {
139 ### like 'grep' but with submatches
140
141 for line in (io.stdin) {
142 var m = line.search(pattern)
143 if (m) {
144 #pp asdl_ (m)
145 #var groups = m.groups()
146
147 # Should we also pass _line?
148
149 if (block) {
150 call io->eval(block, dollar0=m.group(0))
151 } elif (template) {
152 echo TEMPLATE
153 } else {
154 echo TSV
155 }
156 }
157 }
158
159 # always succeeds - I think must-match is the one that can fail
160}
161
162proc must-match (; pattern; block) {
163 ### like if-match
164
165 echo TODO
166}
167
168proc line-data {
169 # note: trailing ''' issue, I should probably get rid of the last line
170
171 write --end '' -- '''
172 prefix 30 foo
173 oils
174 /// 42 bar
175 '''
176}
177
178const pat = /<capture d+> s+ <capture w+>/
179
180proc test-if-match {
181 var z = 'z' # test out scoping
182 var count = 0 # test out mutation
183
184 # Test cases should be like:
185 # grep: print the matches, or just count them
186 # sed: print a new line based on submatches
187 # awk: re-arrange the cols, and also accumulate counters
188
189 line-data | if-match (pat) {
190 echo "$z $0 $z"
191 # TODO: need pos_args
192
193 #echo "-- $2 $1 --"
194
195 setvar count += 1
196 }
197 echo "count = $count"
198}
199
200proc test-if-match-2 {
201 # If there's no block or template, it should print out a TSV with:
202 #
203 # $0 ...
204 # $1 $2
205 # $_line maybe?
206
207 #line-data | if-match (pat)
208
209 var z = 'z' # scoping
210 line-data | if-match (pat, ^"$z $0 $z")
211 line-data | if-match (pat, ^"-- $0 --")
212}
213
214# might be a nice way to write it, not sure if byo.sh can discover it
215if false {
216tests 'if-match' {
217 proc case-block {
218 echo TODO
219 }
220 proc case-template {
221 echo TODO
222 }
223}
224}
225
226# Protocol:
227#
228# - The file lists its tests the "actions"
229# - Then the test harness runs them
230# - But should it be ENV vars
231#
232# - BYO_LIST_TESTS=1
233# - BYO_RUN_TEST=foo
234# - $PWD is a CLEAN temp dir, the process doesn't have to do anything
235
236# - silent on success, but prints file on output
237# - OK this makes sense
238#
239# The trivial test in Python:
240#
241# from test import byo
242# byo.maybe_main()
243#
244# bash library:
245# source --builtin byo-server.sh
246#
247# byo-maybe-main # reads env variables, and then exits
248#
249# source --builtin assertions.ysh
250#
251# assert-ok 'echo hi'
252# assert-stdout 'hi' 'echo -n hi'
253#
254# "$@"
255#
256# Run all tests
257# util/byo-client.sh run-tests $YSH stdlib/table.ysh
258# util/byo-client.sh run-tests -f x $YSH stdlib/table.ysh
259
260# Clean process
261# Clean working dir
262
263#
264# Stream Protocol:
265# #.byo - is this she-dot, that's for a file
266# Do we need metadata?
267#
268
269# The harness
270#
271# It's process based testing.
272#
273# Test runner process: bash or OSH (unlike sharness!)
274# Tested process: any language - bash,
275#
276# Key point: you don't have to quote shell code?
277
278list-byo-tests() {
279 echo TODO
280}
281
282run-byo-tests() {
283 # source it
284 echo TODO
285}
286
287byo-maybe-run