* rename to pipe

* add security scan

* use var in Makefile
This commit is contained in:
Ruidy 2022-03-31 11:37:02 -04:00 committed by GitHub
parent 1166c701ac
commit f6af583408
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 82 additions and 116 deletions

View file

@ -5,3 +5,4 @@
.idea/ .idea/
.golangci.yml .golangci.yml
coverage.out coverage.out
.trivycache/

View file

@ -1,25 +1,11 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL" name: "CodeQL"
on: on:
push: push:
branches: [ main ] branches: [ main ]
pull_request: pull_request:
# The branches below must be a subset of the branches above
branches: [ main ] branches: [ main ]
schedule: schedule:
- cron: '24 15 * * 6' - cron: '24 15 * * 6'
jobs: jobs:
analyze: analyze:
name: Analyze name: Analyze
@ -28,43 +14,18 @@ jobs:
actions: read actions: read
contents: read contents: read
security-events: write security-events: write
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
language: [ 'go' ] language: [ 'go' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v2 uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v1 uses: github/codeql-action/init@v1
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v1 uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1 uses: github/codeql-action/analyze@v1

1
.gitignore vendored
View file

@ -58,3 +58,4 @@ Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
docs/public docs/public
.trivycache/

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "docs/themes/compose"]
path = docs/themes/compose
url = https://github.com/onweru/compose/

View file

@ -2,8 +2,9 @@ FROM golang:1.18-alpine
ENV CGO_ENABLED 0 ENV CGO_ENABLED 0
ENV GOOS linux ENV GOOS linux
ENV GOARCH amd64
RUN apk update --no-cache RUN apk upgrade --no-cache
WORKDIR /lib WORKDIR /lib

View file

@ -1,10 +1,17 @@
TEST = "go test ./... -coverpkg=./... -coverprofile coverage.out -covermode=count; go tool cover -func coverage.out; rm coverage.out" TEST = "go test ./... -coverpkg=./... -coverprofile coverage.out -covermode=count; go tool cover -func coverage.out; rm coverage.out"
IMAGE=underscore
build: build:
docker build -t underscore:latest . docker build -t $(IMAGE):latest .
test: build test: build
docker run --name underscore --rm -i -t underscore sh -c $(TEST) docker run --name $(IMAGE) --rm -i -t $(IMAGE) sh -c $(TEST)
scan:
trivy --cache-dir .trivycache/ image --exit-code 0 --no-progress --severity CRITICAL $(IMAGE)
scan-config:
trivy config .
docs: docs:
cd docs && hugo server -D cd docs && hugo server -D

View file

@ -1,11 +1,11 @@
# Underscore # _Underscore
![License](https://img.shields.io/github/license/rjNemo/underscore?style=for-the-badge) ![License](https://img.shields.io/github/license/rjNemo/underscore?style=for-the-badge)
[![Go version](https://img.shields.io/github/go-mod/go-version/rjNemo/underscore?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/rjNemo/underscore) [![Go version](https://img.shields.io/github/go-mod/go-version/rjNemo/underscore?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/rjNemo/underscore)
![Go report](https://goreportcard.com/badge/github.com/rjNemo/underscore?style=for-the-badge) ![Go report](https://goreportcard.com/badge/github.com/rjNemo/underscore?style=for-the-badge)
![test coverage](https://img.shields.io/codecov/c/github/rjNemo/underscore?style=for-the-badge&logo=codecov) ![test coverage](https://img.shields.io/codecov/c/github/rjNemo/underscore?style=for-the-badge&logo=codecov)
![underscore](https://socialify.git.ci/rjNemo/underscore/image?description=1&descriptionEditable=Useful%20functional%20programming%20helpers%20for%20Go%201.18%20and%20beyond&font=Raleway&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FrjNemo%2Funderscore%2Fmain%2Fdocs%2Fstatic%2Flogo.png&owner=1&pattern=Floating%20Cogs&stargazers=1&theme=Light) ![underscore](https://socialify.git.ci/rjNemo/underscore/image?description=1&font=KoHo&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FrjNemo%2Funderscore%2Fmain%2Fdocs%2Fstatic%2Flogo.png&owner=1&pattern=Floating%20Cogs&stargazers=1&theme=Dark)
`underscore` is a `Go` library providing useful functional programming helpers without extending any built-in objects. `underscore` is a `Go` library providing useful functional programming helpers without extending any built-in objects.
@ -82,7 +82,7 @@ make test
## Functions ## Functions
`underscore` provides 100s of functions that support your favorite functional helpers `underscore` provides many of functions that support your favorite functional helpers
### Collections ### Collections
@ -98,9 +98,9 @@ make test
- `Partition` - `Partition`
- `Reduce` - `Reduce`
### Chaining ### Pipe
Calling `chain.Of` will cause all future method calls to return wrapped values. When you've finished the computation, Calling `NewPipe` will cause all future method calls to return wrapped values. When you've finished the computation,
call `Value` to retrieve the final value. call `Value` to retrieve the final value.
Methods not returning a slice such as `Reduce`, `All`, `Any`, will break the `Chain` and return `Value` instantly. Methods not returning a slice such as `Reduce`, `All`, `Any`, will break the `Chain` and return `Value` instantly.

View file

@ -1,5 +1,5 @@
--- ---
title: underscore title: _Underscore
--- ---
![License](https://img.shields.io/github/license/rjNemo/underscore?style=for-the-badge) ![License](https://img.shields.io/github/license/rjNemo/underscore?style=for-the-badge)
@ -7,7 +7,7 @@ title: underscore
![Go report](https://goreportcard.com/badge/github.com/rjNemo/underscore?style=for-the-badge) ![Go report](https://goreportcard.com/badge/github.com/rjNemo/underscore?style=for-the-badge)
![test coverage](https://img.shields.io/codecov/c/github/rjNemo/underscore?style=for-the-badge&logo=codecov) ![test coverage](https://img.shields.io/codecov/c/github/rjNemo/underscore?style=for-the-badge&logo=codecov)
![underscore](https://socialify.git.ci/rjNemo/underscore/image?description=1&font=Raleway&language=1&logo=https%3A%2F%2Fgithub.com%2FrjNemo%2Funderscore%2Fblob%2Fmain%2Fdocs%2Fstatic%2Flogo.png%3Fraw%3Dtrue&name=1&pattern=Floating%20Cogs&theme=Light) ![underscore](https://socialify.git.ci/rjNemo/underscore/image?description=1&font=KoHo&language=1&logo=https%3A%2F%2Fraw.githubusercontent.com%2FrjNemo%2Funderscore%2Fmain%2Fdocs%2Fstatic%2Flogo.png&owner=1&pattern=Floating%20Cogs&stargazers=1&theme=Dark)
`underscore` is a `Go` library providing useful functional programming helpers without extending any built-in objects. `underscore` is a `Go` library providing useful functional programming helpers without extending any built-in objects.

View file

@ -1,10 +1,10 @@
--- ---
title: "Of" title: "NewPipe"
date: 2021-12-31T13:11:41-04:00 date: 2021-12-31T13:11:41-04:00
--- ---
Calling `Of` will cause all future method calls to return wrapped objects. When you've finished the computation, Calling `NewPipe` will cause all future method calls to return wrapped objects. When you've finished the computation,
call `Value` to retrieve the final value. call `Value` to retrieve the final value.
Methods not returning a collection such as `Reduce`, `All`, `Any`, will break the chain and return `Value` instantly. Methods not returning a collection such as `Reduce`, `All`, `Any`, will break the chain and return `Value` instantly.
@ -14,11 +14,11 @@ package main
import ( import (
"fmt" "fmt"
"github.com/rjNemo/underscore/chain" u "github.com/rjNemo/underscore"
) )
func main() { func main() {
sum := chain.Of([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}). sum := u.NewPipe([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}).
// filter even numbers from the slice // filter even numbers from the slice
Filter(func(n int) bool { return n%2 == 0 }). Filter(func(n int) bool { return n%2 == 0 }).
// square every number in the slice // square every number in the slice

View file

@ -1,7 +1,7 @@
package underscore package underscore
// Each iterates over a slice of elements, yielding each in turn to an action function. // Each iterates over a slice of elements, yielding each in turn to an action function.
// Returns the slice for chaining. // Returns the slice for piping.
func Each[T any](values []T, action func(T)) []T { func Each[T any](values []T, action func(T)) []T {
for _, v := range values { for _, v := range values {
action(v) action(v)

View file

@ -1,11 +1,11 @@
package examples package examples
import ( import (
"github.com/rjNemo/underscore/chain" u "github.com/rjNemo/underscore"
) )
func chaining() int { func piping() int {
return chain.Of([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}). return u.NewPipe([]int{1, 2, 3, 4, 5, 6, 7, 8, 9}).
// filter even numbers from the slice // filter even numbers from the slice
Filter(func(n int) bool { return n%2 == 0 }). Filter(func(n int) bool { return n%2 == 0 }).
// square every number in the slice // square every number in the slice

View file

@ -6,6 +6,6 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestChainingExample(t *testing.T) { func TestPipingExample(t *testing.T) {
assert.Equal(t, 120, chaining()) assert.Equal(t, 120, piping())
} }

View file

@ -1,94 +1,92 @@
package chain package underscore
import ( import (
"golang.org/x/exp/constraints" "golang.org/x/exp/constraints"
u "github.com/rjNemo/underscore"
) )
type Chain[T constraints.Ordered] struct { type Pipe[T constraints.Ordered] struct {
Value []T Value []T
} }
// Of starts a Chain. All future method calls will return Chain structs. When you've finished the computation, // NewPipe starts a Pipe. All future method calls will return Pipe structs. When you've finished the computation,
// call Value to retrieve the final value. // call Value to retrieve the final value.
// //
// Methods not returning a slice such as Reduce, All, Any, will break the chain and return Value instantly. // Methods not returning a slice such as Reduce, All, Any, will break the Pipe and return Value instantly.
func Of[T constraints.Ordered](value []T) Chain[T] { func NewPipe[T constraints.Ordered](value []T) Pipe[T] {
return Chain[T]{Value: value} return Pipe[T]{Value: value}
} }
// All returns true if all the values in the slice pass the predicate truth test. // All returns true if all the values in the slice pass the predicate truth test.
// Short-circuits and stops traversing the slice if a false element is found. // Short-circuits and stops traversing the slice if a false element is found.
// Breaks the Chain. // Breaks the Pipe.
func (c Chain[T]) All(predicate func(T) bool) bool { func (c Pipe[T]) All(predicate func(T) bool) bool {
return u.All(c.Value, predicate) return All(c.Value, predicate)
} }
// Any returns true if any of the values in the slice pass the predicate truth test. // Any returns true if any of the values in the slice pass the predicate truth test.
// Short-circuits and stops traversing the slice if a true element is found. // Short-circuits and stops traversing the slice if a true element is found.
// Breaks the Chain. // Breaks the Pipe.
func (c Chain[T]) Any(predicate func(T) bool) bool { func (c Pipe[T]) Any(predicate func(T) bool) bool {
return u.Any(c.Value, predicate) return Any(c.Value, predicate)
} }
// Contains returns true if the value is present in the slice and breaks the Chain. // Contains returns true if the value is present in the slice and breaks the Pipe.
func (c Chain[T]) Contains(value T) bool { func (c Pipe[T]) Contains(value T) bool {
return u.Contains(c.Value, value) return Contains(c.Value, value)
} }
// Each iterates over a slice of elements, yielding each in turn to an action function. // Each iterates over a slice of elements, yielding each in turn to an action function.
// Breaks the Chain. // Breaks the Pipe.
func (c Chain[T]) Each(action func(T)) { func (c Pipe[T]) Each(action func(T)) {
u.Each(c.Value, action) Each(c.Value, action)
} }
// Filter looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate). // Filter looks through each value in the slice, returning a slice of all the values that pass a truth test (predicate).
func (c Chain[T]) Filter(predicate func(n T) bool) Chain[T] { func (c Pipe[T]) Filter(predicate func(n T) bool) Pipe[T] {
return Chain[T]{Value: u.Filter(c.Value, predicate)} return Pipe[T]{Value: Filter(c.Value, predicate)}
} }
// Find looks through each value in the slice, returning the first one that passes a truth test (predicate), // Find looks through each value in the slice, returning the first one that passes a truth test (predicate),
// or the default value for the type and an error if no value passes the test. // or the default value for the type and an error if no value passes the test.
// The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice. // The function returns as soon as it finds an acceptable element, and doesn't traverse the entire slice.
// Breaks the Chain. // Breaks the Pipe.
func (c Chain[T]) Find(predicate func(n T) bool) (T, error) { func (c Pipe[T]) Find(predicate func(n T) bool) (T, error) {
return u.Find(c.Value, predicate) return Find(c.Value, predicate)
} }
// Map produces a new slice of values by mapping each value in the slice through // Map produces a new slice of values by mapping each value in the slice through
// a transform function. // a transform function.
// //
// TODO: Move from T to P. // TODO: Move from T to P.
func (c Chain[T]) Map(transform func(n T) T) Chain[T] { func (c Pipe[T]) Map(transform func(n T) T) Pipe[T] {
return Chain[T]{Value: u.Map(c.Value, transform)} return Pipe[T]{Value: Map(c.Value, transform)}
} }
// Max returns the maximum value in the slice. // Max returns the maximum value in the slice.
// This function can currently only compare numbers reliably. // This function can currently only compare numbers reliably.
// This function uses operator <. // This function uses operator <.
// Breaks the Chain. // Breaks the Pipe.
func (c Chain[T]) Max() T { func (c Pipe[T]) Max() T {
return u.Max(c.Value) return Max(c.Value)
} }
// Min returns the minimum value in the slice. // Min returns the minimum value in the slice.
// This function can currently only compare numbers reliably. // This function can currently only compare numbers reliably.
// This function uses operator <. // This function uses operator <.
// Breaks the Chain. // Breaks the Pipe.
func (c Chain[T]) Min() T { func (c Pipe[T]) Min() T {
return u.Min(c.Value) return Min(c.Value)
} }
// Partition splits the slice into two slices: one whose elements all satisfy predicate // Partition splits the slice into two slices: one whose elements all satisfy predicate
// and one whose elements all do not satisfy predicate. // and one whose elements all do not satisfy predicate.
// Breaks the Chain. // Breaks the Pipe.
func (c Chain[T]) Partition(predicate func(T) bool) ([]T, []T) { func (c Pipe[T]) Partition(predicate func(T) bool) ([]T, []T) {
return u.Partition(c.Value, predicate) return Partition(c.Value, predicate)
} }
// Reduce combine a list of values into a single value and breaks the Chain. // Reduce combine a list of values into a single value and breaks the Pipe.
// acc is the initial state, and each successive step of it should be returned by the reduction function. // acc is the initial state, and each successive step of it should be returned by the reduction function.
func (c Chain[T]) Reduce(reducer func(n, acc T) T, acc T) T { func (c Pipe[T]) Reduce(reducer func(n, acc T) T, acc T) T {
return u.Reduce(c.Value, reducer, acc) return Reduce(c.Value, reducer, acc)
} }

View file

@ -1,18 +1,18 @@
package chain_test package underscore_test
import ( import (
"testing" "testing"
"github.com/stretchr/testify/assert" u "github.com/rjNemo/underscore"
"github.com/rjNemo/underscore/chain" "github.com/stretchr/testify/assert"
) )
func TestChainFilter(t *testing.T) { func TestChainFilter(t *testing.T) {
want := []int{2, 4, 6, 8} want := []int{2, 4, 6, 8}
assert.Equal(t, assert.Equal(t,
want, want,
chain.Of(nums).Filter(isEven).Value, u.NewPipe(nums).Filter(isEven).Value,
) )
} }
@ -20,7 +20,7 @@ func TestChainFilterMap(t *testing.T) {
want := []int{4, 16, 36, 64} want := []int{4, 16, 36, 64}
assert.Equal(t, assert.Equal(t,
want, want,
chain.Of(nums). u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Value) Value)
@ -30,14 +30,14 @@ func TestChainFilterMapReduce(t *testing.T) {
want := 120 want := 120
assert.Equal(t, assert.Equal(t,
want, want,
chain.Of(nums). u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Reduce(sum, 0)) Reduce(sum, 0))
} }
func TestChainFilterMapContains(t *testing.T) { func TestChainFilterMapContains(t *testing.T) {
assert.True(t, chain.Of(nums). assert.True(t, u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Contains(16)) Contains(16))
@ -46,7 +46,7 @@ func TestChainFilterMapContains(t *testing.T) {
func TestChainFilterMapEach(t *testing.T) { func TestChainFilterMapEach(t *testing.T) {
want := []int{5, 17, 37, 65} want := []int{5, 17, 37, 65}
res := make([]int, 0) res := make([]int, 0)
chain.Of(nums). u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Each(func(n int) { res = append(res, n+1) }) Each(func(n int) { res = append(res, n+1) })
@ -54,14 +54,14 @@ func TestChainFilterMapEach(t *testing.T) {
} }
func TestChainFilterMapAll(t *testing.T) { func TestChainFilterMapAll(t *testing.T) {
assert.True(t, chain.Of(nums). assert.True(t, u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
All(func(n int) bool { return n%4 == 0 })) All(func(n int) bool { return n%4 == 0 }))
} }
func TestChainFilterMapFind(t *testing.T) { func TestChainFilterMapFind(t *testing.T) {
n, err := chain.Of(nums). n, err := u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Find(func(n int) bool { return n%4 == 0 }) Find(func(n int) bool { return n%4 == 0 })
@ -71,7 +71,7 @@ func TestChainFilterMapFind(t *testing.T) {
func TestChainFilterMapMax(t *testing.T) { func TestChainFilterMapMax(t *testing.T) {
want := 64 want := 64
assert.Equal(t, want, chain.Of(nums). assert.Equal(t, want, u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Max()) Max())
@ -79,7 +79,7 @@ func TestChainFilterMapMax(t *testing.T) {
func TestChainFilterMapMin(t *testing.T) { func TestChainFilterMapMin(t *testing.T) {
w := 4 w := 4
assert.Equal(t, w, chain.Of(nums). assert.Equal(t, w, u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Min()) Min())
@ -88,7 +88,7 @@ func TestChainFilterMapMin(t *testing.T) {
func TestChainFilterMapPartition(t *testing.T) { func TestChainFilterMapPartition(t *testing.T) {
wantLeft := []int{4, 16} wantLeft := []int{4, 16}
wantRight := []int{36, 64} wantRight := []int{36, 64}
left, right := chain.Of(nums). left, right := u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Partition(func(n int) bool { return n < 20 }) Partition(func(n int) bool { return n < 20 })
@ -98,7 +98,7 @@ func TestChainFilterMapPartition(t *testing.T) {
} }
func TestChainFilterMapAny(t *testing.T) { func TestChainFilterMapAny(t *testing.T) {
assert.True(t, chain.Of(nums). assert.True(t, u.NewPipe(nums).
Filter(isEven). Filter(isEven).
Map(toSquare). Map(toSquare).
Any(func(n int) bool { return n%64 == 0 })) Any(func(n int) bool { return n%64 == 0 }))