') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); GitHub - rjNemo/underscore: 🌟 Useful functional programming helpers for Go · GitHub
Skip to content

Latest commit

History

117 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

_Underscore

LicenseGo versionGo reporttest coverageOpenSSF Best Practices

underscore

underscore is a Go library providing useful functional programming helpers without extending any built-in objects.

It is mostly a port from the underscore.js library based on generics brought by Go 1.18.

Usage

📚 Follow this link for the documentation.

Install the library using

go get github.com/rjNemo/underscore@latest

Please check out the examples to see how to use the library.

package main
import (
"fmt"
u "github.com/rjNemo/underscore"
)
funcmain() {
numbers:= []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
// filter even numbers from the sliceevens:=u.Filter(numbers, func(nint) bool { returnn%2==0 })
// square every number in the slicesquares:=u.Map(evens, func(nint) int { returnn*n })
// reduce to the sumres:=u.Reduce(squares, func(n, accint) int { returnn+acc }, 0)
fmt.Println(res) // 120
}

Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

Prerequisites

You need at least go1.24 for development. The project is shipped with a Dockerfile based on go1.24.

If you prefer local development, navigate to the official download page and install version 1.24 or beyond.

Installing

First clone the repository

git clone https://github.com/rjNemo/underscore.git

Install dependencies

go mod download

And that's it.

Tests

To run the unit tests, you can simply run:

make test

Functions

underscore provides many of functions that support your favorite functional helpers

Collections

  • All
  • Any
  • Chunk
  • Contains
  • ContainsBy
  • Count
  • Difference
  • Drop
  • Each
  • Filter
  • Find
  • Flatmap
  • GroupBy
  • Intersection
  • Join / JoinProject
  • Last
  • Map
  • Max
  • Min
  • OrderBy
  • Partition
  • Range
  • Reduce
  • RemoveAt
  • Sum / SumMap
  • Unique
  • UniqueBy
  • UniqueInPlace
  • Zip

Pipe

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.

Methods not returning a slice such as Reduce, All, Any, will break the Chain and return Value instantly.

Concurrency

  • ParallelMap(ctx, values, workers, fn): apply a function concurrently while preserving order and supporting context cancellation.
  • ParallelFilter(ctx, values, workers, fn): filter concurrently with order preserved and context support.
package main
import (
"context""fmt"
u "github.com/rjNemo/underscore"
)
funcmain() {
out, err:=u.ParallelMap(context.Background(), []int{1, 2, 3, 4}, 4,
func(ctx context.Context, nint) (int, error) { returnn*n, nil },
)
fmt.Println(out, err) // [1 4 9 16] <nil>
}
// ParallelFilter examplepackage main
import (
"context""fmt"
u "github.com/rjNemo/underscore"
)
funcmain() {
out, err:=u.ParallelFilter(context.Background(), []int{1,2,3,4,5}, 3,
func(ctx context.Context, nint) (bool, error) { returnn%2==0, nil },
)
fmt.Println(out, err) // [2 4] <nil>
}

Utilities

  • Ternary: conditional expression helper
  • ToPointer: convert values to pointers
  • SortSliceASC / SortSliceDESC: sort slices in ascending or descending order
  • Result, Ok, Err, ToResult: Result type for error handling
  • Tuple: generic tuple type for paired values

Subpackages

  • maps.Keys(m) / maps.Values(m): extract keys or values from maps
  • maps.Map(m, fn): transform map entries

Built With

  • Go - Build fast, reliable, and efficient software at scale

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

Authors

  • Ruidy - Initial work - Ruidy

See also the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE.md file for details

Acknowledgments

This project is largely inspired by Underscore.js library. Check out the original project if you don't already know it.

About

🌟 Useful functional programming helpers for Go

Topics

Resources

Contributing

Stars

119 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages