Current section
8 Versions
Jump to
Current section
8 Versions
Compare versions
6
files changed
+167
additions
-118
deletions
| @@ -1,9 +1,9 @@ | |
| 1 1 | {<<"links">>, |
| 2 2 | [{<<"Gitlab">>,<<"https://gitlab.com/lab42-hex-projects/cliex_map">>}]}. |
| 3 3 | {<<"name">>,<<"cliex_map">>}. |
| 4 | - {<<"version">>,<<"0.2.5">>}. |
| 4 | + {<<"version">>,<<"0.2.6">>}. |
| 5 5 | {<<"description">>,<<"Map lines with a powerful mini language">>}. |
| 6 | - {<<"elixir">>,<<"~> 1.15">>}. |
| 6 | + {<<"elixir">>,<<"~> 1.16">>}. |
| 7 7 | {<<"app">>,<<"cliex_map">>}. |
| 8 8 | {<<"files">>, |
| 9 9 | [<<"lib">>,<<"lib/cliex_map.ex">>,<<"lib/cliex_map">>, |
| @@ -99,15 +99,39 @@ defmodule CliexMap do | |
| 99 99 | iex(13)> run(["", "", ""], "%xmics", C.for_now(1691231907123456)) |
| 100 100 | ["6022a9d0e9100", "6022a9d0e9100", "6022a9d0e9100"] |
| 101 101 | |
| 102 | + ### Regex Pattern Matches |
| 103 | + |
| 104 | + This builtin will also filter out lines that are not matched unless a replacement string is provided. |
| 105 | + In its simplest form the whole match of the field is returned |
| 106 | + |
| 107 | + iex(14)> run(["a", "12"], ~s{%(rgx "[[:digit:]]+")}) |
| 108 | + ["12"] |
| 109 | + |
| 110 | + Or we can just get a capture group |
| 111 | + |
| 112 | + iex(15)> run(["a", "12"], ~s{%(rgx "(.)([[:digit:]])" 2)}) |
| 113 | + ["2"] |
| 114 | + |
| 115 | + And we can provide a default value |
| 116 | + |
| 117 | + iex(16)> run(["a", "12"], ~s{%(rgx "(.)([[:digit:]])" 2 "no digit found")}) |
| 118 | + ["no digit found", "2"] |
| 119 | + |
| 120 | + Which we can also do if we want to match the whole regex |
| 121 | + |
| 122 | + iex(17)> run(["a", "12"], ~s{%(rgx "[[:digit:]]+" oh_no)}) |
| 123 | + ["oh_no", "12"] |
| 124 | + |
| 125 | + |
| 102 126 | ### Variables |
| 103 127 | |
| 104 128 | While, up to here, patterns have been simple we will see later that they can become quite complicated. |
| 105 129 | Without explaining the details of the following examples we will see that we need to rewrite a long |
| 106 130 | pattern to create the desired command for each input line |
| 107 131 | |
| 108 | - iex(14)> run(["src/DIR/subdir/file.jsno"], |
| 109 | - ...(14)> ~s{mkdir -p bup/%xs/%(segments 1 -2)(downcase); cp % bup/%xs/%(segments 1 -2)(downcase)/%(segments -1)(sub ".jsno" ".json")}, |
| 110 | - ...(14)> C.for_now(1691231907123456)) |
| 132 | + iex(18)> run(["src/DIR/subdir/file.jsno"], |
| 133 | + ...(18)> ~s{mkdir -p bup/%xs/%(segments 1 -2)(downcase); cp % bup/%xs/%(segments 1 -2)(downcase)/%(segments -1)(sub ".jsno" ".json")}, |
| 134 | + ...(18)> C.for_now(1691231907123456)) |
| 111 135 | ["mkdir -p bup/64ce26a3/dir/subdir; cp src/DIR/subdir/file.jsno bup/64ce26a3/dir/subdir/file.json"] |
| 112 136 | |
| 113 137 | Actually the patterns above are a little bit more complicated as needed but this is to demonstrate the usage of Variables |
| @@ -117,22 +141,22 @@ defmodule CliexMap do | |
| 117 141 | The `%S<varname><pattern>` will compile `<pattern>` but instead of rendering its result it will store it in the context, thusly the |
| 118 142 | following is useless |
| 119 143 | |
| 120 | - iex(15)> run(["useless input"], "%Saa<%(split)(revlist)(join)>") |
| 144 | + iex(19)> run(["useless input"], "%Saa<%(split)(revlist)(join)>") |
| 121 145 | [""] |
| 122 146 | |
| 123 147 | We can, however use the variable **after** its declaration, and that, many times |
| 124 148 | |
| 125 | - iex(16)> run(["A B"], "%Sx<%(downcase)(split)(revlist)(join)>-%Lx-%Lx-%Lx-") |
| 149 | + iex(20)> run(["A B"], "%Sx<%(downcase)(split)(revlist)(join)>-%Lx-%Lx-%Lx-") |
| 126 150 | ["-ba-ba-ba-"] |
| 127 151 | |
| 128 152 | Of course a loaded variable can be modified as every other field |
| 129 153 | |
| 130 | - iex(17)> run(["A B"], "%Sx<%(downcase)(split)(revlist)(join)>-%Lx-%Lx(upcase)") |
| 154 | + iex(21)> run(["A B"], "%Sx<%(downcase)(split)(revlist)(join)>-%Lx-%Lx(upcase)") |
| 131 155 | ["-ba-BA"] |
| 132 156 | |
| 133 157 | Variables can also be used to store constant strings |
| 134 158 | |
| 135 | - iex(18)> run([""], "%Sworld<Brave new world>%Lworld %Lworld(split)(at 1)") |
| 159 | + iex(22)> run([""], "%Sworld<Brave new world>%Lworld %Lworld(split)(at 1)") |
| 136 160 | ["Brave new world new"] |
| 137 161 | |
| 138 162 | ## Pattern Modifiers |
| @@ -144,8 +168,8 @@ defmodule CliexMap do | |
| 144 168 | injected into the second s-expression and so forth, here are some examples to demonstrate the |
| 145 169 | principle |
| 146 170 | |
| 147 | - iex(19)> run(["alpha"], "%(reverse)") |
| 148 | - ["ahpla"] |
| 171 | + iex(23)> run(["alpha"], "%(reverse)") |
| 172 | + ["ahpla"] |
| 149 173 | |
| 150 174 | Below we will list all available built in functions, but here we will also show the more common use |
| 151 175 | cases like splitting, extracting and combining segments of strings, formatting output and the shortcut |
| @@ -156,24 +180,24 @@ defmodule CliexMap do | |
| 156 180 | Let us imagien that we want to preceede line numbers by their tenfolds and want to start with 10, what |
| 157 181 | we can do of course is to use LLLML as follows |
| 158 182 | |
| 159 | - iex(20)> run(["a", "a", "a", "a"], "%n(+ 1)(* 10) %") |
| 183 | + iex(24)> run(["a", "a", "a", "a"], "%n(+ 1)(* 10) %") |
| 160 184 | ["10 a", "20 a", "30 a", "40 a"] |
| 161 185 | |
| 162 186 | There are cases where we need the injected line number to be the second argument of a function, e.g. |
| 163 187 | if we want to count down. We can indicate the position where a value shall be injected by the placeholder `_` |
| 164 188 | |
| 165 | - iex(21)> run(["b", "b", "b"], "%n(* -10)(+ 110) %") |
| 189 | + iex(25)> run(["b", "b", "b"], "%n(* -10)(+ 110) %") |
| 166 190 | ["110 b", "100 b", "90 b"] |
| 167 191 | |
| 168 192 | |
| 169 193 | This is obviously a handful, and therefore we provide a shortcut with a simple value notation |
| 170 194 | |
| 171 | - iex(22)> run(["b", "b", "b"], "%n:110,-10: %") |
| 195 | + iex(26)> run(["b", "b", "b"], "%n:110,-10: %") |
| 172 196 | ["110 b", "100 b", "90 b"] |
| 173 197 | |
| 174 198 | And the one value version can be used to change the start count, 1 being a popular choice ;) |
| 175 199 | |
| 176 | - iex(23)> run(["b", "b", "e"], "%n:1: %") |
| 200 | + iex(27)> run(["b", "b", "e"], "%n:1: %") |
| 177 201 | ["1 b", "2 b", "3 e"] |
| 178 202 | |
| 179 203 | ### Formatting Modifiers and their shortcuts |
| @@ -183,36 +207,36 @@ defmodule CliexMap do | |
| 183 207 | as we will show here, shorter patterns are desired and therefore implemented. |
| 184 208 | |
| 185 209 | #### Aligning strings and numbers |
| 186 | - iex(24)> run(~w[alpha beta], "%(rpad 6)") |
| 210 | + iex(28)> run(~w[alpha beta], "%(rpad 6)") |
| 187 211 | ["alpha ", "beta "] |
| 188 212 | |
| 189 213 | And the shorter |
| 190 214 | |
| 191 | - iex(25)> run(~w[alpha beta], "%<-6>") |
| 215 | + iex(29)> run(~w[alpha beta], "%<-6>") |
| 192 216 | ["alpha ", "beta "] |
| 193 217 | |
| 194 218 | Or |
| 195 219 | |
| 196 | - iex(26)> run(~w[alpha beta], "%(lpad 6 -)") |
| 220 | + iex(30)> run(~w[alpha beta], "%(lpad 6 -)") |
| 197 221 | ["-alpha", "--beta"] |
| 198 222 | |
| 199 223 | And the shorter |
| 200 224 | |
| 201 | - iex(27)> run(~w[alpha beta], "%<6->") |
| 225 | + iex(31)> run(~w[alpha beta], "%<6->") |
| 202 226 | ["-alpha", "--beta"] |
| 203 227 | |
| 204 228 | |
| 205 | - iex(28)> run(["", ""], "%n<2 0>") # Note the space in order to avoid a length of 20 |
| 229 | + iex(32)> run(["", ""], "%n<2 0>") # Note the space in order to avoid a length of 20 |
| 206 230 | ["00", "01"] |
| 207 231 | |
| 208 232 | #### Formatting Numbers |
| 209 233 | |
| 210 | - iex(29)> run(["", ""], "%n:15:(to_s 16)(lpad 2 0)") |
| 234 | + iex(33)> run(["", ""], "%n:15:(to_s 16)(lpad 2 0)") |
| 211 235 | ["0f", "10"] |
| 212 236 | |
| 213 237 | And the shorter |
| 214 238 | |
| 215 | - iex(30)> run(["", ""], "%n:15:<2x0>") |
| 239 | + iex(34)> run(["", ""], "%n:15:<2x0>") |
| 216 240 | ["0f", "10"] |
| 217 241 | |
| 218 242 | |
| @@ -227,7 +251,7 @@ defmodule CliexMap do | |
| 227 251 | We can demonstrate with an explicit implementation of counting down line numbers (which of course is done with the |
| 228 252 | shortcuts shown above |
| 229 253 | |
| 230 | - iex(31)> run(["", "", ""], "%n(- 10 _)") |
| 254 | + iex(35)> run(["", "", ""], "%n(- 10 _)") |
| 231 255 | ["10", "9", "8"] |
| 232 256 | |
| 233 257 | ## Cookbooks |
| @@ -272,21 +296,21 @@ defmodule CliexMap do | |
| 272 296 | |
| 273 297 | By using the output from, e.g. `git ls-files src` or `find src -name '*.json'` we can map the input with the following pattern |
| 274 298 | |
| 275 | - iex(32)> input = ~W[ src/namespace_1/file1.json src/namespace_2/file1.json src/namespace_2/file2.json ] |
| 276 | - ...(32)> run(input, "mkdir -p tests/json_tests/%(segment 1); touch tests/json_tests/%(segments 1 2)(sub '.json' '_test.exs')") |
| 277 | - [ |
| 278 | - "mkdir -p tests/json_tests/namespace_1; touch tests/json_tests/namespace_1/file1_test.exs", |
| 279 | - "mkdir -p tests/json_tests/namespace_2; touch tests/json_tests/namespace_2/file1_test.exs", |
| 280 | - "mkdir -p tests/json_tests/namespace_2; touch tests/json_tests/namespace_2/file2_test.exs" |
| 281 | - ] |
| 299 | + iex(36)> input = ~W[ src/namespace_1/file1.json src/namespace_2/file1.json src/namespace_2/file2.json ] |
| 300 | + ...(36)> run(input, "mkdir -p tests/json_tests/%(segment 1); touch tests/json_tests/%(segments 1 2)(sub '.json' '_test.exs')") |
| 301 | + [ |
| 302 | + "mkdir -p tests/json_tests/namespace_1; touch tests/json_tests/namespace_1/file1_test.exs", |
| 303 | + "mkdir -p tests/json_tests/namespace_2; touch tests/json_tests/namespace_2/file1_test.exs", |
| 304 | + "mkdir -p tests/json_tests/namespace_2; touch tests/json_tests/namespace_2/file2_test.exs" |
| 305 | + ] |
| 282 306 | |
| 283 307 | Changing and using extensions of filenames is frequent enough to justify the `ext` builtin |
| 284 308 | |
| 285 | - iex(33)> input = ~W[ src/namespace_1/file1.json ] |
| 286 | - ...(33)> run(input, "mkdir -p tests/json_tests/%(segment 1); touch tests/json_tests/%(segments 1 2)(ext _test.exs)") |
| 287 | - [ |
| 288 | - "mkdir -p tests/json_tests/namespace_1; touch tests/json_tests/namespace_1/file1_test.exs", |
| 289 | - ] |
| 309 | + iex(37)> input = ~W[ src/namespace_1/file1.json ] |
| 310 | + ...(37)> run(input, "mkdir -p tests/json_tests/%(segment 1); touch tests/json_tests/%(segments 1 2)(ext _test.exs)") |
| 311 | + [ |
| 312 | + "mkdir -p tests/json_tests/namespace_1; touch tests/json_tests/namespace_1/file1_test.exs", |
| 313 | + ] |
| 290 314 | |
| 291 315 | ## Comprehensive List of Builtin Functions |
| 292 316 | |
| @@ -294,191 +318,191 @@ defmodule CliexMap do | |
| 294 318 | only if needed |
| 295 319 | |
| 296 320 | ### abs |
| 297 | - iex(34)> B.abs(nil, [-10]) |
| 321 | + iex(38)> B.abs(nil, [-10]) |
| 298 322 | 10 |
| 299 323 | |
| 300 324 | ### add (used for `+`) |
| 301 | - iex(35)> B._add(nil, [1, 2, 3, 4]) |
| 325 | + iex(39)> B._add(nil, [1, 2, 3, 4]) |
| 302 326 | 10 |
| 303 327 | |
| 304 328 | ### at (alias to Enum.at) |
| 305 | - iex(36)> B.at(nil, [~w[a b c], 2]) |
| 329 | + iex(40)> B.at(nil, [~w[a b c], 2]) |
| 306 330 | "c" |
| 307 331 | |
| 308 | - iex(37)> B.at(nil, [~w[a b c], -3]) |
| 332 | + iex(41)> B.at(nil, [~w[a b c], -3]) |
| 309 333 | "a" |
| 310 334 | |
| 311 | - iex(38)> B.at(nil, [~w[a b c], 1, :default]) |
| 335 | + iex(42)> B.at(nil, [~w[a b c], 1, :default]) |
| 312 336 | "b" |
| 313 337 | |
| 314 | - iex(39)> B.at(nil, [~w[a b c], 3, :default]) |
| 338 | + iex(43)> B.at(nil, [~w[a b c], 3, :default]) |
| 315 339 | :default |
| 316 340 | |
| 317 341 | ### bn (Path.basename) |
| 318 | - iex(40)> B.bn(nil, ~W[a/b]) |
| 342 | + iex(44)> B.bn(nil, ~W[a/b]) |
| 319 343 | "b" |
| 320 344 | |
| 321 | - iex(41)> B.bn(nil, ~W[b.ext]) |
| 345 | + iex(45)> B.bn(nil, ~W[b.ext]) |
| 322 346 | "b.ext" |
| 323 347 | |
| 324 | - iex(42)> B.bn(nil, ~W[a/c/b.ext]) |
| 348 | + iex(46)> B.bn(nil, ~W[a/c/b.ext]) |
| 325 349 | "b.ext" |
| 326 350 | |
| 327 351 | ### div (used for `/`) |
| 328 | - iex(43)> B._div(nil, [9, 4]) |
| 352 | + iex(47)> B._div(nil, [9, 4]) |
| 329 353 | 2.25 |
| 330 354 | |
| 331 355 | ### dn (Path.dirname) |
| 332 | - iex(44)> B.dn(nil, ~W[a/b]) |
| 356 | + iex(48)> B.dn(nil, ~W[a/b]) |
| 333 357 | "a" |
| 334 358 | |
| 335 | - iex(45)> B.dn(nil, ~W[b.ext]) |
| 359 | + iex(49)> B.dn(nil, ~W[b.ext]) |
| 336 360 | "." |
| 337 361 | |
| 338 | - iex(46)> B.dn(nil, ~W[a/c/b.ext]) |
| 362 | + iex(50)> B.dn(nil, ~W[a/c/b.ext]) |
| 339 363 | "a/c" |
| 340 364 | |
| 341 365 | ### downcase |
| 342 | - iex(47)> B.downcase(nil, ["HELLO"]) |
| 366 | + iex(51)> B.downcase(nil, ["HELLO"]) |
| 343 367 | "hello" |
| 344 368 | |
| 345 369 | ### ext/1 |
| 346 370 | Returns last extension of a filename |
| 347 371 | |
| 348 | - iex(48)> B.ext(nil, ["a.html.eex"]) |
| 372 | + iex(52)> B.ext(nil, ["a.html.eex"]) |
| 349 373 | "eex" |
| 350 374 | |
| 351 375 | If no extension is found it returns an empty string |
| 352 376 | |
| 353 | - iex(49)> B.ext(nil, ["a"]) |
| 377 | + iex(53)> B.ext(nil, ["a"]) |
| 354 378 | "" |
| 355 379 | |
| 356 380 | ### ext/2 |
| 357 381 | Changes last extension of a filename, **N.B.** that the `.` is not added automatically |
| 358 | - iex(50)> B.ext(nil, ["a.html.erb", ".eex"]) |
| 382 | + iex(54)> B.ext(nil, ["a.html.erb", ".eex"]) |
| 359 383 | "a.html.eex" |
| 360 384 | |
| 361 385 | ### idiv (used for `:`) |
| 362 | - iex(51)> B._idiv(nil, [9, 4]) |
| 386 | + iex(55)> B._idiv(nil, [9, 4]) |
| 363 387 | 2 |
| 364 388 | |
| 365 389 | ### join |
| 366 | - iex(52)> B.join(nil, [[1, 2]]) |
| 390 | + iex(56)> B.join(nil, [[1, 2]]) |
| 367 391 | "12" |
| 368 392 | |
| 369 | - iex(53)> B.join(nil, [[1, 2, 3], " "]) |
| 393 | + iex(57)> B.join(nil, [[1, 2, 3], " "]) |
| 370 394 | "1 2 3" |
| 371 395 | |
| 372 396 | ### lpad |
| 373 | - iex(54)> B.lpad(nil, ["a", 2]) |
| 374 | - " a" |
| 397 | + iex(58)> B.lpad(nil, ["a", 2]) |
| 398 | + " a" |
| 375 399 | |
| 376 | - iex(55)> B.lpad(nil, ["a", 3, :"-*"]) |
| 377 | - "-*a" |
| 400 | + iex(59)> B.lpad(nil, ["a", 3, :"-*"]) |
| 401 | + "-*a" |
| 378 402 | |
| 379 403 | ### mul |
| 380 | - iex(56)> B._mul(nil, [1, 2, 3, 4]) |
| 404 | + iex(60)> B._mul(nil, [1, 2, 3, 4]) |
| 381 405 | 24 |
| 382 406 | |
| 383 407 | ### reverse |
| 384 | - iex(57)> B.reverse(nil, ["alpha"]) |
| 408 | + iex(61)> B.reverse(nil, ["alpha"]) |
| 385 409 | "ahpla" |
| 386 410 | |
| 387 411 | ### revlist |
| 388 | - iex(58)> B.revlist(nil, [~W[a b]]) |
| 412 | + iex(62)> B.revlist(nil, [~W[a b]]) |
| 389 413 | ~W[b a] |
| 390 414 | |
| 391 415 | ### rpad |
| 392 | - iex(59)> B.rpad(nil, ["a", 2]) |
| 393 | - "a " |
| 416 | + iex(63)> B.rpad(nil, ["a", 2]) |
| 417 | + "a " |
| 394 418 | |
| 395 | - iex(60)> B.rpad(nil, ["a", 3, :"--"]) |
| 396 | - "a--" |
| 419 | + iex(64)> B.rpad(nil, ["a", 3, :"--"]) |
| 420 | + "a--" |
| 397 421 | |
| 398 422 | ### segment Extract a path |
| 399 423 | |
| 400 424 | - with -1 like `basename` |
| 401 | - iex(61)> B.segment(nil, ["a/b/c", -1]) |
| 425 | + iex(65)> B.segment(nil, ["a/b/c", -1]) |
| 402 426 | "c" |
| 403 427 | |
| 404 428 | - without an arg like `dirname` |
| 405 | - iex(62)> B.segment(nil, ["a/b/c"]) |
| 429 | + iex(66)> B.segment(nil, ["a/b/c"]) |
| 406 430 | "a/b" |
| 407 431 | |
| 408 432 | - or any part |
| 409 433 | |
| 410 | - iex(63)> B.segment(nil, ["a/b/c", 0]) |
| 434 | + iex(67)> B.segment(nil, ["a/b/c", 0]) |
| 411 435 | "a" |
| 412 436 | |
| 413 | - iex(64)> B.segment(nil, ["a/b/c", -2]) |
| 437 | + iex(68)> B.segment(nil, ["a/b/c", -2]) |
| 414 438 | "b" |
| 415 439 | |
| 416 440 | |
| 417 441 | ### segments (short for `(splicej "/" _1 _2)`) |
| 418 | - iex(65)> B.segments(nil, ["x/y/z", 2]) |
| 442 | + iex(69)> B.segments(nil, ["x/y/z", 2]) |
| 419 443 | "z" |
| 420 444 | |
| 421 | - iex(66)> B.segments(nil, ["x/y/z", -2, -1]) |
| 445 | + iex(70)> B.segments(nil, ["x/y/z", -2, -1]) |
| 422 446 | "y/z" |
| 423 447 | |
| 424 448 | ### slice |
| 425 449 | |
| 426 450 | #### lists |
| 427 451 | |
| 428 | - iex(67)> B.slice(nil, [~w[a b c d], 1]) |
| 452 | + iex(71)> B.slice(nil, [~w[a b c d], 1]) |
| 429 453 | ~w[b c d] |
| 430 454 | |
| 431 | - iex(68)> B.slice(nil, [~w[a b c d], 2, 3]) |
| 455 | + iex(72)> B.slice(nil, [~w[a b c d], 2, 3]) |
| 432 456 | ~w[c d] |
| 433 457 | |
| 434 | - iex(69)> B.slice(nil, [~w[a b c d], -2]) |
| 458 | + iex(73)> B.slice(nil, [~w[a b c d], -2]) |
| 435 459 | ~w[c d] |
| 436 460 | |
| 437 | - iex(70)> B.slice(nil, [~w[a b c d], -4, -2]) |
| 461 | + iex(74)> B.slice(nil, [~w[a b c d], -4, -2]) |
| 438 462 | ~w[a b c] |
| 439 463 | |
| 440 | - iex(71)> B.slice(nil, [~w[a b c d], -4, 1]) |
| 464 | + iex(75)> B.slice(nil, [~w[a b c d], -4, 1]) |
| 441 465 | ~w[a b] |
| 442 466 | |
| 443 | - iex(72)> B.slice(nil, [~w[a b c d], 1, 0]) |
| 467 | + iex(76)> B.slice(nil, [~w[a b c d], 1, 0]) |
| 444 468 | [] |
| 445 469 | |
| 446 470 | #### strings |
| 447 471 | |
| 448 | - iex(73)> B.slice(nil, ["abc", 1]) |
| 472 | + iex(77)> B.slice(nil, ["abc", 1]) |
| 449 473 | "bc" |
| 450 474 | |
| 451 | - iex(74)> B.slice(nil, ["abc", -1]) |
| 475 | + iex(78)> B.slice(nil, ["abc", -1]) |
| 452 476 | "c" |
| 453 477 | |
| 454 | - iex(75)> B.slice(nil, ["abc", 1, 2]) |
| 478 | + iex(79)> B.slice(nil, ["abc", 1, 2]) |
| 455 479 | "bc" |
| 456 480 | |
| 457 | - iex(76)> B.slice(nil, ["abcd", -2, -1]) |
| 481 | + iex(80)> B.slice(nil, ["abcd", -2, -1]) |
| 458 482 | "cd" |
| 459 483 | |
| 460 | - iex(77)> B.slice(nil, ["abcd", -2, 3]) |
| 484 | + iex(81)> B.slice(nil, ["abcd", -2, 3]) |
| 461 485 | "cd" |
| 462 486 | |
| 463 | - iex(78)> B.slice(nil, ["abc", 0, -2]) |
| 487 | + iex(82)> B.slice(nil, ["abc", 0, -2]) |
| 464 488 | "ab" |
| 465 489 | |
| 466 490 | #### safe |
| 467 491 | |
| 468 492 | - First index out of bounds |
| 469 493 | |
| 470 | - iex(79)> B.slice(nil, ["abc", 4]) |
| 494 | + iex(83)> B.slice(nil, ["abc", 4]) |
| 471 495 | "" |
| 472 496 | |
| 473 | - iex(80)> B.slice(nil, [~w[a b], 2]) |
| 497 | + iex(84)> B.slice(nil, [~w[a b], 2]) |
| 474 498 | [] |
| 475 499 | |
| 476 500 | - Last index out of bounds |
| 477 501 | |
| 478 | - iex(81)> B.slice(nil, ["abc", 2, 5]) |
| 502 | + iex(85)> B.slice(nil, ["abc", 2, 5]) |
| 479 503 | "c" |
| 480 504 | |
| 481 | - iex(82)> B.slice(nil, [~w[a b], 1, 4]) |
| 505 | + iex(86)> B.slice(nil, [~w[a b], 1, 4]) |
| 482 506 | ~w[b] |
| 483 507 | |
| 484 508 | |
| @@ -486,47 +510,47 @@ defmodule CliexMap do | |
| 486 510 | |
| 487 511 | - join on original seperator |
| 488 512 | |
| 489 | - iex(83)> B.splicej(nil, ["a/b/c/d/e", "/", 2, 3]) |
| 490 | - "c/d" |
| 513 | + iex(87)> B.splicej(nil, ["a/b/c/d/e", "/", 2, 3]) |
| 514 | + "c/d" |
| 491 515 | |
| 492 516 | - join on original seperator, slice to the end |
| 493 517 | |
| 494 | - iex(84)> B.splicej(nil, ["a/b/c/d/e", "/", 2]) |
| 495 | - "c/d/e" |
| 518 | + iex(88)> B.splicej(nil, ["a/b/c/d/e", "/", 2]) |
| 519 | + "c/d/e" |
| 496 520 | |
| 497 521 | - join with different string |
| 498 522 | |
| 499 | - iex(85)> B.splice_join(nil, ["a/b/c/d/e", "/", 2, 3, ","]) |
| 500 | - "c,d" |
| 523 | + iex(89)> B.splice_join(nil, ["a/b/c/d/e", "/", 2, 3, ","]) |
| 524 | + "c,d" |
| 501 525 | |
| 502 526 | ### split |
| 503 527 | |
| 504 | - iex(86)> B.split(nil, ["a b"]) |
| 528 | + iex(90)> B.split(nil, ["a b"]) |
| 505 529 | ["a", "b"] |
| 506 530 | |
| 507 | - iex(87)> B.split(nil, ["a,b", ","]) |
| 531 | + iex(91)> B.split(nil, ["a,b", ","]) |
| 508 532 | ["a", "b"] |
| 509 533 | |
| 510 534 | ### sub (from `-`) (use with care) |
| 511 | - iex(88)> B._sub(nil, [1, 2, 3, 4]) |
| 535 | + iex(92)> B._sub(nil, [1, 2, 3, 4]) |
| 512 536 | -8 |
| 513 537 | |
| 514 538 | ### sub (from `sub`) |
| 515 | - iex(89)> B.sub(nil, ["Hello World", "l"]) |
| 539 | + iex(93)> B.sub(nil, ["Hello World", "l"]) |
| 516 540 | "Heo Word" |
| 517 541 | |
| 518 | - iex(90)> B.sub(nil, ["Hello World", "l", "L"]) |
| 542 | + iex(94)> B.sub(nil, ["Hello World", "l", "L"]) |
| 519 543 | "HeLLo WorLd" |
| 520 544 | |
| 521 545 | ### to_s (for numbers only) |
| 522 | - iex(91)> B.to_s(nil, [12]) |
| 546 | + iex(95)> B.to_s(nil, [12]) |
| 523 547 | "12" |
| 524 548 | |
| 525 | - iex(92)> B.to_s(nil, [12, 16]) |
| 549 | + iex(96)> B.to_s(nil, [12, 16]) |
| 526 550 | "c" |
| 527 551 | |
| 528 552 | ### upcase |
| 529 | - iex(93)> B.upcase(nil, ["hello"]) |
| 553 | + iex(97)> B.upcase(nil, ["hello"]) |
| 530 554 | "HELLO" |
| 531 555 | |
| 532 556 | """ |
| @@ -81,6 +81,24 @@ defmodule CliexMap.Builtins do | |
| 81 81 | @spec revlist(Context.t, list()) :: list() |
| 82 82 | def revlist(_context, [list]), do: Enum.reverse(list) |
| 83 83 | |
| 84 | + @spec rgx(Context.t, list()) :: binary() |
| 85 | + def rgx(context, [src, pattern]) do |
| 86 | + rgx(context, [src, pattern, 0]) |
| 87 | + end |
| 88 | + def rgx(context, [src, pattern, count]) when is_number(count) do |
| 89 | + rgx(context, [src, pattern, count, nil]) |
| 90 | + end |
| 91 | + def rgx(context, [src, pattern, count]) do |
| 92 | + rgx(context, [src, pattern, 0, to_string(count)]) |
| 93 | + end |
| 94 | + def rgx(_context, [src, pattern, count, replacement]) do |
| 95 | + p = Regex.compile!(to_string(pattern)) |
| 96 | + case Regex.run(p, src) do |
| 97 | + nil -> if replacement, do: replacement, else: {:halt, :ignore} |
| 98 | + m -> Enum.at(m, count) |
| 99 | + end |
| 100 | + end |
| 101 | + |
| 84 102 | @spec rnd(Context.t, list()) :: binary() |
| 85 103 | def rnd(_context, args) do |
| 86 104 | case args do |
| @@ -52,7 +52,7 @@ defmodule CliexMap.Cli do | |
| 52 52 | |> Enum.each(&IO.puts/1) |
| 53 53 | end |
| 54 54 | |
| 55 | - @spec help_pattern() :: :ok |
| 55 | + @spec help_pattern() :: nil |
| 56 56 | defp help_pattern do |
| 57 57 | # Color.putc([ |
| 58 58 | # "A pattern always starts with a ", |
| @@ -3,7 +3,7 @@ defmodule CliexMap.Mapper do | |
| 3 3 | |
| 4 4 | alias CliexMap.{Context, Fn, FunctionList} |
| 5 5 | |
| 6 | - @moduledoc ~S""" |
| 6 | + @moduledoc ~S""" |
| 7 7 | Maps each line according to pattern to a new, `\n` terminated string |
| 8 8 | """ |
| 9 9 | |
| @@ -15,20 +15,25 @@ defmodule CliexMap.Mapper do | |
| 15 15 | Stream.zip(line_numbers, input_stream |> Stream.map(&String.trim_trailing(&1, "\n"))) |
| 16 16 | |
| 17 17 | numbered_lines |
| 18 | - |> Enum.map(&transform_line(&1, function_pipeline, context)) |
| 18 | + |> Stream.map(&transform_line(&1, function_pipeline, context)) |
| 19 | + |> Enum.filter(&is_binary/1) |
| 19 20 | end |
| 20 21 | |
| 21 22 | @spec transform_line(numbered_line_t(), list(FunctionList.t()), Context.t()) :: binary() |
| 22 23 | def transform_line(line, function_pipelines, context) do |
| 23 24 | with {_context, outputresult} <- |
| 24 25 | function_pipelines |
| 25 | - |> Enum.reduce({context, []}, fn pipeline, {ctxt, output} -> |
| 26 | - {ctxt1, output1} = transform_chunk(line, pipeline, ctxt) |
| 27 | - {ctxt1, [output1 | output]} |
| 26 | + |> Enum.reduce_while({context, []}, fn pipeline, {ctxt, output} -> |
| 27 | + case transform_chunk(line, pipeline, ctxt) do |
| 28 | + {ctxt1, output1} -> {:cont, {ctxt1, [output1 | output]}} |
| 29 | + :ignore -> {:halt, :ignore} |
| 30 | + _value -> raise "Not yet implemented" |
| 31 | + end |
| 28 32 | end) do |
| 29 | - outputresult |
| 30 | - |> Enum.reverse |
| 31 | - |> Enum.join |
| 33 | + case outputresult do |
| 34 | + :ignore -> :ignore |
| 35 | + o -> o |> Enum.reverse |> Enum.join |
| 36 | + end |
| 32 37 | end |
| 33 38 | end |
| 34 39 | |
| @@ -38,10 +43,12 @@ defmodule CliexMap.Mapper do | |
| 38 43 | # |
| 39 44 | function_pipeline.functions |
| 40 45 | |> Enum.reverse() |
| 41 | - |> Enum.reduce({context, line}, fn function, {ctxt, input} -> |
| 46 | + |> Enum.reduce_while({context, line}, fn function, {ctxt, input} -> |
| 42 47 | case Fn.call(function, input, ctxt) do |
| 43 | - {ctxt1, text} -> {ctxt1, text} |
| 44 | - text -> {ctxt, text} |
| 48 | + :halt -> {:halt, :ignore} |
| 49 | + {:halt, _} = hv -> hv |
| 50 | + {_, _} = cc -> {:cont, cc} |
| 51 | + text -> {:cont, {ctxt, text}} |
| 45 52 | end |
| 46 53 | end) |
| 47 54 | end |
Loading more files…