Class: CommandTower::Messaging::Rendering::TemplateResolver

Inherits:
Object
  • Object
show all
Defined in:
app/services/command_tower/messaging/rendering/template_resolver.rb

Overview

Internal Execution-pipeline collaborator (not a Service/Workflow/Controller).

Resolves one rendered-destination basename (e.g. "email", "sms") to an ActionView template, preferring a notification_type_key-specific view over the generic one, and preferring the host application's app/views over CommandTower's own engine views for either.

Host convention (documentation, not code):

app/views/command_tower/messaging/rendering/
email.html.erb                     # optional host override of the generic chrome
<notification_type_key>/email.html.erb  # optional type-specific override

Hosts customize by dropping ERB files at that path; they never call this class directly. ChannelRenderer remains the only public Ruby entry into rendering. prepend_view_path/reset_view_paths! exist solely as a messaging spec fixture seam (mirrors Rails' own prepend_view_path testing idiom) and are not part of any host-facing contract.

Constant Summary collapse

TEMPLATE_PREFIX =
"command_tower/messaging/rendering"
TYPE_KEY_PATTERN =
/\A[a-z0-9_]+\z/

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.extra_view_paths ⇒ Object



65
66
67
# File 'app/services/command_tower/messaging/rendering/template_resolver.rb', line 65

def extra_view_paths
  @extra_view_paths ||= []
end

.prepend_view_path(path) ⇒ Object

Spec-only seam: prepend an additional view root ahead of the host and engine defaults so fixture views can prove override precedence.



43
44
45
# File 'app/services/command_tower/messaging/rendering/template_resolver.rb', line 43

def prepend_view_path(path)
  extra_view_paths.unshift(path.to_s)
end

.render(basename:, format:, notification_type_key:, generic_locals:, type_locals:) ⇒ Object



31
32
33
34
35
36
37
38
39
# File 'app/services/command_tower/messaging/rendering/template_resolver.rb', line 31

def render(basename:, format:, notification_type_key:, generic_locals:, type_locals:)
  new.render(
    basename:,
    format:,
    notification_type_key:,
    generic_locals:,
    type_locals:,
  )
end

.render_type_template(basename:, format:, notification_type_key:, locals:) ⇒ Object

Type-only, no-generic-fallback resolution: returns nil when there is no matching type template (invalid/sanitized-out key, or the type directory/basename simply does not exist) instead of raising Errno::ENOENT like .render does. Callers that have no generic ERB file to fall back to (e.g. InboxDocumentRenderer, whose generic path is a pure-Ruby builder) use this instead of .render. A template that is found but raises mid-render still propagates (via render_named's ActionView::Template::Error unwrap) so callers can distinguish "no type content" from "type content is broken" if they choose to.



61
62
63
# File 'app/services/command_tower/messaging/rendering/template_resolver.rb', line 61

def render_type_template(basename:, format:, notification_type_key:, locals:)
  new.render_type_template(basename:, format:, notification_type_key:, locals:)
end

.reset_view_paths! ⇒ Object



47
48
49
# File 'app/services/command_tower/messaging/rendering/template_resolver.rb', line 47

def reset_view_paths!
  extra_view_paths.clear
end

Instance Method Details

#render(basename:, format:, notification_type_key:, generic_locals:, type_locals:) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'app/services/command_tower/messaging/rendering/template_resolver.rb', line 70

def render(basename:, format:, notification_type_key:, generic_locals:, type_locals:)
  type_key = sanitized_type_key(notification_type_key)

  if type_key
    begin
      return render_named("#{TEMPLATE_PREFIX}/#{type_key}/#{basename}", format, type_locals)
    rescue ActionView::MissingTemplate
      # No type-specific template for this basename; fall through to generic.
    end
  end

  begin
    render_named("#{TEMPLATE_PREFIX}/#{basename}", format, generic_locals)
  rescue ActionView::MissingTemplate
    raise Errno::ENOENT, "missing template #{basename}.#{format}.erb"
  end
end

#render_type_template(basename:, format:, notification_type_key:, locals:) ⇒ Object



88
89
90
91
92
93
94
95
# File 'app/services/command_tower/messaging/rendering/template_resolver.rb', line 88

def render_type_template(basename:, format:, notification_type_key:, locals:)
  type_key = sanitized_type_key(notification_type_key)
  return nil unless type_key

  render_named("#{TEMPLATE_PREFIX}/#{type_key}/#{basename}", format, locals)
rescue ActionView::MissingTemplate
  nil
end