Skip to content

Commit 3474b32

Browse files
authored
Merge pull request #2 from RaduBerinde/crstrings
add crstrings library
2 parents ae293ba + 8212df1 commit 3474b32

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

crstrings/utils.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright 2024 The Cockroach Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
// implied. See the License for the specific language governing
13+
// permissions and limitations under the License.
14+
15+
package crstrings
16+
17+
import (
18+
"fmt"
19+
"slices"
20+
"strings"
21+
)
22+
23+
// JoinStringers concatenates the string representations of the given
24+
// fmt.Stringer implementations.
25+
func JoinStringers[T fmt.Stringer](delim string, args ...T) string {
26+
switch len(args) {
27+
case 0:
28+
return ""
29+
case 1:
30+
return args[0].String()
31+
}
32+
elems := make([]string, len(args))
33+
for i := range args {
34+
elems[i] = args[i].String()
35+
}
36+
return strings.Join(elems, delim)
37+
}
38+
39+
// MapAndJoin converts each argument to a string using the given function and
40+
// joins the strings with the given delimiter.
41+
func MapAndJoin[T any](fn func(T) string, delim string, args ...T) string {
42+
switch len(args) {
43+
case 0:
44+
return ""
45+
case 1:
46+
return fn(args[0])
47+
}
48+
elems := make([]string, len(args))
49+
for i := range args {
50+
elems[i] = fn(args[i])
51+
}
52+
return strings.Join(elems, delim)
53+
}
54+
55+
// If returns the given value if the flag is true, otherwise an empty string.
56+
func If(flag bool, trueValue string) string {
57+
return IfElse(flag, trueValue, "")
58+
}
59+
60+
// IfElse returns the value that matches the value of the flag.
61+
func IfElse(flag bool, trueValue, falseValue string) string {
62+
if flag {
63+
return trueValue
64+
}
65+
return falseValue
66+
}
67+
68+
// WithSep prints the strings a and b with the given separator in-between,
69+
// unless one of the strings is empty (in which case the other string is
70+
// returned).
71+
func WithSep(a string, separator string, b string) string {
72+
if a == "" {
73+
return b
74+
}
75+
if b == "" {
76+
return a
77+
}
78+
return strings.Join([]string{a, b}, separator)
79+
}
80+
81+
// FilterEmpty removes empty strings from the given slice.
82+
func FilterEmpty(elems []string) []string {
83+
return slices.DeleteFunc(elems, func(s string) bool {
84+
return s == ""
85+
})
86+
}
87+
88+
// Lines breaks up the given string into lines.
89+
func Lines(s string) []string {
90+
// Remove any trailing newline (to avoid getting an extraneous empty line at
91+
// the end).
92+
s = strings.TrimSuffix(s, "\n")
93+
if s == "" {
94+
// In this case, Split returns a slice with a single empty string (which is
95+
// not what we want).
96+
return nil
97+
}
98+
return strings.Split(s, "\n")
99+
}

crstrings/utils_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright 2024 The Cockroach Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12+
// implied. See the License for the specific language governing
13+
// permissions and limitations under the License.
14+
15+
package crstrings
16+
17+
import (
18+
"fmt"
19+
"strings"
20+
"testing"
21+
)
22+
23+
type num int
24+
25+
func (n num) String() string {
26+
return fmt.Sprintf("%03d", int(n))
27+
}
28+
29+
func TestJoinStringers(t *testing.T) {
30+
nums := []num{0, 1, 2, 3}
31+
expect(t, "", JoinStringers(", ", nums[:0]...))
32+
expect(t, "000", JoinStringers(", ", nums[0]))
33+
expect(t, "000, 001", JoinStringers(", ", nums[0], nums[1]))
34+
expect(t, "000, 001, 002, 003", JoinStringers(", ", nums...))
35+
}
36+
37+
func TestMapAndJoin(t *testing.T) {
38+
nums := []int{0, 1, 2, 3}
39+
fn := func(n int) string {
40+
return fmt.Sprintf("%d", n)
41+
}
42+
expect(t, "", MapAndJoin(fn, ", ", nums[:0]...))
43+
expect(t, "0", MapAndJoin(fn, ", ", nums[0]))
44+
expect(t, "0, 1", MapAndJoin(fn, ", ", nums[0], nums[1]))
45+
expect(t, "0, 1, 2, 3", MapAndJoin(fn, ", ", nums...))
46+
}
47+
48+
func expect(t *testing.T, expected, actual string) {
49+
t.Helper()
50+
if actual != expected {
51+
t.Errorf("expected %q got %q", expected, actual)
52+
}
53+
}
54+
55+
func TestIf(t *testing.T) {
56+
expect(t, "", If(false, "true"))
57+
expect(t, "true", If(true, "true"))
58+
}
59+
60+
func TestIfElse(t *testing.T) {
61+
expect(t, "false", IfElse(false, "true", "false"))
62+
expect(t, "true", IfElse(true, "true", "false"))
63+
}
64+
65+
func TestWithSep(t *testing.T) {
66+
expect(t, "a,b", WithSep("a", ",", "b"))
67+
expect(t, "a", WithSep("a", ",", ""))
68+
expect(t, "b", WithSep("", ",", "b"))
69+
}
70+
71+
func TestFilterEmpty(t *testing.T) {
72+
s := []string{"a", "", "b", "", "c", ""}
73+
expect(t, "a,b,c", strings.Join(FilterEmpty(s), ","))
74+
}
75+
76+
func TestLines(t *testing.T) {
77+
expect(t, `["a" "b" "c"]`, fmt.Sprintf("%q", Lines("a\nb\nc")))
78+
expect(t, `["a" "b" "c"]`, fmt.Sprintf("%q", Lines("a\nb\nc\n")))
79+
expect(t, `["a" "b" "c" ""]`, fmt.Sprintf("%q", Lines("a\nb\nc\n\n")))
80+
expect(t, `["" "a" "b" "c"]`, fmt.Sprintf("%q", Lines("\na\nb\nc\n")))
81+
expect(t, `[]`, fmt.Sprintf("%q", Lines("")))
82+
expect(t, `[]`, fmt.Sprintf("%q", Lines("\n")))
83+
}

0 commit comments

Comments
 (0)