From eff1ae9bf93646bb630cf4598a6443822d7858da Mon Sep 17 00:00:00 2001 From: Christopher Doris Date: Wed, 29 Jan 2025 11:24:46 +0000 Subject: [PATCH] Rename package from Chevy to Chevrons --- Project.toml | 2 +- README.md | 66 ++++++++++++++++----------------- src/{Chevy.jl => Chevrons.jl} | 54 +++++++++++++-------------- test/aqua.jl | 2 +- test/integration.jl | 10 ++--- test/unit.jl | 70 ++++++++++++++++++----------------- 6 files changed, 104 insertions(+), 100 deletions(-) rename src/{Chevy.jl => Chevrons.jl} (85%) diff --git a/Project.toml b/Project.toml index 80eb7e6..58ec156 100644 --- a/Project.toml +++ b/Project.toml @@ -1,4 +1,4 @@ -name = "Chevy" +name = "Chevrons" uuid = "d9083b8b-98e7-4ee6-a2c7-6db47b61bf48" authors = ["Christopher Doris "] version = "1.0.0" diff --git a/README.md b/README.md index 3846f1e..1eb6907 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# » Chevy.jl +# » Chevrons.jl [![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) -[![Test Status](https://github.com/cjdoris/Chevy.jl/actions/workflows/tests.yml/badge.svg)](https://github.com/cjdoris/Chevy.jl/actions/workflows/tests.yml) -[![Codecov](https://codecov.io/gh/cjdoris/Chevy.jl/branch/main/graph/badge.svg?token=1flP5128hZ)](https://codecov.io/gh/cjdoris/Chevy.jl) +[![Test Status](https://github.com/cjdoris/Chevrons.jl/actions/workflows/tests.yml/badge.svg)](https://github.com/cjdoris/Chevrons.jl/actions/workflows/tests.yml) +[![Codecov](https://codecov.io/gh/cjdoris/Chevrons.jl/branch/main/graph/badge.svg?token=1flP5128hZ)](https://codecov.io/gh/cjdoris/Chevrons.jl) Your `friendly >> chevron >> based` syntax for piping data through multiple transformations. @@ -13,9 +13,9 @@ A [Julia](https://julialang.org/) package with all the good ideas from Here is a simple example: ```julia-repl -julia> using Chevy, DataFrames, TidierData +julia> using Chevrons, DataFrames, TidierData -julia> Chevy.enable_repl() # magic to enable Chevy syntax in the REPL +julia> Chevrons.enable_repl() # magic to enable Chevrons syntax in the REPL julia> df = DataFrame(name=["John", "Sally", "Roger"], age=[54, 34, 79], children=[0, 2, 4]) 3×3 DataFrame @@ -37,7 +37,7 @@ julia> df >> @filter(age > 40) >> @select(num_children=children, age) Quick comparison with similar packages: -| Feature | Chevy.jl | [Chain.jl](https://github.com/jkrumbiegel/Chain.jl) | [Pipe.jl](https://github.com/oxinabox/Pipe.jl) | +| Feature | Chevrons.jl | [Chain.jl](https://github.com/jkrumbiegel/Chain.jl) | [Pipe.jl](https://github.com/oxinabox/Pipe.jl) | | --- | --- | --- | --- | | [Piping syntax](#getting-started) | ✔️ (`>>`) | ✔️ (`@chain`) | ✔️ (`\|>`) | | [Side effects](#side-effects-with-) | ✔️ (`>>>`) | ✔️ (`@aside`) | ❌ | @@ -53,15 +53,15 @@ Quick comparison with similar packages: Click `]` to enter the Pkg REPL then do: ``` -pkg> add Chevy +pkg> add Chevrons ``` ### Getting started -Chevy exports a macro `@chevy` which transforms expressions like `x >> f(y, z)` into +Chevrons exports a macro `@chevrons` which transforms expressions like `x >> f(y, z)` into `f(x, y, z)`. These can be chained together, so that ```julia -@chevy Int[] >> push!(5, 2, 4, 3, 1) >> sort!() +@chevrons Int[] >> push!(5, 2, 4, 3, 1) >> sort!() ``` is equivalent to ```julia @@ -71,22 +71,22 @@ sort!(push!(Int[], 5, 2, 4, 3, 1)) In fact we can see exactly what it is transformed to with `@macroexpand`. This is equivalent code but with intermediate results saved for clarity. ```julia-repl -julia> @macroexpand @chevy Int[] >> push!(5, 2, 4, 3, 1) >> sort!() +julia> @macroexpand @chevrons Int[] >> push!(5, 2, 4, 3, 1) >> sort!() quote - var"##chevy#241" = Int[] - var"##chevy#242" = push!(var"##chevy#241", 5, 2, 4, 3, 1) - sort!(var"##chevy#242") + var"##chevrons#241" = Int[] + var"##chevrons#242" = push!(var"##chevrons#241", 5, 2, 4, 3, 1) + sort!(var"##chevrons#242") end ``` ### REPL integration -If you are using the Julia REPL, you can activate Chevy's REPL integration like +If you are using the Julia REPL, you can activate Chevrons's REPL integration like ```julia-repl -julia> Chevy.enable_repl() +julia> Chevrons.enable_repl() ``` -This allows you to use this syntax from the Julia REPL without typing `@chevy` every -time. Use `Chevy.enable_repl(false)` to disable it again. The rest of the examples here +This allows you to use this syntax from the Julia REPL without typing `@chevrons` every +time. Use `Chevrons.enable_repl(false)` to disable it again. The rest of the examples here will be from the REPL. Also see [this tip](#startup-file) for automatically enabling the REPL integration. @@ -174,15 +174,15 @@ julia> ( ### Recursive usage -The `@chevy` macro works recursively, meaning you can wrap an entire module (or script +The `@chevrons` macro works recursively, meaning you can wrap an entire module (or script or function or any code block) and all `>>`/`>>>`/`<<` expressions will be converted. For example here is the first example in this README converted to a script: ```julia -using Chevy, DataFrames, TidierData +using Chevrons, DataFrames, TidierData -@chevy begin +@chevrons begin df = DataFrame(name=["John", "Sally", "Roger"], age=[54, 34, 79], children=[0, 2, 4]) df2 = df >> @filter(age > 40) >> @select(num_children=children, age) df2 >> println("data:", _) @@ -193,7 +193,7 @@ end Or the data manipulation step can be encapsulated as a function like so: ```julia -@chevy munge(df) = df >> @filter(age > 40) >> @select(num_children=children, age) +@chevrons munge(df) = df >> @filter(age > 40) >> @select(num_children=children, age) ``` ### Pro tips @@ -205,17 +205,17 @@ on a separate line for clarity. This also allows you to easily comment out indiv transformations. ```julia -@chevy ( +@chevrons ( df # >> @filter(age > 40) - >> @select(nchildren=children, age) + >> @select(nchildren=children, age), ) ``` Or you can use `>>(x, y, z)` syntax instead of `x >> y >> z` like so: ```julia -@chevy >>( +@chevrons >>( df, # @filter(age > 40), @select(nchildren=children, age), @@ -225,27 +225,27 @@ Or you can use `>>(x, y, z)` syntax instead of `x >> y >> z` like so: #### Startup file You can add the following lines to your `startup.jl` file (usually at -`~/.julia/config/startup.jl`) to enable Chevy's REPL integration automatically: +`~/.julia/config/startup.jl`) to enable Chevrons's REPL integration automatically: ```julia if isinteractive() try - using Chevy + using Chevrons catch - @warn "Chevy not available" + @warn "Chevrons not available" end - if @isdefined Chevy - Chevy.enable_repl() + if @isdefined Chevrons + Chevrons.enable_repl() end end ``` -Chevy has no dependencies so is safe to add to your global environment - then it will +Chevrons has no dependencies so is safe to add to your global environment - then it will always be available at the REPL. ## API See the docstrings for more help: -- `@chevy ...`: Transform and execute the given code. -- `chevy(expr)`: Transform the given expression. -- `Chevy.enable_repl(on=true)`: Enable/disable the REPL integration. +- `@chevrons ...`: Transform and execute the given code. +- `chevrons(expr)`: Transform the given expression. +- `Chevrons.enable_repl(on=true)`: Enable/disable the REPL integration. diff --git a/src/Chevy.jl b/src/Chevrons.jl similarity index 85% rename from src/Chevy.jl rename to src/Chevrons.jl index d791061..420cc2d 100644 --- a/src/Chevy.jl +++ b/src/Chevrons.jl @@ -1,6 +1,6 @@ -module Chevy +module Chevrons -export chevy, @chevy +export chevrons, @chevrons if VERSION ≥ v"1.11" eval(Expr(:public, :enable_repl)) @@ -8,13 +8,13 @@ end function enable_repl end -function chevy end +function chevrons end -macro chevy end +macro chevrons end module Internals -import ..Chevy: enable_repl, chevy, @chevy +import ..Chevrons: enable_repl, chevrons, @chevrons const tmp_index = Ref(0) @@ -31,16 +31,16 @@ function tmpsym() tmp_index[] = i + 1 Symbol(:tmp, i) else - gensym(:chevy) + gensym(:chevrons) end end """ - chevy(ex) + chevrons(ex) -Transforms an expression exactly the way [`@chevy`](@ref) does. +Transforms an expression exactly the way [`@chevrons`](@ref) does. """ -function chevy(ex) +function chevrons(ex) if ( ex isa Expr && ex.head == :call && @@ -51,10 +51,10 @@ function chevy(ex) nargs = length(ex.args) if nargs == 1 # nullary `>>()` not allowed - error("Chevy cannot handle zero-argument `$ex`") + error("Chevrons cannot handle zero-argument `$ex`") elseif nargs == 2 - # unary `>>(x)` is just `@chevy(x)` - return chevy(ex.args[2]) + # unary `>>(x)` is just `@chevrons(x)` + return chevrons(ex.args[2]) elseif nargs == 3 # binary (lhs >> rhs) or (lhs << rhs) or (lhs >>> rhs) expression op, lhs, rhs = ex.args @@ -67,11 +67,11 @@ function chevy(ex) end # recurse on lhs and rhs if op == :<< - lhs2 = chevy(rhs) - rhs2 = chevy(lhs) + lhs2 = chevrons(rhs) + rhs2 = chevrons(lhs) else - lhs2 = chevy(lhs) - rhs2 = chevy(rhs) + lhs2 = chevrons(lhs) + rhs2 = chevrons(rhs) end # construct an answer block ans = Expr(:block) @@ -101,7 +101,7 @@ function chevy(ex) return ans elseif ex isa Expr # otherwise recurse into expressions - return Expr(ex.head, map(chevy, ex.args)...) + return Expr(ex.head, map(chevrons, ex.args)...) else # otherwise no-op return ex @@ -109,7 +109,7 @@ function chevy(ex) end """ - @chevy ex + @chevrons ex Recursively replace `>>` chained function calls. @@ -127,8 +127,8 @@ Also `>>>` can be used to keep the previous value. - `x >>> f() >> g()` becomes `tmp = x; f(tmp); g(tmp)` """ -macro chevy(ex) - return esc(chevy(ex)) +macro chevrons(ex) + return esc(chevrons(ex)) end """ @@ -136,7 +136,7 @@ end Enable or disable REPL integration. -When enabled, all commands in the REPL are transformed by [`chevy`](@ref). +When enabled, all commands in the REPL are transformed by [`chevrons`](@ref). You can call this in your `startup.jl` file. """ @@ -151,16 +151,16 @@ function enable_repl(on::Bool = true) # if not, modify the list of default transforms transforms = Base.REPL_MODULE_REF[].repl_ast_transforms else - error("Cannot enable Chevy in the REPL.") + error("Cannot enable Chevrons in the REPL.") end - filter!(is_not_chevy, transforms) + filter!(is_not_chevrons, transforms) if on - pushfirst!(transforms, chevy) + pushfirst!(transforms, chevrons) end return end -is_not_chevy(x) = x !== chevy +is_not_chevrons(x) = x !== chevrons function sub_placeholder(x, f) # directly substitute _/__/___/etc @@ -233,7 +233,7 @@ function sub_specialcase(x, f) end # give up error( - "Chevy cannot substitute into `$(truncate(f))`; expecting `_` or a function/macro call, indexing or property access.", + "Chevrons cannot substitute into `$(truncate(f))`; expecting `_` or a function/macro call, indexing or property access.", ) end @@ -247,4 +247,4 @@ end end -end # module Chevy +end # module Chevrons diff --git a/test/aqua.jl b/test/aqua.jl index 6c07c90..2df8f39 100644 --- a/test/aqua.jl +++ b/test/aqua.jl @@ -1,4 +1,4 @@ @testitem "Aqua" begin using Aqua - Aqua.test_all(Chevy) + Aqua.test_all(Chevrons) end diff --git a/test/integration.jl b/test/integration.jl index 723c4b1..5167352 100644 --- a/test/integration.jl +++ b/test/integration.jl @@ -11,7 +11,7 @@ end @testitem "DataFrames" setup = [Data] begin using DataFrames - @test @chevy( + @test @chevrons( Data.df1 >> subset(:age => age -> age .> 40) >> select(:children => :number_of_children, :age) ) == Data.df1b @@ -19,28 +19,28 @@ end @testitem "DataFramesMeta" setup = [Data] begin using DataFramesMeta - @test @chevy( + @test @chevrons( Data.df1 >> @subset(:age .> 40) >> @select(:number_of_children = :children, :age) ) == Data.df1b end @testitem "DataFrameMacros" setup = [Data] begin using DataFrameMacros - @test @chevy( + @test @chevrons( Data.df1 >> @subset(:age > 40) >> @select(:number_of_children = :children, :age) ) == Data.df1b end @testitem "TidierData" setup = [Data] begin using TidierData - @test @chevy( + @test @chevrons( Data.df1 >> @filter(age > 40) >> @select(number_of_children = children, age) ) == Data.df1b end @testitem "Query" setup = [Data] begin using DataFrames, Query - @test @chevy( + @test @chevrons( Data.df1 >> @filter(__.age > 40)() >> @map({number_of_children = __.children, __.age})() >> DataFrame() ) == Data.df1b diff --git a/test/unit.jl b/test/unit.jl index 7ca0b45..84328dd 100644 --- a/test/unit.jl +++ b/test/unit.jl @@ -18,7 +18,7 @@ end end -@testitem "chevy" setup = [Helpers] begin +@testitem "chevrons" setup = [Helpers] begin using .Helpers: @ex @testset "$(case.input)" for case in [ # noop @@ -116,42 +116,42 @@ end output = @ex(tmp1 = x, tmp2 = f(tmp1, y), g(z, tmp2)) ), ] - @assert Chevy.Internals.tmp_index[] == 0 - Chevy.Internals.tmp_index[] = 1 + @assert Chevrons.Internals.tmp_index[] == 0 + Chevrons.Internals.tmp_index[] = 1 try - @test chevy(case.input) == case.output + @test chevrons(case.input) == case.output finally - Chevy.Internals.tmp_index[] = 0 + Chevrons.Internals.tmp_index[] = 0 end - @assert Chevy.Internals.tmp_index[] == 0 + @assert Chevrons.Internals.tmp_index[] == 0 end # syntax errors @testset "$input" for input in [@ex(x >> y), @ex(x >> [1, 2, 3])] @test_throws( - r"Chevy cannot substitute into `.*`; expecting `_` or a function/macro call, indexing or property access.", - chevy(input) + r"Chevrons cannot substitute into `.*`; expecting `_` or a function/macro call, indexing or property access.", + chevrons(input) ) end # nullary calls @testset "$input" for input in [@ex(>>()), @ex(<<()), @ex(>>>())] - @test_throws(r"Chevy cannot handle zero-argument `.*`", chevy(input)) + @test_throws(r"Chevrons cannot handle zero-argument `.*`", chevrons(input)) end end -@testitem "@chevy" begin - # most testing happens in the "chevy" test +@testitem "@chevrons" begin + # most testing happens in the "chevrons" test @testset "basics" begin - @test @chevy(1 + 2) == 3 - @test @chevy(Int[] >> push!(4, 2, 3, 5, 1) >> filter!(isodd, _) >> sort!()) == + @test @chevrons(1 + 2) == 3 + @test @chevrons(Int[] >> push!(4, 2, 3, 5, 1) >> filter!(isodd, _) >> sort!()) == [1, 3, 5] - @test @chevy(10 >> (_ - __) << 1) == 9 + @test @chevrons(10 >> (_ - __) << 1) == 9 end @testset "side-effects" begin x = 0 # can't put this inside @test because it introduces a new scope - y = @chevy(10 >>> (x = _) >> (x^2 - _)) + y = @chevrons(10 >>> (x = _) >> (x^2 - _)) @test y == 90 @test x == 10 end @@ -192,30 +192,34 @@ end Base.REPL_MODULE_REF[] = fake_repl try if case == :none - @test_throws r"Cannot enable Chevy in the REPL." Chevy.enable_repl() - @test_throws r"Cannot enable Chevy in the REPL." Chevy.enable_repl(true) - @test_throws r"Cannot enable Chevy in the REPL." Chevy.enable_repl(false) + @test_throws r"Cannot enable Chevrons in the REPL." Chevrons.enable_repl() + @test_throws r"Cannot enable Chevrons in the REPL." Chevrons.enable_repl( + true, + ) + @test_throws r"Cannot enable Chevrons in the REPL." Chevrons.enable_repl( + false, + ) else @test ts == Any[1, 2, 3] - Chevy.enable_repl() - @test ts == Any[chevy, 1, 2, 3] - Chevy.enable_repl(false) + Chevrons.enable_repl() + @test ts == Any[chevrons, 1, 2, 3] + Chevrons.enable_repl(false) @test ts == Any[1, 2, 3] - Chevy.enable_repl(true) - @test ts == Any[chevy, 1, 2, 3] - Chevy.enable_repl() - @test ts == Any[chevy, 1, 2, 3] - Chevy.enable_repl(false) + Chevrons.enable_repl(true) + @test ts == Any[chevrons, 1, 2, 3] + Chevrons.enable_repl() + @test ts == Any[chevrons, 1, 2, 3] + Chevrons.enable_repl(false) @test ts == Any[1, 2, 3] - push!(ts, chevy) - @test ts == Any[1, 2, 3, chevy] - Chevy.enable_repl(false) + push!(ts, chevrons) + @test ts == Any[1, 2, 3, chevrons] + Chevrons.enable_repl(false) @test ts == Any[1, 2, 3] @test ts == Any[1, 2, 3] - push!(ts, chevy) - @test ts == Any[1, 2, 3, chevy] - Chevy.enable_repl() - @test ts == Any[chevy, 1, 2, 3] + push!(ts, chevrons) + @test ts == Any[1, 2, 3, chevrons] + Chevrons.enable_repl() + @test ts == Any[chevrons, 1, 2, 3] end finally @eval Base active_repl_backend = $orig_backend