Skip to content

Commit

Permalink
Add some clearification to the README file
Browse files Browse the repository at this point in the history
  • Loading branch information
ivancorrales committed May 23, 2023
1 parent f3c5f79 commit e3f64d8
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 109 deletions.
59 changes: 47 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,42 @@
[![Build Status](https://img.shields.io/github/actions/workflow/status/astrokube/pathify/build.yml?branch=main)](https://github.com/astrokube/pathify/actions?query=workflow%3ABuild+branch%3Amain)
[![CodeQL](https://github.com/astrokube/pathify/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/astrokube/pathify/actions/workflows/codeql.yml)

# PAthify
# Pathify

The swiss knife to create your own maps taking advanage of a JSONPath approach
The swiss knife to dea with the hassle of manipulate generic

## History and project status

This module is still `in active development` and the API is still subject to breaking changes.
This module is already `ready-for-production` and the [astrokube organization](https://www.github.com/astrokube) already
take advantage of it for our internal projects.

## Pathify Highlights

* **Easy integration**: It's straightforward to be integrated with your current developments.

## Installation

Use go get to retrieve the library to add it to your GOPATH workspace, or project's Go module dependencies.

```bash
go get -u github.com/astrokube/pathifyv2
go get -u github.com/astrokube/pathify
```

To update the library use go get -u to retrieve the latest version of it.

```bash
go get -u github.com/astrokube/pathifyv2
go get -u github.com/astrokube/pathify
```

You could specify a concrete version of this module as It's shown on the below. Replace x.y.z by the desired version.

```bash
module github.com/<org>/<repository>
require (
github.com/astrokube/pathifyv2 vX.Y.Z
github.com/astrokube/pathify vX.Y.Z
)
```

## Overview of packages

The library is composed by:

* `package`: .....

## Getting started

### Pre-requisites
Expand All @@ -52,6 +51,42 @@ The library is composed by:

A rich and growing set of examples of usage of this module can be found in folder `examples`.

```go
package main

import (
"strings"

"github.com/astrokube/pathify"
)

var peopleArray = []any{
map[string]any{
"firstname": "John",
"lastname": "Doe",
"age": 29,
},
map[string]any{
"firstname": "Jane",
"lastname": "Moe",
"age": 30,
},
}

func main() {
p := pathify.Load[[]any](peopleArray).Set(
"[1].lastname", "Doe",
"[0].firstname", "Wendy",
"[2].firstname", "Cindy",
"[1].firstname", strings.ToUpper,
)
b, _ := p.YAML()
println(string(b))
b, _ = p.JSON()
println(string(b))
}
```


### Contributing

Expand Down
42 changes: 0 additions & 42 deletions examples/load.go

This file was deleted.

68 changes: 26 additions & 42 deletions examples/main.go
Original file line number Diff line number Diff line change
@@ -1,49 +1,33 @@
package main

import "encoding/json"

/*
*
func buildNode() pathifyv2.Node[map[string]any] {
john := pathifyv2.New().
SetValue("firstname", "John").
SetValue("lastname", "Doe").Out()
wendy := pathifyv2.New().
SetValue("firstname", "Wendy").Out()
return pathifyv2.New().
SetValue("salary", 120).
SetValue("dad", john).
SetValue("mom.firstname", "Jane").
SetValue("mom.lastName", "Dane").
SetValue("children[0].firstname", "David").
SetValue("children[0].age", 20).
SetValue("children[0].tutor", wendy)
}
import (
"strings"

"github.com/astrokube/pathify"
)

var peopleArray = []any{
map[string]any{
"firstname": "John",
"lastname": "Doe",
"age": 29,
},
map[string]any{
"firstname": "Jane",
"lastname": "Moe",
"age": 30,
},
}

*
*/
func main() {
/**
out := complexMapStructure()
b, err := json.MarshalIndent(out, " ", " ")
if err != nil {
println(err.Error())
//os.Exit(1)
}
p := pathify.Load[[]any](peopleArray).Set(
"[1].lastname", "Doe",
"[0].firstname", "Wendy",
"[2].firstname", "Cindy",
"[1].firstname", strings.ToUpper,
)
b, _ := p.YAML()
println(string(b))
prettyPrint()
println("------------ Pathify Load ------------")
**/
//exampleLoad()
printJSON(loadArray())
// printJSON(loadMap())
}

func printJSON(content any) {
b, _ := json.Marshal(content)
b, _ = p.JSON()
println(string(b))
}
30 changes: 28 additions & 2 deletions pathify/mutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package pathify

import (
"fmt"
"reflect"
"strconv"
)

Expand All @@ -27,6 +28,27 @@ type mutator struct {
value any
}

func (m *mutator) applyValue(in any) any {
val := reflect.ValueOf(m.value)
switch val.Kind() {
case reflect.Struct:
return nil
case reflect.Func:
x := reflect.TypeOf(m.value)
if x.NumIn() != 1 || x.NumOut() != 1 {
return nil
}
inVal := reflect.ValueOf(in)
if x.In(0).Kind() != inVal.Kind() {
return nil
}
out := val.Call([]reflect.Value{inVal})
return out[0].String()
default:
return m.value
}
}

func (m *mutator) String() string {
return m.pretty("")
}
Expand Down Expand Up @@ -60,7 +82,9 @@ func (m *mutator) toMap(content map[string]any) map[string]any {
content = make(map[string]any)
}
if m.child == nil {
content[m.name] = m.value
if m.value != nil {
content[m.name] = m.applyValue(content[m.name])
}
return content
}
mt := *m.child
Expand Down Expand Up @@ -100,7 +124,9 @@ func (m *mutator) toArray(content []any) []any {
// This means that we should apply a '*'
}
if m.child == nil {
content[index] = m.value
if m.value != nil {
content[index] = m.applyValue(content[index])
}
return content
}
c := content[index]
Expand Down
3 changes: 2 additions & 1 deletion pathify/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ type parser struct {
}

func regExpFromAttributeFormat(attributeFormat string) *regexp.Regexp {
regExpStr := fmt.Sprintf(`^(?P<parent>(((\.)?%s|\[%s\]))*)((\.)(?P<attribute>%s)|(\[(?P<index>%s)\]))$`, attributeFormat, arrayIndexExprStr, attributeFormat, arrayIndexExprStr)
regExpStr := fmt.Sprintf(`^(?P<parent>(((\.)?%s|\[%s\]))*)((\.)(?P<attribute>%s)|(\[(?P<index>%s)\]))$`,
attributeFormat, arrayIndexExprStr, attributeFormat, arrayIndexExprStr)
return regexp.MustCompile(regExpStr)
}

Expand Down
38 changes: 32 additions & 6 deletions pathify/pathifier.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
package pathify

import (
"encoding/json"
"gopkg.in/yaml.v3"
"log"
"reflect"
)

type Pathifier[S Type] interface {
Set(pathValueList ...any) Pathifier[S]
Out() S
JSON() ([]byte, error)
YAML() ([]byte, error)
}

type Type interface {
map[string]any | []any
}

func checkValue(value any) any {
switch reflect.ValueOf(value).Kind() {
case reflect.Struct:
return nil
default:
return value
}
}

type pathifier[T Type] struct {
mutators []mutator
sanitizer *sanitizer
Expand Down Expand Up @@ -69,10 +82,11 @@ func WithAttributeNameFormat(attrNameFmt string) func(builder *builder) {
}

func (p *pathifier[S]) Set(args ...any) Pathifier[S] {
pathValueList := p.sanitizer.sanitize(args...)
pathValueList := p.sanitizer.sanitizePathValueList(args...)
for _, pathValue := range pathValueList {
v := checkValue(pathValue.value)
m := p.parser.parse(pathValue.path)
m.withValue(pathValue.value)
m.withValue(v)
p.mutators = append(p.mutators, *m)
}
return p
Expand All @@ -83,14 +97,26 @@ func (p *pathifier[S]) Out() S {
for _, m := range p.mutators {
switch reflect.TypeOf(content).Kind() {
case reflect.Array, reflect.Slice:
in := reflect.ValueOf(content).Interface().([]any)
content = reflect.ValueOf(m.child.toArray(in)).Interface().(S)
in, ok := reflect.ValueOf(content).Interface().([]any)
if ok {
content, _ = reflect.ValueOf(m.child.toArray(in)).Interface().(S)
}
case reflect.Map:
in := reflect.ValueOf(content).Interface().(map[string]any)
content = reflect.ValueOf(m.child.toMap(in)).Interface().(S)
in, ok := reflect.ValueOf(content).Interface().(map[string]any)
if ok {
content, _ = reflect.ValueOf(m.child.toMap(in)).Interface().(S)
}
default:
log.Fatalf("unsupporteed output type '%s'", reflect.TypeOf(content).Kind())
}
}
return content
}

func (p *pathifier[S]) JSON() ([]byte, error) {
return json.Marshal(p.Out())
}

func (p *pathifier[S]) YAML() ([]byte, error) {
return yaml.Marshal(p.Out())
}
3 changes: 2 additions & 1 deletion pathify/sanitizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ type sanitizer struct {
strict bool
}

func (s *sanitizer) sanitize(args ...any) pathValueList {
func (s *sanitizer) sanitizePathValueList(args ...any) pathValueList {
if len(args)%2 != 0 {
args = append(args, emptyValue)
}
//nolint: gomnd
list := make(pathValueList, len(args)/2)
arg := 0
invalidPathValues := 0
Expand Down
6 changes: 3 additions & 3 deletions pathify/sanitizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,10 @@ func Test_sanitizer_sanitize(t *testing.T) {
strict: tt.fields.strict,
}
if tt.panicked {
assert.Panics(t, func() { s.sanitize(tt.args.args...) }, "The execution should end panicking")
assert.Panics(t, func() { s.sanitizePathValueList(tt.args.args...) }, "The execution should end panicking")
} else {
if got := s.sanitize(tt.args.args...); !reflect.DeepEqual(got, tt.want) {
t.Errorf("sanitize() = %v, want %v", got, tt.want)
if got := s.sanitizePathValueList(tt.args.args...); !reflect.DeepEqual(got, tt.want) {
t.Errorf("sanitizePathValueList() = %v, want %v", got, tt.want)
}
}
})
Expand Down

0 comments on commit e3f64d8

Please sign in to comment.