| 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
|
| 9 | source $LIB_OSH/byo-server.sh
|
| 10 |
|
| 11 | source $LIB_YSH/args.ysh
|
| 12 |
|
| 13 | proc 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 |
|
| 30 | proc 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 |
|
| 59 | proc 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 |
|
| 78 | proc test-each-line {
|
| 79 | echo 'TODO: need basic test runner'
|
| 80 |
|
| 81 | # ysh-tool test stream.ysh
|
| 82 | #
|
| 83 | # Col
|
| 84 | }
|
| 85 |
|
| 86 | proc each-j8-line (; ; ; block) {
|
| 87 | for _line in (io.stdin) {
|
| 88 | # TODO: fromJ8Line() toJ8Line()
|
| 89 | # var _line = fromJson(_line)
|
| 90 | call io->eval(block, vars={_line})
|
| 91 | }
|
| 92 | }
|
| 93 |
|
| 94 | proc test-each-j8-line {
|
| 95 | var lines = []
|
| 96 | var prefix = 'z'
|
| 97 |
|
| 98 | # unquoted
|
| 99 | seq 3 | each-j8-line {
|
| 100 | call lines->append(prefix ++ _line)
|
| 101 | }
|
| 102 | pp test_ (lines)
|
| 103 |
|
| 104 | # Note: no trailing new lines, since they aren't significant in Unix
|
| 105 | var expected = ['z1', 'z2', 'z3']
|
| 106 | assert [expected === lines]
|
| 107 | }
|
| 108 |
|
| 109 | proc each-row (; ; block) {
|
| 110 | echo TODO
|
| 111 | }
|
| 112 |
|
| 113 | proc split-by (; delim; ifs=null; block) {
|
| 114 |
|
| 115 | # TODO: provide the option to bind names? Or is that a separate thing?
|
| 116 | # The output of this is "ragged"
|
| 117 |
|
| 118 | for line in (io.stdin) {
|
| 119 | #pp (line)
|
| 120 | var parts = line.split(delim)
|
| 121 | pp (parts)
|
| 122 |
|
| 123 | # variable number
|
| 124 | call io->eval(block, dollar0=line, pos_args=parts)
|
| 125 | }
|
| 126 | }
|
| 127 |
|
| 128 | proc chop () {
|
| 129 | ### alias for split-by
|
| 130 | echo TODO
|
| 131 | }
|
| 132 |
|
| 133 | proc test-split-by {
|
| 134 | var z = 'z' # test out scoping
|
| 135 | var count = 0 # test out mutation
|
| 136 |
|
| 137 | # TODO: need split by space
|
| 138 | # Where the leading and trailing are split
|
| 139 | # if-split-by(' ') doesn't work well
|
| 140 |
|
| 141 | line-data | split-by (/s+/) {
|
| 142 |
|
| 143 | # how do we deal with nonexistent?
|
| 144 | # should we also bind _parts or _words?
|
| 145 |
|
| 146 | echo "$z | $0 | $1 | $z"
|
| 147 |
|
| 148 | setvar count += 1
|
| 149 | }
|
| 150 | echo "count = $count"
|
| 151 | }
|
| 152 |
|
| 153 | proc must-split-by (; ; ifs=null; block) {
|
| 154 | ### like if-split-by
|
| 155 |
|
| 156 | echo TODO
|
| 157 | }
|
| 158 |
|
| 159 | # Naming: each-match, each-split?
|
| 160 |
|
| 161 | proc if-match (; pattern, template=null; ; block=null) {
|
| 162 | ### like 'grep' but with submatches
|
| 163 |
|
| 164 | for line in (io.stdin) {
|
| 165 | var m = line.search(pattern)
|
| 166 | if (m) {
|
| 167 | #pp asdl_ (m)
|
| 168 | #var groups = m.groups()
|
| 169 |
|
| 170 | # Should we also pass _line?
|
| 171 |
|
| 172 | if (block) {
|
| 173 | call io->eval(block, dollar0=m.group(0))
|
| 174 | } elif (template) {
|
| 175 | echo TEMPLATE
|
| 176 | } else {
|
| 177 | echo TSV
|
| 178 | }
|
| 179 | }
|
| 180 | }
|
| 181 |
|
| 182 | # always succeeds - I think must-match is the one that can fail
|
| 183 | }
|
| 184 |
|
| 185 | proc must-match (; pattern; block) {
|
| 186 | ### like if-match
|
| 187 |
|
| 188 | echo TODO
|
| 189 | }
|
| 190 |
|
| 191 | proc line-data {
|
| 192 | # note: trailing ''' issue, I should probably get rid of the last line
|
| 193 |
|
| 194 | write --end '' -- '''
|
| 195 | prefix 30 foo
|
| 196 | oils
|
| 197 | /// 42 bar
|
| 198 | '''
|
| 199 | }
|
| 200 |
|
| 201 | const pat = /<capture d+> s+ <capture w+>/
|
| 202 |
|
| 203 | proc test-if-match {
|
| 204 | var z = 'z' # test out scoping
|
| 205 | var count = 0 # test out mutation
|
| 206 |
|
| 207 | # Test cases should be like:
|
| 208 | # grep: print the matches, or just count them
|
| 209 | # sed: print a new line based on submatches
|
| 210 | # awk: re-arrange the cols, and also accumulate counters
|
| 211 |
|
| 212 | line-data | if-match (pat) {
|
| 213 | echo "$z $0 $z"
|
| 214 | # TODO: need pos_args
|
| 215 |
|
| 216 | #echo "-- $2 $1 --"
|
| 217 |
|
| 218 | setvar count += 1
|
| 219 | }
|
| 220 | echo "count = $count"
|
| 221 | }
|
| 222 |
|
| 223 | proc test-if-match-2 {
|
| 224 | # If there's no block or template, it should print out a TSV with:
|
| 225 | #
|
| 226 | # $0 ...
|
| 227 | # $1 $2
|
| 228 | # $_line maybe?
|
| 229 |
|
| 230 | #line-data | if-match (pat)
|
| 231 |
|
| 232 | var z = 'z' # scoping
|
| 233 | line-data | if-match (pat, ^"$z $0 $z")
|
| 234 | line-data | if-match (pat, ^"-- $0 --")
|
| 235 | }
|
| 236 |
|
| 237 | # might be a nice way to write it, not sure if byo.sh can discover it
|
| 238 | if false {
|
| 239 | tests 'if-match' {
|
| 240 | proc case-block {
|
| 241 | echo TODO
|
| 242 | }
|
| 243 | proc case-template {
|
| 244 | echo TODO
|
| 245 | }
|
| 246 | }
|
| 247 | }
|
| 248 |
|
| 249 | # Protocol:
|
| 250 | #
|
| 251 | # - The file lists its tests the "actions"
|
| 252 | # - Then the test harness runs them
|
| 253 | # - But should it be ENV vars
|
| 254 | #
|
| 255 | # - BYO_LIST_TESTS=1
|
| 256 | # - BYO_RUN_TEST=foo
|
| 257 | # - $PWD is a CLEAN temp dir, the process doesn't have to do anything
|
| 258 |
|
| 259 | # - silent on success, but prints file on output
|
| 260 | # - OK this makes sense
|
| 261 | #
|
| 262 | # The trivial test in Python:
|
| 263 | #
|
| 264 | # from test import byo
|
| 265 | # byo.maybe_main()
|
| 266 | #
|
| 267 | # bash library:
|
| 268 | # source --builtin byo-server.sh
|
| 269 | #
|
| 270 | # byo-maybe-main # reads env variables, and then exits
|
| 271 | #
|
| 272 | # source --builtin assertions.ysh
|
| 273 | #
|
| 274 | # assert-ok 'echo hi'
|
| 275 | # assert-stdout 'hi' 'echo -n hi'
|
| 276 | #
|
| 277 | # "$@"
|
| 278 | #
|
| 279 | # Run all tests
|
| 280 | # util/byo-client.sh run-tests $YSH stdlib/table.ysh
|
| 281 | # util/byo-client.sh run-tests -f x $YSH stdlib/table.ysh
|
| 282 |
|
| 283 | # Clean process
|
| 284 | # Clean working dir
|
| 285 |
|
| 286 | #
|
| 287 | # Stream Protocol:
|
| 288 | # #.byo - is this she-dot, that's for a file
|
| 289 | # Do we need metadata?
|
| 290 | #
|
| 291 |
|
| 292 | # The harness
|
| 293 | #
|
| 294 | # It's process based testing.
|
| 295 | #
|
| 296 | # Test runner process: bash or OSH (unlike sharness!)
|
| 297 | # Tested process: any language - bash,
|
| 298 | #
|
| 299 | # Key point: you don't have to quote shell code?
|
| 300 |
|
| 301 | list-byo-tests() {
|
| 302 | echo TODO
|
| 303 | }
|
| 304 |
|
| 305 | run-byo-tests() {
|
| 306 | # source it
|
| 307 | echo TODO
|
| 308 | }
|
| 309 |
|
| 310 | byo-maybe-run
|