navigable 0.2.0 → 1.0.2

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: 83333f93d812c30f98148fc513bc729dda72f19f31b2c4844454bf04129088d2
4
- data.tar.gz: f991e29b72390bc4f5cb430c90f0a2b0b92f39ea0b8ffc3c065357c1d2eaf947
3
+ metadata.gz: b96bb3ac3fd1a2e93eaaa1517c7bf890065f9ee803f4e20269bf96fcaea7f78f
4
+ data.tar.gz: 3e08676aef87c9340af3b58e0b8124221e17a7ced004813dddd8f9377d9da9e0
5
5
  SHA512:
6
- metadata.gz: 0b3d8c979bc045be112bd2e8004442b45da433e40a6f8e338ab64c0f090da5b3645f8acab84a592adcebf68d731fae0aedce54035725fad1136c906ead3e164e
7
- data.tar.gz: f96fe9e564224cd802bcebdb3ac8da0ca7fad76dddbe6c041d440e7c1371f6f7cd58d8ad298d93dfcbeaa7ab571e173ee359352d769dedb10d38caff118f93b1
6
+ metadata.gz: 689df880596033ed27ef92716554f2534a12a43b5d6c54a100eb363d8b3a57eed6ed356d77fbbcfddcf2ffc6509c6e866b0d6365ba27b9ecd908216b4d6b9322
7
+ data.tar.gz: 298e1239bfd0cf6e7050766173dfee8cbae94af0cf2994e2d4bb0b7a318f3303da09878c55c45dcffff1356a8a3d69072154bb9bd8d81b17219bae42090224f0
@@ -2,5 +2,13 @@
2
2
  language: ruby
3
3
  cache: bundler
4
4
  rvm:
5
- - 2.7.0
5
+ - 2.7.1
6
6
  before_install: gem install bundler -v 2.1.4
7
+ before_script:
8
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
9
+ - chmod +x ./cc-test-reporter
10
+ - ./cc-test-reporter before-build
11
+ script:
12
+ - bundle exec rspec
13
+ after_script:
14
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
55
55
  ## Enforcement
56
56
 
57
57
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at alan@ridlehoover.com. All
58
+ reported by contacting the project team at [navigable@firsttry.software][mail]. All
59
59
  complaints will be reviewed and investigated and will result in a response that
60
60
  is deemed necessary and appropriate to the circumstances. The project team is
61
61
  obligated to maintain confidentiality with regard to the reporter of an incident.
@@ -72,3 +72,4 @@ available at [https://contributor-covenant.org/version/1/4][version]
72
72
 
73
73
  [homepage]: https://contributor-covenant.org
74
74
  [version]: https://contributor-covenant.org/version/1/4/
75
+ [mail]: mailto:navigable@firsttry.software
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020 Alan Ridlehoover
3
+ Copyright (c) 2020 Alan Ridlehoover and Fito von Zastrow
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,7 +1,175 @@
1
- <img src="assets/navigable.png">
1
+ <a target="top" href="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/navigable.png"><img alt="Navigable" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/header.png"></a>
2
2
 
3
3
  # Navigable
4
4
 
5
+ [![Gem Version](https://badge.fury.io/rb/navigable.svg)](https://badge.fury.io/rb/navigable) [![Build Status](https://travis-ci.org/first-try-software/navigable.svg?branch=main)](https://travis-ci.org/first-try-software/navigable) [![Maintainability](https://api.codeclimate.com/v1/badges/33ca28cb17e1b512e006/maintainability)](https://codeclimate.com/github/first-try-software/navigable/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/33ca28cb17e1b512e006/test_coverage)](https://codeclimate.com/github/first-try-software/navigable/test_coverage)
6
+
7
+ Navigable is a family of gems that together provide all the tools you need to build fast, testable, and reliable JSON and/or GraphQL based APIs with isolated, composable business logic. The gems include:
8
+
9
+ <table style="margin: 20px 0">
10
+ <tr height="140">
11
+ <td width="130"><img alt="Clipper Ship" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/clipper.png"></td>
12
+ <td>
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, Hanami, and Sinatra.
16
+
17
+ </td>
18
+ </tr>
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>
21
+ <td>
22
+
23
+ **Navigable Server** *(coming soon)*<br>
24
+ A Rack-based web server for building Navigable-backed applications.
25
+
26
+ </td>
27
+ </tr>
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>
30
+ <td>
31
+
32
+ **Navigable API** *(coming soon)*<br>
33
+ An extension of Navigable Server for building restful JSON APIs.
34
+
35
+ </td>
36
+ </tr>
37
+ <tr height="140">
38
+ <td width="130"><img alt="Map" src="https://raw.githubusercontent.com/first-try-software/navigable/main/assets/map.png"></td>
39
+ <td>
40
+
41
+ **Navigable GraphQL** *(coming soon)*<br>
42
+ An extension of Navigable Server for building GraphQL APIs.
43
+
44
+ </td>
45
+ </tr>
46
+ </table>
47
+
48
+ <br><br>
49
+
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
+
52
+ <br>
53
+
54
+ # The Navigable Charter
55
+
56
+ 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.
57
+
58
+ 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.
59
+
60
+ ## Who We Are
61
+
62
+ We are professional Rubyists. We could write software in any language, but we choose to work in Ruby because it is so beautiful and expressive. We love Ruby.
63
+
64
+ We are test-oriented developers. We always write tests for our code, often before we've written the code. And, despite the conventional wisdom that investing in tests produces diminishing returns as you approach 100% coverage, we prefer the confidence we get with full coverage.
65
+
66
+ We are also students of software architecture. We apply SOLID object-oriented design principles like the [Single Responsibility][srp] and [Open/Closed][ocp] Principles to everything we build. And, we follow [Sandi Metz's Rules][sandi] as much as possible. This leads us to write small, loosely coupled, highly cohesive classes.
67
+
68
+ ## Why We Wrote Navigable
69
+
70
+ Besides being Rubyists, we are also seasoned Rails developers. Most of our experience with Ruby has involved Rails. We've also built applications in Sinatra, and dabbled with Hanami. And, while they all have strengths, we're not completely satisfied with any of them.
71
+
72
+ ### Rails
73
+
74
+ In our experience, Rails is a fantastic tool for building complex web applications. But, too often, we see engineers let Rails constrain them into thinking that all of their business logic belongs in models (and controllers, and even views!). This leads to overly complex classes with too many responsibilities that are difficult to test. It also reduces the reusability of any one bit of business logic to have it burried in a 5,000 line file. (Yes, we've seen 5,000 line models and controllers, and much worse!) Rails is also a bit of a large toolbox when all you want to do is build a JSON and/or GraphQL API.
75
+
76
+ ### Hanami
77
+
78
+ In dabbling with Hanami, we feel it has a great deal of promise. As proponents of [Domain Driven Design][ddd], we agree with many of the decisions that went into the framework. But, given that it uses convention as much as Rails, and given the lack of a dedicated home for business logic, we worry that Hanami applications will fall prey to the same problem many large Rails apps face: bloated models/entities and controller actions.
79
+
80
+ ### Sinatra
81
+
82
+ In our experience, Sinatra is a great tool for small, simple applications. But, it's too slow to be of much use with larger, enterprise applications. So, we've limited our use to very specific types of applications with limited scope.
83
+
84
+ ### And, finally...
85
+
86
+ All three of these frameworks take a central role in the organization of an application. We've worked on Rails applications in multiple different domains. They all looked like Rails applications. You had to dig into them to discover the core concepts of each specific domain. We believe software should be more reflective of the problem space than it is of the framework used to solve the problem.
87
+
88
+ ## How is Navigable Different?
89
+
90
+ So, we built Navigable to help separate the web adapter (controller) and persistence layer (model) from your actual business logic. And, we did it in a composable manner that allows for incredible flexibility. Here's a peek:
91
+
92
+ ```ruby
93
+ class CreateAlert
94
+ extend Navigable::Command
95
+
96
+ corresponds_to :create_alert
97
+ corresponds_to :create_alert_with_notifications
98
+
99
+ def execute
100
+ return failed_to_validate(new_alert) unless new_alert.valid?
101
+ return failed_to_create(new_alert) unless created_alert.persisted?
102
+
103
+ successfully created_alert
104
+ end
105
+
106
+ # ...
107
+ end
108
+
109
+ class AllRecipientsNotifier
110
+ extend Navigable::Observer
111
+
112
+ observes :create_alert_with_notifications
113
+
114
+ def on_success(alert)
115
+ NotifyAllRecipientsWorker.perform_async(alert_id: alert.id)
116
+ end
117
+ end
118
+ ```
119
+
120
+ In these two classes, Navigable enables you to execute multiple use cases. You can create an alert:
121
+
122
+ ```ruby
123
+ Navigable::Dispatcher.dispatch(:create_alert, params: alert_params)
124
+ ```
125
+
126
+ Or, create an alert and notify all recipients:
127
+
128
+ ```ruby
129
+ Navigable::Dispatcher.dispatch(:create_alert_with_notifications, params: alert_params)
130
+ ```
131
+
132
+ All without having to add conditional logic about the notifications to the `CreateAlert` class.
133
+
134
+ Similarly, you can add cross-cutting concerns to an application just as easily:
135
+
136
+ ```ruby
137
+ class Monitor
138
+ extend Navigable::Observer
139
+
140
+ observes_all_commands
141
+
142
+ def on_success(*args)
143
+ increment_counter(observed_command_key, :success)
144
+ end
145
+
146
+ def on_failed_to_validate(*args)
147
+ increment_counter(observed_command_key, :failed_to_validate)
148
+ end
149
+
150
+ def on_failed_to_create(*args)
151
+ increment_counter(observed_command_key, :failed_to_create)
152
+ end
153
+
154
+ # ...
155
+ end
156
+ ```
157
+ Here are a few things to look for in the code above:
158
+
159
+ * The DSL in the `execute` method of the `CreateAlert` class is built into Navigable. Methods like `successfully` tell Navigable the results of the command so that it can notify the observers.
160
+
161
+ * The two `corresponds_to` statements in `CreateAlert` tell Navigable to execute that command when either key is dispatched. You can register a command under as many different keys as you need.
162
+
163
+ * The single `observes` statement in `AllRecipientsNotifier` class tells Navigable to send a message to that class only when the `:create_alert_with_notifications` key is dispatched. One observer can observe as many commands as you need. And, many observers can observe the same command.
164
+
165
+ * 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
+
167
+ ## Feedback
168
+
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
+
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!
172
+
5
173
  ## Installation
6
174
 
7
175
  Add this line to your application's Gemfile:
@@ -35,3 +203,10 @@ The gem is available as open source under the terms of the [MIT License](https:/
35
203
  ## Code of Conduct
36
204
 
37
205
  Everyone interacting in the Navigable project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/first-try-software/navigable/blob/main/CODE_OF_CONDUCT.md).
206
+
207
+
208
+ [sandi]: https://thoughtbot.com/blog/sandi-metz-rules-for-developers
209
+ [srp]: https://en.wikipedia.org/wiki/Single-responsibility_principle
210
+ [ocp]: https://en.wikipedia.org/wiki/Open–closed_principle
211
+ [ddd]: https://en.wikipedia.org/wiki/Domain-driven_design
212
+ [mail]: mailto:navigable@firsttry.software
@@ -0,0 +1,24 @@
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
@@ -1,12 +1,12 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- require 'navigable/null_resolver'
3
+ require 'navigable/basic_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: NullResolver.new)
9
+ def self.dispatch(key, params: {}, resolver: BasicResolver.new)
10
10
  self.new(key, params: params, resolver: resolver).dispatch
11
11
  end
12
12
 
@@ -25,7 +25,7 @@ module Navigable
25
25
  end
26
26
 
27
27
  def observers
28
- Manufacturable.build_all(Observer::TYPE, key).push(resolver)
28
+ Manufacturable.build_all(Observer::TYPE, key, params: params).push(resolver)
29
29
  end
30
30
 
31
31
  def command
@@ -21,6 +21,12 @@ module Navigable
21
21
  end
22
22
 
23
23
  base.class_eval do
24
+ attr_reader :params
25
+
26
+ def initialize(params: {})
27
+ @params = params
28
+ end
29
+
24
30
  def observed_command_key
25
31
  manufacturable_item_key
26
32
  end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Navigable
4
4
  module ObserverInterface
5
- def on_success(*args); end
6
- def on_failure_to_validate(*args); end
7
- def on_failure_to_find(*args); end
8
- def on_failure_to_create(*args); end
9
- def on_failure_to_update(*args); end
10
- def on_failure_to_delete(*args); end
11
- def on_failure(*args); end
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
12
12
  end
13
13
  end
@@ -1,5 +1,5 @@
1
1
  # frozen-string-literal: true
2
2
 
3
3
  module Navigable
4
- VERSION = "0.2.0"
4
+ VERSION = "1.0.2"
5
5
  end
@@ -5,24 +5,24 @@ Gem::Specification.new do |spec|
5
5
  spec.version = Navigable::VERSION
6
6
  spec.platform = Gem::Platform::RUBY
7
7
  spec.authors = ["Alan Ridlehoover", "Fito von Zastrow"]
8
- spec.email = ["alan@ridlehoover.com", "adolfovon@gmail.com"]
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.\n\nWe 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.}
12
- spec.homepage = "https://github.com/first_try/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
+ spec.homepage = "https://firsttry.software"
13
13
  spec.license = "MIT"
14
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
15
15
 
16
16
  spec.metadata["homepage_uri"] = spec.homepage
17
- spec.metadata["source_code_uri"] = "https://github.com/first_try/navigable"
18
- spec.metadata["bug_tracker_uri"] = "https://github.com/first_try/navigable/issues"
17
+ spec.metadata["source_code_uri"] = "https://github.com/first-try-software/navigable"
18
+ spec.metadata["bug_tracker_uri"] = "https://github.com/first-try-software/navigable/issues"
19
19
 
20
20
  spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
21
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets)/}) }
22
22
  end
23
23
  spec.bindir = "exe"
24
24
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
- spec.require_paths = ["lib", "assets"]
25
+ spec.require_paths = ["lib"]
26
26
 
27
27
  spec.add_dependency "manufacturable", "~> 1.4"
28
28
 
@@ -30,5 +30,5 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "rake", "~> 12.0"
31
31
  spec.add_development_dependency "rspec", "~> 3.0"
32
32
  spec.add_development_dependency "rspec_junit_formatter", "~>0.4"
33
- spec.add_development_dependency "simplecov", "~>0.16"
33
+ spec.add_development_dependency "simplecov", "~>0.17.0"
34
34
  end
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: 0.2.0
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alan Ridlehoover
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-09-10 00:00:00.000000000 Z
12
+ date: 2020-09-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: manufacturable
@@ -87,23 +87,21 @@ dependencies:
87
87
  requirements:
88
88
  - - "~>"
89
89
  - !ruby/object:Gem::Version
90
- version: '0.16'
90
+ version: 0.17.0
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
95
  - - "~>"
96
96
  - !ruby/object:Gem::Version
97
- version: '0.16'
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.\n\nWe 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.
97
+ version: 0.17.0
98
+ description: A stand-alone tool for isolating business logic from external interfaces
99
+ and cross-cutting concerns. Navigable composes self-configured command and observer
100
+ objects to allow you to extend your business logic without modifying it. Navigable
101
+ is compatible with any Ruby-based application development framework, including Rails,
102
+ Hanami, and Sinatra.
104
103
  email:
105
- - alan@ridlehoover.com
106
- - adolfovon@gmail.com
104
+ - navigable@firsttry.software
107
105
  executables: []
108
106
  extensions: []
109
107
  extra_rdoc_files: []
@@ -114,40 +112,37 @@ files:
114
112
  - ".travis.yml"
115
113
  - CODE_OF_CONDUCT.md
116
114
  - Gemfile
117
- - Gemfile.lock
118
115
  - LICENSE.txt
119
116
  - README.md
120
117
  - Rakefile
121
- - assets/navigable.png
122
118
  - bin/console
123
119
  - bin/setup
124
120
  - lib/navigable.rb
121
+ - lib/navigable/basic_resolver.rb
125
122
  - lib/navigable/command.rb
126
123
  - lib/navigable/dispatcher.rb
127
- - lib/navigable/null_resolver.rb
128
124
  - lib/navigable/observable.rb
129
125
  - lib/navigable/observer.rb
130
126
  - lib/navigable/observer_interface.rb
131
127
  - lib/navigable/resolver.rb
132
128
  - lib/navigable/version.rb
133
129
  - navigable.gemspec
134
- homepage: https://github.com/first_try/navigable
130
+ homepage: https://firsttry.software
135
131
  licenses:
136
132
  - MIT
137
133
  metadata:
138
- homepage_uri: https://github.com/first_try/navigable
139
- source_code_uri: https://github.com/first_try/navigable
140
- bug_tracker_uri: https://github.com/first_try/navigable/issues
134
+ homepage_uri: https://firsttry.software
135
+ source_code_uri: https://github.com/first-try-software/navigable
136
+ bug_tracker_uri: https://github.com/first-try-software/navigable/issues
141
137
  post_install_message:
142
138
  rdoc_options: []
143
139
  require_paths:
144
140
  - lib
145
- - assets
146
141
  required_ruby_version: !ruby/object:Gem::Requirement
147
142
  requirements:
148
143
  - - ">="
149
144
  - !ruby/object:Gem::Version
150
- version: 2.7.0
145
+ version: 2.3.0
151
146
  required_rubygems_version: !ruby/object:Gem::Requirement
152
147
  requirements:
153
148
  - - ">="
@@ -157,5 +152,5 @@ requirements: []
157
152
  rubygems_version: 3.1.2
158
153
  signing_key:
159
154
  specification_version: 4
160
- summary: Ahoy! Navigable will get you there!
155
+ summary: Ahoy! Welcome aboard Navigable!
161
156
  test_files: []
Binary file
@@ -1,11 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- require 'navigable/resolver'
4
-
5
- module Navigable
6
- class NullResolver
7
- extend Resolver
8
-
9
- def resolve; end
10
- end
11
- end