Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions lib/hub_kernel/exposes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ class NotAllowed < StandardError; end
class Refused < StandardError; end

module Exposes
Exposed = Data.define(:name, :takes, :writes, :earlier_answers) do
Exposed = Data.define(:name, :takes, :writes, :earlier_answers, :answer_shape) do
def earlier_answer(major) = earlier_answers.find { |earlier| earlier.major == major }
end
EarlierAnswer = Data.define(:major, :translation) do
EarlierAnswer = Data.define(:major, :translation, :answer_shape) do
def translate(answer) = translation.call(answer)
end

def exposes(name, takes:, writes:, earlier_answers: {})
def exposes(name, takes:, writes:, earlier_answers: {}, answer_shape: nil)
Interface::ExposingHubs.add(self)
exposed_methods[name.to_s] = Exposed.new(name: name, takes: takes, writes: writes, earlier_answers: earlier_answers.map { |major, translation| EarlierAnswer.new(major: major, translation: translation) })
exposed_methods[name.to_s] = Exposed.new(name: name, takes: takes, writes: writes, earlier_answers: earlier_answers.map { |major, declared| earlier_answer_from(major, declared) }, answer_shape: answer_shape)
end

def exposed(name) = exposed_methods[name.to_s]
Expand Down Expand Up @@ -59,6 +59,12 @@ def exposed_methods = @exposed_methods ||= {}

def exposing_hub = name.demodulize

def earlier_answer_from(major, declared)
return EarlierAnswer.new(major: major, translation: declared, answer_shape: nil) if declared.respond_to?(:call)

EarlierAnswer.new(major: major, translation: declared[:translation], answer_shape: declared[:answer_shape])
end

def refuse_without_caller(person, account)
raise MissingArgumentError, "A call by name needs a person" if person.nil?
raise MissingArgumentError, "A call by name needs an account" if account.nil?
Expand Down
32 changes: 32 additions & 0 deletions test/hub_kernel/exposes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,18 @@ module Baker
exposes :price_of, takes: %i[item], writes: false, earlier_answers: { 1 => ->(answer) { answer[:price] }, 2 => ->(answer) { { price: answer[:cents] } } }
end

module Butcher
extend HubKernel::Exposes

exposes :weigh_cut, takes: %i[cut], writes: false, answer_shape: { "type" => "integer" }
end

module Florist
extend HubKernel::Exposes

exposes :price_of, takes: %i[item], writes: false, earlier_answers: { 1 => { translation: ->(answer) { answer.to_s }, answer_shape: { "type" => "string" } } }
end

test "an exposed method is found by its name with the values it takes" do
assert_equal %i[supplier_id bought_on lines], Supplies.exposed("record_purchase").takes
end
Expand Down Expand Up @@ -71,6 +83,26 @@ module Baker
assert_equal({ price: 300 }, Baker.exposed("price_of").earlier_answer(2).translate({ cents: 300 }))
end

test "a method exposed without an answer shape reads as having none" do
assert_nil Supplies.exposed("record_purchase").answer_shape
end

test "an earlier answer given only a translation reads as having no answer shape" do
assert_nil Grocer.exposed("price_of").earlier_answer(1).answer_shape
end

test "a method is exposed with the JSON Schema of its answer as its answer shape" do
assert_equal({ "type" => "integer" }, Butcher.exposed("weigh_cut").answer_shape)
end

test "an earlier answer is given the JSON Schema of the answer at its major beside its translation" do
assert_equal({ "type" => "string" }, Florist.exposed("price_of").earlier_answer(1).answer_shape)
end

test "an earlier answer given a translation beside its answer shape translates the answer of the major after it" do
assert_equal "300", Florist.exposed("price_of").earlier_answer(1).translate(300)
end

test "a hub that declares an exposed method is recorded as a hub that exposes methods" do
assert_includes HubKernel::Interface::ExposingHubs.list, Supplies
end
Expand Down
Loading