Class: Clickwrap::DocumentDefinition

Inherits:
Object
  • Object
show all
Defined in:
lib/clickwrap/document_definition.rb

Overview

A declared document version, before it is published.

Clickwrap.document :terms,
from: Rails.root.join("app/content/legal/terms.md")

Clickwrap.document :terms,
version: "2026-08-15",
locale: :en,
effective_at: Time.utc(2026, 8, 15),
from: Rails.root.join("app/content/legal/terms.en.md")

Clickwrap.document :terms,
from: Rails.root.join("app/content/legal/terms.md"),
link: "/legal/terms"

link: is where a PERSON reads this document — the host's own formatted page, with its typography, its navigation, and its language switcher — rather than the engine's plain rendering of the published bytes. It is the path Clickwrap presents beside the control AND the path it signs into the presentation manifest, so the evidence never cites a different target from the link somebody could actually press.

The trade is explicit and belongs to the host: a host page shows whatever is current, so the signed path is a stable address rather than an immutable snapshot. The bytes are still frozen, digested, and recorded — what changes is which URL the receipt says was offered. A host that wants the immutable rendering in the evidence simply leaves link: off and gets the engine's per-version route, as before.

The declaration says which bytes to publish. bin/rails clickwrap:publish reads them once, digests them, and freezes a database snapshot. From then on the snapshot is the evidence; the file on disk is only where it came from. Changing the file does not change published evidence, and reusing a version label for different bytes is refused rather than silently accepted.

version: is optional exactly when the source can name its own: a file or inline content whose leading YAML front matter carries clickwrap_version: (or last_updated:) IS the single source of truth for its label, so bumping a legal text is one edit in one file. A source with no front-matter version and no explicit version: is refused at boot with a sentence — Clickwrap never invents a label, because a policy that requires a current version cannot be satisfied by a guess.

Constant Summary collapse

SOURCE_KINDS =
%i[file inline resolver].freeze
MEDIA_TYPES_BY_EXTENSION =
{
  ".md" => "text/markdown",
  ".markdown" => "text/markdown",
  ".html" => "text/html",
  ".htm" => "text/html",
  ".txt" => "text/plain",
  ".json" => "application/json",
  ".pdf" => "application/pdf"
}.freeze
REFUSED_VERSION_LABELS =
%w[unversioned current latest head none default].freeze
%r{\A(?:/[^/]|/\z|https://|http://)}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key:, version: nil, locale: :en, media_type: nil, effective_at: nil, tenant: nil, from: nil, content: nil, resolver: nil, renderer: nil, link: nil) ⇒ DocumentDefinition

Returns a new instance of DocumentDefinition.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/clickwrap/document_definition.rb', line 70

def initialize(key:, version: nil, locale: :en, media_type: nil, effective_at: nil,
               tenant: nil, from: nil, content: nil, resolver: nil, renderer: nil,
               link: nil)
  @key = normalize_key(key)
  @locale = locale.to_s
  @effective_at = effective_at
  @tenant_key = tenant&.to_s
  @renderer = renderer
  @link = normalize_link(link)

  assign_source(from:, content:, resolver:)
  @version_label = normalize_version(version || version_label_from_front_matter)
  @media_type = (media_type || infer_media_type).to_s

  validate!
  freeze
end

Instance Attribute Details

#effective_atObject (readonly)

Returns the value of attribute effective_at.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def effective_at
  @effective_at
end

#inline_contentObject (readonly)

Returns the value of attribute inline_content.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def inline_content
  @inline_content
end

#keyObject (readonly)

Returns the value of attribute key.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def key
  @key
end

Returns the value of attribute link.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def link
  @link
end

#localeObject (readonly)

Returns the value of attribute locale.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def locale
  @locale
end

#media_typeObject (readonly)

Returns the value of attribute media_type.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def media_type
  @media_type
end

#rendererObject (readonly)

Returns the value of attribute renderer.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def renderer
  @renderer
end

#resolverObject (readonly)

Returns the value of attribute resolver.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def resolver
  @resolver
end

#source_kindObject (readonly)

Returns the value of attribute source_kind.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def source_kind
  @source_kind
end

#source_referenceObject (readonly)

Returns the value of attribute source_reference.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def source_reference
  @source_reference
end

#tenant_keyObject (readonly)

Returns the value of attribute tenant_key.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def tenant_key
  @tenant_key
end

#version_labelObject (readonly)

Returns the value of attribute version_label.



66
67
68
# File 'lib/clickwrap/document_definition.rb', line 66

def version_label
  @version_label
end

Instance Method Details

#identityObject



99
# File 'lib/clickwrap/document_definition.rb', line 99

def identity = [tenant_key, key, version_label, locale]

#read_bytesObject

Reads the exact bytes this definition points at. Called at publish time, never at export time: an export that re-read a mutable source and called the result historical evidence would be a lie.



91
92
93
94
95
96
97
# File 'lib/clickwrap/document_definition.rb', line 91

def read_bytes
  case source_kind
  when :inline then inline_content.to_s.dup
  when :file then read_file_bytes
  when :resolver then read_resolver_bytes
  end
end

#to_sObject



101
102
103
# File 'lib/clickwrap/document_definition.rb', line 101

def to_s
  "#{key} #{version_label} (#{locale})"
end