{"id":15465006,"url":"https://github.com/blocknotes/eventish","last_synced_at":"2025-04-22T10:43:41.611Z","repository":{"id":39385531,"uuid":"493127623","full_name":"blocknotes/eventish","owner":"blocknotes","description":"A simple and composable event library","archived":false,"fork":false,"pushed_at":"2022-06-01T06:15:43.000Z","size":97,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-15T00:17:25.597Z","etag":null,"topics":["events","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/blocknotes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["blocknotes"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2022-05-17T06:43:20.000Z","updated_at":"2022-09-01T10:24:33.000Z","dependencies_parsed_at":"2022-09-03T07:53:02.887Z","dependency_job_id":null,"html_url":"https://github.com/blocknotes/eventish","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Feventish","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Feventish/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Feventish/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/blocknotes%2Feventish/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/blocknotes","download_url":"https://codeload.github.com/blocknotes/eventish/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250222421,"owners_count":21394863,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["events","ruby"],"created_at":"2024-10-02T00:44:16.102Z","updated_at":"2025-04-22T10:43:41.590Z","avatar_url":"https://github.com/blocknotes.png","language":"Ruby","readme":"# Eventish\n\n[![Gem Version](https://badge.fury.io/rb/eventish.svg)](https://badge.fury.io/rb/eventish)\n[![Specs Rails 6](https://github.com/blocknotes/eventish/actions/workflows/rails6.yml/badge.svg)](https://github.com/blocknotes/eventish/actions/workflows/rails6.yml)\n[![Specs Rails 7](https://github.com/blocknotes/eventish/actions/workflows/rails7.yml/badge.svg)](https://github.com/blocknotes/eventish/actions/workflows/rails7.yml)\n[![Linters](https://github.com/blocknotes/eventish/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/eventish/actions/workflows/linters.yml)\n\nYet another events library with a _simple_ API to handle... events :tada:\n\nMain features:\n- _composable_: just require the components that you need;\n- with [adapters](#adapters): support ActiveSupport::Notifications and Wisper for pub/sub events;\n- with [async events](#async-events): support ActiveJob for events background execution;\n- with [callbacks wrapper](#callbacks): support ActiveRecord callbacks;\n- with [plugins](#plugins): a simple logger and a Rails logger are included;\n- with conditional event execution (overriding `callable?`).\n\nThis component can be useful to:\n- decouple callbacks from the side-effect;\n- permit to test the side-effects in isolation;\n- permit to spy/block the side-effects;\n- permit to execute the side-effects from other contexts.\n\nPlease :star: if you like it.\n\n\u003e Do you want to speak by events? Try _eventish_ :smile:\n\n## Install\n\n- Add to your Gemfile: `gem 'eventish'` (and execute `bundle`)\n- Create an initializer - ex. _config/initializers/eventish.rb_:\n\n```rb\nrequire 'eventish/adapters/active_support'\n\nEventish.setup do |config|\n  config.adapter = Eventish::Adapters::ActiveSupport\nend\n\nRails.configuration.to_prepare do\n  # NOTE: required to load the event descendants when eager_load is off\n  unless Rails.configuration.eager_load\n    events = Rails.root.join('app/events/**/*.rb').to_s\n    Dir[events].sort.each { |event| require event }\n  end\nend\n\nRails.configuration.after_initialize do\n  Eventish::SimpleEvent.subscribe_all # NOTE: events will be available after this point\n\n  Eventish.publish('app_loaded') # just a test event\nend\n```\n\n- Create some events - ex. _app/events/main/app_loaded_event.rb_:\n\n```rb\nmodule Main\n  class AppLoadedEvent \u003c Eventish::SimpleEvent\n    def call(_none, _options = {})\n      puts '\u003e App loaded event'\n    end\n  end\nend\n```\n\nFor a complete example please take a look at the [dummy app](spec/dummy) in the specs.\n\n### Adapters\n\nUsed for events subscription and publishing.\n\n_ActiveSupport Notification_:\n\n```rb\n# initializer setup\nrequire 'eventish/adapters/active_support'\n\nEventish.setup do |config|\n  config.adapter = Eventish::Adapters::ActiveSupport\nend\n```\n\n_Wisper_ (NOTE: around callback wrappers are not supported):\n\n```rb\n# initializer setup\nrequire 'wisper'\nrequire 'eventish/adapters/wisper'\n\nEventish.setup do |config|\n  config.adapter = Eventish::Adapters::Wisper\nend\n```\n\n### Simple events\n\nGeneric events not related to a specific component.\n\n```rb\n# initializer setup\nRails.configuration.after_initialize do\n  # Subscribe all Eventish::SimpleEvent descendants using the configured adapter\n  # The descendants event classes must be loaded before this point - see eager_load notes in the Install section\n  Eventish::SimpleEvent.subscribe_all\nend\n```\n\nSample event - ex. _app/events/main/test_event.rb_:\n\n```rb\nmodule Main\n  class TestEvent \u003c Eventish::SimpleEvent\n    def call(_none, _options = {})\n      puts '\u003e A test event'\n    end\n\n    class \u003c\u003c self\n      def event_name\n        # this is optional, if not set the class name to string will be used\n        'some_event'\n      end\n    end\n  end\nend\n```\n\nPublish the event with:\n\n```rb\nEventish.publish('some_event')\n```\n\n### Async events\n\nEvents executed in a background process.\nOnly _ActiveJob_ is supported for now.\n\n```rb\n# initializer setup\nrequire 'active_job/railtie'\nrequire 'eventish/active_job_event'\n\nRails.configuration.after_initialize do\n  Eventish::ActiveJobEvent.subscribe_all\nend\n```\n\nSample event - ex. _app/events/notifications/user_after_save_commit_event.rb_:\n\n```rb\nmodule Notifications\n  class UserAfterCommitEvent \u003c Eventish::ActiveJobEvent\n    def call(user, _options = {})\n      Rails.logger.info \"\u003e\u003e\u003e User ##{user.id} after commit notification\"\n    end\n  end\nend\n```\n\n### Callbacks\n\nWrappers for ActiveRecord callbacks using the postfix `_event` (ex. `after_commit_event SomeEvent`).\n\n```rb\n# initializer setup\nrequire 'eventish/active_record/callback'\n```\n\n```rb\n# sample model\nclass SomeModel \u003c ActiveRecord::Base\n  extend ::Eventish::ActiveRecord::Callback\n\n  before_validation_event SomeBeforeValidationEvent\nend\n```\n\nThe related callback will be setup by the wrapper and the specified event class will be invoked accordingly.\n\n### Plugins\n\nA plugins system is available for custom processing, a logger and a Rails logger are included in the gem.\n\n```rb\n# initializer setup\nrequire 'eventish/plugins/rails_logger' # without rails_ for a simple stdout logger\n\nEventish.setup do |config|\n  config.before_event = [Eventish::Plugins::RailsLogger]\n  config.after_event = [Eventish::Plugins::RailsLogger]\nend\n```\n\nA sample plugin:\n\n```rb\nmodule Eventish::Plugins::RailsLogger\n  class \u003c\u003c self\n    def call(target, _args, event:, hook: nil, \u0026_block)\n      Rails.logger.debug \"EVENT: #{hook} #{event.class.event_name} on #{target.inspect}\"\n    end\n  end\nend\n```\n\nPlugins can also be configured for single events overriding _before_event_ and _after_event_.\n\n### Conditional events\n\nOptionally an event can override the `callable?` method to define preconditions on the execution of the `call` method.\n\nExample:\n\n```rb\nclass TestEvent \u003c Eventish::SimpleEvent\n  def callable?(target)\n    target.ready?\n  end\n\n  def call(target, _options = {})\n    puts '\u003e A test event'\n  end\nend\n```\n\n## Do you like it? Star it!\n\nIf you use this component just star it. A developer is more motivated to improve a project when there is some interest.\n\nOr consider offering me a coffee, it's a small thing but it is greatly appreciated: [about me](https://www.blocknot.es/about-me).\n\n## Contributors\n\n- [Mattia Roccoberton](https://www.blocknot.es): author\n\n## License\n\nThe gem is available as open-source under the terms of the [MIT](LICENSE.txt).\n","funding_links":["https://github.com/sponsors/blocknotes"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Feventish","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fblocknotes%2Feventish","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fblocknotes%2Feventish/lists"}