Created
October 19, 2022 02:18
-
-
Save dhnaranjo/3decca0782374aaa7f2200d69bd710ee to your computer and use it in GitHub Desktop.
Tryinna work out a cleaner way to access Phlex components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
require "singleton" | |
require "bundler/inline" | |
gemfile do | |
gem "phlex" | |
end | |
class ComponentRegistry | |
include Singleton | |
def initialize | |
@scopes = {} | |
end | |
def register(component) | |
parts = component.name.split("::") | |
scopes = parts.map.with_index { |_, index| parts[0, index].join("::") } | |
component_names = parts.map.with_index { |_, index| parts[index, parts.size].join("_") } | |
scopes.each_with_index do |scope, index| | |
@scopes[scope] ||= RegistryScope.new | |
component_names[0..index].each do |component_name| | |
@scopes[scope].component_method(component_name, component) | |
end | |
end | |
end | |
def fetch_scopes(context) | |
parts = context.name.split("::") | |
parts.size | |
.times | |
.map { |n| parts.first(parts.size - n) } | |
.map { |path_parts| path_parts.join("::") } | |
.filter_map { |path| @scopes[path] } | |
end | |
end | |
class RegistryScope | |
def with_caller(caller) | |
@caller = caller | |
yield | |
end | |
def component_method(component_name, component) | |
define_singleton_method(component_name.to_sym) do |*args, **kwargs, &block| | |
@caller.render(component.new(*args, **kwargs), &block) | |
end | |
end | |
end | |
module RegisterableComponent | |
def self.included(base) | |
ComponentRegistry.instance.register(base) | |
end | |
end | |
module ComponentAccess | |
def c | |
ComponentRegistry.instance | |
.fetch_scopes(self.class) | |
.find do |scope| | |
scope.with_caller(self) { yield_self } | |
rescue NoMethodError | |
next | |
end | |
end | |
end | |
module One | |
module Two | |
module Three | |
module Four | |
class Component < Phlex::View | |
include RegisterableComponent | |
def initialize(param) | |
@param = param | |
end | |
def template(&block) | |
p do | |
span { @param } | |
whitespace | |
span(&block) | |
end | |
end | |
end | |
end | |
end | |
end | |
end | |
module One | |
module Two | |
module TwoPointFive | |
class View < Phlex::View | |
include ComponentAccess | |
def template | |
c.One_Two_Three_Four_Component("Deep paths") { "work fine" } | |
c.Three_Four_Component("Shallow ones") { "also good" } | |
begin | |
c.Component("Not this one") { "nope" } | |
rescue | |
nil | |
end | |
end | |
end | |
end | |
end | |
end | |
puts One::Two::TwoPointFive::View.new.call | |
# <p><span>Deep paths</span> <span>work fine</span></p><p><span>Shallow ones</span> <span>also good</span></p> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment