Last active
August 21, 2025 00:23
-
-
Save bradgessler/f10cc44695e1a50ef9c4d88be5168995 to your computer and use it in GitHub Desktop.
Superform kits
This file contains hidden or 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 "bundler/inline" | |
| gemfile do | |
| source "https://rubygems.org" | |
| gem "phlex" | |
| end | |
| require "phlex" | |
| module Alpha | |
| module Superform | |
| module Kit | |
| def self.extended(mod) | |
| # define helpers for already-present constants in this namespace | |
| mod.constants.each { |name| mod.__define_kit_method__(name) } | |
| end | |
| # Fires whenever a constant is defined directly under the module | |
| def const_added(name) | |
| __define_kit_method__(name) | |
| super | |
| end | |
| # protected | |
| # Define the instance helper once per constant (idempotent) | |
| def __define_kit_method__(name) | |
| define_method name do |key, *args, **kwargs, &block| | |
| klass = self.class.const_get(name) # reload-safe lookup | |
| component = klass.new(field(key), *args, **kwargs) | |
| render(component, &block) | |
| end | |
| end | |
| end | |
| module Fields | |
| class Base | |
| def initialize(field) | |
| end | |
| end | |
| Input = Base | |
| class Select < Base | |
| def initialize(field, collection) | |
| @collection = collection | |
| end | |
| end | |
| end | |
| end | |
| class Form | |
| module Fields | |
| include Superform::Fields | |
| extend Superform::Kit | |
| # Define your input fields here... | |
| end | |
| def render(field) | |
| puts "Rendering field #{field.inspect}" | |
| end | |
| def field(key) | |
| puts "Field #{key}" | |
| end | |
| include Fields | |
| end | |
| Form.new.tap do |form| | |
| form.Input(:name) | |
| form.Select(:age, 1..100) | |
| end | |
| end | |
| module Beta | |
| class Input | |
| def initialize(...) | |
| end | |
| end | |
| class Form | |
| def render(component) | |
| puts "Rendering #{component.inspect}" | |
| end | |
| def field(key) | |
| p key | |
| end | |
| def self.field(name) | |
| define_method("#{name}_field") do |key, *args, **kwargs, &block| | |
| render self.send(name, field(key), *args, **kwargs, &block) | |
| end | |
| end | |
| field def input(key, *, **) | |
| Input.new(field(key), *, **) | |
| end | |
| end | |
| Form.new.tap do |form| | |
| form.input_field(:name) | |
| form.input(:email, type: :email) | |
| end | |
| end | |
| module Gamma | |
| class Input | |
| def initialize(field, **) | |
| @field = field | |
| end | |
| end | |
| class Form | |
| class Field | |
| attr_accessor :key | |
| def initialize(key, form) | |
| @key = key | |
| @form = form | |
| end | |
| def input(**) | |
| @form.render Input.new(self, **) | |
| end | |
| end | |
| def field(key) | |
| Field.new(key, self) | |
| end | |
| def render(component) | |
| puts "Rendering #{component.inspect}" | |
| end | |
| end | |
| Form.new.tap do |form| | |
| form.field(:name).input | |
| form.field(:email) | |
| end | |
| end | |
| module Delta | |
| class Input < Phlex::HTML | |
| def initialize(field, **) | |
| @field = field | |
| end | |
| def view_template | |
| input(type: :text, name: @field.key) | |
| end | |
| end | |
| class Form | |
| class Field | |
| attr_accessor :key | |
| def initialize(key) | |
| @key = key | |
| end | |
| class Kit | |
| def initialize(field, form) | |
| @field = field | |
| @form = form | |
| end | |
| end | |
| def self.method_added(name) | |
| self::Kit.define_method(name) do |*args, **kwargs, &block| | |
| instance = @field.send(name, *args, **kwargs, &block) | |
| raise "#{instance} is not a Phlex component" unless instance.is_a?(Phlex::HTML) | |
| @form.render instance | |
| end | |
| end | |
| def input(**) | |
| Input.new(self, **) | |
| end | |
| end | |
| def field(key) | |
| self.class::Field.new(key) | |
| end | |
| def Field(key) | |
| self.class::Field::Kit.new(field(key), self) | |
| end | |
| def render(component) | |
| puts "Rendering #{component.call}" | |
| end | |
| end | |
| Form.new.tap do |form| | |
| form.Field(:name).input | |
| form.render form.field(:phone).input | |
| end | |
| class MyForm < Form | |
| class Field < Field | |
| def my_input(**) | |
| Input.new(self, **) | |
| end | |
| end | |
| end | |
| MyForm.new.tap do |form| | |
| form.Field(:first_name).my_input | |
| form.Field(:last_name).input | |
| form.render form.field(:email).my_input | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment