Skip to content

Commit

Permalink
Merge pull request #5 from atarikguney/master
Browse files Browse the repository at this point in the history
Corrected some of the grammatical and contextual errors.
  • Loading branch information
olebedev committed Sep 30, 2017
2 parents 9110dba + a62d24e commit a2d0ac5
Showing 1 changed file with 27 additions and 25 deletions.
52 changes: 27 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Emitter [![wercker status](https://app.wercker.com/status/e5a44746dc89b513ed28e8a18c5c05c2/s "wercker status")](https://app.wercker.com/project/bykey/e5a44746dc89b513ed28e8a18c5c05c2) [![Coverage Status](https://coveralls.io/repos/olebedev/emitter/badge.svg?branch=HEAD&service=github)](https://coveralls.io/github/olebedev/emitter?branch=HEAD) [![godoc](http://img.shields.io/badge/godoc-reference-blue.svg?style=flat)](https://godoc.org/github.com/olebedev/emitter) [![Code Climate](https://codeclimate.com/github/olebedev/emitter/badges/gpa.svg)](https://codeclimate.com/github/olebedev/emitter)

Package emitter implements channel based pubsub pattern. The design goals are use Golang concurrency model instead of flat callbacks and the simplest API to understand and use.

The emitter package implements a channel-based pubsub pattern. The design goals are to use Golang concurrency model instead of flat callbacks and to design a very simple API that is easy to consume.
## Why?
Go has expressive concurrency model but nobody doesn't use it properly for pubsub, as I see(at the end of 2015). I had implemented my own as I didn't find any acceptable. Please, read [this article](#) for more information.
Go has expressive concurrency model but nobody uses it properly for pubsub as far as I can tell (in the year 2015). I implemented my own solution as I could not find any other that meets my expectations. Please, read [this article](#) for more information.


## What it does?
Expand All @@ -22,57 +21,61 @@ Go has expressive concurrency model but nobody doesn't use it properly for pubsu
```go
e := &emitter.Emitter{}
go func(){
<-e.Emit("change", 42) // wait for event sent successfully
<-e.Emit("change", 42) // wait for the event sent successfully
<-e.Emit("change", 37)
e.Off("*") // unsubscribe any listeners
}()

for event := range e.On("change") {
// do something with event.Args
plintln(event.Int(0)) // cast first argument to int
plintln(event.Int(0)) // cast the first argument to int
}
// listener channel was closed
```

## Constructor
`emitter.New` takes a `uint` as first argument to indicate what buffer size should be used for listeners. Also possible to change capacity at runtime: `e.Cap = 10`.
`emitter.New` takes a `uint` as the first argument to indicate what buffer size should be used for listeners. It is also possible to change the buffer capacity during runtime using the following code: `e.Cap = 10`.

By default emitter use goroutine per listener to send an event. You may want to change it via `e.Use("*", emitter.Sync)`. I recommend to specify middlewares(see [below](#middlewares)) for the emitter at start.
By default, the emitter uses one goroutine per listener to send an event. You can change that behavior from asynchronous to synchronous by passing `emitter.Sync` flag as shown here: `e.Use("*", emitter.Sync)`. I recommend specifying middlewares(see [below](#middlewares)) for the emitter at the begining.

## Wildcard
The package allows publications and subscriptions with wildcard. This feature based on `path.Match` function.
The package allows publications and subscriptions with wildcard. This feature is based on `path.Match` function.

Example:

```go
go e.Emit("something:special", 42)
event := <-e.Once("*") // grub any events
event := <-e.Once("*") // search any events
println(event.Int(0)) // will print 42

// or emit event with wildcard path
// or emit an event with wildcard path
go e.Emit("*", 37) // emmit for everyone
event := <-e.Once("something:special")
println(event.Int(0)) // will print 37
```

Note that wildcard uses `path.Match`, but the lib is not return errors related for parsing. As this is not main feature. Please check the topic explicitly via `emitter.Test()` function.

Note that the wildcard uses `path.Match`, but the lib does not return errors related to parsing for this is not the main feature. Please check the topic specifically via `emitter.Test()` function.

## Middlewares
Important part of pubsub package is predicates. It should be allow to skip some event. Middlewares solve this problem.
Middleware is a function that takes a pointer to the Event as first argument. All that middlewares can do is just modify the event. It allows to skip sending it needed or modify event's agruments. Or specify the mode to describe how exactly event should be emitted(see [below](#flags)).
An important part of pubsub package is the predicates. It should be allowed to skip some events. Middlewares address this problem.
The middleware is a function that takes a pointer to the `Event` as its first argument. A middleware is capable of doing the following items:

There are two ways to add middleware into emitting flow:
1. It allows you to modify an event.
2. It allows skipping the event emitting if needed.
3. It also allows modification of the event's arguments.
4. It allows you to specify the mode to describe how exactly an event should be emitted(see [below](#flags)).

There are two ways to add middleware into the event emitting flow:

- via .On("event", middlewares...)
- via .Use("event", middlewares...)

The first add middlewares ony for this listener, but the second add middlewares for all events with given topic.
The first one add middlewares only for a particular listener, while the second one adds middlewares for all events with a given topic.

For example:
```go
// use synchronous mode for all events, it also depends
// on emitter capacity(buffered/unbuffered channels)
// on the emitter capacity(buffered/unbuffered channels)
e.Use("*", emitter.Sync)
go e.Emit("something:special", 42)

Expand All @@ -88,9 +91,9 @@ panic("will never happen")


## Flags
Flags needs to describe how exactly the event should be emitted. Available options are listed [here](https://godoc.org/github.com/olebedev/emitter#Flag).
Flags needs to describe how exactly the event should be emitted. The available options are listed [here](https://godoc.org/github.com/olebedev/emitter#Flag).

Every event(`emitter.Event`) has field `.Flags` that contains flags as binary mask.
Every event(`emitter.Event`) has a field called`.Flags` that contains flags as a binary mask.
Flags can be set only via middlewares(see above).

There are several predefined middlewares to set needed flags:
Expand All @@ -102,7 +105,7 @@ There are several predefined middlewares to set needed flags:
- [`emitter.Sync`](https://godoc.org/github.com/olebedev/emitter#Sync)
- [`emitter.Reset`](https://godoc.org/github.com/olebedev/emitter#Reset)

You can combine it as a chain:
You can chain the above flags as shown below:
```go
e.Use("*", emitter.Void) // skip sending for any events
go e.Emit("surprise", 65536)
Expand All @@ -111,7 +114,7 @@ pintln(event.Int(0)) // prints 65536
```

## Cancellation
Golang give as more control for asynchronous flow. We may know it the channel is blocked and we may discard sending as well. So, emitter allows to discard emitting based on this language feature. It's good practice to design your application with timeouts and cancellation possibilities.
Golang provides developers with a powerful control for its concurrency flow. We know the state of a channel and whether it would block a go routine or not. So, by using this language construct, we can discard any emitted event. It's a good practice to design your application with timeouts so that you cancel the operations if needed as shown below:

Assume you have time out to emit the events:
```go
Expand All @@ -126,11 +129,10 @@ case <-time.After(timeout):
}
```

It's pretty useful to control any goroutines inside th emitter instance.

It's pretty useful to control any goroutines inside an emitter instance.

## Callbacks-only usage
Use emitter in traditional way is also possible. If you don't need async mode or you very attentive to application resources. The recipe is use emitter with zero capacity, define `FlagVoid` to skip sending into the listener channel and use middleware as callback:
using the emitter in more traditional way is possible, as well. If you don't need the async mode or you very attentive to the application resources, then the recipe is to use an emitter with zero capacity or to use `FlagVoid` to skip sending into the listener channel and use middleware as callback:

```go
e := &emitter.Emitter{}
Expand Down Expand Up @@ -167,7 +169,7 @@ See the api [here](https://godoc.org/github.com/olebedev/emitter#Group).


## Event
Event is struct that contain event [info](https://godoc.org/github.com/olebedev/emitter#Event). Also Event has some helpers to cast arguments into `bool`, `string`, `float64`, `int` by given argiment index with optional default value.
Event is a struct that contains event [information](https://godoc.org/github.com/olebedev/emitter#Event). Also, th event has some helpers to cast various arguments into `bool`, `string`, `float64`, `int` by given argument index with an optional default value.

Example:
```go
Expand Down

0 comments on commit a2d0ac5

Please sign in to comment.