README.md in wisper-2.0.0.rc1 vs README.md in wisper-2.0.0

- old
+ new

@@ -1,13 +1,13 @@ # Wisper *A micro library providing Ruby objects with Publish-Subscribe capabilities* -[![Gem Version](https://badge.fury.io/rb/wisper.png)](http://badge.fury.io/rb/wisper) -[![Code Climate](https://codeclimate.com/github/krisleech/wisper.png)](https://codeclimate.com/github/krisleech/wisper) -[![Build Status](https://travis-ci.org/krisleech/wisper.png?branch=master)](https://travis-ci.org/krisleech/wisper) -[![Coverage Status](https://coveralls.io/repos/krisleech/wisper/badge.png?branch=master)](https://coveralls.io/r/krisleech/wisper?branch=master) +[![Gem Version](https://badge.fury.io/rb/wisper.svg)](http://badge.fury.io/rb/wisper) +[![Code Climate](https://codeclimate.com/github/krisleech/wisper.svg)](https://codeclimate.com/github/krisleech/wisper) +[![Build Status](https://travis-ci.org/krisleech/wisper.svg?branch=master)](https://travis-ci.org/krisleech/wisper) +[![Coverage Status](https://coveralls.io/repos/krisleech/wisper/badge.svg?branch=master)](https://coveralls.io/r/krisleech/wisper?branch=master) * Decouple core business logic from external concerns in Hexagonal style architectures * Use as an alternative to ActiveRecord callbacks and Observers in Rails apps * Connect objects based on context without permanence * React to events synchronously or asynchronously @@ -17,16 +17,16 @@ ## Installation Add this line to your application's Gemfile: ```ruby -gem 'wisper' +gem 'wisper', '2.0.0' ``` ## Usage -Any class with the `Wisper::Publisher` module included can broadcast events +Any class with the `Wisper::Publisher` module included can broadcast events to subscribed listeners. Listeners subscribe, at runtime, to the publisher. ### Publishing ```ruby @@ -45,11 +45,11 @@ end end end ``` -When a publisher broadcasts an event it can include number of arguments. +When a publisher broadcasts an event it can include any number of arguments. The `broadcast` method is also aliased as `publish`. You can also include `Wisper.publisher` instead of `Wisper::Publisher`. @@ -71,11 +71,11 @@ ```ruby class OrderNotifier def cancel_order_successful(order_id) order = Order.find_by_id(order_id) - + # notify someone ... end end ``` @@ -86,32 +86,63 @@ ```ruby cancel_order = CancelOrder.new cancel_order.on(:cancel_order_successful) { |order_id| ... } .on(:cancel_order_failed) { |order_id| ... } - + cancel_order.call(order_id) ``` +You can also subscribe to multiple events using `on` by passing +additional events as arguments. + +```ruby +cancel_order = CancelOrder.new + +cancel_order.on(:cancel_order_successful) { |order_id| ... } + .on(:cancel_order_failed, + :cancel_order_invalid) { |order_id| ... } + +cancel_order.call(order_id) +``` + +Do not `return` from inside a subscribed block, due to the way +[Ruby treats blocks](http://product.reverb.com/2015/02/28/the-strange-case-of-wisper-and-ruby-blocks-behaving-like-procs/) +this will prevent any subsequent listeners having their events delivered. + ### Handling Events Asynchronously ```ruby cancel_order.subscribe(OrderNotifier.new, async: true) ``` Wisper has various adapters for asynchronous event handling, please refer to [wisper-celluloid](https://github.com/krisleech/wisper-celluloid), -[wisper-sidekiq](https://github.com/krisleech/wisper-sidekiq) or -[wisper-activejob](https://github.com/krisleech/wisper-activejob). +[wisper-sidekiq](https://github.com/krisleech/wisper-sidekiq), +[wisper-activejob](https://github.com/krisleech/wisper-activejob), or +[wisper-que](https://github.com/joevandyk/wisper-que). -Depending on the adapter used the listener may need to be a class instead of an object. +Depending on the adapter used the listener may need to be a class instead of an object. In this situation, every method corresponding to events should be declared as a class method, too. For example: +```ruby +class OrderNotifier + # declare a class method if you are subscribing the listener class instead of its instance like: + # cancel_order.subscribe(OrderNotifier) + # + def self.cancel_order_successful(order_id) + order = Order.find_by_id(order_id) + + # notify someone ... + end +end +``` + ### ActionController ```ruby class CancelOrderController < ApplicationController - + def create cancel_order = CancelOrder.new cancel_order.subscribe(OrderMailer, async: true) cancel_order.subscribe(ActivityRecorder, async: true) @@ -130,11 +161,11 @@ If you wish to publish directly from ActiveRecord models you can broadcast events from callbacks: ```ruby class Order < ActiveRecord::Base include Wisper::Publisher - + after_commit :publish_creation_successful, on: :create after_validation :publish_creation_failed, on: :create private @@ -169,13 +200,16 @@ You might want to globally subscribe a listener to publishers with a certain class. ```ruby Wisper.subscribe(MyListener.new, scope: :MyPublisher) +Wisper.subscribe(MyListener.new, scope: MyPublisher) +Wisper.subscribe(MyListener.new, scope: "MyPublisher") +Wisper.subscribe(MyListener.new, scope: [:MyPublisher, :MyOtherPublisher]) ``` -This will subscribe the listener to all instances of `MyPublisher` and its +This will subscribe the listener to all instances of the specified class(es) and their subclasses. Alternatively you can also do exactly the same with a publisher class itself: ```ruby @@ -191,36 +225,36 @@ # do stuff end ``` Any events broadcast within the block by any publisher will be sent to the -listeners. +listeners. This is useful for capturing events published by objects to which you do not have access in a given context. Temporary Global Listeners are threadsafe. ## Subscribing to selected events By default a listener will get notified of all events it can respond to. You -can limit which events a listener is notified of by passing an string, symbol, +can limit which events a listener is notified of by passing a string, symbol, array or regular expression to `on`: ```ruby -post_creater.subscribe(PusherListener.new, on: :create_post_successful) +post_creator.subscribe(PusherListener.new, on: :create_post_successful) ``` ## Prefixing broadcast events If you would prefer listeners to receive events with a prefix, for example `on`, you can do so by passing a string or symbol to `prefix:`. ```ruby -post_creater.subscribe(PusherListener.new, prefix: :on) +post_creator.subscribe(PusherListener.new, prefix: :on) ``` -If `post_creater` where to broadcast the event `post_created` the subscribed +If `post_creator` were to broadcast the event `post_created` the subscribed listeners would receive `on_post_created`. You can also pass `true` which will use the default prefix, "on". ## Mapping an event to a different method @@ -229,11 +263,11 @@ ```ruby report_creator.subscribe(MailResponder.new, with: :successful) ``` -This is pretty useless unless used in conjuction with `on:`, since all events +This is pretty useless unless used in conjunction with `on:`, since all events will get mapped to `:successful`. Instead you might do something like this: ```ruby report_creator.subscribe(MailResponder.new, on: :create_report_successful, with: :successful) @@ -253,37 +287,59 @@ ``` You could also alias the method within your listener, as such `alias successful create_report_successful`. -## RSpec +## Testing -Please see [wisper-rspec](https://github.com/krisleech/wisper-rspec). +Testing matchers and stubs are in seperate gems. -## Clearing Global Listeners +* [wisper-rspec](https://github.com/krisleech/wisper-rspec) +* [wisper-minitest](https://github.com/digitalcuisine/wisper-minitest) +### Clearing Global Listeners + If you use global listeners in non-feature tests you _might_ want to clear them in a hook to prevent global subscriptions persisting between tests. ```ruby after { Wisper.clear } ``` +## Need help? + +The [Wiki](https://github.com/krisleech/wisper/wiki) has more examples, +articles and talks. + +Got a specific question, try the +[Wisper tag on StackOverflow](http://stackoverflow.com/questions/tagged/wisper). + ## Compatibility -Tested with MRI 1.9.x, MRI 2.0.0, JRuby (1.9 and 2.0 mode) and Rubinius (1.9 -mode). +Tested with MRI 2.x, JRuby and Rubinius. See the [build status](https://travis-ci.org/krisleech/wisper) for details. ## Running Specs ``` -rspec spec +bundle exec rspec ``` -There is both a `Rakefile` and `Guardfile`, if you like you prefer to run the -specs using `guard-rspec` or `rake`. +To run the specs on code changes try [entr](http://entrproject.org/): + +``` +ls **/*.rb | entr bundle exec rspec +``` + +## Contributing + +Please read the [Contributing Guidelines](https://github.com/krisleech/wisper/blob/master/CONTRIBUTING.md). + +## Security + +* gem releases are [signed](http://guides.rubygems.org/security/) ([public key](https://github.com/krisleech/wisper/blob/master/gem-public_cert.pem)) +* commits are GPG signed ([public key](https://pgp.mit.edu/pks/lookup?op=get&search=0x3ABC74851F7CCC88)) ## License (The MIT License)