ventable 1.0.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: d49bbdbaf27b03c942ba8887eb4eca4c89f63cbc
4
- data.tar.gz: c75ae281c96bfa5998c6f338ba5fd6d5bb164ace
2
+ SHA256:
3
+ metadata.gz: 6f8a7adee18ece871971236ea00ee70c35c278259fed5cd499c1f3c8d5e097d0
4
+ data.tar.gz: 4e4137f676a3374e17377db94ede9c59d232358f9bc82e3fbbbf90b817bbe514
5
5
  SHA512:
6
- metadata.gz: 7d130ab305df24c7f31e1fc11dcf7cc64c560edd2311ff6330ebeb33394ed819e444795b8f6c5fb3aff8ba9371c96c746dbec17db3ac3b368a149891bde5fc0c
7
- data.tar.gz: 2f12228bb3d42a58d7534f077844b26c5f1212c104b5da2bbf8aa4facb2f1783f86cfa1abc10e8b08982cbcfd6a07efbd6dd8f8afb9e76e42ecd271e06f07887
6
+ metadata.gz: 85a2ae18e873826a4ac34790d99ac5ed4f65e9ab2995e71edcf14b7cd78f86507df842c3c78ecafaae8df21e533e4c0fa39f765429ec9992056a776caf7fd4df
7
+ data.tar.gz: fa01a1e9de8962f299fa332ac542d34389eb853a9ddce5047dd85fbf5897e377a139ac6f598fe2112e9ba20361a8ca5564238ec9c940a203812dbe8d7ad6a806
@@ -0,0 +1,36 @@
1
+ name: Rubocop
2
+
3
+ on:
4
+ push:
5
+ branches: [ "main" ]
6
+ pull_request:
7
+ branches: [ "main" ]
8
+
9
+ jobs:
10
+ build:
11
+ name: Rubocop
12
+ runs-on: ubuntu-latest
13
+ permissions:
14
+ contents: read
15
+ packages: write
16
+
17
+ strategy:
18
+ matrix:
19
+ ruby-version: ['2.7', '3.0', '3.1', '3.2']
20
+
21
+ steps:
22
+ - uses: actions/checkout@v3
23
+ - name: Set up Ruby ${{ matrix.ruby-version }}
24
+ uses: ruby/setup-ruby@ec02537da5712d66d4d50a0f33b7eb52773b5ed1
25
+ with:
26
+ ruby-version: ${{ matrix.ruby-version }}
27
+
28
+ - name: Bundle Install
29
+ run: |
30
+ bundle check || bundle install -j 5
31
+
32
+ - name: Rubocop
33
+ run: |
34
+ bundle exec rubocop
35
+
36
+
@@ -0,0 +1,34 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+ name: RSpec
8
+
9
+ on:
10
+ push:
11
+ branches: [ "main" ]
12
+ pull_request:
13
+ branches: [ "main" ]
14
+
15
+ jobs:
16
+ test:
17
+ runs-on: ubuntu-latest
18
+ strategy:
19
+ matrix:
20
+ ruby-version: ['2.7', '3.0', '3.1', '3.2']
21
+
22
+ steps:
23
+ - uses: actions/checkout@v3
24
+ - name: Set up Ruby
25
+ # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
26
+ # change this to (see https://github.com/ruby/setup-ruby#versioning):
27
+ uses: ruby/setup-ruby@v1
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: bundle
32
+ run: bundle check || bundle install -j 4
33
+ - name: RSpecs
34
+ run: bundle exec rspec --format documentation
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ **/.DS_Store
1
2
  *.gem
2
3
  *.rbc
3
4
  .bundle
@@ -5,6 +6,7 @@
5
6
  .yardoc
6
7
  InstalledFiles
7
8
  _yardoc
9
+ Gemfile.lock
8
10
  coverage
9
11
  doc/
10
12
  lib/bundler/man
@@ -15,3 +17,6 @@ test/tmp
15
17
  test/version_tmp
16
18
  tmp
17
19
  .idea/
20
+ vendor/
21
+ .rubocop/cache
22
+ .rubocop-*
data/.rubocop.yml ADDED
@@ -0,0 +1,21 @@
1
+ inherit_from:
2
+ - .rubocop_todo.yml
3
+ - https://relaxed.ruby.style/rubocop.yml
4
+
5
+ inherit_mode:
6
+ merge:
7
+ - Exclude
8
+
9
+ require:
10
+ - rubocop-rspec
11
+ - rubocop-rake
12
+
13
+ AllCops:
14
+ TargetRubyVersion: '2.7'
15
+ UseCache: true
16
+ CacheRootDirectory: ./.rubocop/cache
17
+ NewCops: enable
18
+ Exclude:
19
+ - 'bin/*'
20
+ - 'vendor/*'
21
+
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,82 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2023-08-28 17:02:07 UTC using RuboCop version 1.56.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: Severity, Include.
11
+ # Include: **/*.gemspec
12
+ Gemspec/RequiredRubyVersion:
13
+ Exclude:
14
+ - 'ventable.gemspec'
15
+
16
+ # Offense count: 11
17
+ # Configuration parameters: AllowedMethods.
18
+ # AllowedMethods: enums
19
+ Lint/ConstantDefinitionInBlock:
20
+ Exclude:
21
+ - 'spec/ventable/ventable_spec.rb'
22
+
23
+ # Offense count: 1
24
+ # Configuration parameters: AllowComments.
25
+ Lint/EmptyClass:
26
+ Exclude:
27
+ - 'spec/ventable/ventable_spec.rb'
28
+
29
+ # Offense count: 2
30
+ Lint/RescueException:
31
+ Exclude:
32
+ - 'spec/ventable/ventable_spec.rb'
33
+
34
+ # Offense count: 1
35
+ # Configuration parameters: Prefixes, AllowedPatterns.
36
+ # Prefixes: when, with, without
37
+ RSpec/ContextWording:
38
+ Exclude:
39
+ - 'spec/ventable/ventable_spec.rb'
40
+
41
+ # Offense count: 7
42
+ # Configuration parameters: CountAsOne.
43
+ RSpec/ExampleLength:
44
+ Max: 26
45
+
46
+ # Offense count: 2
47
+ RSpec/ExpectInHook:
48
+ Exclude:
49
+ - 'spec/ventable/ventable_spec.rb'
50
+
51
+ # Offense count: 12
52
+ RSpec/LeakyConstantDeclaration:
53
+ Exclude:
54
+ - 'spec/ventable/ventable_spec.rb'
55
+
56
+ # Offense count: 1
57
+ # Configuration parameters: .
58
+ # SupportedStyles: have_received, receive
59
+ RSpec/MessageSpies:
60
+ EnforcedStyle: receive
61
+
62
+ # Offense count: 5
63
+ RSpec/MultipleExpectations:
64
+ Max: 9
65
+
66
+ # Offense count: 1
67
+ # Configuration parameters: AllowedGroups.
68
+ RSpec/NestedGroups:
69
+ Max: 4
70
+
71
+ # Offense count: 1
72
+ # Configuration parameters: AllowedPatterns.
73
+ # AllowedPatterns: ^expect_, ^assert_
74
+ RSpec/NoExpectationExample:
75
+ Exclude:
76
+ - 'spec/ventable/ventable_spec.rb'
77
+
78
+ # Offense count: 2
79
+ # This cop supports safe autocorrection (--autocorrect).
80
+ Rake/Desc:
81
+ Exclude:
82
+ - 'Rakefile'
data/Gemfile CHANGED
@@ -1,4 +1,14 @@
1
- source 'https://rubygems.org'
1
+ # frozen_string_literal: true
2
2
 
3
- # Specify your gem's dependencies in ventable.gemspec
3
+ source 'https://rubygems.org'
4
4
  gemspec
5
+
6
+ gem 'guard-rspec'
7
+ gem "rake"
8
+ gem "rspec"
9
+ gem "rspec-its"
10
+ gem "rspec-mocks"
11
+ gem "rubocop"
12
+ gem "rubocop-rake"
13
+ gem "rubocop-rspec"
14
+ gem "simplecov"
data/Guardfile CHANGED
@@ -1,15 +1,16 @@
1
1
  #!/usr/bin/env ruby
2
- #^syntax detection
2
+ # frozen_string_literal: true
3
+
4
+ # ^syntax detection
3
5
 
4
6
  # A sample Guardfile
5
7
  # More info at https://github.com/guard/guard#readme
6
8
 
7
9
  guard 'rspec' do
8
- watch(%r{^ventable\.gemspec}) { "spec"}
10
+ watch(/^ventable\.gemspec/) { "spec" }
9
11
  watch(%r{^lib/(.+)\.rb$}) { "spec" }
10
12
 
11
13
  watch(%r{^spec/.+_spec\.rb$})
12
- watch('spec/spec_helper.rb') { "spec" }
14
+ watch('spec/spec_helper.rb') { "spec" }
13
15
  watch(%r{spec/support/.*}) { "spec" }
14
16
  end
15
-
data/README.md CHANGED
@@ -1,14 +1,44 @@
1
- [![Gem Version](https://badge.fury.io/rb/ventable.png)](http://badge.fury.io/rb/ventable)
2
- [![Build status](https://secure.travis-ci.org/kigster/ventable.png)](http://travis-ci.org/kigster/ventable)
3
- [![Code Climate](https://codeclimate.com/github/kigster/ventable.png)](https://codeclimate.com/github/kigster/ventable)
1
+ ![Gem Version](https://badge.fury.io/rb/ventable.svg)
2
+ [![Gitter](https://img.shields.io/gitter/room/gitterHQ/gitter.svg)](https://gitter.im/kigster/ventable)
3
+ ![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkigster%2Fventable.svg?type=shield)
4
4
 
5
+ [![RSpec](https://github.com/kigster/ventable/actions/workflows/ruby.yml/badge.svg)](https://github.com/kigster/ventable/actions/workflows/ruby.yml)
6
+ [![Rubocop](https://github.com/kigster/ventable/actions/workflows/rubocop.yml/badge.svg)](https://github.com/kigster/ventable/actions/workflows/rubocop.yml)
5
7
 
6
- # Ventable
8
+ # Ventable — Observable Pattern On Steroids
7
9
 
8
- Simple eventing gem that implements Observable pattern, but with more options, ability to group observers and wrap
9
- them in arbitrary blocks of code. For example, when a certain event fires, some observers may be called within
10
- a transaction context, while others maybe called outside of the transaction context.
10
+ This gem is a variation of the [Observer Design Pattern](https://en.wikipedia.org/wiki/Observer_pattern).
11
11
 
12
+ In particular:
13
+
14
+ * Ventable requires creation of simple event classes that may carry data and be serialized.
15
+ * Observers can be grouped together, and notified within a pre-defined `Proc`. For example, using grouping some observers may be called within the boundaries of a database transaction, while others maybe called outside of it.
16
+ * Ventable allows both compile time and run time observer binding.
17
+ * Ventable calls specific method on each observer, using automatically derived method name from the event class. A generic `#handle_event` method is also supported.
18
+
19
+ Limitations:
20
+
21
+ * At the moment, Ventable can only notify observers within the current ruby process.
22
+
23
+ ## Plugins
24
+
25
+ Ventable has several plugins that add various functionality on top of the basic event dispatch mechanism.
26
+
27
+ * [ventable-statsd](https://github.com/kigster/ventable-statsd) is an extension that allows notifying Statsd whenever an event occurs.
28
+ * [simple-feed](https://github.com/kigster/simple-feed) is a generic implementation of the activity feed concept commonly seen on social networks, and it integrates nicely with Ventable.
29
+
30
+ ## Ruby Versions
31
+
32
+ This gem has been verified to work in the following ruby versions:
33
+
34
+ * MRI Ruby
35
+ * 3.2
36
+ * 3.1
37
+ * 3.0
38
+ * 2.7
39
+
40
+ The gem also likely works with non-MRI rubies, but it has not been tested.
41
+
12
42
  ## Installation
13
43
 
14
44
  Add this line to your application's Gemfile:
@@ -25,13 +55,16 @@ Or install it yourself as:
25
55
 
26
56
  ## Usage
27
57
 
28
- 1. Create your own plain ruby Event class that optionally carries some data important to the event. Include module ```Ventable::Event```.
58
+ 1. Create your own plain ruby Event class that optionally carries some data important to the event. Include module `Ventable::Event`.
59
+
29
60
  2. Create one or more observers. Observer can be any class that implements event handler method as a class method, such as a
30
- generic method ```self.handle(event)``` or a more specific method mapped to the event name: say for event UserRegistered the
31
- callback event would be ```self.handle_user_registered(event)```
32
- 3. Register your observers with the event using ```notifies``` event method, or register groups using ```group``` method, and then
33
- use ```notify``` with options ```inside: :group_name```
34
- 4. Instantiate your event class (optionally with some data), and call ```fire!``` method.
61
+ generic method `self.handle(event)` or a more specific method mapped to the event name: say for event UserRegistered the
62
+ callback event would be `self.handle_user_registered(event)`
63
+
64
+ 3. Register your observers with the event using `notifies` event method, or register groups using `group` method, and then
65
+ use `notify` with options `inside: :group_name`
66
+
67
+ 4. Instantiate your event class (optionally with some data), and call `publish` or, a deprecated `fire!` method.
35
68
 
36
69
  ## Example
37
70
 
@@ -62,7 +95,7 @@ end
62
95
  AlarmSoundEvent.notifies SleepingPerson
63
96
 
64
97
  # Create and fire the event
65
- AlarmSoundEvent.new(Date.new).fire!
98
+ AlarmSoundEvent.new(Date.new).publish
66
99
  ```
67
100
 
68
101
  ## Using #configure and groups
@@ -101,7 +134,7 @@ SomeEvent.configure do
101
134
  notifies ObserverClass1, ObserverClass2, inside: :transaction
102
135
  end
103
136
 
104
- SomeEvent.new.fire!
137
+ SomeEvent.new.publish
105
138
  ```
106
139
 
107
140
  ## Callback Method Name
@@ -119,23 +152,23 @@ using the following logic:
119
152
 
120
153
  You should start by defining your event library for your application (list of events
121
154
  that are important to you), you can place these files anywhere you like, such as
122
- ```lib/events``` or ```app/events```, etc.
155
+ `lib/events` or `app/events`, etc.
123
156
 
124
- It is recommended to ```configure``` all events and their observers in the ```event_initializer.rb``` file,
125
- inside the ```config/ininitalizers``` folder. You may need to require your events in that file also.
157
+ It is recommended to `configure` all events and their observers in the `event_initializer.rb` file,
158
+ inside the `config/ininitalizers` folder. You may need to require your events in that file also.
126
159
 
127
160
  When your event is tied to a creation of a "first class objects", such as user registration,
128
161
  it is recommended to create the User record first, commit it to the database, and then throw
129
- a ```UserRegisteredEvent.new(user).fire!```, and have all subsequent logic broeken into
130
- their respective classes. For example, if you need to send an email to the user, have a ```Mailer```
131
- class observe the ```UserRegisteredEvent```, and so all the mailing logic can live inside the ```Mailer```
132
- class, instead of, say, registration controller directly calling ```Mailer.deliver_user_registration!(user)```.
162
+ a `UserRegisteredEvent.new(user).publish`, and have all subsequent logic broeken into
163
+ their respective classes. For example, if you need to send an email to the user, have a `Mailer`
164
+ class observe the `UserRegisteredEvent`, and so all the mailing logic can live inside the `Mailer`
165
+ class, instead of, say, registration controller directly calling `Mailer.deliver_user_registration!(user)`.
133
166
  The callback method will receive the event, that wraps the User instance, or any other useful data necessary.
134
167
 
135
168
  ## Integration with tests
136
169
 
137
170
  There are times when it may be desirable to disable all eventing. For instance, when writing unit tests,
138
- testing that events are fired may be useful, but integrating with all observers adds complexity and confusion.
171
+ testing that events are published may be useful, but integrating with all observers adds complexity and confusion.
139
172
  In these cases, Ventable may be globally disabled.
140
173
 
141
174
  ```ruby
@@ -153,14 +186,14 @@ Now in a spec file:
153
186
  ```ruby
154
187
  describe "Stuff", eventing: false do
155
188
  it 'does stuff' do
156
- ... my code that fires events, in isolation from event observers
189
+ ... my code that publishes events, in isolation from event observers
157
190
  end
158
191
 
159
- it 'tests that events are fired, using stubs' do
160
- event = double(fire!: true)
192
+ it 'tests that events are published, using stubs' do
193
+ event = double(publish: true)
161
194
  allow(MyEvent).to receive(:new).and_return(event)
162
195
  ... my code that should fire event
163
- expect(event).to have_received(:fire!)
196
+ expect(event).to have_received(:publish)
164
197
  end
165
198
  end
166
199
 
@@ -197,3 +230,7 @@ For more information, check out the following blog post:
197
230
  ## Author
198
231
 
199
232
  Konstantin Gredeskoul, @kig, http://github.com/kigster
233
+
234
+
235
+ ## License
236
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkigster%2Fventable.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkigster%2Fventable?ref=badge_large)
data/Rakefile CHANGED
@@ -1,3 +1,23 @@
1
- #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
3
2
 
3
+ require 'bundler/gem_tasks'
4
+
5
+ def shell(*args)
6
+ puts "running: #{args.join(' ')}"
7
+ system(args.join(' '))
8
+ end
9
+
10
+ task :clean do
11
+ shell('rm -rf pkg/ tmp/ coverage/ doc/ ' )
12
+ end
13
+
14
+ task gem: [:build] do
15
+ shell('gem install pkg/*')
16
+ end
17
+
18
+ task permissions: [:clean] do
19
+ shell("chmod -v o+r,g+r * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/*")
20
+ shell("find . -type d -exec chmod o+x,g+x {} \\;")
21
+ end
22
+
23
+ task build: :permissions
@@ -1,55 +1,58 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'set'
4
+ require 'active_support/inflector'
2
5
 
3
6
  module ::Ventable
4
7
  class Error < RuntimeError
5
8
  end
6
9
 
7
10
  module Event
8
- def self.included(klazz)
9
- klazz.instance_eval do
11
+ def self.included(klass)
12
+ klass.instance_eval do
10
13
  @observers = Set.new
11
14
  class << self
12
15
  attr_accessor :observers
13
16
  end
14
17
  end
15
18
 
16
- klazz.extend ClassMethods
19
+ klass.extend ClassMethods
17
20
  end
18
21
 
19
22
  def fire!
20
23
  notify_observer_set(self.class.observers) if Ventable.enabled?
21
24
  end
22
25
 
26
+ alias publish fire!
27
+
23
28
  private
24
29
 
25
30
  def notify_observer_set(observer_set)
26
31
  observer_set.each do |observer_entry|
27
32
  if observer_entry.is_a?(Hash)
28
33
  around_block = observer_entry[:around_block]
29
- inside_block = -> { notify_observer_set(observer_entry[:observers]) }
30
- around_block.call(inside_block)
31
- elsif observer_entry
32
- notify_observer(observer_entry)
34
+ around_block&.call(-> { notify_observer_set(observer_entry[:observers]) })
33
35
  else
34
- raise Ventable::Error.new("nil in observer_entry set #{observer_set.inspect}!")
36
+ notify_observer(observer_entry)
35
37
  end
36
38
  end
37
39
  end
38
40
 
39
41
  def notify_observer(observer)
40
42
  case observer
41
- when Proc
42
- observer.call(self)
43
- else # class
44
- notify_class_observer(observer)
43
+ when Proc
44
+ observer.call(self)
45
+ else # class
46
+ notify_class_observer(observer)
45
47
  end
46
48
  end
47
49
 
48
50
  def notify_class_observer(observer)
49
- default_handler = self.class.default_callback_method
51
+ default_handler = self.class.send(:default_callback_method)
50
52
  return observer.send(default_handler, self) if observer.respond_to?(default_handler)
51
53
  return observer.send(:handle_event, self) if observer.respond_to?(:handle_event)
52
- raise Ventable::Error.new("no suitable event handler method found for #{self.class} in observer #{observer} (try adding #{default_handler} to this observer)")
54
+
55
+ raise Ventable::Error, "no suitable event handler method found for #{self.class} in observer #{observer} (try adding #{default_handler} to this observer)"
53
56
  end
54
57
 
55
58
  module ClassMethods
@@ -57,43 +60,45 @@ module ::Ventable
57
60
  class_eval(&block)
58
61
  end
59
62
 
60
- def notifies(*observer_list, &block)
61
- options = {}
62
- options.merge! observer_list.pop if observer_list.last.is_a?(Hash)
63
- observer_set = self.observers
63
+ def notifies(*observer_list, **options, &block)
64
+ observer_set = observers
64
65
  if options[:inside]
65
- observer_entry = self.find_observer_group(options[:inside])
66
- if observer_entry.nil?
67
- raise Ventable::Error.new("No group with name #{options[:inside]} found.")
68
- end
66
+ observer_entry = find_observer_group(options[:inside])
67
+ raise Ventable::Error, "No group with name #{options[:inside]} found." if observer_entry.nil?
68
+
69
69
  observer_set = observer_entry[:observers]
70
70
  end
71
- raise Ventable::Error.new("found nil observer in params #{observer_list.inspect}") if observer_list.any?{|l| l.nil?}
71
+ raise Ventable::Error, "found nil observer in params #{observer_list.inspect}" if observer_list.any?(&:nil?)
72
+
72
73
  observer_list.compact.each { |o| observer_set << o } unless observer_list.empty?
73
74
  observer_set << block if block
74
75
  end
75
76
 
76
77
  def group(name, &block)
77
- g = find_observer_group(name)
78
- raise "Group #{name} already defined by #{g}" if g
79
- self.observers <<
80
- { name: name,
81
- around_block: block,
82
- observers: Set.new
83
- }
78
+ observers << { name: name,
79
+ around_block: block,
80
+ observers: Set.new }
84
81
  end
85
82
 
83
+ protected
84
+
86
85
  def find_observer_group(name)
87
- self.observers.find { |o| o.is_a?(Hash) && o[:name] == name }
86
+ observers.find { |o| o.is_a?(Hash) && o[:name] == name }
88
87
  end
89
88
 
89
+ private
90
+
90
91
  # Determine method name to call when notifying observers from this event.
91
92
  def default_callback_method
92
93
  if respond_to?(:ventable_callback_method_name)
93
- self.ventable_callback_method_name
94
+ ventable_callback_method_name
94
95
  else
95
96
  target = self
96
- method = "handle_" + target.name.gsub(/::/,'__').underscore.gsub(/_event/, '')
97
+
98
+ method = "handle_#{ActiveSupport::Inflector.underscore(target.name)}".
99
+ gsub(%r{/([^/]*)}, '__\1').
100
+ gsub(/_event$/, '')
101
+
97
102
  method.to_sym
98
103
  end
99
104
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Ventable
2
- VERSION = "1.0.0"
4
+ VERSION = '1.3.1'
3
5
  end
data/lib/ventable.rb CHANGED
@@ -1,8 +1,9 @@
1
- require "ventable/version"
2
- require "ventable/event"
1
+ # frozen_string_literal: true
3
2
 
4
- module Ventable
3
+ require 'ventable/version'
4
+ require 'ventable/event'
5
5
 
6
+ module Ventable
6
7
  def self.disable
7
8
  @disabled = true
8
9
  end
@@ -12,16 +13,16 @@ module Ventable
12
13
  end
13
14
 
14
15
  def self.enabled?
15
- @disabled != true
16
+ !@disabled
16
17
  end
17
18
  end
18
19
 
19
20
  class String
20
21
  def underscore
21
- self.gsub(/::/, '/').
22
- gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
23
- gsub(/([a-z\d])([A-Z])/, '\1_\2').
24
- tr("-", "_").
25
- downcase
22
+ gsub("::", '/').
23
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
24
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').
25
+ tr('-', '_').
26
+ downcase
26
27
  end
27
28
  end
data/spec/spec_helper.rb CHANGED
@@ -1,17 +1,13 @@
1
- # This file was generated by the `rspec --init` command. Conventionally, all
2
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
- # Require this file using `require "spec_helper"` to ensure that it is only
4
- # loaded once.
5
- #
6
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ require 'rspec'
5
+
6
+ SimpleCov.start
7
7
 
8
- ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
9
- require 'rubygems'
10
- require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
11
8
  require 'ventable'
12
9
 
13
10
  RSpec.configure do |config|
14
- config.treat_symbols_as_metadata_keys_with_true_values = true
15
11
  config.run_all_when_everything_filtered = true
16
12
  config.filter_run :focus
17
13
 
@@ -1,4 +1,6 @@
1
- require 'ventable'
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
2
4
 
3
5
  describe Ventable do
4
6
  before do
@@ -8,61 +10,62 @@ describe Ventable do
8
10
  end
9
11
 
10
12
  describe '::enabled?' do
11
- after { Ventable.enable }
13
+ after { described_class.enable }
12
14
 
13
15
  it 'is true by default' do
14
- expect(Ventable.enabled?).to be true
16
+ expect(described_class.enabled?).to be true
15
17
  end
16
18
 
17
19
  it 'is false after Ventable is disabled' do
18
- Ventable.disable
19
- expect(Ventable.enabled?).to be false
20
+ described_class.disable
21
+ expect(described_class.enabled?).to be false
20
22
  end
21
23
 
22
24
  it 'is true after Ventable is re-enabled' do
23
- Ventable.disable
24
- Ventable.enable
25
- expect(Ventable.enabled?).to be true
25
+ described_class.disable
26
+ described_class.enable
27
+ expect(described_class.enabled?).to be true
26
28
  end
27
29
  end
28
30
 
29
- describe "including Ventable::Event" do
30
- it "should create a class instance variable to keep observers" do
31
+ describe 'including Ventable::Event' do
32
+ it 'creates a class instance variable to keep observers' do
31
33
  expect(TestEvent.observers).not_to be_nil
32
- expect(TestEvent.observers.class.name).to eq("Set")
34
+ expect(TestEvent.observers.class.name).to eq('Set')
33
35
  end
34
36
 
35
- it "should see observers variable from instance methods" do
37
+ it 'sees observers variable from instance methods' do
36
38
  observers = nil
37
39
  TestEvent.new.instance_eval do
38
40
  observers = self.class.observers
39
41
  end
40
- expect(observers).to_not be_nil
42
+ expect(observers).not_to be_nil
41
43
  end
42
44
 
43
- it "should maintain separate sets of observers for each event" do
45
+ it 'maintains separate sets of observers for each event' do
44
46
  class AnotherEvent
45
47
  include Ventable::Event
46
48
  end
47
- expect(AnotherEvent.observers.object_id).to_not eq(TestEvent.observers.object_id)
49
+
50
+ expect(AnotherEvent.observers.object_id).not_to eq(TestEvent.observers.object_id)
48
51
  end
49
52
  end
50
53
 
51
- describe "#fire" do
54
+ describe '#fire' do
52
55
  before do
53
56
  class TestEvent
54
57
  include Ventable::Event
55
58
  end
56
59
  end
57
60
 
58
- it "should properly call a Proc observer" do
61
+ it 'properly call a Proc observer' do
59
62
  run_block = false
60
63
  event = nil
61
64
  TestEvent.notifies do |e|
62
65
  run_block = true
63
66
  event = e
64
67
  end
65
- expect(run_block).to eq(false)
68
+ expect(run_block).to be(false)
66
69
  expect(event).to be_nil
67
70
 
68
71
  # fire the event
@@ -72,30 +75,65 @@ describe Ventable do
72
75
  expect(event).not_to be_nil
73
76
  end
74
77
 
75
- it "should properly call a class observer" do
76
- class TestEvent
77
- class << self
78
- attr_accessor :flag
78
+ describe 'class observer' do
79
+ before do
80
+ class TestEvent
81
+ class << self
82
+ attr_accessor :flag
83
+ end
84
+
85
+ self.flag = 'unset'
86
+
87
+ def flag=(value)
88
+ self.class.flag = value
89
+ end
79
90
  end
80
- self.flag = "unset"
81
- def flag= value
82
- self.class.flag = value
91
+
92
+ class TestEventObserver
93
+ def self.handle_test(event)
94
+ event.flag = 'boo'
95
+ end
83
96
  end
84
- end
85
97
 
86
- class TestEventObserver
87
- def self.handle_test event
88
- event.flag = "boo"
98
+ class GlobalObserver
99
+ class << self
100
+ def handle_event(event)
101
+ puts event.inspect
102
+ end
103
+ end
89
104
  end
105
+
106
+ TestEvent.notifies TestEventObserver, GlobalObserver
107
+ expect(TestEvent.flag).to eq('unset')
108
+ expect(GlobalObserver).to receive(:handle_event).with(event)
90
109
  end
91
- TestEvent.notifies TestEventObserver
92
- expect(TestEvent.flag).to eq("unset")
93
110
 
94
- TestEvent.new.fire!
95
- expect(TestEvent.flag).to eq("boo")
111
+ let(:event) { TestEvent.new }
112
+
113
+ it 'sets the flag and call observers' do
114
+ event.fire!
115
+ expect(TestEvent.flag).to eq('boo')
116
+ end
117
+
118
+ it 'also fire via the publish alias' do
119
+ event.publish
120
+ end
121
+
122
+ context 'observer without a handler' do
123
+ before {
124
+ class ObserverWithoutAHandler
125
+ end
126
+
127
+ TestEvent.notifies ObserverWithoutAHandler
128
+ }
129
+
130
+ it 'raises an exception' do
131
+ expect { event.publish }.to raise_error(Ventable::Error)
132
+ end
133
+ end
96
134
  end
97
135
 
98
- it "should properly call a group of observers" do
136
+ it 'properly call a group of observers' do
99
137
  transaction_called = false
100
138
  transaction_completed = false
101
139
  transaction = ->(observer_block) {
@@ -123,22 +161,22 @@ describe Ventable do
123
161
 
124
162
  TestEvent.new.fire!
125
163
 
126
- expect(transaction_called).to be true
127
- expect(observer_block_called).to be true
128
- expect(transaction_called).to be true
164
+ expect(transaction_called).to be true
165
+ expect(observer_block_called).to be true
166
+ expect(transaction_called).to be true
129
167
  expect(transaction_already_completed).to be false
130
- expect(event_inside).to_not be_nil
168
+ expect(event_inside).not_to be_nil
131
169
  expect(event_inside).to be_a(TestEvent)
132
170
  end
133
171
 
134
172
  context 'when globally disabled' do
135
- before { Ventable.disable }
136
- after { Ventable.enable }
173
+ before { described_class.disable }
174
+ after { described_class.enable }
137
175
 
138
176
  it 'does not notify observers' do
139
177
  observers_notified = false
140
178
 
141
- TestEvent.notifies do |event|
179
+ TestEvent.notifies do |_event|
142
180
  observers_notified = true
143
181
  end
144
182
 
@@ -148,7 +186,7 @@ describe Ventable do
148
186
  end
149
187
  end
150
188
 
151
- describe "#default_callback_method" do
189
+ describe '#default_callback_method' do
152
190
  before do
153
191
  class SomeAwesomeEvent
154
192
  include Ventable::Event
@@ -160,9 +198,6 @@ describe Ventable do
160
198
  end
161
199
  end
162
200
 
163
- class SomeOtherStuffHappened
164
- include Ventable::Event
165
- end
166
201
  class ClassWithCustomCallbackMethodEvent
167
202
  include Ventable::Event
168
203
 
@@ -170,18 +205,35 @@ describe Ventable do
170
205
  :handle_my_special_event
171
206
  end
172
207
  end
208
+
209
+ module Blah
210
+ module Foo
211
+ class BarClosedEvent
212
+ include Ventable::Event
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ it 'properly sets the callback method on a Module-less class' do
219
+ expect(SomeAwesomeEvent.send(:default_callback_method)).to eq(:handle_some_awesome)
173
220
  end
174
221
 
175
- it "should properly set the callback method name" do
176
- expect(SomeAwesomeEvent.default_callback_method).to eq(:handle_some_awesome)
177
- expect(Blah::AnotherSweetEvent.default_callback_method).to eq(:handle_blah__another_sweet)
178
- expect(SomeOtherStuffHappened.default_callback_method).to eq(:handle_some_other_stuff_happened)
179
- expect(ClassWithCustomCallbackMethodEvent.default_callback_method).to eq(:handle_my_special_event)
222
+ it 'properly sets the callback method on a Class within a Module' do
223
+ expect(Blah::AnotherSweetEvent.send(:default_callback_method)).to eq(:handle_blah__another_sweet)
224
+ end
225
+
226
+ it 'properly sets the callback method on a class with a custom default method handler name' do
227
+ expect(ClassWithCustomCallbackMethodEvent.send(:default_callback_method)).to eq(:handle_my_special_event)
228
+ end
229
+
230
+ it 'properly sets the callback method on a class within a nested module' do
231
+ expect(Blah::Foo::BarClosedEvent.send(:default_callback_method)).to eq(:handle_blah__foo__bar_closed)
180
232
  end
181
233
  end
182
234
 
183
- describe "#configure" do
184
- it "properly configures the event with observers" do
235
+ describe '#configure' do
236
+ it 'properly configures the event with observers' do
185
237
  notified_observer = false
186
238
  TestEvent.configure do
187
239
  notifies do
@@ -192,11 +244,11 @@ describe Ventable do
192
244
  expect(notified_observer).to be true
193
245
  end
194
246
 
195
- it "configures observers with groups" do
247
+ it 'configures observers with groups' do
196
248
  notified_observer = false
197
249
  called_transaction = false
198
250
  TestEvent.configure do
199
- group :transaction, &->(b){
251
+ group :transaction, &->(b) {
200
252
  b.call
201
253
  called_transaction = true
202
254
  }
@@ -209,27 +261,24 @@ describe Ventable do
209
261
  expect(called_transaction).to be true
210
262
  end
211
263
 
212
- it "throws exception if :inside references unknown group" do
213
- begin
214
- TestEvent.configure do
215
- notifies inside: :transaction do
216
- # some stuff
217
- end
264
+ it 'throws exception if :inside references unknown group' do
265
+ TestEvent.configure do
266
+ notifies inside: :transaction do
267
+ # some stuff
218
268
  end
219
- fail "Shouldn't reach here, must throw a valid exception"
220
- rescue Exception => e
221
- expect(e.class).to eq(Ventable::Error)
222
269
  end
270
+ fail 'Shouldn\'t reach here, must throw a valid exception'
271
+ rescue Exception => e
272
+ expect(e.class).to eq(Ventable::Error)
223
273
  end
224
- it "throws exception if nil observer added to the list" do
225
- begin
226
- TestEvent.configure do
227
- notifies nil
228
- end
229
- fail "Shouldn't reach here, must throw a valid exception"
230
- rescue Exception => e
231
- expect(e.class).to eq(Ventable::Error)
274
+
275
+ it 'throws exception if nil observer added to the list' do
276
+ TestEvent.configure do
277
+ notifies nil
232
278
  end
279
+ fail 'Shouldn\'t reach here, must throw a valid exception'
280
+ rescue Exception => e
281
+ expect(e.class).to eq(Ventable::Error)
233
282
  end
234
283
  end
235
284
  end
data/ventable.gemspec CHANGED
@@ -1,23 +1,21 @@
1
+ # frozen_string_literal: true
1
2
 
2
- # -*- encoding: utf-8 -*-
3
- require File.expand_path('../lib/ventable/version', __FILE__)
3
+ require File.expand_path('lib/ventable/version', __dir__)
4
4
 
5
5
  Gem::Specification.new do |gem|
6
6
  gem.authors = ["Konstantin Gredeskoul"]
7
7
  gem.email = ["kigster@gmail.com"]
8
- gem.description = %q{Event/Observable design pattern in ruby}
9
- gem.summary = %q{Event/Observable design pattern in ruby}
8
+ gem.description = 'Event/Observable design pattern in ruby'
9
+ gem.summary = 'Event/Observable design pattern in ruby'
10
10
  gem.homepage = "https://github.com/kigster/ventable"
11
11
 
12
12
  gem.files = `git ls-files`.split($\)
13
13
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
14
  gem.name = "ventable"
16
15
  gem.require_paths = ["lib"]
17
16
  gem.version = Ventable::VERSION
18
17
 
19
- gem.add_development_dependency "rake"
20
- gem.add_development_dependency "rspec"
21
- gem.add_development_dependency "rspec-mocks"
22
- gem.add_development_dependency 'guard-rspec'
18
+ gem.metadata['rubygems_mfa_required'] = 'true'
19
+
20
+ gem.add_runtime_dependency 'activesupport', '>= 5'
23
21
  end
metadata CHANGED
@@ -1,71 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ventable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-28 00:00:00.000000000 Z
11
+ date: 2024-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rake
14
+ name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :development
19
+ version: '5'
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: rspec
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec-mocks
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: guard-rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
26
+ version: '5'
69
27
  description: Event/Observable design pattern in ruby
70
28
  email:
71
29
  - kigster@gmail.com
@@ -74,11 +32,13 @@ extensions: []
74
32
  extra_rdoc_files: []
75
33
  files:
76
34
  - ".atom-build.json"
35
+ - ".github/workflows/rubocop.yml"
36
+ - ".github/workflows/ruby.yml"
77
37
  - ".gitignore"
78
38
  - ".rspec"
79
- - ".travis.yml"
39
+ - ".rubocop.yml"
40
+ - ".rubocop_todo.yml"
80
41
  - Gemfile
81
- - Gemfile.lock
82
42
  - Guardfile
83
43
  - LICENSE
84
44
  - README.md
@@ -91,8 +51,9 @@ files:
91
51
  - ventable.gemspec
92
52
  homepage: https://github.com/kigster/ventable
93
53
  licenses: []
94
- metadata: {}
95
- post_install_message:
54
+ metadata:
55
+ rubygems_mfa_required: 'true'
56
+ post_install_message:
96
57
  rdoc_options: []
97
58
  require_paths:
98
59
  - lib
@@ -107,11 +68,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
68
  - !ruby/object:Gem::Version
108
69
  version: '0'
109
70
  requirements: []
110
- rubyforge_project:
111
- rubygems_version: 2.5.1
112
- signing_key:
71
+ rubygems_version: 3.5.6
72
+ signing_key:
113
73
  specification_version: 4
114
74
  summary: Event/Observable design pattern in ruby
115
- test_files:
116
- - spec/spec_helper.rb
117
- - spec/ventable/ventable_spec.rb
75
+ test_files: []
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 1.9.3
4
- script: "bundle exec rspec"
5
- notifications:
6
- email:
7
- recipients:
8
- - kigster@gmail.com
9
- on_success: never
10
- on_failure: always
data/Gemfile.lock DELETED
@@ -1,72 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- ventable (1.0.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- coderay (1.1.0)
10
- diff-lcs (1.2.5)
11
- ffi (1.9.10)
12
- formatador (0.2.5)
13
- guard (2.13.0)
14
- formatador (>= 0.2.4)
15
- listen (>= 2.7, <= 4.0)
16
- lumberjack (~> 1.0)
17
- nenv (~> 0.1)
18
- notiffany (~> 0.0)
19
- pry (>= 0.9.12)
20
- shellany (~> 0.0)
21
- thor (>= 0.18.1)
22
- guard-compat (1.2.1)
23
- guard-rspec (4.6.4)
24
- guard (~> 2.1)
25
- guard-compat (~> 1.1)
26
- rspec (>= 2.99.0, < 4.0)
27
- listen (3.0.5)
28
- rb-fsevent (>= 0.9.3)
29
- rb-inotify (>= 0.9)
30
- lumberjack (1.0.10)
31
- method_source (0.8.2)
32
- nenv (0.2.0)
33
- notiffany (0.0.8)
34
- nenv (~> 0.1)
35
- shellany (~> 0.0)
36
- pry (0.10.3)
37
- coderay (~> 1.1.0)
38
- method_source (~> 0.8.1)
39
- slop (~> 3.4)
40
- rake (10.5.0)
41
- rb-fsevent (0.9.7)
42
- rb-inotify (0.9.5)
43
- ffi (>= 0.5.0)
44
- rspec (3.4.0)
45
- rspec-core (~> 3.4.0)
46
- rspec-expectations (~> 3.4.0)
47
- rspec-mocks (~> 3.4.0)
48
- rspec-core (3.4.1)
49
- rspec-support (~> 3.4.0)
50
- rspec-expectations (3.4.0)
51
- diff-lcs (>= 1.2.0, < 2.0)
52
- rspec-support (~> 3.4.0)
53
- rspec-mocks (3.4.1)
54
- diff-lcs (>= 1.2.0, < 2.0)
55
- rspec-support (~> 3.4.0)
56
- rspec-support (3.4.1)
57
- shellany (0.0.1)
58
- slop (3.6.0)
59
- thor (0.19.1)
60
-
61
- PLATFORMS
62
- ruby
63
-
64
- DEPENDENCIES
65
- guard-rspec
66
- rake
67
- rspec
68
- rspec-mocks
69
- ventable!
70
-
71
- BUNDLED WITH
72
- 1.11.2