navigable 1.0.2 → 1.5.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 +4 -4
- data/.gitignore +1 -0
- data/README.md +16 -17
- data/lib/navigable.rb +1 -0
- data/lib/navigable/command.rb +18 -13
- data/lib/navigable/dispatcher.rb +8 -4
- data/lib/navigable/executor.rb +9 -0
- data/lib/navigable/null_resolver.rb +19 -0
- data/lib/navigable/observable.rb +13 -23
- data/lib/navigable/observer.rb +17 -15
- data/lib/navigable/observer_interface.rb +5 -7
- data/lib/navigable/observer_map.rb +16 -0
- data/lib/navigable/resolver.rb +20 -5
- data/lib/navigable/version.rb +1 -1
- data/navigable.gemspec +2 -1
- metadata +21 -6
- data/.ruby-version +0 -1
- data/lib/navigable/basic_resolver.rb +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 966eb5d995d2e8f36c4450d4e2519457da26c2a0002710c12f77a612826d1807
|
4
|
+
data.tar.gz: 103449a1ac072269ea8b1286b47b07d6be5d6964adc04ca4b183ba40232d4ea8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97a549b8a71e31b29c3c99773a4ad24f1ce653b5223c5e526de33130196c025ffe502b296ae5719b67bee26d9d206a9c738f8ac5b8a4eed025295392c7b2396c
|
7
|
+
data.tar.gz: 62cd0c2c211d3e4056c6cb6cb3801a165842af287a09f95451fe78b265f6b04111acee9ae4b0cbadee246b3c80748a4ba38afd17e00ac8032ef32f4d224159fb
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -11,26 +11,26 @@ Navigable is a family of gems that together provide all the tools you need to bu
|
|
11
11
|
<td width="130"><img alt="Clipper Ship" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/clipper.png"></td>
|
12
12
|
<td>
|
13
13
|
|
14
|
-
**Navigable**<br>
|
14
|
+
**[Navigable][navigable]**<br>
|
15
15
|
A stand-alone tool for isolating business logic from external interfaces and cross-cutting concerns. Navigable composes self-configured command and observer objects to allow you to extend your business logic without modifying it. Navigable is compatible with any Ruby-based application development framework, including Rails, Hanami, and Sinatra.
|
16
16
|
|
17
17
|
</td>
|
18
18
|
</tr>
|
19
19
|
<tr height="140">
|
20
|
-
<td width="130"><img alt="Compass" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/
|
20
|
+
<td width="130"><img alt="Compass" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/sextant.png"></td>
|
21
21
|
<td>
|
22
22
|
|
23
|
-
**Navigable
|
24
|
-
A Rack-based
|
23
|
+
**[Navigable Router][router]** *(coming soon)*<br>
|
24
|
+
A simple, highly-performant, Rack-based router.
|
25
25
|
|
26
26
|
</td>
|
27
27
|
</tr>
|
28
28
|
<tr height="140">
|
29
|
-
<td width="130"><img alt="
|
29
|
+
<td width="130"><img alt="Compass" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/compass.png"></td>
|
30
30
|
<td>
|
31
31
|
|
32
|
-
**Navigable
|
33
|
-
|
32
|
+
**[Navigable Server][server]** *(coming soon)*<br>
|
33
|
+
A Rack-based server for building Ruby and Navigable web applications.
|
34
34
|
|
35
35
|
</td>
|
36
36
|
</tr>
|
@@ -38,7 +38,7 @@ An extension of Navigable Server for building restful JSON APIs.
|
|
38
38
|
<td width="130"><img alt="Map" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/map.png"></td>
|
39
39
|
<td>
|
40
40
|
|
41
|
-
**Navigable GraphQL** *(coming soon)*<br>
|
41
|
+
**[Navigable GraphQL][graphql]** *(coming soon)*<br>
|
42
42
|
An extension of Navigable Server for building GraphQL APIs.
|
43
43
|
|
44
44
|
</td>
|
@@ -49,8 +49,6 @@ An extension of Navigable Server for building GraphQL APIs.
|
|
49
49
|
|
50
50
|
<img style="width: 600px; display: block; margin: 0 auto;" alt="Lighthouse" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/lighthouse.png">
|
51
51
|
|
52
|
-
<br>
|
53
|
-
|
54
52
|
# The Navigable Charter
|
55
53
|
|
56
54
|
We hold these truths to be self-evident, that not all objects are created equal, that poorly structured code leads to poorly tested code, and that poorly tested code leads to rigid software and fearful engineers.
|
@@ -164,11 +162,13 @@ Here are a few things to look for in the code above:
|
|
164
162
|
|
165
163
|
* Use the `observes_all_commands` statement (as shown in the `Monitor` class) for cross-cutting concerns. It tells Navigable to send messages to the observer no matter which command was executed.
|
166
164
|
|
165
|
+
For a deeper look at the core concepts introduced by Navigable, please have a look at our [wiki][wiki].
|
166
|
+
|
167
167
|
## Feedback
|
168
168
|
|
169
169
|
We are really excited about Navigable! We think it solves the problem of seperating business logic from the web interface, persistence layer, and even cross-cutting concerns in an elegant and simple way.
|
170
170
|
|
171
|
-
We
|
171
|
+
We're thrilled you're checking out Navigable! If you have any questions or comments, please feel free to reach out to [navigable@firsttry.software][mail].
|
172
172
|
|
173
173
|
## Installation
|
174
174
|
|
@@ -186,12 +186,6 @@ Or install it yourself as:
|
|
186
186
|
|
187
187
|
$ gem install navigable
|
188
188
|
|
189
|
-
## Development
|
190
|
-
|
191
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
192
|
-
|
193
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
194
|
-
|
195
189
|
## Contributing
|
196
190
|
|
197
191
|
Bug reports and pull requests are welcome on GitHub at https://github.com/first-try-software/navigable.
|
@@ -210,3 +204,8 @@ Everyone interacting in the Navigable project's codebases, issue trackers, chat
|
|
210
204
|
[ocp]: https://en.wikipedia.org/wiki/Open–closed_principle
|
211
205
|
[ddd]: https://en.wikipedia.org/wiki/Domain-driven_design
|
212
206
|
[mail]: mailto:navigable@firsttry.software
|
207
|
+
[wiki]: https://github.com/first-try-software/navigable/wiki
|
208
|
+
[navigable]: https://github.com/first-try-software/navigable
|
209
|
+
[router]: https://github.com/first-try-software/navigable-router
|
210
|
+
[server]: https://github.com/first-try-software/navigable-server
|
211
|
+
[graphql]: https://github.com/first-try-software/navigable-graphql
|
data/lib/navigable.rb
CHANGED
data/lib/navigable/command.rb
CHANGED
@@ -4,30 +4,35 @@ require 'navigable/observable'
|
|
4
4
|
|
5
5
|
module Navigable
|
6
6
|
module Command
|
7
|
+
class NotFoundError < StandardError; end
|
8
|
+
|
7
9
|
TYPE = :__command__
|
8
10
|
EXECUTE_NOT_IMPLEMENTED_MESSAGE = 'Class must implement `execute` method.'
|
9
11
|
|
10
12
|
def self.extended(base)
|
11
13
|
base.extend(Manufacturable::Item)
|
14
|
+
base.extend(ClassMethods)
|
12
15
|
base.include(Observable)
|
16
|
+
base.include(InstanceMethods)
|
17
|
+
end
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
19
|
+
module ClassMethods
|
20
|
+
def corresponds_to(key)
|
21
|
+
super(key, TYPE)
|
18
22
|
end
|
23
|
+
end
|
19
24
|
|
20
|
-
|
21
|
-
|
25
|
+
module InstanceMethods
|
26
|
+
attr_reader :params, :observers, :resolver
|
22
27
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
def inject(params: {}, observers: [], resolver: NullResolver.new)
|
29
|
+
@params = params
|
30
|
+
@observers = observers
|
31
|
+
@resolver = resolver
|
32
|
+
end
|
27
33
|
|
28
|
-
|
29
|
-
|
30
|
-
end
|
34
|
+
def execute
|
35
|
+
raise NotImplementedError.new(EXECUTE_NOT_IMPLEMENTED_MESSAGE)
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
data/lib/navigable/dispatcher.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
-
require 'navigable/
|
3
|
+
require 'navigable/null_resolver'
|
4
4
|
require 'navigable/observer'
|
5
5
|
require 'navigable/command'
|
6
6
|
|
7
7
|
module Navigable
|
8
8
|
class Dispatcher
|
9
|
-
def self.dispatch(key, params: {}, resolver:
|
9
|
+
def self.dispatch(key, params: {}, resolver: NullResolver.new)
|
10
10
|
self.new(key, params: params, resolver: resolver).dispatch
|
11
11
|
end
|
12
12
|
|
@@ -25,11 +25,15 @@ module Navigable
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def observers
|
28
|
-
Manufacturable.build_all(Observer::TYPE, key
|
28
|
+
Manufacturable.build_all(Observer::TYPE, key) { |observer| observer.inject(params: params) }
|
29
29
|
end
|
30
30
|
|
31
31
|
def command
|
32
|
-
|
32
|
+
build_command.tap { |command| raise Navigable::Command::NotFoundError unless command }
|
33
|
+
end
|
34
|
+
|
35
|
+
def build_command
|
36
|
+
Manufacturable.build_one(Command::TYPE, key) { |command| command.inject(params: params, observers: observers, resolver: resolver) }
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
require 'navigable/resolver'
|
4
|
+
|
5
|
+
module Navigable
|
6
|
+
class NullResolver
|
7
|
+
extend Navigable::Resolver
|
8
|
+
|
9
|
+
def resolve
|
10
|
+
@result
|
11
|
+
end
|
12
|
+
|
13
|
+
ObserverMap::METHODS.values.each do |observer_method|
|
14
|
+
define_method(observer_method) do |result|
|
15
|
+
@result = result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/navigable/observable.rb
CHANGED
@@ -1,39 +1,29 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
+
require 'navigable/observer_map'
|
4
|
+
require 'navigable/executor'
|
5
|
+
|
3
6
|
module Navigable
|
4
7
|
module Observable
|
5
8
|
OBSERVERS_NOT_IMPLEMENTED_MESSAGE = 'Class must implement `observers` method.'
|
9
|
+
RESOLVER_NOT_IMPLEMENTED_MESSAGE = 'Class must implement `resolver` method.'
|
6
10
|
|
7
11
|
def observers
|
8
12
|
raise NotImplementedError.new(OBSERVERS_NOT_IMPLEMENTED_MESSAGE)
|
9
13
|
end
|
10
14
|
|
11
|
-
def
|
12
|
-
|
13
|
-
end
|
14
|
-
|
15
|
-
def failed_to_validate(*args)
|
16
|
-
observers.each { |observer| observer.on_failure_to_validate(*args) }
|
17
|
-
end
|
18
|
-
|
19
|
-
def failed_to_find(*args)
|
20
|
-
observers.each { |observer| observer.on_failure_to_find(*args) }
|
15
|
+
def resolver
|
16
|
+
raise NotImplementedError.new(RESOLVER_NOT_IMPLEMENTED_MESSAGE)
|
21
17
|
end
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
observers.each { |observer| observer.on_failure_to_update(*args) }
|
29
|
-
end
|
30
|
-
|
31
|
-
def failed_to_delete(*args)
|
32
|
-
observers.each { |observer| observer.on_failure_to_delete(*args) }
|
33
|
-
end
|
19
|
+
ObserverMap::METHODS.each_pair do |observable_method, observer_method|
|
20
|
+
define_method(observable_method) do |*args, **kwargs|
|
21
|
+
observers.each do |observer|
|
22
|
+
Navigable::Executor.execute { observer.send(observer_method, *args, **kwargs) }
|
23
|
+
end
|
34
24
|
|
35
|
-
|
36
|
-
|
25
|
+
resolver.send(observer_method, *args, **kwargs)
|
26
|
+
end
|
37
27
|
end
|
38
28
|
end
|
39
29
|
end
|
data/lib/navigable/observer.rb
CHANGED
@@ -8,28 +8,30 @@ module Navigable
|
|
8
8
|
|
9
9
|
def self.extended(base)
|
10
10
|
base.extend(Manufacturable::Item)
|
11
|
+
base.extend(ClassMethods)
|
11
12
|
base.include(ObserverInterface)
|
13
|
+
base.include(InstanceMethods)
|
14
|
+
end
|
12
15
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
module ClassMethods
|
17
|
+
def observes_all_commands
|
18
|
+
corresponds_to_all(TYPE)
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
end
|
21
|
+
def observes(key)
|
22
|
+
corresponds_to(key, TYPE)
|
21
23
|
end
|
24
|
+
end
|
22
25
|
|
23
|
-
|
24
|
-
|
26
|
+
module InstanceMethods
|
27
|
+
attr_reader :params
|
25
28
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
def inject(params: {})
|
30
|
+
@params = params
|
31
|
+
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
+
def observed_command_key
|
34
|
+
manufacturable_item_key
|
33
35
|
end
|
34
36
|
end
|
35
37
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
|
+
require 'navigable/observer_map'
|
4
|
+
|
3
5
|
module Navigable
|
4
6
|
module ObserverInterface
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
def on_failure_to_create(*args, **kwargs); end
|
9
|
-
def on_failure_to_update(*args, **kwargs); end
|
10
|
-
def on_failure_to_delete(*args, **kwargs); end
|
11
|
-
def on_failure(*args, **kwargs); end
|
7
|
+
ObserverMap::METHODS.values.each do |observer_method|
|
8
|
+
define_method(observer_method) { |*args, **kwargs| }
|
9
|
+
end
|
12
10
|
end
|
13
11
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Navigable
|
4
|
+
class ObserverMap
|
5
|
+
METHODS = {
|
6
|
+
successfully: :on_success,
|
7
|
+
successfully_created: :on_creation,
|
8
|
+
failed_to_validate: :on_failure_to_validate,
|
9
|
+
failed_to_find: :on_failure_to_find,
|
10
|
+
failed_to_create: :on_failure_to_create,
|
11
|
+
failed_to_update: :on_failure_to_update,
|
12
|
+
failed_to_delete: :on_failure_to_delete,
|
13
|
+
failed: :on_failure
|
14
|
+
}.freeze
|
15
|
+
end
|
16
|
+
end
|
data/lib/navigable/resolver.rb
CHANGED
@@ -4,14 +4,29 @@ require 'navigable/observer_interface'
|
|
4
4
|
|
5
5
|
module Navigable
|
6
6
|
module Resolver
|
7
|
-
|
7
|
+
TYPE = :__resolver__
|
8
|
+
RESOLVE_NOT_IMPLEMENTED_MESSAGE = 'Resolver classes must implement a `resolve` method.'
|
8
9
|
|
9
10
|
def self.extended(base)
|
11
|
+
base.extend(Manufacturable::Item)
|
12
|
+
base.extend(ClassMethods)
|
10
13
|
base.include(ObserverInterface)
|
11
|
-
base.
|
12
|
-
|
13
|
-
|
14
|
-
|
14
|
+
base.include(InstanceMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def default_resolver
|
19
|
+
default_manufacturable(TYPE)
|
20
|
+
end
|
21
|
+
|
22
|
+
def resolves(key)
|
23
|
+
corresponds_to(key, TYPE)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module InstanceMethods
|
28
|
+
def resolve
|
29
|
+
raise NotImplementedError.new(RESOLVE_NOT_IMPLEMENTED_MESSAGE)
|
15
30
|
end
|
16
31
|
end
|
17
32
|
end
|
data/lib/navigable/version.rb
CHANGED
data/navigable.gemspec
CHANGED
@@ -24,7 +24,8 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ["lib"]
|
26
26
|
|
27
|
-
spec.add_dependency "
|
27
|
+
spec.add_dependency "concurrent-ruby", "~> 1.1.7"
|
28
|
+
spec.add_dependency "manufacturable", "~> 1.5"
|
28
29
|
|
29
30
|
spec.add_development_dependency "bundler", "~> 2.0"
|
30
31
|
spec.add_development_dependency "rake", "~> 12.0"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: navigable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alan Ridlehoover
|
@@ -9,22 +9,36 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-
|
12
|
+
date: 2020-12-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: concurrent-ruby
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 1.1.7
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.1.7
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: manufacturable
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
17
31
|
requirements:
|
18
32
|
- - "~>"
|
19
33
|
- !ruby/object:Gem::Version
|
20
|
-
version: '1.
|
34
|
+
version: '1.5'
|
21
35
|
type: :runtime
|
22
36
|
prerelease: false
|
23
37
|
version_requirements: !ruby/object:Gem::Requirement
|
24
38
|
requirements:
|
25
39
|
- - "~>"
|
26
40
|
- !ruby/object:Gem::Version
|
27
|
-
version: '1.
|
41
|
+
version: '1.5'
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: bundler
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,7 +122,6 @@ extra_rdoc_files: []
|
|
108
122
|
files:
|
109
123
|
- ".gitignore"
|
110
124
|
- ".rspec"
|
111
|
-
- ".ruby-version"
|
112
125
|
- ".travis.yml"
|
113
126
|
- CODE_OF_CONDUCT.md
|
114
127
|
- Gemfile
|
@@ -118,12 +131,14 @@ files:
|
|
118
131
|
- bin/console
|
119
132
|
- bin/setup
|
120
133
|
- lib/navigable.rb
|
121
|
-
- lib/navigable/basic_resolver.rb
|
122
134
|
- lib/navigable/command.rb
|
123
135
|
- lib/navigable/dispatcher.rb
|
136
|
+
- lib/navigable/executor.rb
|
137
|
+
- lib/navigable/null_resolver.rb
|
124
138
|
- lib/navigable/observable.rb
|
125
139
|
- lib/navigable/observer.rb
|
126
140
|
- lib/navigable/observer_interface.rb
|
141
|
+
- lib/navigable/observer_map.rb
|
127
142
|
- lib/navigable/resolver.rb
|
128
143
|
- lib/navigable/version.rb
|
129
144
|
- navigable.gemspec
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.7.1
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen-string-literal: true
|
2
|
-
|
3
|
-
require 'navigable/resolver'
|
4
|
-
|
5
|
-
module Navigable
|
6
|
-
class BasicResolver
|
7
|
-
extend Navigable::Resolver
|
8
|
-
|
9
|
-
def resolve
|
10
|
-
@result
|
11
|
-
end
|
12
|
-
|
13
|
-
def on_success(result)
|
14
|
-
@result = result
|
15
|
-
end
|
16
|
-
|
17
|
-
alias_method :on_failure_to_validate, :on_success
|
18
|
-
alias_method :on_failure_to_find, :on_success
|
19
|
-
alias_method :on_failure_to_create, :on_success
|
20
|
-
alias_method :on_failure_to_update, :on_success
|
21
|
-
alias_method :on_failure_to_delete, :on_success
|
22
|
-
alias_method :on_failure, :on_success
|
23
|
-
end
|
24
|
-
end
|