octiron 0.1.0
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 +7 -0
- data/.codeclimate.yml +31 -0
- data/.gitignore +39 -0
- data/.rspec +2 -0
- data/.rubocop.yml +78 -0
- data/.travis.yml +11 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +70 -0
- data/LICENSE +30 -0
- data/README.md +159 -0
- data/Rakefile +25 -0
- data/lib/octiron.rb +11 -0
- data/lib/octiron/events/bus.rb +161 -0
- data/lib/octiron/support/camel_case.rb +27 -0
- data/lib/octiron/support/constantize.rb +43 -0
- data/lib/octiron/support/identifiers.rb +45 -0
- data/lib/octiron/transmogrifiers/registry.rb +201 -0
- data/lib/octiron/version.rb +12 -0
- data/lib/octiron/world.rb +94 -0
- data/octiron.gemspec +50 -0
- data/spec/events_bus_spec.rb +322 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support_camel_case_spec.rb +24 -0
- data/spec/support_constantize_spec.rb +64 -0
- data/spec/support_identifiers_spec.rb +70 -0
- data/spec/transmogrifiers_registry_spec.rb +311 -0
- data/spec/world_spec.rb +58 -0
- metadata +191 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0a1d5d04db3e10eb26f3292976922347550a8174
|
4
|
+
data.tar.gz: 609b4ac6d312fc78d74bbe3d3a127cc937584798
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8783e03aa012d7b3049ea7824b00a8699d94ac703ee1506bc6bd9e080367506aebc022e060fa6099a565620ce3146d808743adb5585cbac152271baec5b0471b
|
7
|
+
data.tar.gz: b0d09e6f7d9336fb965272a7d2d66264f1e698377563acd4988472c95901959b8434a8fa20ac757a1dda3b0f5129842db7e7454ff1fe414dbd575f9ac6ea6f01
|
data/.codeclimate.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
---
|
2
|
+
engines:
|
3
|
+
bundler-audit:
|
4
|
+
enabled: true
|
5
|
+
duplication:
|
6
|
+
enabled: true
|
7
|
+
exclude_fingerprints:
|
8
|
+
- 8d15a3402e79d161b5ae30535883e4e4
|
9
|
+
engines:
|
10
|
+
config:
|
11
|
+
languages:
|
12
|
+
- ruby
|
13
|
+
- javascript
|
14
|
+
- python
|
15
|
+
- php
|
16
|
+
fixme:
|
17
|
+
enabled: true
|
18
|
+
rubocop:
|
19
|
+
enabled: true
|
20
|
+
ratings:
|
21
|
+
paths:
|
22
|
+
- Gemfile.lock
|
23
|
+
- "**.inc"
|
24
|
+
- "**.js"
|
25
|
+
- "**.jsx"
|
26
|
+
- "**.module"
|
27
|
+
- "**.php"
|
28
|
+
- "**.py"
|
29
|
+
- "**.rb"
|
30
|
+
exclude_paths:
|
31
|
+
- spec/
|
data/.gitignore
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
## Specific to RubyMotion:
|
14
|
+
.dat*
|
15
|
+
.repl_history
|
16
|
+
build/
|
17
|
+
|
18
|
+
## Documentation cache and generated files:
|
19
|
+
/.yardoc/
|
20
|
+
/_yardoc/
|
21
|
+
/doc/
|
22
|
+
/rdoc/
|
23
|
+
|
24
|
+
## Environment normalization:
|
25
|
+
/.bundle/
|
26
|
+
/vendor/bundle
|
27
|
+
/lib/bundler/man/
|
28
|
+
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
31
|
+
# Gemfile.lock
|
32
|
+
# .ruby-version
|
33
|
+
# .ruby-gemset
|
34
|
+
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
36
|
+
.rvmrc
|
37
|
+
|
38
|
+
# Editor files
|
39
|
+
.*.sw*
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.2
|
3
|
+
|
4
|
+
# Metrics
|
5
|
+
|
6
|
+
Metrics/LineLength:
|
7
|
+
Max: 83
|
8
|
+
Details: >-
|
9
|
+
Line length of 80 is ideal for readability and compatibility; we'll accept
|
10
|
+
an extra 3 for minor edge cases.
|
11
|
+
|
12
|
+
Metrics/MethodLength:
|
13
|
+
Max: 35
|
14
|
+
|
15
|
+
Metrics/BlockNesting:
|
16
|
+
Max: 5
|
17
|
+
|
18
|
+
Metrics/AbcSize:
|
19
|
+
Max: 50
|
20
|
+
|
21
|
+
Metrics/PerceivedComplexity:
|
22
|
+
Max: 15
|
23
|
+
|
24
|
+
Metrics/CyclomaticComplexity:
|
25
|
+
Max: 15
|
26
|
+
|
27
|
+
Metrics/ClassLength:
|
28
|
+
Max: 300
|
29
|
+
|
30
|
+
Metrics/ModuleLength:
|
31
|
+
Max: 300
|
32
|
+
|
33
|
+
# Style
|
34
|
+
|
35
|
+
Style/StringLiterals:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Style/ConditionalAssignment:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/EmptyLinesAroundModuleBody:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/AndOr:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
Style/Not:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Style/NegatedIf:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
Style/RedundantReturn:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
Style/IfUnlessModifier:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
Style/TrailingCommaInLiteral:
|
60
|
+
Enabled: false
|
61
|
+
|
62
|
+
Style/FirstParameterIndentation:
|
63
|
+
Enabled: false
|
64
|
+
|
65
|
+
Style/TrailingUnderscoreVariable:
|
66
|
+
Enabled: false
|
67
|
+
|
68
|
+
Style/NumericLiterals:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
Style/FileName:
|
72
|
+
Enabled: false
|
73
|
+
|
74
|
+
Style/SpaceAfterNot:
|
75
|
+
Enabled: false
|
76
|
+
|
77
|
+
Style/ClassAndModuleChildren:
|
78
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
octiron (0.1.0)
|
5
|
+
collapsium (~> 0.8)
|
6
|
+
rgl (~> 0.5)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
ast (2.3.0)
|
12
|
+
codeclimate-test-reporter (1.0.3)
|
13
|
+
simplecov
|
14
|
+
collapsium (0.8.2)
|
15
|
+
diff-lcs (1.2.5)
|
16
|
+
docile (1.1.5)
|
17
|
+
json (2.0.2)
|
18
|
+
lazy_priority_queue (0.1.1)
|
19
|
+
parser (2.3.3.1)
|
20
|
+
ast (~> 2.2)
|
21
|
+
powerpack (0.1.1)
|
22
|
+
rainbow (2.1.0)
|
23
|
+
rake (11.3.0)
|
24
|
+
rgl (0.5.2)
|
25
|
+
lazy_priority_queue (~> 0.1.0)
|
26
|
+
stream (~> 0.5.0)
|
27
|
+
rspec (3.5.0)
|
28
|
+
rspec-core (~> 3.5.0)
|
29
|
+
rspec-expectations (~> 3.5.0)
|
30
|
+
rspec-mocks (~> 3.5.0)
|
31
|
+
rspec-core (3.5.4)
|
32
|
+
rspec-support (~> 3.5.0)
|
33
|
+
rspec-expectations (3.5.0)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.5.0)
|
36
|
+
rspec-mocks (3.5.0)
|
37
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
+
rspec-support (~> 3.5.0)
|
39
|
+
rspec-support (3.5.0)
|
40
|
+
rubocop (0.46.0)
|
41
|
+
parser (>= 2.3.1.1, < 3.0)
|
42
|
+
powerpack (~> 0.1)
|
43
|
+
rainbow (>= 1.99.1, < 3.0)
|
44
|
+
ruby-progressbar (~> 1.7)
|
45
|
+
unicode-display_width (~> 1.0, >= 1.0.1)
|
46
|
+
ruby-progressbar (1.8.1)
|
47
|
+
simplecov (0.12.0)
|
48
|
+
docile (~> 1.1.0)
|
49
|
+
json (>= 1.8, < 3)
|
50
|
+
simplecov-html (~> 0.10.0)
|
51
|
+
simplecov-html (0.10.0)
|
52
|
+
stream (0.5)
|
53
|
+
unicode-display_width (1.1.1)
|
54
|
+
yard (0.9.5)
|
55
|
+
|
56
|
+
PLATFORMS
|
57
|
+
ruby
|
58
|
+
|
59
|
+
DEPENDENCIES
|
60
|
+
bundler (~> 1.13)
|
61
|
+
codeclimate-test-reporter
|
62
|
+
octiron!
|
63
|
+
rake (~> 11.3)
|
64
|
+
rspec (~> 3.5)
|
65
|
+
rubocop (~> 0.46)
|
66
|
+
simplecov (~> 0.12)
|
67
|
+
yard (~> 0.9)
|
68
|
+
|
69
|
+
BUNDLED WITH
|
70
|
+
1.13.6
|
data/LICENSE
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Copyright (c) Jens Finkhaeuser (http://finkhaeuser.de/) and other octiron
|
2
|
+
contributors. All rights not covered below are reserved.
|
3
|
+
|
4
|
+
The MIT +no-false-attribs License (MITNFA)
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to
|
8
|
+
deal in the Software without restriction, including without limitation the
|
9
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
10
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
Distributions of all or part of the Software intended to be used by the
|
17
|
+
recipients as they would use the unmodified Software, containing modifications
|
18
|
+
that substantially alter, remove, or disable functionality of the Software,
|
19
|
+
outside of the documented configuration mechanisms provided by the Software,
|
20
|
+
shall be modified such that the Original Author's bug reporting email addresses
|
21
|
+
and urls are either replaced with the contact information of the parties
|
22
|
+
responsible for the changes, or removed entirely.
|
23
|
+
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
29
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
30
|
+
IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
# octiron
|
2
|
+
|
3
|
+
*Octiron is an event bus with the ability to magically transform events.*
|
4
|
+
|
5
|
+
Events octiron responds to can be any classes or Hash prototypes. Using
|
6
|
+
transmogrifiers, events can be turned into other kinds of events
|
7
|
+
transparently.
|
8
|
+
|
9
|
+
[](https://badge.fury.io/rb/octiron)
|
10
|
+
[](https://travis-ci.org/jfinkhaeuser/octiron)
|
11
|
+
[](https://codeclimate.com/github/jfinkhaeuser/octiron)
|
12
|
+
[](https://codeclimate.com/github/jfinkhaeuser/octiron/coverage)
|
13
|
+
|
14
|
+
# Usage
|
15
|
+
|
16
|
+
So what does this all mean?
|
17
|
+
|
18
|
+
## Fundamentals
|
19
|
+
|
20
|
+
First of all, the gem contains a publish/subscribe event bus, which easily
|
21
|
+
allows you to subscribe handlers to events of a particular class:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'octiron'
|
25
|
+
|
26
|
+
class MyEvent
|
27
|
+
# ...
|
28
|
+
end
|
29
|
+
|
30
|
+
on_event(MyEvent) do |event|
|
31
|
+
# event.is_a?(MyEvent) == true
|
32
|
+
# do something with the event
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
You can subscribe as many handlers to an event class as you want.
|
37
|
+
|
38
|
+
Next, you can transmogrify objects - typically events. Similar to suscribing
|
39
|
+
event handlers, you can register transmogrifiers for a particular
|
40
|
+
transmogrification.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
class AnotherEvent
|
44
|
+
end
|
45
|
+
|
46
|
+
on_transmogrify(MyEvent).to AnotherEvent do |my_event|
|
47
|
+
# guaranteed: my_event.is_a?(MyEvent) == true
|
48
|
+
AnotherEvent.new
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
As long as the transmogrifier returns an object of the `AnotherEvent` type,
|
53
|
+
all is well.
|
54
|
+
|
55
|
+
Putting this together with the hitherto unmentioned `#publish` method, you can
|
56
|
+
easily build processing pipelines.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
on_transmogrify(MyEvent).to AnotherEvent do |my_event|
|
60
|
+
# do something more meaningful
|
61
|
+
AnotherEvent.new
|
62
|
+
end
|
63
|
+
|
64
|
+
on_event(MyEvent) do |event|
|
65
|
+
publish transmogrify(event).to AnotherEvent
|
66
|
+
end
|
67
|
+
|
68
|
+
on_event(AnotherEvent) do |event|
|
69
|
+
# We'll end up here with the transmogrified event
|
70
|
+
end
|
71
|
+
|
72
|
+
publish MyEvent.new
|
73
|
+
```
|
74
|
+
|
75
|
+
## Advanced Usage
|
76
|
+
|
77
|
+
There are some more advanced topics that might be useful to understand.
|
78
|
+
|
79
|
+
### Singletons vs. API
|
80
|
+
|
81
|
+
The octiron gem exposes a number of simple wrapper functions we've used so far
|
82
|
+
to hide the API complexity a little. These wrapper functions make use of a
|
83
|
+
singleton event bus instance, and a singleton transmogrifier registry:
|
84
|
+
|
85
|
+
- `#on_event` delegates `Octiron::Events::Bus#subscribe`
|
86
|
+
- `#publish` delegates `Octiron::Events::Bus#publish`
|
87
|
+
- `#on_transmogrify` delegates to `Octiron::Transmogrifiers::Registry#register`
|
88
|
+
- `#transmogrify` delegates to `Octiron::Transmogrifiers::Registry#transmogrify`
|
89
|
+
|
90
|
+
You can just as well use these underlying API functions with multiple instances
|
91
|
+
of the event bus or the transmogrifier registry.
|
92
|
+
|
93
|
+
### Hash Prototypes
|
94
|
+
|
95
|
+
The octiron gem implements something of a prototyping mechanic for using Hashes
|
96
|
+
as events, but also as sources and targets of transmogrification. If the event
|
97
|
+
bus would register handlers for the Hash class, all Hashes would trigger the
|
98
|
+
same handlers (and similar for the transmogrifier registry).
|
99
|
+
|
100
|
+
Instead, where you would normally provide classes (e.g. `#on_event`), you can
|
101
|
+
specify a Hash that acts as a prototype. Then, where you would normally use
|
102
|
+
instances (e.g. `#publish`), you can provide a Hash again. If that published
|
103
|
+
Hash matches the prototype Hash, the handler associated with the prototype is
|
104
|
+
triggered.
|
105
|
+
|
106
|
+
So how does this matching work?
|
107
|
+
|
108
|
+
- If a prototype specifies a key without value (i.e. a nil value), the published
|
109
|
+
instance *must* contain the key, but the value or value type is ignored.
|
110
|
+
- If a prototype specifies a key with a value, the published instance *must*
|
111
|
+
contain the key, and it's value *must* match the respective value in the
|
112
|
+
prototype.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
proto1 = {
|
116
|
+
a: nil,
|
117
|
+
}
|
118
|
+
|
119
|
+
proto2 = {
|
120
|
+
b: 42,
|
121
|
+
}
|
122
|
+
|
123
|
+
published1 = {
|
124
|
+
a: 'foo',
|
125
|
+
}
|
126
|
+
# published1 matches proto1, but not proto2
|
127
|
+
|
128
|
+
published2 = {
|
129
|
+
b: 42,
|
130
|
+
}
|
131
|
+
# published2 matches proto2, but not proto1
|
132
|
+
```
|
133
|
+
|
134
|
+
Hash prototyping is supported both for subscribing event handlers, and
|
135
|
+
registering transmogrifiers, allowing for something of the following:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
on_transmogrify(proto1).to proto2 do |event|
|
139
|
+
x = event.dup
|
140
|
+
x.delete(:a)
|
141
|
+
x[:b] = 42
|
142
|
+
x
|
143
|
+
end
|
144
|
+
|
145
|
+
on_event(proto1) do |event|
|
146
|
+
publish transmogrify(event).to proto2
|
147
|
+
end
|
148
|
+
|
149
|
+
on_event(proto2) do |event|
|
150
|
+
# we'll end up here
|
151
|
+
end
|
152
|
+
|
153
|
+
publish published1
|
154
|
+
```
|
155
|
+
|
156
|
+
*Note* that you can produce closed loops by publishing events from within event
|
157
|
+
handlers. In the above example, if the transmogrifier did not delete the `:a`
|
158
|
+
key from the newly created event, it would still match the `proto1` prototype,
|
159
|
+
which would trigger that handler and the transmogrifier again and again.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Rubocop
|
2
|
+
require 'rubocop/rake_task'
|
3
|
+
RuboCop::RakeTask.new(:rubocop)
|
4
|
+
|
5
|
+
# Rspec
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
RSpec::Core::RakeTask.new(:rspec)
|
8
|
+
|
9
|
+
# Documentation
|
10
|
+
require 'yard'
|
11
|
+
YARD::Rake::YardocTask.new do |t|
|
12
|
+
t.files = ['lib/**/*.rb']
|
13
|
+
t.options = ['-m', 'markdown']
|
14
|
+
t.stats_options = ['--list-undoc']
|
15
|
+
end
|
16
|
+
|
17
|
+
# Combined test task
|
18
|
+
desc "Test all the things!"
|
19
|
+
task :test do
|
20
|
+
Rake::Task[:rubocop].invoke
|
21
|
+
Rake::Task[:rspec].invoke
|
22
|
+
end
|
23
|
+
|
24
|
+
# Default is the test task
|
25
|
+
task default: :test
|