Skip to content

Commit

Permalink
refactor event emit to accept variadic args
Browse files Browse the repository at this point in the history
  • Loading branch information
maxence-charriere committed Dec 22, 2018
1 parent 5a4eb32 commit d7f7732
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 39 deletions.
6 changes: 3 additions & 3 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,9 @@ func NewMsg(key string) Msg {
return &msg{key: key}
}

// Emit emits the event with the given value.
func Emit(e Event, value interface{}) {
events.Emit(e, value)
// Emit emits the event with the given arguments.
func Emit(e Event, args ...interface{}) {
events.Emit(e, args...)
}

// NewSubscriber creates an event subscriber to return when implementing the
Expand Down
2 changes: 1 addition & 1 deletion app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestApp(t *testing.T) {
assert.NotNil(t, app.Dock())
assert.NotNil(t, app.NewStatusMenu(app.StatusMenuConfig{}))

app.Emit("test", nil)
app.Emit("test")

app.UI(func() {
app.Logf("hello")
Expand Down
10 changes: 5 additions & 5 deletions drivers/mac/driver_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,17 +279,17 @@ func (d *Driver) onRun(in map[string]interface{}) interface{} {
app.NewWindow(d.DefaultWindow)
}

d.events.Emit(app.Running, nil)
d.events.Emit(app.Running)
return nil
}

func (d *Driver) onFocus(in map[string]interface{}) interface{} {
d.events.Emit(app.Focused, nil)
d.events.Emit(app.Focused)
return nil
}

func (d *Driver) onBlur(in map[string]interface{}) interface{} {
d.events.Emit(app.Blurred, nil)
d.events.Emit(app.Blurred)
return nil
}

Expand All @@ -300,7 +300,7 @@ func (d *Driver) onReopen(in map[string]interface{}) interface{} {
app.NewWindow(d.DefaultWindow)
}

d.events.Emit(app.Reopened, nil)
d.events.Emit(app.Reopened)
return nil
}

Expand All @@ -323,7 +323,7 @@ func (d *Driver) onFileDrop(in map[string]interface{}) interface{} {
}

func (d *Driver) onClose(in map[string]interface{}) interface{} {
d.events.Emit(app.Closed, nil)
d.events.Emit(app.Closed)

d.UI(func() {
d.stop()
Expand Down
2 changes: 1 addition & 1 deletion drivers/mac/menubar.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func (m *AppMenu) Render() string {

// OnPreferences is the function called when the Preferences button is clicked.
func (m *AppMenu) OnPreferences() {
app.Emit(PreferencesRequested, nil)
app.Emit(PreferencesRequested)
}

// EditMenu is a component that describes the default edit menu.
Expand Down
2 changes: 1 addition & 1 deletion drivers/test/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (d *Driver) Run(c app.DriverConfig) error {
defer cancel()
d.stop = cancel

d.events.Emit(app.Running, nil)
d.events.Emit(app.Running)

for {
select {
Expand Down
55 changes: 31 additions & 24 deletions event.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ type Subscriber struct {
unsuscribes []func()
}

// Subscribe subscribes a function to the given key.
// It panics if f is not a func.
// Subscribe subscribes a function to the given event. Emit fails if the
// subscribbed func have more arguments than the emitted event.
//
// Panics if f is not a func.
func (s *Subscriber) Subscribe(e Event, f interface{}) *Subscriber {
unsubscribe := s.Events.subscribe(e, f)
s.unsuscribes = append(s.unsuscribes, unsubscribe)
Expand Down Expand Up @@ -101,37 +103,42 @@ func (r *EventRegistry) unsubscribe(e Event, id string) {
}
}

// Emit emits the event with the given value.
func (r *EventRegistry) Emit(e Event, v interface{}) {
// Emit emits the event with the given arguments.
func (r *EventRegistry) Emit(e Event, args ...interface{}) {
r.mutex.RLock()
defer r.mutex.RUnlock()

for _, h := range r.handlers[e] {
val := reflect.ValueOf(h.Handler)
typ := val.Type()

if typ.NumIn() == 0 {
r.ui <- func() {
val.Call(nil)
}
return
if err := r.callHandler(h.Handler, args...); err != nil {
Log("emitting %s failed: %s", e, err)
}
}
}

argVal := reflect.ValueOf(v)
argTyp := typ.In(0)
func (r *EventRegistry) callHandler(h interface{}, args ...interface{}) error {
v := reflect.ValueOf(h)
t := v.Type()

if !argVal.Type().ConvertibleTo(argTyp) {
Log("dispatching event %s failed: %s",
e,
errors.Errorf("can't convert %s to %s", argVal.Type(), argTyp),
)
return
argsv := make([]reflect.Value, t.NumIn())

for i := 0; i < t.NumIn(); i++ {
argt := t.In(i)

if i >= len(args) {
return errors.Errorf("missing %v at index %v", argt, i)
}

r.ui <- func() {
val.Call([]reflect.Value{
argVal.Convert(argTyp),
})
argv := reflect.ValueOf(args[i])
if !argv.Type().ConvertibleTo(argt) {
return errors.Errorf("arg at index %v is not a %v: %v", i, argt, argv.Type())
}

argsv[i] = argv.Convert(argt)
}

r.ui <- func() {
v.Call(argsv)
}

return nil
}
20 changes: 16 additions & 4 deletions event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestEventRegistry(t *testing.T) {
panic bool
}{
{
scenario: "register and dispatch without arg",
scenario: "register and emit without arg",
subName: "test",
handler: func(called *bool) interface{} {
return func() {
Expand All @@ -35,7 +35,7 @@ func TestEventRegistry(t *testing.T) {
dispArg: nil,
},
{
scenario: "register without arg and dispatch with arg",
scenario: "register without arg and emit with arg",
subName: "test",
handler: func(called *bool) interface{} {
return func() {
Expand All @@ -47,7 +47,7 @@ func TestEventRegistry(t *testing.T) {
dispArg: "foobar",
},
{
scenario: "register and dispatch with arg",
scenario: "register and emit with arg",
subName: "test",
handler: func(called *bool) interface{} {
return func(arg string) {
Expand All @@ -63,7 +63,19 @@ func TestEventRegistry(t *testing.T) {
dispArg: "hello",
},
{
scenario: "register and dispatch with bad arg",
scenario: "register and emit without enough args",
subName: "test",
handler: func(called *bool) interface{} {
return func(string, bool) {
*called = true
}
},
called: false,
dispName: "test",
dispArg: "hello",
},
{
scenario: "register and emit with bad arg",
subName: "test",
handler: func(called *bool) interface{} {
return func(arg int) {
Expand Down
2 changes: 2 additions & 0 deletions internal/core/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
)

func TestDriver(t *testing.T) {
app.Logger = t.Logf

d := &Driver{}
require.Implements(t, (*app.Driver)(nil), d)

Expand Down

0 comments on commit d7f7732

Please sign in to comment.