navigable 1.0.1 → 1.4.0

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
2
  SHA256:
3
- metadata.gz: 3f47d6738b26354f6097bf64b14b7d8646746419f6565e6bb5f90d7263292b0f
4
- data.tar.gz: 9fd0a0522220322ad95a4c40153049ba3a25e86db5a5226ce7308ff276c261f6
3
+ metadata.gz: cb34750833af0f6d8cd1acbd902c18aac498d4f4ccc7395aaec1013f9a558b99
4
+ data.tar.gz: b7724f9edac3d02dd90c7f26b8a3713b2449700a3e89a68d43e439927d954571
5
5
  SHA512:
6
- metadata.gz: 468eadb7a3ddbd2ec5520506e4b55643444f5c9fbe546aab51e902456c7c81d9754c5b8e74c141f9fdad41b4ca5d1667d6c73ac051ffa33fab1fc40aac1c14ab
7
- data.tar.gz: 4fedf730e7b7cc6ac4ded07b0485322b2593b2d2ec88e96adffc5fab72405bf984ee7cf520c25ad1458826a3d95f65dcf7f90dae4d2e771203ca2c0a671a75de
6
+ metadata.gz: 202e9957715004b886d76be87d2b6c856809b4ca04b2f9a62432f460dc2c3f28f8cd31a13bd2cf85bfed329765c6082fb40ccee3ee0c666b930c499517c818ec
7
+ data.tar.gz: e7dfad712e84d3c7339ba71749c4525e36e1b087cccaaca074e6967b509fb192f70b750460881cbc7ba194955cde4dd687e21eb4bac3b3cefb2cb6e2e74f14af
data/.gitignore CHANGED
@@ -13,5 +13,6 @@
13
13
  # rspec failure tracking
14
14
  .rspec_status
15
15
 
16
+ .DS_Store
16
17
  Gemfile.lock
17
18
 
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>
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 and Hanami.
14
+ **[Navigable][navigable]**<br>
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/compass.png"></td>
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 Server** *(coming soon)*<br>
24
- A Rack-based web server for building Navigable-backed applications.
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="Telescope" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/telescope.png"></td>
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 API** *(coming soon)*<br>
33
- An extension of Navigable Server for building restful JSON APIs.
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 sincerely hope you'll download Navigable and play with it! If you do, please send us a note to [navigable@firsttry.software][mail] to give us your thoughts!
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
@@ -1,5 +1,6 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require 'concurrent'
3
4
  require 'manufacturable'
4
5
 
5
6
  require 'navigable/version'
@@ -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
- base.instance_eval do
15
- def corresponds_to(key)
16
- super(key, TYPE)
17
- end
19
+ module ClassMethods
20
+ def corresponds_to(key)
21
+ super(key, TYPE)
18
22
  end
23
+ end
19
24
 
20
- base.class_eval do
21
- attr_reader :params, :observers
25
+ module InstanceMethods
26
+ attr_reader :params, :observers, :resolver
22
27
 
23
- def initialize(params: {}, observers: [])
24
- @params = params
25
- @observers = observers
26
- end
28
+ def inject(params: {}, observers: [], resolver: NullResolver.new)
29
+ @params = params
30
+ @observers = observers
31
+ @resolver = resolver
32
+ end
27
33
 
28
- def execute
29
- raise NotImplementedError.new(EXECUTE_NOT_IMPLEMENTED_MESSAGE)
30
- end
34
+ def execute
35
+ raise NotImplementedError.new(EXECUTE_NOT_IMPLEMENTED_MESSAGE)
31
36
  end
32
37
  end
33
38
  end
@@ -1,12 +1,12 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- require 'navigable/basic_resolver'
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: BasicResolver.new)
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, params: params).push(resolver)
28
+ Manufacturable.build_all(Observer::TYPE, key) { |observer| observer.inject(params: params) }
29
29
  end
30
30
 
31
31
  def command
32
- Manufacturable.build_one(Command::TYPE, key, params: params, observers: observers)
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,9 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Navigable
4
+ class Executor
5
+ def self.execute(&block)
6
+ ENV['CONCURRENT_OBSERVERS'] ? Concurrent.global_io_executor.post(&block) : block.call
7
+ end
8
+ end
9
+ end
@@ -3,7 +3,7 @@
3
3
  require 'navigable/resolver'
4
4
 
5
5
  module Navigable
6
- class BasicResolver
6
+ class NullResolver
7
7
  extend Navigable::Resolver
8
8
 
9
9
  def resolve
@@ -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 successfully(*args)
12
- observers.each { |observer| observer.on_success(*args) }
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
- def failed_to_create(*args)
24
- observers.each { |observer| observer.on_failure_to_create(*args) }
25
- end
26
-
27
- def failed_to_update(*args)
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
- def failed(*args)
36
- observers.each { |observer| observer.on_failure(*args) }
25
+ resolver.send(observer_method, *args, **kwargs)
26
+ end
37
27
  end
38
28
  end
39
29
  end
@@ -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
- base.instance_eval do
14
- def observes_all_commands
15
- corresponds_to_all(TYPE)
16
- end
16
+ module ClassMethods
17
+ def observes_all_commands
18
+ corresponds_to_all(TYPE)
19
+ end
17
20
 
18
- def observes(key)
19
- corresponds_to(key, TYPE)
20
- end
21
+ def observes(key)
22
+ corresponds_to(key, TYPE)
21
23
  end
24
+ end
22
25
 
23
- base.class_eval do
24
- attr_reader :params
26
+ module InstanceMethods
27
+ attr_reader :params
25
28
 
26
- def initialize(params: {})
27
- @params = params
28
- end
29
+ def inject(params: {})
30
+ @params = params
31
+ end
29
32
 
30
- def observed_command_key
31
- manufacturable_item_key
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
- def on_success(*args, **kwargs); end
6
- def on_failure_to_validate(*args, **kwargs); end
7
- def on_failure_to_find(*args, **kwargs); end
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,15 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Navigable
4
+ class ObserverMap
5
+ METHODS = {
6
+ successfully: :on_success,
7
+ failed_to_validate: :on_failure_to_validate,
8
+ failed_to_find: :on_failure_to_find,
9
+ failed_to_create: :on_failure_to_create,
10
+ failed_to_update: :on_failure_to_update,
11
+ failed_to_delete: :on_failure_to_delete,
12
+ failed: :on_failure
13
+ }.freeze
14
+ end
15
+ end
@@ -4,14 +4,29 @@ require 'navigable/observer_interface'
4
4
 
5
5
  module Navigable
6
6
  module Resolver
7
- RESOLVE_NOT_IMPLEMENTED_MESSAGE = 'Class must implement `resolve` method.'
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.class_eval do
12
- def resolve
13
- raise NotImplementedError.new(RESOLVE_NOT_IMPLEMENTED_MESSAGE)
14
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  module Navigable
4
- VERSION = "1.0.1"
4
+ VERSION = "1.4.0"
5
5
  end
@@ -7,8 +7,8 @@ Gem::Specification.new do |spec|
7
7
  spec.authors = ["Alan Ridlehoover", "Fito von Zastrow"]
8
8
  spec.email = ["navigable@firsttry.software"]
9
9
 
10
- spec.summary = %q{Ahoy! Navigable will get you there!}
11
- spec.description = %q{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. We believe a framework should break free of this tyranny. It should be simple, testable, and fast. It can be opinionated. But, it should leverage SOLID principles to guide us toward well structured, well tested, maleable code that is truly navigable.}
10
+ spec.summary = %q{Ahoy! Welcome aboard Navigable!}
11
+ spec.description = %q{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.}
12
12
  spec.homepage = "https://firsttry.software"
13
13
  spec.license = "MIT"
14
14
  spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
@@ -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 "manufacturable", "~> 1.4"
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.1
4
+ version: 1.4.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-09-17 00:00:00.000000000 Z
12
+ date: 2020-10-04 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.4'
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.4'
41
+ version: '1.5'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: bundler
30
44
  requirement: !ruby/object:Gem::Requirement
@@ -95,12 +109,11 @@ dependencies:
95
109
  - - "~>"
96
110
  - !ruby/object:Gem::Version
97
111
  version: 0.17.0
98
- description: We hold these truths to be self-evident, that not all objects are created
99
- equal, that poorly structured code leads to poorly tested code, and that poorly
100
- tested code leads to rigid software and fearful engineers. We believe a framework
101
- should break free of this tyranny. It should be simple, testable, and fast. It can
102
- be opinionated. But, it should leverage SOLID principles to guide us toward well
103
- structured, well tested, maleable code that is truly navigable.
112
+ description: A stand-alone tool for isolating business logic from external interfaces
113
+ and cross-cutting concerns. Navigable composes self-configured command and observer
114
+ objects to allow you to extend your business logic without modifying it. Navigable
115
+ is compatible with any Ruby-based application development framework, including Rails,
116
+ Hanami, and Sinatra.
104
117
  email:
105
118
  - navigable@firsttry.software
106
119
  executables: []
@@ -109,7 +122,6 @@ extra_rdoc_files: []
109
122
  files:
110
123
  - ".gitignore"
111
124
  - ".rspec"
112
- - ".ruby-version"
113
125
  - ".travis.yml"
114
126
  - CODE_OF_CONDUCT.md
115
127
  - Gemfile
@@ -119,12 +131,14 @@ files:
119
131
  - bin/console
120
132
  - bin/setup
121
133
  - lib/navigable.rb
122
- - lib/navigable/basic_resolver.rb
123
134
  - lib/navigable/command.rb
124
135
  - lib/navigable/dispatcher.rb
136
+ - lib/navigable/executor.rb
137
+ - lib/navigable/null_resolver.rb
125
138
  - lib/navigable/observable.rb
126
139
  - lib/navigable/observer.rb
127
140
  - lib/navigable/observer_interface.rb
141
+ - lib/navigable/observer_map.rb
128
142
  - lib/navigable/resolver.rb
129
143
  - lib/navigable/version.rb
130
144
  - navigable.gemspec
@@ -153,5 +167,5 @@ requirements: []
153
167
  rubygems_version: 3.1.2
154
168
  signing_key:
155
169
  specification_version: 4
156
- summary: Ahoy! Navigable will get you there!
170
+ summary: Ahoy! Welcome aboard Navigable!
157
171
  test_files: []
@@ -1 +0,0 @@
1
- 2.7.1