hub_kernel 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0e433f46a0cd33d7236e9f57f150a4c8e59b778a320c4dcf1252093a405fbcce
4
+ data.tar.gz: c8898bc61f4c65dd72a0008ca1dd75e36508102089636964c68da9ec4863115a
5
+ SHA512:
6
+ metadata.gz: a453b3e41b68ba7f7b9c06b31546fb92ec0d840e6f949657a5a5ec6a8d4b4708d88c3fd21963bd37fe9ebb224362a69e4d287d20f65c24eb275d557dacdee923
7
+ data.tar.gz: 1eb7d7a09b26da2997ebee5145d148c5f98111fe8372b868e3bdb1290bc2decb401aa406fe6405844d9b0aa00527ef03101939482c970f0f7e3de35ad40da4d1
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright tylercschneider
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # HubKernel
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "hub_kernel"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install hub_kernel
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ require "bundler/gem_tasks"
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ HubKernel::Engine.routes.draw do
2
+ end
@@ -0,0 +1,13 @@
1
+ module HubKernel
2
+ class MissingArgumentError < ArgumentError; end
3
+
4
+ module Action
5
+ attr_reader :person, :account, :values
6
+
7
+ def initialize(person:, account:, values:)
8
+ @person = person
9
+ @account = account
10
+ @values = values
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module HubKernel
2
+ class AnswerNotMetError < StandardError; end
3
+
4
+ module Answer
5
+ def self.met_by?(answer)
6
+ answer.respond_to?(:ok?) && answer.respond_to?(:message)
7
+ end
8
+
9
+ def self.met!(answer)
10
+ return answer if met_by?(answer)
11
+
12
+ raise AnswerNotMetError, "an answer must respond to ok? and message, got #{answer.class}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ module HubKernel
2
+ class NonBooleanAnswerError < StandardError; end
3
+
4
+ module Authz
5
+ module Vocabulary
6
+ def gates(*actions)
7
+ gated_actions.concat(actions)
8
+ end
9
+
10
+ def gated_actions
11
+ @gated_actions ||= []
12
+ end
13
+ end
14
+
15
+ def self.included(hub)
16
+ hub.extend(Vocabulary)
17
+ end
18
+
19
+ def allowed?(actor, action)
20
+ answer = authz.allowed?(actor, action)
21
+ raise NonBooleanAnswerError, "allowed? must return true or false, got #{answer.inspect}" unless [ true, false ].include?(answer)
22
+
23
+ answer
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ require "active_support/concern"
2
+
3
+ module HubKernel
4
+ module Conformance
5
+ module Action
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def saving_object(&block)
10
+ saving_objects(the_only: block)
11
+ end
12
+
13
+ def saving_objects(**objects)
14
+ define_method(:the_saving_objects) { objects.transform_values(&:call) }
15
+ define_method(:the_saving_object) { the_saving_objects.values.first }
16
+ end
17
+ end
18
+
19
+ included do
20
+ test "each named object takes the person, the account and the submitted values" do
21
+ the_saving_objects.each_value do |object|
22
+ assert_respond_to object.new(person: a_person, account: an_account, values: values_it_keeps), :call
23
+ end
24
+ end
25
+
26
+ test "each named object answers whether the change was kept" do
27
+ the_saving_objects.each_value do |object|
28
+ answer = object.new(person: a_person, account: an_account, values: values_it_keeps).call
29
+
30
+ assert HubKernel::Answer.met_by?(answer), "#{object} must answer with ok? and message"
31
+ end
32
+ end
33
+
34
+ test "a refused answer carries the reason" do
35
+ the_saving_objects.each_value do |object|
36
+ answer = object.new(person: a_person, account: an_account, values: values_it_refuses).call
37
+
38
+ assert_not_empty answer.message.to_s, "#{object} must say why it refused"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,52 @@
1
+ require "active_support/concern"
2
+
3
+ module HubKernel
4
+ module Conformance
5
+ module Partial
6
+ extend ActiveSupport::Concern
7
+
8
+ class_methods do
9
+ def markup(&block)
10
+ define_method(:the_markup) { block.call }
11
+ end
12
+
13
+ def submits(*names)
14
+ define_method(:the_action_names) { names }
15
+ end
16
+ end
17
+
18
+ included do
19
+ def the_action_names = []
20
+
21
+ def the_addresses
22
+ return { submit_url: "/an/address" } if the_action_names.empty?
23
+
24
+ { submit_urls: the_action_names.to_h { |name| [ name, "/an/address/#{name}" ] } }
25
+ end
26
+
27
+ def render_the_markup
28
+ render partial: the_markup, locals: { person: a_person, account: an_account, **the_addresses }
29
+ end
30
+
31
+ test "it submits to the addresses it was given" do
32
+ render_the_markup
33
+
34
+ expected = the_action_names.empty? ? [ "/an/address" ] : the_action_names.map { |name| "/an/address/#{name}" }
35
+ expected.each { |address| assert_includes rendered, %(action="#{address}") }
36
+ end
37
+
38
+ test "it reads nothing from an instance variable" do
39
+ source = File.read(lookup_context.find(the_markup, [], true).identifier)
40
+
41
+ assert_no_match(/@[a-z_]+/, source)
42
+ end
43
+
44
+ test "it draws no page heading, page frame or layout of its own" do
45
+ render_the_markup
46
+
47
+ assert_no_match(/<h1|<html|<body/, rendered)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ module HubKernel
2
+ module Context
3
+ class Null
4
+ def actor
5
+ :null_actor
6
+ end
7
+
8
+ def tenant
9
+ :null_tenant
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module HubKernel
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace HubKernel
4
+ end
5
+ end
@@ -0,0 +1,36 @@
1
+ module HubKernel
2
+ class UndeclaredEventError < StandardError; end
3
+ class UnwiredEventError < StandardError; end
4
+
5
+ module Events
6
+ def declared_events
7
+ instance_methods(false)
8
+ end
9
+
10
+ def on(name, &handler)
11
+ raise UndeclaredEventError, "undeclared event :#{name}; declared events are #{declared_events}" unless declared_events.include?(name)
12
+
13
+ handlers[name] << handler
14
+ end
15
+
16
+ def emit(name, payload)
17
+ handlers[name].each { |handler| handler.call(payload) }
18
+ end
19
+
20
+ def verify_wired!
21
+ return if unwired_events.empty?
22
+
23
+ raise UnwiredEventError, "unwired events: #{unwired_events}"
24
+ end
25
+
26
+ private
27
+
28
+ def unwired_events
29
+ declared_events.reject { |name| handlers[name].any? }
30
+ end
31
+
32
+ def handlers
33
+ @handlers ||= Hash.new { |table, name| table[name] = [] }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,9 @@
1
+ module HubKernel
2
+ module FollowUp
3
+ attr_reader :controller
4
+
5
+ def initialize(controller:)
6
+ @controller = controller
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module HubKernel
2
+ module Markup
3
+ def markup_path(within: "app/views")
4
+ File.join(root.to_s, within, "**", "*.erb")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module HubKernel
2
+ VERSION = "0.1.0"
3
+ end
data/lib/hub_kernel.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "hub_kernel/version"
2
+ require "hub_kernel/engine"
3
+ require "hub_kernel/action"
4
+ require "hub_kernel/answer"
5
+ require "hub_kernel/follow_up"
6
+ require "hub_kernel/markup"
7
+
8
+ module HubKernel
9
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hub_kernel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - tylercschneider
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 8.1.3
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 8.1.3
26
+ description: 'hub_kernel wraps a domain and connects it to a host app''s infrastructure
27
+ through named ports. It ships no domain of its own: each hub is hub_kernel wrapped
28
+ around one domain.'
29
+ email:
30
+ - tylercschneider@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - MIT-LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - config/routes.rb
39
+ - lib/hub_kernel.rb
40
+ - lib/hub_kernel/action.rb
41
+ - lib/hub_kernel/answer.rb
42
+ - lib/hub_kernel/authz.rb
43
+ - lib/hub_kernel/conformance/action.rb
44
+ - lib/hub_kernel/conformance/partial.rb
45
+ - lib/hub_kernel/context.rb
46
+ - lib/hub_kernel/engine.rb
47
+ - lib/hub_kernel/events.rb
48
+ - lib/hub_kernel/follow_up.rb
49
+ - lib/hub_kernel/markup.rb
50
+ - lib/hub_kernel/version.rb
51
+ homepage: https://github.com/tylercschneider/hub_kernel
52
+ licenses:
53
+ - MIT
54
+ metadata:
55
+ allowed_push_host: https://rubygems.org
56
+ homepage_uri: https://github.com/tylercschneider/hub_kernel
57
+ source_code_uri: https://github.com/tylercschneider/hub_kernel
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: 3.2.0
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubygems_version: 4.0.20
73
+ specification_version: 4
74
+ summary: Headless Rails engine that binds a domain to a host app through ports.
75
+ test_files: []