Module: Causalontology::Canonical

Defined in:
lib/causalontology/canonical.rb

Constant Summary collapse

IDENTITY_FIELDS =
{
  "occurrent"  => ["label", "category"],
  "cro"        => ["causes", "effects", "mechanism", "temporal", "modality",
                   "context", "refines"],
  "continuant" => ["label", "category"],
  "realizable" => ["kind", "bearer"],
  "assertion"  => ["about", "source", "evidence_type", "evidence", "strength",
                   "confidence", "timestamp"],
  "enrichment" => ["about", "field", "entry", "source", "timestamp"],
  "retraction" => ["retracts", "source", "timestamp"],
  "succession" => ["predecessor", "successor", "timestamp"],
}.freeze
PREFIX =
{
  "occurrent" => "occ", "cro" => "cro", "continuant" => "cnt",
  "realizable" => "rlz", "assertion" => "ast", "enrichment" => "enr",
  "retraction" => "ret", "succession" => "suc",
}.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).



73
74
75
76
# File 'lib/causalontology/canonical.rb', line 73

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.



79
80
81
82
83
# File 'lib/causalontology/canonical.rb', line 79

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].



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/causalontology/canonical.rb', line 60

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)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/causalontology/canonical.rb', line 40

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 "cro" 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