duck

package module
v0.0.0-...-fd7e2f4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 6, 2017 License: Apache-2.0 Imports: 6 Imported by: 0

README

MIT licensed Go Report Card Build Status Coverage Status GoDoc

Duck

Sometimes in golang a function returns an interface (or perhaps something was marshalled into an interface). Duck allows you to manipulate and convert from interfaces in a very simple manner. Duck is very eager to fit the inputs to the wanted format.

Type Conversions

The most basic actions are conversions between the standard built-in types.

//true, true
b,ok := duck.Bool(1.0)
//false, true
b,ok = duck.Bool(0.0)

//"1337", true
s, ok := duck.String(1337)
//"true", true
s, ok := duck.String(true)

//56, true
i, ok := duck.Int("56.0")

//1.0, true
f, ok := duck.Float(true)

var vptr interface{}

v := 6.0
vptr := &v	//duck follows pointers

//"6.0",true
s, ok = duck.String(vptr)
//6,true
i,ok = duck.Int(vptr)
//6.0,true
f,ok = duck.Float(vptr)
//true,true
b,ok = duck.Bool(vptr)

Comparisons

Duck allows comparing interfaces with similar conversions as the type functions.

//true, true ("34.5" < 35)
out, ok := duck.Lt("34.5",35)
//false, true
out, ok = duck.Lt("34.5",34)

//true,true
out, ok = duck.Eq("1.0", true)

//false,true - this one is unusual, true is defined as 1 (as in c)
out, ok = duck.Eq("2.0", true)

//false,true - false is defined as 0
out, ok = duck.Eq("2.0", false)

//true, true (34.6 >= 34)
out,ok = duck.Gte(34.6, 34)

if duck.Cmp(45,45.32)==duck.LessThan {
	//true!
}

if duck.Cmp(45," LOL ")==duck.CantCompare {
	//true!
}

if duck.Cmp(45,45.0)==duck.Equals {
	//true!
}

Objects

Duck gets very liberal with its duck-typing for objects. The main function here is Get which gets an element from the object. Since duck just loves duck-typing, as long as the requested element can be found in the given object, it is extracted - no matter if the object is a map, struct or array/slice.

floatarray := []float32{0.0,1.0,2.0,3.0,4.0}

// 1.0, true
e,ok := duck.Get(floatarray,1)
e,ok = duck.Get(floatarray,1.0)
e,ok = duck.Get(floatarray,true)
e,ok = duck.Get(floatarray,"1.0")

//Python-style indexing!
//4.0,true
e, ok = duck.Get(floatarray,-1.0)

//Currently, only map[string] is supported - panics on other map types!
smap := map[string]string{"foo": "bar", "true": "wow", "1": "one"}

//"bar", true
s, ok := duck.Get(smap, "foo")
//"wow", true
s, ok = duck.Get(smap,true)
// "one", true
s, ok = duck.Get(smap,1)	//Note that string conversions ALWAYS convert 1.000 -> 1

st := struct {
	MyElement string
	SecondElement int
}{"woo",1337}

//"woo", true
sv, ok := duck.Get(st,"MyElement")
//nil, false
sv, ok = duck.Get(st,"Nonexisting")

Duck-Tags

Sometimes you want structs to be recognized by a special tag in Get. The duck tag allows you to do that.

val := struct{
	A1 string `duck:"lol"`
	A2 string `duck:"-"`
}{"foo","bar"}

//nil,false
v,ok := duck.Get(val,"A1")
v,ok = duck.Get(val,"A2")

//"foo", true
v, ok = duck.Get(val,"lol")

Set

Initial support for setting values is also available.

var integer int
//true
ok := duck.Set(&integer,"54")
if (intger==54) {
	//true!
}

var mystring string
//true
ok = duck.Set(&mystring,13.0)
if (mystring=="13") {
	//true!
}

var iface interface{}

//true
ok = duck.Set(&iface, true)
//true!
_,ok = iface.(bool)

//Currently, only map[string]interface{} is supported for setting values
// reflect makes it very difficult to set map values. Structs and arrays work fine.
mymap := map[string]interface{}{"foo":"bar"}
ok = duck.Set(&mymap,1337,"foo")
//mymap["foo"]=1337 now

//Arbitrary object depth is supported
mysuperobject := struct{
	A1 []interface{}
	A2 string
}{
	A1: []interface{}{"hello","world"},
}
//world
duck.Get(mysuperobject,"A1",1)

//sets "world" to "not world anymore"
ok = duck.Set(&m,"not world anymore","A1",1)


If you need speed

Duck itself is very general, but not particularly fast. To work in restricted environments where speed is critical, a limited version of duck was created: quack. Quack is located in the quack subfolder, with the same API. It is much quicker.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	LessThan    = -1
	GreaterThan = 1
	Equals      = 0
	CantCompare = -2
)

Variables used for Cmp

Functions

func Add

func Add(i1, i2 interface{}) (res interface{}, ok bool)

Add attempts to add two interfaces. It works similarly to expectations everywhere, with the extra 'extreme string ducktyping' twist.

"hello" + "world" = "helloworld"
true + 1 = 2
3.14 + 1 = 4.14
"23"+"42" = 65

func Bool

func Bool(i interface{}) (res bool, ok bool)

Bool attempts to convert the given interface into a boolean. There can be a loss of information in this one.

"hi" -> !ok
true -> true
"true" -> true
"false" -> false
"0.0" -> false
"3.34" -> true
1 -> true
1337 -> true
1.434 -> true
-1 -> false
nil -> false
0.0 -> false
0 -> false
"" -> false

func Cmp

func Cmp(arg1 interface{}, arg2 interface{}) int

Cmp performs a comparison between the two values, and returns the result of the comparison (LessThan, GreaterThan, Equals, CantCompare), which are defined as ints

func Copy

func Copy(copyfrom interface{}) (interface{}, error)

Copy performs a deep copy of the given interface. The copy makes sure that no pointers/maps are shared

between the original data and new points.

WARNING: This is not a real deep copy. It totally cheats at the moment. Do not use when you need

to preserve structs in output.

WARNING 2: Converts int to float. Ultimately, this function is not yet good for normal use. It is just

barely useful for our own internal usage. Feel free to fix it.

func Divide

func Divide(i1, i2 interface{}) (res float64, ok bool)

Divide attempts to convert to numbers, and divide the first by the second

func Eq

func Eq(arg1 interface{}, arg2 interface{}) (res bool, ok bool)

Eq is short-hand for Equal. Look at Equal for detailed description

func Equal

func Equal(arg1 interface{}, arg2 interface{}) (res bool, ok bool)

Equal attempts to check equality between two interfaces. If the values are not directly comparable thru DeepEqual, tries to do a "duck" comparison.

true true -> true
"true" true -> true
"1" true -> true
1.0 1 -> true
1.345 "1.345" -> true
50.0 true -> true
0.0 false -> true

func Float

func Float(i interface{}) (res float64, ok bool)

Float attempts to convert the given interface into a float

1 -> 1.0
"1.34" -> 1.34
1.34 -> 1.34
false -> 0.0
true -> 1.0
"false" -> 0.0
" 2.3 " -> !ok
nil -> 0.0

func Get

func Get(i interface{}, elem ...interface{}) (val interface{}, ok bool)

Get takes an object, and the element name/index to extract, and returns the element, as well as an ok boolean specifying if the element was found. Remember that only exported fields are available from structs One note: only `map[string]` is supported right now. maps of another type will cause get to panic! This is an active weakness in the current implementation. It should be enough to get data from arbitrary marshalled json.

Get also supports multiple args for multilevel data:

//returns deeplyNestedStruct->foo->bar
duck.Get(deeplyNestedStruct, "foo","bar")

func Gt

func Gt(arg1 interface{}, arg2 interface{}) (res bool, ok bool)

Gt returns true if arg1 > arg2

func Gte

func Gte(arg1 interface{}, arg2 interface{}) (res bool, ok bool)

Gte returns true if arg1 >= arg2

func Int

func Int(i interface{}) (res int64, ok bool)

Int attempts to convert the given interface into an integer

"1" -> 1
1 -> 1
1.0 -> 1
"1.0" -> 1
false -> 0
true -> 1
"1.3" -> !ok
nil -> 0

func JSONString

func JSONString(i interface{}) string

JSONString attempts to convert to a string... but if that fails it marshals the given data into json, and returns the json string. If it can't marshal, it just returns an empty string

func Keys

func Keys(i interface{}) (keys []string, ok bool)

Keys gets the field names by which the object can be accessed. Note that arrays do not return any keys

func Length

func Length(i interface{}) (l int, ok bool)

Length extracts the length of an array/map (anything that can have len() run on it)

func Lt

func Lt(arg1 interface{}, arg2 interface{}) (res bool, ok bool)

Lt returns true if arg1 < arg2

func Lte

func Lte(arg1 interface{}, arg2 interface{}) (res bool, ok bool)

Lte returns true if arg1 <= arg2

func Mod

func Mod(i1, i2 interface{}) (res float64, ok bool)

Mod finds the i1%i2.

func Multiply

func Multiply(i1, i2 interface{}) (res float64, ok bool)

Multiply tries to convert the two to numbers and multiply them

func Set

func Set(i interface{}, setto interface{}, elem ...interface{}) (ok bool)

Set attempts to set a subelement of the passed-in object. In the same way that Get gets the value, Set allows to set it. The only possibly confusing thing about Set is that the "to" value and the element names are reversed to allow for multiple arguments (as in Get)

v := map[string]string{"hi":"world"}
duck.Set(&v,45,"hi")
//now v["hi"] == "45"

v2 := map[string]interface{}{"foo":map[string]interface{}{"bar": 23}}
duck.Set(&v2,"hello!","foo","bar")
//v2["foo"]["bar"] == "hello!"

NOTE: Currently setting structs (ie, if setto is a struct) is non-functional if the receiving end is not interface{}. Also, only map[string]interface{} is supported of maps to receive values. You are risking panic if another map type is used

func String

func String(i interface{}) (res string, ok bool)

String attempts to convert the given interface into a string. Examples:

1 -> "1"
2.45 -> "2.45"
"hi" -> "hi"
false -> "false"
true -> "true"

func Subtract

func Subtract(i1, i2 interface{}) (res float64, ok bool)

Subtract attempts to perform i1-i2. It does not have any special weirdness, it simply converts the two to floats, and subtracts them.

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL