Module: Causalontology::Canonical

Defined in:
lib/causalontology/canonical.rb

Constant Summary collapse

IDENTITY_FIELDS =

The identity-bearing fields of each of the seventeen kinds. "type" is always injected, so it is not listed here. Order does not matter (JCS sorts keys).

{
  # ---- type tier ----
  "occurrent"  => ["label", "category", "stratum"],
  "causal_relation_object" => ["causes", "effects", "mechanism", "temporal",
                               "modality", "context", "refines", "skips"],
  "continuant" => ["label", "category"],
  "realizable" => ["kind", "bearer", "label"],
  "stratum"    => ["label", "scheme", "ordinal", "unit", "governs"],
  "bridge"     => ["coarse", "fine", "relation"],
  "port"       => ["bearer", "label", "direction", "accepts", "realizable"],
  "conduit"    => ["label", "from", "to", "carries", "transform"],
  "quality"    => ["label", "datatype", "unit", "stratum"],
  # ---- token tier ----
  "token_individual"   => ["instantiates", "designator", "part_of"],
  "token_occurrence"   => ["instantiates", "interval", "participants",
                           "locus", "observer"],
  "state_assertion"    => ["subject", "quality", "value", "interval"],
  "token_causal_claim" => ["causes", "effects", "covering_law",
                           "actual_delay", "counterfactual"],
  # ---- provenance tier ----
  "assertion"  => ["about", "source", "evidence_type", "evidence", "strength",
                   "confidence", "timestamp", "evidenced_by"],
  "enrichment" => ["about", "field", "entry", "source", "timestamp"],
  "retraction" => ["retracts", "source", "timestamp"],
  "succession" => ["predecessor", "successor", "timestamp"],
}.freeze
PREFIX =

Whole-word re-mint (P7): the scheme IS the type value for every kind.

IDENTITY_FIELDS.keys.each_with_object({}) { |k, h| h[k] = k }.freeze
KIND_OF_PREFIX =
PREFIX.invert.freeze

Class Method Summary collapse

Class Method Details

.canonicalize(obj, kind = nil) ⇒ Object

The RFC 8785 identity-bearing bytes of an object (a UTF-8 string).



88
89
90
91
# File 'lib/causalontology/canonical.rb', line 88

def canonicalize(obj, kind = nil)
  _, ib = identity_bearing(obj, kind)
  Jcs.encode(ib).encode(Encoding::UTF_8)
end

.identify(obj, kind = nil) ⇒ Object

The content-addressed identifier: scheme + ":" + SHA-256 hex.



94
95
96
97
98
# File 'lib/causalontology/canonical.rb', line 94

def identify(obj, kind = nil)
  kind, ib = identity_bearing(obj, kind)
  digest = Digest::SHA256.hexdigest(Jcs.encode(ib).encode(Encoding::UTF_8))
  PREFIX[kind] + ":" + digest
end

.identity_bearing(obj, kind = nil) ⇒ Object

The identity-bearing subset of an object, with type always present. Returns [kind, subset].



75
76
77
78
79
80
81
82
83
84
85
# File 'lib/causalontology/canonical.rb', line 75

def identity_bearing(obj, kind = nil)
  kind ||= infer_kind(obj)
  unless IDENTITY_FIELDS.key?(kind)
    raise ArgumentError, "unknown kind: #{kind.inspect}"
  end
  out = { "type" => kind }
  IDENTITY_FIELDS[kind].each do |field|
    out[field] = obj[field] if obj.key?(field)
  end
  [kind, out]
end

.infer_kind(obj) ⇒ Object

Infer an object's kind from its type field, id prefix, or shape.

Raises:

  • (ArgumentError)


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/causalontology/canonical.rb', line 54

def infer_kind(obj)
  return obj["type"] if obj.key?("type")
  if obj.key?("id") && obj["id"].is_a?(String) && obj["id"].include?(":")
    pre = obj["id"].split(":", 2)[0]
    return KIND_OF_PREFIX[pre] if KIND_OF_PREFIX.key?(pre)
  end
  return "bridge" if obj.key?("coarse") && obj.key?("fine")
  return "causal_relation_object" if obj.key?("causes") && obj.key?("effects")
  return "retraction" if obj.key?("retracts")
  return "succession" if obj.key?("predecessor") && obj.key?("successor")
  return "enrichment" if obj.key?("field") && obj.key?("entry")
  return "assertion" if obj.key?("evidence_type") ||
                        (obj.key?("about") && obj.key?("confidence"))
  return "realizable" if obj.key?("kind") && obj.key?("bearer")
  raise ArgumentError,
        "cannot infer kind (occurrents and continuants share a shape); " \
        "pass kind explicitly"
end