Skip to content
My own gem implentation of the Observer / Subscribe - Publish design pattern for use in my projects, and for anyone else who wishes to use it.
Ruby Shell
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin
lib
spec
.gitignore
.rspec
.travis.yml
CODE_OF_CONDUCT.md
Gemfile
LICENSE.txt
README.md
Rakefile
bottled_observers.gemspec

README.md

BottledObservers

The best thing to happen since bottled water

Wait, wasn't that bottled_decorators?, or was it bottled_services?, I am starting to lose track. Anyway! bottled_observers are an easy-to-use solution, for the Observer / Subscribe-Publish pattern in ruby. all you need to worry about is adding your business logic, let bottled_observers handle the rest!

Installation

Add this line to your application's Gemfile:

gem 'bottled_observers'

And then execute:

$ bundle

Or install it yourself as:

$ gem install bottled_observers

Usage

bottled_observers has two main modules you need to be aware of; BottledObserver and BottledObservable.

BottledObserver

This module should be included in your observer class, and that observer class should only contain a single public method: #call.
eg:

class SendPushNotification
  include BottledObserver # <-- just like this!
  
  def call
    # Some intense and awesome logic to notify the hell out of them users.
  end
end

That is all there is to it, your observer is now ready to rock'n'roll.

BottledObservable

This module is included in any class that should allow observers to subscribe to it.
eg:

class Product
  include BottledObservable # <-- and just like this!
  
  # The rest of the class....
end

And that is it, your whole bottled_observers subscribe/publish cycle is ready to go.

The Subscribe / Publish Cycle

There are three main methods available in your arsenal that you need to be aware of:

  • #add_subscription
  • #modified
  • #publish

These are available to your observable class instances, so if we wanted to subscribe our SendPushNotification observer to an instance of our Product class, we could do the following:

@product = Product.find(1)                     # <-- instantiate Product from a record in the database. 
@product.add_subscription SendPushNotification # <-- add a subscription for the SendPushNotification class

We now have a SendPushNotification observer lying in wait for any publications from the @product instance.
Then, when we want to notify the observer(s) of any changes to the instance, just set the state of the instance as modified using the #modified method, and publish this change of state to its subscribers:

Example case: sending push notifications after a successful save of the @product instance.

# The product is only in a modified state if the save is successful
@product.modified if @product.save
 
# If the @product's state is 'modified' the observers call method will be excecuted. 
# If the state is not modified, nothing will happen.
@product.publish

Super simple!

Another thing that needs to be noted is, after publishing, the instances modified state is reset, so to publish anything again, it must be set again.

@product.modified
@product.publish # <-- push notifications sent.
@product.publish # <-- push notifications not sent.
@product.modified
@product.publish # <-- push notifications sent.
@product.modified
@product.publish # <-- push notifications sent.

Extras

You can have as many observers subscribed to a single instance as you like:

@product.add_subscription SendPushNotification
@product.add_subscription MailToMailingList
@product.add_subscription CreateRecentActivityRecord

@product.modified if @product.save
@product.publish

#subscriptions will return an array of current observer instances subscribed to the observable instance:

@product.add_subscription SendPushNotification
@product.subscriptions #=> [#<SendPushNotification:0x00...>]

To remove observers of a particular class, use #remove_subscription:

@product.add_subscription SendPushNotification
@product.subscriptions #=> [#<SendPushNotification:0x00...>]
@product.remove_subscription SendPushNotification
@product.subscriptions #=> []

Or use #remove_subscriptions (notice the plural) to, you guessed it, remove all observers:

@product.add_subscription SendPushNotification
@product.add_subscription MailToMailingList
@product.add_subscription CreateRecentActivityRecord
@product.subscriptions #=> [#<SendPushNotification:0x00...>, ...]

@product.remove_subscriptions
@product.subscriptions #=> []

You can also check if your product is in a modified state by checking if it is #publishable?:

@product.publishable? #=> false
@product.modified
@product.publishable? #=> true

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rspec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/John-Hayes-Reed/bottled_observers. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the BottledObservers project’s codebases, issue trackers, chat rooms and mailing lists is expected to have a beer or two before and enjoy life. Oh yeah and apparently this too: code of conduct.

You can’t perform that action at this time.