mirror of
https://github.com/MontFerret/ferret.git
synced 2024-12-14 11:23:02 +02:00
Feature/#95 deepclone (#101)
* rename method Clone to Copy * added Cloneable interface * added Value to Cloneable interface * implemented Cloneable intefrace by array * implemented Cloneable interface by Object * unit tests for Object.Clone * move core.IsCloneable to value.go * change Clone function * move IsClonable to package values
This commit is contained in:
parent
88188cac2c
commit
f91fbf6f8c
@ -176,7 +176,7 @@ func (doc *HTMLDocument) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (doc *HTMLDocument) Clone() core.Value {
|
||||
func (doc *HTMLDocument) Copy() core.Value {
|
||||
return values.None
|
||||
}
|
||||
|
||||
|
@ -276,7 +276,7 @@ func (el *HTMLElement) Value() core.Value {
|
||||
return val
|
||||
}
|
||||
|
||||
func (el *HTMLElement) Clone() core.Value {
|
||||
func (el *HTMLElement) Copy() core.Value {
|
||||
return values.None
|
||||
}
|
||||
|
||||
@ -300,7 +300,7 @@ func (el *HTMLElement) GetAttributes() core.Value {
|
||||
}
|
||||
|
||||
// returning shallow copy
|
||||
return val.Clone()
|
||||
return val.Copy()
|
||||
}
|
||||
|
||||
func (el *HTMLElement) GetAttribute(name values.String) core.Value {
|
||||
|
@ -3,14 +3,15 @@ package static
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/html/common"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/corpix/uarand"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sethgrid/pester"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type Driver struct {
|
||||
|
@ -2,11 +2,12 @@ package static
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"hash/fnv"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/html/common"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/values"
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"hash/fnv"
|
||||
)
|
||||
|
||||
type HTMLElement struct {
|
||||
@ -69,7 +70,7 @@ func (el *HTMLElement) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (el *HTMLElement) Clone() core.Value {
|
||||
func (el *HTMLElement) Copy() core.Value {
|
||||
c, _ := NewHTMLElement(el.selection.Clone())
|
||||
|
||||
return c
|
||||
|
6
pkg/runtime/core/cloneable.go
Normal file
6
pkg/runtime/core/cloneable.go
Normal file
@ -0,0 +1,6 @@
|
||||
package core
|
||||
|
||||
type Cloneable interface {
|
||||
Value
|
||||
Clone() Cloneable
|
||||
}
|
@ -46,7 +46,7 @@ type Value interface {
|
||||
Compare(other Value) int
|
||||
Unwrap() interface{}
|
||||
Hash() uint64
|
||||
Clone() Value
|
||||
Copy() Value
|
||||
}
|
||||
|
||||
func IsTypeOf(value Value, check Type) bool {
|
||||
|
@ -110,7 +110,7 @@ func (t *Array) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (t *Array) Clone() core.Value {
|
||||
func (t *Array) Copy() core.Value {
|
||||
c := NewArray(len(t.value))
|
||||
|
||||
for _, el := range t.value {
|
||||
@ -206,3 +206,18 @@ func (t *Array) RemoveAt(idx Int) {
|
||||
|
||||
t.value = append(t.value[:i], t.value[i+1:]...)
|
||||
}
|
||||
|
||||
func (t *Array) Clone() core.Cloneable {
|
||||
cloned := NewArray(0)
|
||||
|
||||
var value core.Value
|
||||
for idx := NewInt(0); idx < t.Length(); idx++ {
|
||||
value = t.Get(idx)
|
||||
if IsCloneable(value) {
|
||||
value = value.(core.Cloneable).Clone()
|
||||
}
|
||||
cloned.Push(value)
|
||||
}
|
||||
|
||||
return cloned
|
||||
}
|
||||
|
@ -502,4 +502,62 @@ func TestArray(t *testing.T) {
|
||||
So(arr.Get(0), ShouldEqual, 1)
|
||||
})
|
||||
})
|
||||
|
||||
Convey(".Clone", t, func() {
|
||||
Convey("Cloned array should be equal to source array", func() {
|
||||
arr := values.NewArrayWith(
|
||||
values.NewInt(0),
|
||||
values.NewObjectWith(
|
||||
values.NewObjectProperty("one", values.NewInt(1)),
|
||||
),
|
||||
values.NewArrayWith(
|
||||
values.NewInt(2),
|
||||
),
|
||||
)
|
||||
|
||||
clone := arr.Clone().(*values.Array)
|
||||
|
||||
So(arr.Length(), ShouldEqual, clone.Length())
|
||||
So(arr.Compare(clone), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Cloned array should be independent of the source array", func() {
|
||||
arr := values.NewArrayWith(
|
||||
values.NewInt(0),
|
||||
values.NewInt(1),
|
||||
values.NewInt(2),
|
||||
values.NewInt(3),
|
||||
values.NewInt(4),
|
||||
values.NewInt(5),
|
||||
)
|
||||
|
||||
clone := arr.Clone().(*values.Array)
|
||||
|
||||
arr.Push(values.NewInt(6))
|
||||
|
||||
So(arr.Length(), ShouldNotEqual, clone.Length())
|
||||
So(arr.Compare(clone), ShouldNotEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Cloned array must contain copies of the nested objects", func() {
|
||||
arr := values.NewArrayWith(
|
||||
values.NewArrayWith(
|
||||
values.NewInt(0),
|
||||
values.NewInt(1),
|
||||
values.NewInt(2),
|
||||
values.NewInt(3),
|
||||
values.NewInt(4),
|
||||
),
|
||||
)
|
||||
|
||||
clone := arr.Clone().(*values.Array)
|
||||
|
||||
nestedInArr := arr.Get(values.NewInt(0)).(*values.Array)
|
||||
nestedInArr.Push(values.NewInt(5))
|
||||
|
||||
nestedInClone := clone.Get(values.NewInt(0)).(*values.Array)
|
||||
|
||||
So(nestedInArr.Compare(nestedInClone), ShouldNotEqual, 0)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -2,10 +2,11 @@ package values
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"hash/fnv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
)
|
||||
|
||||
type Binary struct {
|
||||
@ -72,7 +73,7 @@ func (b *Binary) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (b *Binary) Clone() core.Value {
|
||||
func (b *Binary) Copy() core.Value {
|
||||
c := make([]byte, len(b.values))
|
||||
|
||||
copy(c, b.values)
|
||||
|
@ -2,10 +2,11 @@ package values
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Boolean bool
|
||||
@ -108,6 +109,6 @@ func (t Boolean) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (t Boolean) Clone() core.Value {
|
||||
func (t Boolean) Copy() core.Value {
|
||||
return t
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
package values
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"hash/fnv"
|
||||
"time"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
)
|
||||
|
||||
const defaultTimeLayout = time.RFC3339
|
||||
@ -109,6 +110,6 @@ func (t DateTime) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (t DateTime) Clone() core.Value {
|
||||
func (t DateTime) Copy() core.Value {
|
||||
return NewDateTime(t.Time)
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
"hash/fnv"
|
||||
"math"
|
||||
"strconv"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Float float64
|
||||
@ -127,6 +128,6 @@ func (t Float) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (t Float) Clone() core.Value {
|
||||
func (t Float) Copy() core.Value {
|
||||
return t
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ package values
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
)
|
||||
|
||||
func GetIn(from core.Value, byPath []core.Value) (core.Value, error) {
|
||||
@ -294,3 +295,14 @@ func ToBoolean(input core.Value) core.Value {
|
||||
return True
|
||||
}
|
||||
}
|
||||
|
||||
func IsCloneable(value core.Value) Boolean {
|
||||
switch value.Type() {
|
||||
case core.ArrayType:
|
||||
return NewBoolean(true)
|
||||
case core.ObjectType:
|
||||
return NewBoolean(true)
|
||||
default:
|
||||
return NewBoolean(false)
|
||||
}
|
||||
}
|
||||
|
@ -3,10 +3,11 @@ package values
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
"hash/fnv"
|
||||
"strconv"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Int int
|
||||
@ -125,6 +126,6 @@ func (t Int) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (t Int) Clone() core.Value {
|
||||
func (t Int) Copy() core.Value {
|
||||
return t
|
||||
}
|
||||
|
@ -37,6 +37,6 @@ func (t *none) Hash() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (t *none) Clone() core.Value {
|
||||
func (t *none) Copy() core.Value {
|
||||
return None
|
||||
}
|
||||
|
@ -141,7 +141,7 @@ func (t *Object) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (t *Object) Clone() core.Value {
|
||||
func (t *Object) Copy() core.Value {
|
||||
c := NewObject()
|
||||
|
||||
for k, v := range t.value {
|
||||
@ -202,3 +202,20 @@ func (t *Object) Remove(key String) {
|
||||
func (t *Object) SetIn(path []core.Value, value core.Value) error {
|
||||
return SetIn(t, path, value)
|
||||
}
|
||||
|
||||
func (t *Object) Clone() core.Cloneable {
|
||||
cloned := NewObject()
|
||||
|
||||
var value core.Value
|
||||
var keyString String
|
||||
for key := range t.value {
|
||||
keyString = NewString(key)
|
||||
value, _ = t.Get(keyString)
|
||||
if IsCloneable(value) {
|
||||
value = value.(core.Cloneable).Clone()
|
||||
}
|
||||
cloned.Set(keyString, value)
|
||||
}
|
||||
|
||||
return cloned
|
||||
}
|
||||
|
@ -300,4 +300,49 @@ func TestObject(t *testing.T) {
|
||||
So(v.Compare(values.NewInt(1)), ShouldEqual, 0)
|
||||
})
|
||||
})
|
||||
|
||||
Convey(".Clone", t, func() {
|
||||
Convey("Cloned object should be equal to source object", func() {
|
||||
obj := values.NewObjectWith(
|
||||
values.NewObjectProperty("one", values.NewInt(1)),
|
||||
values.NewObjectProperty("two", values.NewInt(2)),
|
||||
)
|
||||
|
||||
clone := obj.Clone().(*values.Object)
|
||||
|
||||
So(obj.Compare(clone), ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Cloned object should be independent of the source object", func() {
|
||||
obj := values.NewObjectWith(
|
||||
values.NewObjectProperty("one", values.NewInt(1)),
|
||||
values.NewObjectProperty("two", values.NewInt(2)),
|
||||
)
|
||||
|
||||
clone := obj.Clone().(*values.Object)
|
||||
|
||||
obj.Remove(values.NewString("one"))
|
||||
|
||||
So(obj.Compare(clone), ShouldNotEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Cloned object must contain copies of the nested objects", func() {
|
||||
obj := values.NewObjectWith(
|
||||
values.NewObjectProperty(
|
||||
"arr", values.NewArrayWith(values.NewInt(1)),
|
||||
),
|
||||
)
|
||||
|
||||
clone := obj.Clone().(*values.Object)
|
||||
|
||||
nestedInObj, _ := obj.Get(values.NewString("arr"))
|
||||
nestedInObjArr := nestedInObj.(*values.Array)
|
||||
nestedInObjArr.Push(values.NewInt(2))
|
||||
|
||||
nestedInClone, _ := clone.Get(values.NewString("arr"))
|
||||
nestedInCloneArr := nestedInClone.(*values.Array)
|
||||
|
||||
So(nestedInObjArr.Compare(nestedInCloneArr), ShouldNotEqual, 0)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -3,10 +3,11 @@ package values
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
|
||||
"github.com/MontFerret/ferret/pkg/runtime/core"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type String string
|
||||
@ -103,7 +104,7 @@ func (t String) Hash() uint64 {
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
func (t String) Clone() core.Value {
|
||||
func (t String) Copy() core.Value {
|
||||
return t
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ func Unshift(_ context.Context, args ...core.Value) (core.Value, error) {
|
||||
|
||||
if !ok {
|
||||
// value is not unique, just return a new copy with same elements
|
||||
return arr.Clone(), nil
|
||||
return arr.Copy(), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user