{"id":20575293,"url":"https://github.com/cjdoris/Chevrons.jl","last_synced_at":"2025-09-26T01:31:21.847Z","repository":{"id":262689427,"uuid":"888042883","full_name":"cjdoris/Chevy.jl","owner":"cjdoris","description":"Your friendly \u003e\u003e chevron \u003e\u003e based syntax for piping data through multiple transformations.","archived":false,"fork":false,"pushed_at":"2025-01-16T19:09:24.000Z","size":28,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-16T20:16:34.720Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cjdoris.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-11-13T18:00:34.000Z","updated_at":"2025-01-16T19:09:25.000Z","dependencies_parsed_at":"2025-01-16T20:10:52.318Z","dependency_job_id":"884a8f82-5c56-4527-915f-1f28695bc964","html_url":"https://github.com/cjdoris/Chevy.jl","commit_stats":null,"previous_names":["cjdoris/chevy.jl"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cjdoris%2FChevy.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cjdoris%2FChevy.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cjdoris%2FChevy.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cjdoris%2FChevy.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cjdoris","download_url":"https://codeload.github.com/cjdoris/Chevy.jl/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234276837,"owners_count":18806938,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-16T05:38:49.688Z","updated_at":"2025-09-26T01:31:21.842Z","avatar_url":"https://github.com/cjdoris.png","language":"Julia","funding_links":[],"categories":[],"sub_categories":[],"readme":"# » Chevrons.jl\n\n[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)\n[![Test Status](https://github.com/cjdoris/Chevrons.jl/actions/workflows/tests.yml/badge.svg)](https://github.com/cjdoris/Chevrons.jl/actions/workflows/tests.yml)\n[![Codecov](https://codecov.io/gh/cjdoris/Chevrons.jl/branch/main/graph/badge.svg?token=1flP5128hZ)](https://codecov.io/gh/cjdoris/Chevrons.jl)\n\nYour `friendly \u003e\u003e chevron \u003e\u003e based` syntax for piping data through multiple\ntransformations.\n\nA [Julia](https://julialang.org/) package with all the good ideas from\n[Chain.jl](https://github.com/jkrumbiegel/Chain.jl) and\n[Pipe.jl](https://github.com/oxinabox/Pipe.jl), but with nicer syntax and REPL integration.\n\nHere is a simple example:\n```julia-repl\njulia\u003e using Chevrons, DataFrames, TidierData\n\njulia\u003e Chevrons.enable_repl()  # magic to enable Chevrons syntax in the REPL\n\njulia\u003e df = DataFrame(name=[\"John\", \"Sally\", \"Roger\"], age=[54, 34, 79], children=[0, 2, 4])\n3×3 DataFrame\n Row │ name    age    children\n     │ String  Int64  Int64\n─────┼─────────────────────────\n   1 │ John       54         0\n   2 │ Sally      34         2\n   3 │ Roger      79         4\n\njulia\u003e df \u003e\u003e @filter(age \u003e 40) \u003e\u003e @select(num_children=children, age)\n2×2 DataFrame\n Row │ num_children  age\n     │ Int64         Int64\n─────┼─────────────────────\n   1 │            0     54\n   2 │            4     79\n```\n\nQuick comparison with similar packages:\n\n| Feature | Chevrons.jl | [Chain.jl](https://github.com/jkrumbiegel/Chain.jl) | [Pipe.jl](https://github.com/oxinabox/Pipe.jl) |\n| --- | --- | --- | --- |\n| [Piping syntax](#getting-started) | ✔️ (`\u003e\u003e`) | ✔️ (`@chain`) | ✔️ (`\\|\u003e`) |\n| [Side effects](#side-effects-with-) | ✔️ (`\u003e\u003e\u003e`) | ✔️ (`@aside`) | ❌ |\n| [Pipe backwards](#piping-backwards-with-) | ✔️ (`\u003c\u003c`) | ❌ | ❌ |\n| [Recursive syntax](#recursive-usage) | ✔️ | ❌ | ❌ |\n| [REPL integration](#repl-integration) | ✔️ | ❌ | ❌ |\n| Line numbers on errors | ❌ | ✔️ | ❌ |\n\n## Usage\n\n### Installation\n\nClick `]` to enter the Pkg REPL then do:\n\n```\npkg\u003e add Chevrons\n```\n\n### Getting started\n\nChevrons exports a macro `@chevrons` which transforms expressions like `x \u003e\u003e f(y, z)` into\n`f(x, y, z)`. These can be chained together, so that\n```julia\n@chevrons Int[] \u003e\u003e push!(5, 2, 4, 3, 1) \u003e\u003e sort!()\n```\nis equivalent to\n```julia\nsort!(push!(Int[], 5, 2, 4, 3, 1))\n```\n\nIn fact we can see exactly what it is transformed to with `@macroexpand`. This is\nequivalent code but with intermediate results saved for clarity.\n```julia-repl\njulia\u003e @macroexpand @chevrons Int[] \u003e\u003e push!(5, 2, 4, 3, 1) \u003e\u003e sort!()\nquote\n    var\"##chevrons#241\" = Int[]\n    var\"##chevrons#242\" = push!(var\"##chevrons#241\", 5, 2, 4, 3, 1)\n    sort!(var\"##chevrons#242\")\nend\n```\n\n### REPL integration\n\nIf you are using the Julia REPL, you can activate Chevrons's REPL integration like\n```julia-repl\njulia\u003e Chevrons.enable_repl()\n```\nThis allows you to use this syntax from the Julia REPL without typing `@chevrons` every\ntime. Use `Chevrons.enable_repl(false)` to disable it again. The rest of the examples here\nwill be from the REPL.\n\nAlso see [this tip](#startup-file) for automatically enabling the REPL integration.\n\n### Basic piping syntax with `\u003e\u003e`\n\nExpressions like `x \u003e\u003e f(y, z)` are transformed to insert `x` as an extra first argument\nin the function call, like:\n```julia-repl\njulia\u003e [5,2,4,3,1] \u003e\u003e sort!() \u003e\u003e println()\n[1, 2, 3, 4, 5]\n```\n\nIf you want the argument to appear elsewhere, you can indicate where with `_`:\n```julia-repl\njulia\u003e [5,2,4,3,1] \u003e\u003e filter!(isodd, _) \u003e\u003e println()\n[5, 3, 1]\n```\n\nIn fact, you can use any expression involving `_`:\n```julia-repl\njulia\u003e [5,2,4,3,1] \u003e\u003e filter!(isodd, _ .+ 10) \u003e\u003e println()\n[15, 13, 11]\n```\n\n### Side-effects with `\u003e\u003e\u003e`\n\nSometimes you want to do something with an intermediate value in the pipeline, but then\ncontinue with the previous value. For this, you can use `x \u003e\u003e\u003e f()` which is transformed\nto `tmp = x; f(tmp); tmp`. It is very similar to Chain.jl's `@aside` syntax.\n\nOne use for this is to log intermediate values for debugging:\n```julia-repl\njulia\u003e [5,2,4,3,1] \u003e\u003e filter!(isodd, _) \u003e\u003e\u003e println(\"x = \", _) \u003e\u003e sum()\nx = [5, 3, 1]\n9\n```\n\nYou can assign values, and even use them in later steps:\n```julia-repl\njulia\u003e 10 \u003e\u003e (_ * 2) \u003e\u003e\u003e (x = _) \u003e\u003e (x^2 - _)\n380\n\njulia\u003e x\n20\n```\n\nIt is also useful for functions which mutate the argument but do not return it:\n```julia-repl\njulia\u003e [5,2,4,3,1] \u003e\u003e popat!(4)\n3\n\njulia\u003e [5,2,4,3,1] \u003e\u003e\u003e popat!(4) \u003e\u003e println()\n[5, 2, 4, 1]\n```\n\n### Piping backwards with `\u003c\u003c`\n\nYou can use `\u003c\u003c` to pipe backwards: `f(y) \u003c\u003c x` is transformed to `f(x, y)`.\n\nThis can be useful as a sort of \"inline do-notation\":\n```julia-repl\njulia\u003e write(\"hello.txt\", \"ignore this line\\nkeep this line!\");\n\njulia\u003e (\n           \"hello.txt\"\n           \u003e\u003e open()\n           \u003c\u003c (io -\u003e io \u003e\u003e\u003e readline() \u003e\u003e read(String))\n           \u003e\u003e uppercase()\n       )\n\"KEEP THIS LINE!\"\n```\n\nYou can instead just use regular do-notation:\n```\njulia\u003e (\n           \"hello.txt\"\n           \u003e\u003e open() do io\n               io \u003e\u003e\u003e readline() \u003e\u003e read(String)\n           end\n           \u003e\u003e uppercase()\n       )\n\"KEEP THIS LINE!\"\n```\n\n### Recursive usage\n\nThe `@chevrons` macro works recursively, meaning you can wrap an entire module (or script\nor function or any code block) and all `\u003e\u003e`/`\u003e\u003e\u003e`/`\u003c\u003c` expressions will be converted.\n\nFor example here is the first example in this README converted to a script:\n\n```julia\nusing Chevrons, DataFrames, TidierData\n\n@chevrons begin\n    df = DataFrame(name=[\"John\", \"Sally\", \"Roger\"], age=[54, 34, 79], children=[0, 2, 4])\n    df2 = df \u003e\u003e @filter(age \u003e 40) \u003e\u003e @select(num_children=children, age)\n    df2 \u003e\u003e println(\"data:\", _)\n    df2 \u003e\u003e size \u003e\u003e println(\"size:\", _)\nend\n```\n\nOr the data manipulation step can be encapsulated as a function like so:\n\n```julia\n@chevrons munge(df) = df \u003e\u003e @filter(age \u003e 40) \u003e\u003e @select(num_children=children, age)\n```\n\n### Pro tips\n\n#### Parentheses\n\nIf you surround your pipelines with parentheses then you can place each transformation\non a separate line for clarity. This also allows you to easily comment out individual\ntransformations.\n\n```julia\n@chevrons (\n    df\n    # \u003e\u003e @filter(age \u003e 40)\n    \u003e\u003e @select(nchildren=children, age),\n)\n```\n\nOr you can use `\u003e\u003e(x, y, z)` syntax instead of `x \u003e\u003e y \u003e\u003e z` like so:\n\n```julia\n@chevrons \u003e\u003e(\n    df,\n    # @filter(age \u003e 40),\n    @select(nchildren=children, age),\n)\n```\n\n#### Startup file\n\nYou can add the following lines to your `startup.jl` file (usually at\n`~/.julia/config/startup.jl`) to enable Chevrons's REPL integration automatically:\n\n```julia\nif isinteractive()\n    try\n        using Chevrons\n    catch\n        @warn \"Chevrons not available\"\n    end\n    if @isdefined Chevrons\n        Chevrons.enable_repl()\n    end\nend\n```\n\nChevrons has no dependencies so is safe to add to your global environment - then it will\nalways be available at the REPL.\n\n#### Using bit-shift functions\n\nIf you want to use the actual `\u003e\u003e`/`\u003c\u003c`/`\u003e\u003e\u003e` bit-shifting functions in your code, you\ncan do this by giving them a new name like so:\n```julia-repl\njulia\u003e using Base: \u003c\u003c as lshift\n\njulia\u003e lshift(1, 10)\n1024\n```\n\n## API\n\nSee the docstrings for more help:\n- `@chevrons ...`: Transform and execute the given code.\n- `chevrons(expr)`: Transform the given expression.\n- `Chevrons.enable_repl(on=true)`: Enable/disable the REPL integration.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcjdoris%2FChevrons.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcjdoris%2FChevrons.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcjdoris%2FChevrons.jl/lists"}