Module: DocsKit::Registry

Defined in:
lib/docs_kit/registry.rb

Overview

A mixin for an in-memory docs registry (guides, demos, component references).

Two authoring styles, one shared lookup/grouping API:

  1. The one-line page DSL (v2) — the default a site should reach for. slug and view derive from the title (both overridable); instances get default readers + view_class + href for free; the sidebar nav derives from the registry with zero site code:

    class Doc
    extend DocsKit::Registry
    path_prefix    "/docs"                 # href = "#{path_prefix}/#{slug}"
    view_namespace "Views::Docs::Pages"    # view_class resolves under this
    page "Installation",   group: "Guide"                       # slug "installation", view "Installation"
    page "Getting started", group: "Guide", icon: "rocket"      # slug "getting-started", view "GettingStarted"
    page "OAuth", group: "Guide", slug: "auth", view: "OauthGuide"  # every derivation overridable
    end
    
  2. The low-level hash entries API — for a registry with a bespoke schema (custom fields, a non-default view namespace). The site writes its own initialize/readers/view_class:

    class Demo
    extend DocsKit::Registry
    entries [{ slug: "counter", title: "Counter", group: "Examples", view: "Counter" }]
    attr_reader :slug, :title, :group, :view_name
    def initialize(entry) = (@slug, @title, @group, @view_name = entry.values_at(:slug, :title, :group, :view))
    def view_class = "Views::Docs::Pages::#{view_name}".safe_constantize
    end
    

Doc.all # => [entry instances] Doc.from_slug("installation") # => instance | nil Doc.grouped # => { "Guide" => [instances] } Doc.nav_items # => { "Guide" => [NavItem] } (authored pages only)

A registry uses ONE style; mixing page and entries raises Registry::Error.

Defined Under Namespace

Classes: Entry, Error

Instance Method Summary collapse

Instance Method Details

#allObject

All registry instances (built fresh each call — instances are cheap and a site may resolve view classes that change under code reload in development). v2 pages are wrapped in the default Entry; hash entries in the site's class.



99
100
101
102
103
104
105
# File 'lib/docs_kit/registry.rb', line 99

def all
  if defined?(@pages) && @pages
    @pages.map { |attrs| Entry.new(attrs, path_prefix, view_namespace) }
  else
    (entries || []).map { |entry| new(entry) }
  end
end

#entries(list = nil) ⇒ Object

Declares the frozen registry data directly (the low-level hash API). Each entry is a Hash; the site supplies its own instance class behavior.

Raises:



53
54
55
56
57
58
59
# File 'lib/docs_kit/registry.rb', line 53

def entries(list = nil)
  return @entries if list.nil?

  raise Error, "cannot mix `page` and `entries` in one registry" if @pages&.any?

  @entries = list.map(&:freeze).freeze
end

#from_slug(slug) ⇒ Object

The instance whose slug matches, or nil.



108
109
110
# File 'lib/docs_kit/registry.rb', line 108

def from_slug(slug)
  all.find { |item| item.slug.to_s == slug.to_s }
end

#group_by_attribute(attr = nil) ⇒ Object

The attribute used by #grouped (default :group).



91
92
93
94
# File 'lib/docs_kit/registry.rb', line 91

def group_by_attribute(attr = nil)
  @group_by_attribute = attr if attr
  @group_by_attribute || :group
end

#groupedObject

{ group_value => [instances] }, preserving registry order within a group.



113
114
115
# File 'lib/docs_kit/registry.rb', line 113

def grouped
  all.group_by { |item| item.public_send(group_by_attribute) }
end

{ group => [NavItem] } for authored pages only (a resolvable view_class), so the sidebar never links a page that isn't written yet. This is the transform every site used to hand-write in its nav lambda.



120
121
122
123
124
125
126
# File 'lib/docs_kit/registry.rb', line 120

def nav_items
  all.select { |item| item.respond_to?(:view_class) && item.view_class }
     .group_by { |item| item.public_send(group_by_attribute) }
     .transform_values do |items|
    items.map { |item| DocsKit::NavItem.new(href: item.href, label: item.title, icon: item.icon) }
  end
end

#page(title, group:, slug: nil, view: nil, icon: nil) ⇒ Object

Declares one page (the v2 DSL). slug/view derive from the title unless given. Appends to the registry in declaration order (== sidebar order).

page "Getting started", group: "Guide", icon: "rocket", slug: "start", view: "Start"

Raises:



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/docs_kit/registry.rb', line 65

def page(title, group:, slug: nil, view: nil, icon: nil)
  raise Error, "cannot mix `page` and `entries` in one registry" if defined?(@entries) && @entries

  (@pages ||= []) << {
    title: title,
    group: group,
    slug: slug || title.parameterize,
    view: view || title.parameterize(separator: "_").camelize,
    icon: icon
  }.freeze
end

#path_prefix(value = nil) ⇒ Object

href = "##path_prefix/#slug". Defaults to "/docs".



78
79
80
81
# File 'lib/docs_kit/registry.rb', line 78

def path_prefix(value = nil)
  @path_prefix = value if value
  @path_prefix || "/docs"
end

#view_namespace(value = nil) ⇒ Object

The namespace a page's view_class resolves under (v2 pages only), e.g. "Views::Docs::Pages". Required to resolve views via the default Entry.



85
86
87
88
# File 'lib/docs_kit/registry.rb', line 85

def view_namespace(value = nil)
  @view_namespace = value if value
  @view_namespace
end