mirror of
https://github.com/robertkrimen/otto.git
synced 2025-12-24 12:58:05 +08:00
Other methods callable on Maps (#254)
Background:
When methods are attached on a map type like so:
type Foo map[string]string
func (f Foo) Bar() {
fmt.Printf("Hello World");
}
vm := otto.New();
vm.Set("foo", Foo{});
vm.Run(`
foo.Bar();
`);
You get:
Error in Run: TypeError: 'Bar' is not a function
The Fix:
I looked into how/why the same works for arrays. After
all array properties are tested (such as length, and any integer-based members),
the code then looks for any methods attached to that type.
This change literally copies that code over into
maps.
This is very useful when working with the http.Request object which
has the http.Header type that is a map[string][]string, with a lot
of useful methods attached to it.
Added unit test to support/guard the change (and map had no test before)
Responded to PR comments
This commit is contained in:
@@ -53,6 +53,14 @@ func goMapGetOwnProperty(self *_object, name string) *_property {
|
||||
return &_property{self.runtime.toValue(value.Interface()), 0111}
|
||||
}
|
||||
|
||||
// Other methods
|
||||
if method := self.value.(*_goMapObject).value.MethodByName(name); (method != reflect.Value{}) {
|
||||
return &_property{
|
||||
value: self.runtime.toValue(method.Interface()),
|
||||
mode: 0110,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
40
type_go_map_test.go
Normal file
40
type_go_map_test.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package otto
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type GoMapTest map[string]int
|
||||
|
||||
func (s GoMapTest) Join() string {
|
||||
joinedStr := ""
|
||||
|
||||
// Ordering the map takes some effort
|
||||
// because map iterators in golang are unordered by definition.
|
||||
// So we need to extract keys, sort them, and then generate K/V pairs
|
||||
// All of this is meant to ensure that the test is predictable.
|
||||
keys := make([]string, len(s))
|
||||
i := 0
|
||||
for key, _ := range s {
|
||||
keys[i] = key
|
||||
i++
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, key := range keys {
|
||||
joinedStr += key + ": " + fmt.Sprintf("%d", s[key]) + " "
|
||||
}
|
||||
return joinedStr
|
||||
}
|
||||
|
||||
func TestGoMap(t *testing.T) {
|
||||
tt(t, func() {
|
||||
test, vm := test()
|
||||
vm.Set("TestMap", GoMapTest{"one": 1, "two": 2, "three": 3})
|
||||
is(test(`TestMap["one"]`).export(), 1)
|
||||
is(test(`TestMap.Join()`).export(), "one: 1 three: 3 two: 2 ")
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user