ventable 1.0.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/rubocop.yml +36 -0
- data/.github/workflows/ruby.yml +34 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +21 -0
- data/.rubocop_todo.yml +82 -0
- data/Gemfile +12 -2
- data/Guardfile +5 -4
- data/README.md +64 -27
- data/Rakefile +22 -2
- data/lib/ventable/event.rb +38 -33
- data/lib/ventable/version.rb +3 -1
- data/lib/ventable.rb +10 -9
- data/spec/spec_helper.rb +6 -10
- data/spec/ventable/ventable_spec.rb +120 -71
- data/ventable.gemspec +7 -9
- metadata +17 -59
- data/.travis.yml +0 -10
- data/Gemfile.lock +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6f8a7adee18ece871971236ea00ee70c35c278259fed5cd499c1f3c8d5e097d0
|
4
|
+
data.tar.gz: 4e4137f676a3374e17377db94ede9c59d232358f9bc82e3fbbbf90b817bbe514
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
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
|
-
|
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(
|
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')
|
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
|
-
|
2
|
-
[
|
2
|
+
[](https://gitter.im/kigster/ventable)
|
3
|
+

|
4
4
|
|
5
|
+
[](https://github.com/kigster/ventable/actions/workflows/ruby.yml)
|
6
|
+
[](https://github.com/kigster/ventable/actions/workflows/rubocop.yml)
|
5
7
|
|
6
|
-
# Ventable
|
8
|
+
# Ventable — Observable Pattern On Steroids
|
7
9
|
|
8
|
-
|
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
|
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
|
31
|
-
callback event would be
|
32
|
-
|
33
|
-
|
34
|
-
|
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).
|
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.
|
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
|
-
|
155
|
+
`lib/events` or `app/events`, etc.
|
123
156
|
|
124
|
-
It is recommended to
|
125
|
-
inside the
|
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
|
130
|
-
their respective classes. For example, if you need to send an email to the user, have a
|
131
|
-
class observe the
|
132
|
-
class, instead of, say, registration controller directly calling
|
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
|
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
|
189
|
+
... my code that publishes events, in isolation from event observers
|
157
190
|
end
|
158
191
|
|
159
|
-
it 'tests that events are
|
160
|
-
event = double(
|
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(:
|
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
|
+
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fkigster%2Fventable?ref=badge_large)
|
data/Rakefile
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
-
|
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
|
data/lib/ventable/event.rb
CHANGED
@@ -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(
|
9
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
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
|
-
|
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 =
|
66
|
-
if observer_entry.nil?
|
67
|
-
|
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
|
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
|
-
|
78
|
-
|
79
|
-
|
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
|
-
|
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
|
-
|
94
|
+
ventable_callback_method_name
|
94
95
|
else
|
95
96
|
target = self
|
96
|
-
|
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
|
data/lib/ventable/version.rb
CHANGED
data/lib/ventable.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
|
-
|
2
|
-
require "ventable/event"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
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
|
-
|
16
|
+
!@disabled
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
20
|
class String
|
20
21
|
def underscore
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
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 {
|
13
|
+
after { described_class.enable }
|
12
14
|
|
13
15
|
it 'is true by default' do
|
14
|
-
expect(
|
16
|
+
expect(described_class.enabled?).to be true
|
15
17
|
end
|
16
18
|
|
17
19
|
it 'is false after Ventable is disabled' do
|
18
|
-
|
19
|
-
expect(
|
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
|
-
|
24
|
-
|
25
|
-
expect(
|
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
|
30
|
-
it
|
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(
|
34
|
+
expect(TestEvent.observers.class.name).to eq('Set')
|
33
35
|
end
|
34
36
|
|
35
|
-
it
|
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).
|
42
|
+
expect(observers).not_to be_nil
|
41
43
|
end
|
42
44
|
|
43
|
-
it
|
45
|
+
it 'maintains separate sets of observers for each event' do
|
44
46
|
class AnotherEvent
|
45
47
|
include Ventable::Event
|
46
48
|
end
|
47
|
-
|
49
|
+
|
50
|
+
expect(AnotherEvent.observers.object_id).not_to eq(TestEvent.observers.object_id)
|
48
51
|
end
|
49
52
|
end
|
50
53
|
|
51
|
-
describe
|
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
|
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
|
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
|
-
|
76
|
-
|
77
|
-
class
|
78
|
-
|
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
|
-
|
81
|
-
|
82
|
-
self.
|
91
|
+
|
92
|
+
class TestEventObserver
|
93
|
+
def self.handle_test(event)
|
94
|
+
event.flag = 'boo'
|
95
|
+
end
|
83
96
|
end
|
84
|
-
end
|
85
97
|
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
95
|
-
|
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
|
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
|
127
|
-
expect(observer_block_called).to be
|
128
|
-
expect(transaction_called).to be
|
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).
|
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 {
|
136
|
-
after {
|
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 |
|
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
|
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
|
176
|
-
expect(
|
177
|
-
|
178
|
-
|
179
|
-
|
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
|
184
|
-
it
|
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
|
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
|
213
|
-
|
214
|
-
|
215
|
-
|
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
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
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
|
-
|
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 =
|
9
|
-
gem.summary =
|
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.
|
20
|
-
|
21
|
-
gem.
|
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.
|
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:
|
11
|
+
date: 2024-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
type: :
|
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: '
|
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
|
-
- ".
|
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
|
-
|
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
|
-
|
111
|
-
|
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
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
|