Module: Wayfinding
- Defined in:
- lib/wayfinding.rb,
lib/wayfinding/kind.rb,
lib/wayfinding/rspec.rb,
lib/wayfinding/errors.rb,
lib/wayfinding/version.rb,
lib/wayfinding/destination.rb,
lib/wayfinding/destination_list.rb,
lib/wayfinding/url_resolver_context.rb
Overview
Cross-application URL resolution.
Any component can link to any page without depending on the component that owns the route. Registered destinations are data, so this module's public surface never grows as destinations are added.
Wayfinding.register(
name: :home,
engine: -> { Projects::Engine },
helper: :home_path
)
Wayfinding.path_for(:home, home, current_tab: "Projects")
Defined Under Namespace
Modules: RSpecHelpers Classes: Destination, DestinationList, Kind, UrlResolverContext
Constant Summary collapse
- Error =
Class.new(StandardError)
- UnregisteredDestination =
Raised when looking up a destination that was never registered.
Class.new(Error)
- InvalidDestination =
Raised at registration when a destination is missing fields its kind requires, or when its resolution strategy is ambiguous or incomplete.
Class.new(Error)
- UnknownKind =
Raised when a destination declares a kind that was never defined.
Class.new(Error)
- VERSION =
"0.0.1"
Class Method Summary collapse
-
.define_kind(name, requires: []) ⇒ Object
Declare a named field contract.
- .fetch(name) ⇒ Object
- .kinds ⇒ Object
- .of_kind(name) ⇒ Object
- .path_for(name, **params) ⇒ Object
-
.preserve! ⇒ Object
Snapshot the registry, yield, then restore it.
- .register(name:, engine: nil, kind: nil, helper: nil, **attributes, &resolver) ⇒ Object
- .registered?(name) ⇒ Boolean
- .registered_names ⇒ Object
- .reset! ⇒ Object
- .url_for(name, **params) ⇒ Object
-
.verify!(expected) ⇒ Object
Assert every expected destination is registered.
Class Method Details
.define_kind(name, requires: []) ⇒ Object
Declare a named field contract. See Wayfinding::Kind.
26 27 28 29 |
# File 'lib/wayfinding.rb', line 26 def define_kind(name, requires: []) kind = Kind.new(name: name, requires: requires) kinds[kind.name] = kind end |
.fetch(name) ⇒ Object
52 53 54 55 56 57 |
# File 'lib/wayfinding.rb', line 52 def fetch(name) destinations.fetch(name.to_sym) do raise UnregisteredDestination, "No destination registered for #{name.inspect}. Registered: #{registered_names.join(', ')}" end end |
.kinds ⇒ Object
31 |
# File 'lib/wayfinding.rb', line 31 def kinds = @kinds ||= {} |
.of_kind(name) ⇒ Object
47 48 49 50 |
# File 'lib/wayfinding.rb', line 47 def of_kind(name) name = name.to_sym DestinationList.new(destinations.each_value.select { |destination| destination.kind == name }) end |
.path_for(name, **params) ⇒ Object
43 |
# File 'lib/wayfinding.rb', line 43 def path_for(name, *, **params) = fetch(name).path(*, **params) |
.preserve! ⇒ Object
Snapshot the registry, yield, then restore it. Used by the RSpec helper so a destination registered inside an example does not leak.
75 76 77 78 79 80 81 82 |
# File 'lib/wayfinding.rb', line 75 def preserve! destinations_snapshot = destinations.dup kinds_snapshot = kinds.dup yield ensure @destinations = destinations_snapshot @kinds = kinds_snapshot end |
.register(name:, engine: nil, kind: nil, helper: nil, **attributes, &resolver) ⇒ Object
33 34 35 36 37 38 39 40 41 |
# File 'lib/wayfinding.rb', line 33 def register(name:, engine: nil, kind: nil, helper: nil, **attributes, &resolver) validate_resolution!(name, engine, helper, resolver) validate_all_or_none!(name, attributes, %i[action subject]) validate_kind!(name, kind, **attributes) destinations[name.to_sym] = Destination.new( name: name, engine: engine, kind: kind, helper: helper, resolver: resolver, **attributes ) end |
.registered?(name) ⇒ Boolean
59 |
# File 'lib/wayfinding.rb', line 59 def registered?(name) = destinations.key?(name.to_sym) |
.registered_names ⇒ Object
61 |
# File 'lib/wayfinding.rb', line 61 def registered_names = destinations.keys.sort |
.reset! ⇒ Object
84 85 86 87 |
# File 'lib/wayfinding.rb', line 84 def reset! @destinations = {} @kinds = {} end |
.url_for(name, **params) ⇒ Object
45 |
# File 'lib/wayfinding.rb', line 45 def url_for(name, *, **params) = fetch(name).url(*, **params) |
.verify!(expected) ⇒ Object
Assert every expected destination is registered. Call at the end of an initializer so a dropped registration fails the boot rather than rendering a broken link.
66 67 68 69 70 71 |
# File 'lib/wayfinding.rb', line 66 def verify!(expected) missing = Array(expected).map(&:to_sym) - registered_names return true if missing.empty? raise UnregisteredDestination, "Missing destination registrations: #{missing.join(', ')}" end |