Refactor stdlib-candidate for nupm (#790)

Easier to review individual commits because of renames. Happy to provide
DiffNow links if helpful. Involved:

1. Moving scripts to a subdirectory
2. Copying `nupm.nuon` from another directory
3. Making modules work
4. Extracting tests
5. Fixing tests (related to nushell/nushell#12193)

To test first set up nupm then:

```console
nu_scripts on  std-nupm-integration
❯ $env.NUPM_REGISTRIES.nupm_test = 'https://raw.githubusercontent.com/texastoland/nupm/registry-std-rfc/registry.nuon'

nu_scripts on  std-nupm-integration
❯ nupm install std-rfc
╭──────────┬───────────────────────────────────────────╮
│ name     │ std-rfc                                   │
│ version  │ 0.1.0                                     │
│ url      │ https://github.com/texastoland/nu_scripts │
│ revision │ 65aa7cc                                   │
│ path     │ stdlib-candidate                          │
│ type     │ git                                       │
╰──────────┴───────────────────────────────────────────╯
Cloning into 'nu_scripts-4a047f13a05fe35393f3a8d73377b02c-65aa7cc'...
remote: Enumerating objects: 8015, done.
remote: Counting objects: 100% (822/822), done.
remote: Compressing objects: 100% (333/333), done.
remote: Total 8015 (delta 538), reused 641 (delta 445), pack-reused 7193
Receiving objects: 100% (8015/8015), 49.72 MiB | 23.12 MiB/s, done.
Resolving deltas: 100% (4605/4605), done.
Note: switching to '65aa7cc'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 65aa7cc Fix nupm test --dir stdlib-candidate
2024-03-12T20:42:49.462|INF|installing package std-rfc

nu_scripts on  std-nupm-integration took 4s
❯ use std-rfc set-env

nu_scripts on  std-nupm-integration
❯ set-env -h
Gracefully set an environment variable or merge a nested option.
...etc.

nu_scripts on  std-nupm-integration
❯ nupm test --dir stdlib-candidate
Testing package /Users/texas/Developer/nu_scripts/stdlib-candidate
tests record filter-name predicate ... SUCCESS
tests record filter-value predicate ... SUCCESS
tests record list_merge ... SUCCESS
tests str append ... SUCCESS
tests fs file bulk-rename ... SUCCESS
tests str prepend ... SUCCESS
tests record filter-name text ... SUCCESS
Ran 7 tests. 7 succeeded, 0 failed.
```
This commit is contained in:
Texas Toland 2024-03-16 06:57:05 -05:00 committed by GitHub
parent 13a73ab635
commit cf88c11509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 197 additions and 186 deletions

View File

@ -1,84 +0,0 @@
# rename a bulk of files in a directory using a closure
#
# the reason behind this command is quite simple
# - sometimes one receives a bunch of files with integer ids: 1, 2, 3, ...
# - these ids come rarely with padding... i.e. 1 instead of 001 when there are 3-digit ids
# - this means that file with id 9 will be sorted way after file with id 1000
#
# this command allows to do such a task!
#
# # Examples
# rename files in `/foo` with a name that has an id to have 3 digits with 0-padding
# > file bulk-rename /foo {
# parse "some_format_{id}"
# | get 0
# | update id { fill --alignment r --character 0 --width 3 }
# | $"some_format_($in.id)"
# }
export def "file bulk-rename" [
directory: path, # the path where files need to be renamed in bulk
stem_update: closure, # the code to run on the stem of the files: should start with parsing the format and end with reconstructing the same format
--verbose, # be verbose when moving the files around
]: nothing -> nothing {
ls --full-paths $directory | insert new {
get name | path parse | update stem $stem_update | path join
}
| each {
if $verbose {
mv --force --verbose $in.name $in.new
} else {
mv --force $in.name $in.new
}
}
null
}
#[test]
def test [] {
use std assert
let test_dir = $nu.temp-path | path join (random uuid)
mkdir $test_dir
seq 1 10 | each {|i| touch ($test_dir | path join $"some_($i)_format.txt") }
let expected = [
"some_10_format.txt",
"some_1_format.txt",
"some_2_format.txt",
"some_3_format.txt",
"some_4_format.txt",
"some_5_format.txt",
"some_6_format.txt",
"some_7_format.txt",
"some_8_format.txt",
"some_9_format.txt",
]
let actual = glob $"($test_dir)/*" | str replace $test_dir "" | str trim --left --char "/"
assert equal ($actual | sort) $expected
file bulk-rename $test_dir {
parse "some_{i}_format"
| get 0
| update i { fill --alignment r --character 0 --width 3 }
| $"some_($in.i)_format"
}
let expected = [
"some_001_format.txt",
"some_002_format.txt",
"some_003_format.txt",
"some_004_format.txt",
"some_005_format.txt",
"some_006_format.txt",
"some_007_format.txt",
"some_008_format.txt",
"some_009_format.txt",
"some_010_format.txt",
]
let actual = glob $"($test_dir)/*" | str replace $test_dir "" | str trim --left --char "/"
assert equal ($actual | sort) $expected
rm -rf $test_dir
}

View File

@ -0,0 +1,8 @@
{
name: "std-rfc"
description: "Official candidates for Nushell standard library"
documentation: "https://github.com/nushell/nu_scripts/blob/main/stdlib-candidate/std-rfc/README.md"
license: "https://github.com/nushell/nu_scripts/blob/main/LICENSE"
version: 0.1.0
type: "module"
}

View File

@ -1,69 +0,0 @@
# Merge a list of records
export def "list merge" []: list<record> -> record {
let list = $in
mut result = {}
for $obj in $list {
$result = ($result | merge $obj)
}
$result
}
# Filter fields name by predicate
export def "filter-name predicate" [
pred: closure # Predicate closure that checks fields name
]: record -> record {
let $obj_input = $in
$obj_input
| columns
| where { $in | do $pred }
| each {|input|
{ $input: ($obj_input | get $input) }
}
| list merge
}
# Filter fields name by text checking
export def "filter-name text" [
filter: string # Text to match with
--regex(-r) # Match by regex
]: record -> record {
let obj = $in
$obj | filter-name predicate { not ($in | (if $regex {find -r $filter} else {find $filter}) | is-empty) }
}
# Filter fields value by predicate
export def "filter-value predicate" [
pred: closure # Predicate closure that checks fields value
]: record -> record {
let $obj_input = $in
$obj_input
| columns
| where {|col| $obj_input | get $col | do $pred }
| each {|input|
{ $input: ($obj_input | get $input) }
}
| list merge
}
#[test]
def test_record_list_merge [] {
use std assert
assert equal ([{a:1} {b:2} {c:3} {d:4}] | list merge) {a:1 b:2 c:3 d:4}
}
#[test]
def test_record_filtername_predicate [] {
use std assert
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | filter-name predicate {$in | str contains a}) {aa:1 ab:2 ba:3 ca:5}
}
#[test]
def test_record_filtername_text [] {
use std assert
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | filter-name text a) {aa:1 ab:2 ba:3 ca:5}
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | filter-name text -r ^a) {aa:1 ab:2}
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | filter-name text -r ^A) {}
}
#[test]
def test_record_filtervalue_predicate [] {
use std assert
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | filter-value predicate { $in mod 2 == 0 }) {ab:2 bb:4 cb:6}
}

View File

@ -0,0 +1,35 @@
# rename a bulk of files in a directory using a closure
#
# the reason behind this command is quite simple
# - sometimes one receives a bunch of files with integer ids: 1, 2, 3, ...
# - these ids come rarely with padding... i.e. 1 instead of 001 when there are 3-digit ids
# - this means that file with id 9 will be sorted way after file with id 1000
#
# this command allows to do such a task!
#
# # Examples
# rename files in `/foo` with a name that has an id to have 3 digits with 0-padding
# > file bulk-rename /foo {
# parse "some_format_{id}"
# | get 0
# | update id { fill --alignment r --character 0 --width 3 }
# | $"some_format_($in.id)"
# }
export def "file bulk-rename" [
directory: path, # the path where files need to be renamed in bulk
stem_update: closure, # the code to run on the stem of the files: should start with parsing the format and end with reconstructing the same format
--verbose, # be verbose when moving the files around
]: nothing -> nothing {
ls --full-paths $directory | insert new {|row|
$row.name | path parse | update stem $stem_update | path join
}
| each {
if $verbose {
mv --force --verbose $in.name $in.new
} else {
mv --force $in.name $in.new
}
}
null
}

View File

@ -0,0 +1,6 @@
# modules
export module record/
export module str.nu
# commands
export use fs.nu *
export use set-env.nu *

View File

@ -0,0 +1,46 @@
# Merge a list of records
export def "list merge" []: list<record> -> record {
let list = $in
mut result = {}
for $obj in $list {
$result = ($result | merge $obj)
}
$result
}
# Filter fields name by predicate
export def "filter-name predicate" [
pred: closure # Predicate closure that checks fields name
]: record -> record {
let $obj_input = $in
$obj_input
| columns
| where { $in | do $pred }
| each {|input|
{ $input: ($obj_input | get $input) }
}
| list merge
}
# Filter fields name by text checking
export def "filter-name text" [
filter: string # Text to match with
--regex(-r) # Match by regex
]: record -> record {
let obj = $in
$obj | filter-name predicate { not ($in | (if $regex {find -r $filter} else {find $filter}) | is-empty) }
}
# Filter fields value by predicate
export def "filter-value predicate" [
pred: closure # Predicate closure that checks fields value
]: record -> record {
let $obj_input = $in
$obj_input
| columns
| where {|col| $obj_input | get $col | do $pred }
| each {|input|
{ $input: ($obj_input | get $input) }
}
| list merge
}

View File

@ -0,0 +1,17 @@
export def append [tail: string]: [string -> string, list<string> -> list<string>] {
let input = $in
match ($input | describe | str replace --regex '<.*' '') {
"string" => { $input ++ $tail },
"list" => { $input | each {|el| $el ++ $tail} },
_ => $input
}
}
export def prepend [head: string]: [string -> string, list<string> -> list<string>] {
let input = $in
match ($input | describe | str replace --regex '<.*' '') {
"string" => { $head ++ $input },
"list" => { $input | each {|el| $head ++ $el } },
_ => $input
}
}

View File

@ -1,33 +0,0 @@
def "str append" [tail: string]: [string -> string, list<string> -> list<string>] {
let input = $in
match ($input | describe | str replace --regex '<.*' '') {
"string" => { $input ++ $tail },
"list" => { $input | each {|el| $el ++ $tail} },
_ => $input
}
}
def "str prepend" [head: string]: [string -> string, list<string> -> list<string>] {
let input = $in
match ($input | describe | str replace --regex '<.*' '') {
"string" => { $head ++ $input },
"list" => { $input | each {|el| $head ++ $el } },
_ => $input
}
}
#[test]
def test_append [] {
use std assert
assert equal ("foo" | str append "/") "foo/"
assert equal (["foo", "bar", "baz"] | str append "/") ["foo/", "bar/", "baz/"]
}
#[test]
def test_prepend [] {
use std assert
assert equal ("foo" | str prepend "/") "/foo"
assert equal (["foo", "bar", "baz"] | str prepend "/") ["/foo", "/bar", "/baz"]
}

View File

@ -0,0 +1,50 @@
use std assert
use ../std-rfc "file bulk-rename"
alias rename = file bulk-rename
export def "test file bulk-rename" [] {
let test_dir = $nu.temp-path | path join (random uuid)
mkdir $test_dir
seq 1 10 | each {|i| touch ($test_dir | path join $"some_($i)_format.txt") }
let expected = [
"some_10_format.txt",
"some_1_format.txt",
"some_2_format.txt",
"some_3_format.txt",
"some_4_format.txt",
"some_5_format.txt",
"some_6_format.txt",
"some_7_format.txt",
"some_8_format.txt",
"some_9_format.txt",
]
let actual = glob $"($test_dir)/*" | str replace $test_dir "" | str trim --left --char "/"
assert equal ($actual | sort) $expected
rename $test_dir {
parse "some_{i}_format"
| get 0
| update i { fill --alignment r --character 0 --width 3 }
| $"some_($in.i)_format"
}
let expected = [
"some_001_format.txt",
"some_002_format.txt",
"some_003_format.txt",
"some_004_format.txt",
"some_005_format.txt",
"some_006_format.txt",
"some_007_format.txt",
"some_008_format.txt",
"some_009_format.txt",
"some_010_format.txt",
]
let actual = glob $"($test_dir)/*" | str replace $test_dir "" | str trim --left --char "/"
assert equal ($actual | sort) $expected
rm -rf $test_dir
}

View File

@ -0,0 +1,3 @@
export module fs.nu
export module record.nu
export module str.nu

View File

@ -0,0 +1,20 @@
use std assert
use ../std-rfc record
export def "test list_merge" [] {
assert equal ([{a:1} {b:2} {c:3} {d:4}] | record list merge) {a:1 b:2 c:3 d:4}
}
export def "test filter-name predicate" [] {
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | record filter-name predicate {$in | str contains a}) {aa:1 ab:2 ba:3 ca:5}
}
export def "test filter-name text" [] {
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | record filter-name text a) {aa:1 ab:2 ba:3 ca:5}
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | record filter-name text -r ^a) {aa:1 ab:2}
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | record filter-name text -r ^A) {}
}
export def "test filter-value predicate" [] {
assert equal ({aa:1 ab:2 ba:3 bb:4 ca:5 cb:6} | record filter-value predicate { $in mod 2 == 0 }) {ab:2 bb:4 cb:6}
}

View File

@ -0,0 +1,12 @@
use std assert
use ../std-rfc str
export def "test append" [] {
assert equal ("foo" | str append "/") "foo/"
assert equal (["foo", "bar", "baz"] | str append "/") ["foo/", "bar/", "baz/"]
}
export def "test prepend" [] {
assert equal ("foo" | str prepend "/") "/foo"
assert equal (["foo", "bar", "baz"] | str prepend "/") ["/foo", "/bar", "/baz"]
}