Module: Hecks::Bluebook::Assembly::Build

Defined in:
lib/hecks/bluebook/assembly/build.rb

Overview

ONE WAY TO BUILD A CONSTRUCT, for every construct.

There used to be a method per category here — value_object(row), command(row), policy(row) — each one gathering the same keywords the contract already names. This reads the contract instead, so adding a field to the language and forgetting to assemble it is caught by the coverage gate rather than by nobody.

make is the only branch, and it is a real one: a construct that became a class is .declared, an instance is .newed. That is the boundary Query sits on, and it is a fact about Ruby rather than about the domain.

Class Method Summary collapse

Class Method Details

.call(category, row, extra = {}) ⇒ Object



19
20
21
22
23
24
# File 'lib/hecks/bluebook/assembly/build.rb', line 19

def call(category, row, extra = {})
  contract = Assembly.contract(category)
  keywords = contract.fields.to_h { |keyword, (key, reader)| [keyword, read(reader, row[key])] }

  holder(contract).public_send(contract.make, **keywords.merge(extra))
end

.holder(contract) ⇒ Object



26
27
28
# File 'lib/hecks/bluebook/assembly/build.rb', line 26

def holder(contract)
  contract.holder or raise ArgumentError, "#{contract} holds nothing that can be built"
end

.read(reader, value) ⇒ Object

A reader is a Marks method, a list of them, or one of three spellings that need no decoding at all.



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/hecks/bluebook/assembly/build.rb', line 32

def read(reader, value)
  case reader
  when :plain    then value
  when :identity then value&.to_sym
  when :flag     then value ? true : false
  when Array
    # [:each, reader] maps a list ; [:option, name] reads one named option,
    # which needs its name as well as its value.
    reader.first == :each ? Array(value).map { |held| Marks.public_send(reader.last, held) }
                          : Marks.option(reader.last, value)
  else Marks.public_send(reader, value)
  end
end