Skip to content

Commit

Permalink
Merge pull request #36 from b-per/field-as-int
Browse files Browse the repository at this point in the history
Allow setting struct fields as int
  • Loading branch information
alexflint authored Dec 2, 2024
2 parents 6b949f5 + 32b1002 commit 503d0e2
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 1 deletion.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,19 @@ func main() {
}
```

### Ints

It is also possible to set struct fields as `int` to get the string automatically converted.

```go
// Matches "12 wombats", "1 wombat" and store the number as int
type Wisdom struct {
Number int `^\d+`
_ string `\s+`
Animal string `\w+`
}
```

### Optional fields

When nesting one struct within another, you can make the nested struct optional by marking it with `?`. The following example parses floating point numbers with optional sign and exponent:
Expand Down
3 changes: 3 additions & 0 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const (
PosRole
SubstructRole
StringScalarRole
IntScalarRole
ByteSliceScalarRole
SubmatchScalarRole
)
Expand Down Expand Up @@ -106,6 +107,8 @@ func (b *builder) terminal(f reflect.StructField, fullName string) (*Field, *syn
role = EmptyRole
case stringType:
role = StringScalarRole
case intType:
role = IntScalarRole
case byteSliceType:
role = ByteSliceScalarRole
case submatchType:
Expand Down
12 changes: 11 additions & 1 deletion inflate.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ package restructure
import (
"fmt"
"reflect"
"strconv"
)

var (
posType = reflect.TypeOf(Pos(0))

emptyType = reflect.TypeOf(struct{}{})
stringType = reflect.TypeOf("")
intType = reflect.TypeOf(1)
byteSliceType = reflect.TypeOf([]byte{})
submatchType = reflect.TypeOf(Submatch{})
scalarTypes = []reflect.Type{
emptyType,
stringType,
intType,
byteSliceType,
submatchType,
}
Expand Down Expand Up @@ -77,6 +80,13 @@ func inflateScalar(dest reflect.Value, match *match, captureIndex int, role Role
case StringScalarRole:
dest.SetString(string(buf))
return nil
case IntScalarRole:
if intVal, err := strconv.Atoi(string(buf)); err != nil {
return fmt.Errorf("unable to capture into %s", dest.Type().String())
} else {
dest.SetInt(int64(intVal))
return nil
}
case ByteSliceScalarRole:
dest.SetBytes(buf)
return nil
Expand Down Expand Up @@ -128,7 +138,7 @@ func inflateStruct(dest reflect.Value, match *match, structure *Struct) error {
if err := inflatePos(val, match, field.capture); err != nil {
return err
}
case StringScalarRole, ByteSliceScalarRole, SubmatchScalarRole:
case StringScalarRole, ByteSliceScalarRole, SubmatchScalarRole, IntScalarRole:
val := dest.FieldByIndex(field.index)
if err := inflateScalar(val, match, field.capture, field.role); err != nil {
return err
Expand Down
16 changes: 16 additions & 0 deletions restructure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,3 +308,19 @@ func TestFindAllWords_Regions(t *testing.T) {
assertRegion(t, "is", 4, 6, words[1].S)
assertRegion(t, "spam", 7, 11, words[2].S)
}

type ExprWithInt struct {
Number int `regexp:"^\\d+"`
_ string `regexp:"\\s+"`
Animal string `regexp:"\\w+$"`
}

func TestMatchWithInt(t *testing.T) {
pattern, err := Compile(ExprWithInt{}, Options{})
require.NoError(t, err)

var v ExprWithInt
assert.True(t, pattern.Find(&v, "4 wombats"))
assert.Equal(t, 4, v.Number)
assert.Equal(t, "wombats", v.Animal)
}

0 comments on commit 503d0e2

Please sign in to comment.