Skip to content

Commit 8c96102

Browse files
committed
extract string text operation member methods
1 parent b852d57 commit 8c96102

3 files changed

Lines changed: 139 additions & 124 deletions

File tree

docs/architecture.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Key files:
3434
- `vibes/execution_members_string.go` (string member dispatch)
3535
- `vibes/execution_members_string_query.go` (string query/search member methods)
3636
- `vibes/execution_members_string_transforms.go` (string transform/normalization member methods)
37+
- `vibes/execution_members_string_textops.go` (string substitution/splitting/template member methods)
3738
- `vibes/execution_members_string_helpers.go` (string helper routines for member methods)
3839
- `vibes/execution_members_duration.go` (duration member behavior)
3940
- `vibes/execution_members_array.go` (array member dispatch)

vibes/execution_members_string.go

Lines changed: 2 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package vibes
22

33
import (
44
"fmt"
5-
"strings"
65
)
76

87
func stringMember(str Value, property string) (Value, error) {
@@ -11,129 +10,8 @@ func stringMember(str Value, property string) (Value, error) {
1110
return stringMemberQuery(property)
1211
case "strip", "strip!", "squish", "squish!", "lstrip", "lstrip!", "rstrip", "rstrip!", "chomp", "chomp!", "delete_prefix", "delete_prefix!", "delete_suffix", "delete_suffix!", "upcase", "upcase!", "downcase", "downcase!", "capitalize", "capitalize!", "swapcase", "swapcase!", "reverse", "reverse!":
1312
return stringMemberTransforms(property)
14-
case "sub":
15-
return NewAutoBuiltin("string.sub", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
16-
if len(args) != 2 {
17-
return NewNil(), fmt.Errorf("string.sub expects pattern and replacement")
18-
}
19-
regex, err := stringRegexOption("sub", kwargs)
20-
if err != nil {
21-
return NewNil(), err
22-
}
23-
if args[0].Kind() != KindString {
24-
return NewNil(), fmt.Errorf("string.sub pattern must be string")
25-
}
26-
if args[1].Kind() != KindString {
27-
return NewNil(), fmt.Errorf("string.sub replacement must be string")
28-
}
29-
updated, err := stringSub(receiver.String(), args[0].String(), args[1].String(), regex)
30-
if err != nil {
31-
return NewNil(), fmt.Errorf("string.sub invalid regex: %v", err)
32-
}
33-
return NewString(updated), nil
34-
}), nil
35-
case "sub!":
36-
return NewAutoBuiltin("string.sub!", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
37-
if len(args) != 2 {
38-
return NewNil(), fmt.Errorf("string.sub! expects pattern and replacement")
39-
}
40-
regex, err := stringRegexOption("sub!", kwargs)
41-
if err != nil {
42-
return NewNil(), err
43-
}
44-
if args[0].Kind() != KindString {
45-
return NewNil(), fmt.Errorf("string.sub! pattern must be string")
46-
}
47-
if args[1].Kind() != KindString {
48-
return NewNil(), fmt.Errorf("string.sub! replacement must be string")
49-
}
50-
updated, err := stringSub(receiver.String(), args[0].String(), args[1].String(), regex)
51-
if err != nil {
52-
return NewNil(), fmt.Errorf("string.sub! invalid regex: %v", err)
53-
}
54-
return stringBangResult(receiver.String(), updated), nil
55-
}), nil
56-
case "gsub":
57-
return NewAutoBuiltin("string.gsub", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
58-
if len(args) != 2 {
59-
return NewNil(), fmt.Errorf("string.gsub expects pattern and replacement")
60-
}
61-
regex, err := stringRegexOption("gsub", kwargs)
62-
if err != nil {
63-
return NewNil(), err
64-
}
65-
if args[0].Kind() != KindString {
66-
return NewNil(), fmt.Errorf("string.gsub pattern must be string")
67-
}
68-
if args[1].Kind() != KindString {
69-
return NewNil(), fmt.Errorf("string.gsub replacement must be string")
70-
}
71-
updated, err := stringGSub(receiver.String(), args[0].String(), args[1].String(), regex)
72-
if err != nil {
73-
return NewNil(), fmt.Errorf("string.gsub invalid regex: %v", err)
74-
}
75-
return NewString(updated), nil
76-
}), nil
77-
case "gsub!":
78-
return NewAutoBuiltin("string.gsub!", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
79-
if len(args) != 2 {
80-
return NewNil(), fmt.Errorf("string.gsub! expects pattern and replacement")
81-
}
82-
regex, err := stringRegexOption("gsub!", kwargs)
83-
if err != nil {
84-
return NewNil(), err
85-
}
86-
if args[0].Kind() != KindString {
87-
return NewNil(), fmt.Errorf("string.gsub! pattern must be string")
88-
}
89-
if args[1].Kind() != KindString {
90-
return NewNil(), fmt.Errorf("string.gsub! replacement must be string")
91-
}
92-
updated, err := stringGSub(receiver.String(), args[0].String(), args[1].String(), regex)
93-
if err != nil {
94-
return NewNil(), fmt.Errorf("string.gsub! invalid regex: %v", err)
95-
}
96-
return stringBangResult(receiver.String(), updated), nil
97-
}), nil
98-
case "split":
99-
return NewAutoBuiltin("string.split", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
100-
if len(args) > 1 {
101-
return NewNil(), fmt.Errorf("string.split accepts at most one separator")
102-
}
103-
text := receiver.String()
104-
var parts []string
105-
if len(args) == 0 {
106-
parts = strings.Fields(text)
107-
} else {
108-
if args[0].Kind() != KindString {
109-
return NewNil(), fmt.Errorf("string.split separator must be string")
110-
}
111-
parts = strings.Split(text, args[0].String())
112-
}
113-
values := make([]Value, len(parts))
114-
for i, part := range parts {
115-
values[i] = NewString(part)
116-
}
117-
return NewArray(values), nil
118-
}), nil
119-
case "template":
120-
return NewAutoBuiltin("string.template", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
121-
if len(args) != 1 {
122-
return NewNil(), fmt.Errorf("string.template expects exactly one context hash")
123-
}
124-
if args[0].Kind() != KindHash && args[0].Kind() != KindObject {
125-
return NewNil(), fmt.Errorf("string.template context must be hash")
126-
}
127-
strict, err := stringTemplateOption(kwargs)
128-
if err != nil {
129-
return NewNil(), err
130-
}
131-
rendered, err := stringTemplate(receiver.String(), args[0], strict)
132-
if err != nil {
133-
return NewNil(), err
134-
}
135-
return NewString(rendered), nil
136-
}), nil
13+
case "sub", "sub!", "gsub", "gsub!", "split", "template":
14+
return stringMemberTextOps(property)
13715
default:
13816
return NewNil(), fmt.Errorf("unknown string method %s", property)
13917
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package vibes
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
func stringMemberTextOps(property string) (Value, error) {
9+
switch property {
10+
case "sub":
11+
return NewAutoBuiltin("string.sub", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
12+
if len(args) != 2 {
13+
return NewNil(), fmt.Errorf("string.sub expects pattern and replacement")
14+
}
15+
regex, err := stringRegexOption("sub", kwargs)
16+
if err != nil {
17+
return NewNil(), err
18+
}
19+
if args[0].Kind() != KindString {
20+
return NewNil(), fmt.Errorf("string.sub pattern must be string")
21+
}
22+
if args[1].Kind() != KindString {
23+
return NewNil(), fmt.Errorf("string.sub replacement must be string")
24+
}
25+
updated, err := stringSub(receiver.String(), args[0].String(), args[1].String(), regex)
26+
if err != nil {
27+
return NewNil(), fmt.Errorf("string.sub invalid regex: %v", err)
28+
}
29+
return NewString(updated), nil
30+
}), nil
31+
case "sub!":
32+
return NewAutoBuiltin("string.sub!", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
33+
if len(args) != 2 {
34+
return NewNil(), fmt.Errorf("string.sub! expects pattern and replacement")
35+
}
36+
regex, err := stringRegexOption("sub!", kwargs)
37+
if err != nil {
38+
return NewNil(), err
39+
}
40+
if args[0].Kind() != KindString {
41+
return NewNil(), fmt.Errorf("string.sub! pattern must be string")
42+
}
43+
if args[1].Kind() != KindString {
44+
return NewNil(), fmt.Errorf("string.sub! replacement must be string")
45+
}
46+
updated, err := stringSub(receiver.String(), args[0].String(), args[1].String(), regex)
47+
if err != nil {
48+
return NewNil(), fmt.Errorf("string.sub! invalid regex: %v", err)
49+
}
50+
return stringBangResult(receiver.String(), updated), nil
51+
}), nil
52+
case "gsub":
53+
return NewAutoBuiltin("string.gsub", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
54+
if len(args) != 2 {
55+
return NewNil(), fmt.Errorf("string.gsub expects pattern and replacement")
56+
}
57+
regex, err := stringRegexOption("gsub", kwargs)
58+
if err != nil {
59+
return NewNil(), err
60+
}
61+
if args[0].Kind() != KindString {
62+
return NewNil(), fmt.Errorf("string.gsub pattern must be string")
63+
}
64+
if args[1].Kind() != KindString {
65+
return NewNil(), fmt.Errorf("string.gsub replacement must be string")
66+
}
67+
updated, err := stringGSub(receiver.String(), args[0].String(), args[1].String(), regex)
68+
if err != nil {
69+
return NewNil(), fmt.Errorf("string.gsub invalid regex: %v", err)
70+
}
71+
return NewString(updated), nil
72+
}), nil
73+
case "gsub!":
74+
return NewAutoBuiltin("string.gsub!", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
75+
if len(args) != 2 {
76+
return NewNil(), fmt.Errorf("string.gsub! expects pattern and replacement")
77+
}
78+
regex, err := stringRegexOption("gsub!", kwargs)
79+
if err != nil {
80+
return NewNil(), err
81+
}
82+
if args[0].Kind() != KindString {
83+
return NewNil(), fmt.Errorf("string.gsub! pattern must be string")
84+
}
85+
if args[1].Kind() != KindString {
86+
return NewNil(), fmt.Errorf("string.gsub! replacement must be string")
87+
}
88+
updated, err := stringGSub(receiver.String(), args[0].String(), args[1].String(), regex)
89+
if err != nil {
90+
return NewNil(), fmt.Errorf("string.gsub! invalid regex: %v", err)
91+
}
92+
return stringBangResult(receiver.String(), updated), nil
93+
}), nil
94+
case "split":
95+
return NewAutoBuiltin("string.split", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
96+
if len(args) > 1 {
97+
return NewNil(), fmt.Errorf("string.split accepts at most one separator")
98+
}
99+
text := receiver.String()
100+
var parts []string
101+
if len(args) == 0 {
102+
parts = strings.Fields(text)
103+
} else {
104+
if args[0].Kind() != KindString {
105+
return NewNil(), fmt.Errorf("string.split separator must be string")
106+
}
107+
parts = strings.Split(text, args[0].String())
108+
}
109+
values := make([]Value, len(parts))
110+
for i, part := range parts {
111+
values[i] = NewString(part)
112+
}
113+
return NewArray(values), nil
114+
}), nil
115+
case "template":
116+
return NewAutoBuiltin("string.template", func(exec *Execution, receiver Value, args []Value, kwargs map[string]Value, block Value) (Value, error) {
117+
if len(args) != 1 {
118+
return NewNil(), fmt.Errorf("string.template expects exactly one context hash")
119+
}
120+
if args[0].Kind() != KindHash && args[0].Kind() != KindObject {
121+
return NewNil(), fmt.Errorf("string.template context must be hash")
122+
}
123+
strict, err := stringTemplateOption(kwargs)
124+
if err != nil {
125+
return NewNil(), err
126+
}
127+
rendered, err := stringTemplate(receiver.String(), args[0], strict)
128+
if err != nil {
129+
return NewNil(), err
130+
}
131+
return NewString(rendered), nil
132+
}), nil
133+
default:
134+
return NewNil(), fmt.Errorf("unknown string method %s", property)
135+
}
136+
}

0 commit comments

Comments
 (0)