navigable 0.3.1 → 1.0.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: d1a6a151995a3fc11306a19e5aa456017782233ad8b2ca399938e68228a21a8e
4
- data.tar.gz: 0ebc72581760f1227772e55327796a68b9496997321db0d9c5de69ef0e418bee
3
+ metadata.gz: 60c6f7c8bbd71f2616a448c4a43ff4647b4ac0ffd8ff1c3e75d833be6d943c7f
4
+ data.tar.gz: 52af4a03f43abcb62e228edace4e1acf5ca3ba7321ea50eaa63a5c8dd94b0432
5
5
  SHA512:
6
- metadata.gz: 910da8ec34c9f5679eed5e6ad2e1fb51040b483ab17d1b8202c8ded1f4dff7e180aa5c36985fd236824760eef045fca66a3310db52d2fddd9092d23114565e35
7
- data.tar.gz: 17dbf68108f529820220c6017fbb5ce574a0525534a5b9bde7bf3534ac2a097396f83d5ae1837d6240d37a928c338df6f38fe71cdad4815c9b32c90f8244ac73
6
+ metadata.gz: e8485af6e386a84e7bf913af36744abf27ab9549b4961919066de53fb7d0e50d136bdd785d73fa13bdf747788aff305ad85434ecf40288288d0eeaf0f7412e85
7
+ data.tar.gz: b89a7583e5c59e4ebea72c10127eda0c79a79531f39f07098aad468dfedbd6d4b650da0baf734b9b37126f943ea4a2411aa1872e95d6717e7da0f103e2f435ee
@@ -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 navigable@firsttry.software. 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 and Hanami.
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
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -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
 
@@ -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.3.1"
4
+ VERSION = "1.0.0"
5
5
  end
@@ -9,9 +9,9 @@ Gem::Specification.new do |spec|
9
9
 
10
10
  spec.summary = %q{Ahoy! Navigable will get you there!}
11
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.}
12
- spec.homepage = "https://github.com/first-try-software/navigable"
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
17
  spec.metadata["source_code_uri"] = "https://github.com/first-try-software/navigable"
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
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
 
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.3.1
4
+ version: 1.0.0
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-12 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
@@ -116,36 +116,41 @@ files:
116
116
  - LICENSE.txt
117
117
  - README.md
118
118
  - Rakefile
119
+ - assets/clipper.png
120
+ - assets/compass.png
121
+ - assets/header.png
122
+ - assets/lighthouse.png
123
+ - assets/map.png
119
124
  - assets/navigable.png
125
+ - assets/telescope.png
120
126
  - bin/console
121
127
  - bin/setup
122
128
  - lib/navigable.rb
129
+ - lib/navigable/basic_resolver.rb
123
130
  - lib/navigable/command.rb
124
131
  - lib/navigable/dispatcher.rb
125
- - lib/navigable/null_resolver.rb
126
132
  - lib/navigable/observable.rb
127
133
  - lib/navigable/observer.rb
128
134
  - lib/navigable/observer_interface.rb
129
135
  - lib/navigable/resolver.rb
130
136
  - lib/navigable/version.rb
131
137
  - navigable.gemspec
132
- homepage: https://github.com/first-try-software/navigable
138
+ homepage: https://firsttry.software
133
139
  licenses:
134
140
  - MIT
135
141
  metadata:
136
- homepage_uri: https://github.com/first-try-software/navigable
142
+ homepage_uri: https://firsttry.software
137
143
  source_code_uri: https://github.com/first-try-software/navigable
138
144
  bug_tracker_uri: https://github.com/first-try-software/navigable/issues
139
145
  post_install_message:
140
146
  rdoc_options: []
141
147
  require_paths:
142
148
  - lib
143
- - assets
144
149
  required_ruby_version: !ruby/object:Gem::Requirement
145
150
  requirements:
146
151
  - - ">="
147
152
  - !ruby/object:Gem::Version
148
- version: 2.7.0
153
+ version: 2.3.0
149
154
  required_rubygems_version: !ruby/object:Gem::Requirement
150
155
  requirements:
151
156
  - - ">="
@@ -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