rhales 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
 - data/CLAUDE.locale.txt +7 -0
 - data/CLAUDE.md +90 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +881 -0
 - data/lib/rhales/adapters/base_auth.rb +106 -0
 - data/lib/rhales/adapters/base_request.rb +97 -0
 - data/lib/rhales/adapters/base_session.rb +93 -0
 - data/lib/rhales/configuration.rb +156 -0
 - data/lib/rhales/context.rb +240 -0
 - data/lib/rhales/csp.rb +94 -0
 - data/lib/rhales/errors/hydration_collision_error.rb +85 -0
 - data/lib/rhales/errors.rb +36 -0
 - data/lib/rhales/hydration_data_aggregator.rb +220 -0
 - data/lib/rhales/hydration_registry.rb +58 -0
 - data/lib/rhales/hydrator.rb +141 -0
 - data/lib/rhales/parsers/handlebars-grammar-review.txt +39 -0
 - data/lib/rhales/parsers/handlebars_parser.rb +727 -0
 - data/lib/rhales/parsers/rue_format_parser.rb +385 -0
 - data/lib/rhales/refinements/require_refinements.rb +236 -0
 - data/lib/rhales/rue_document.rb +304 -0
 - data/lib/rhales/template_engine.rb +353 -0
 - data/lib/rhales/tilt.rb +214 -0
 - data/lib/rhales/version.rb +6 -0
 - data/lib/rhales/view.rb +412 -0
 - data/lib/rhales/view_composition.rb +165 -0
 - data/lib/rhales.rb +57 -0
 - data/rhales.gemspec +46 -0
 - metadata +78 -0
 
| 
         @@ -0,0 +1,165 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # lib/rhales/view_composition.rb
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'rue_document'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'refinements/require_refinements'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            using Rhales::Ruequire
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Rhales
         
     | 
| 
      
 9 
     | 
    
         
            +
              # ViewComposition builds and represents the complete template dependency graph
         
     | 
| 
      
 10 
     | 
    
         
            +
              # for a view render. It provides a data-agnostic, immutable representation
         
     | 
| 
      
 11 
     | 
    
         
            +
              # of all templates (layout, view, partials) required for rendering.
         
     | 
| 
      
 12 
     | 
    
         
            +
              #
         
     | 
| 
      
 13 
     | 
    
         
            +
              # This class is a key component in the two-pass rendering architecture,
         
     | 
| 
      
 14 
     | 
    
         
            +
              # enabling server-side data aggregation before HTML generation.
         
     | 
| 
      
 15 
     | 
    
         
            +
              #
         
     | 
| 
      
 16 
     | 
    
         
            +
              # Responsibilities:
         
     | 
| 
      
 17 
     | 
    
         
            +
              # - Dependency Resolution: Recursively discovers and loads all partials
         
     | 
| 
      
 18 
     | 
    
         
            +
              # - Structural Representation: Organizes templates into a traversable tree
         
     | 
| 
      
 19 
     | 
    
         
            +
              # - Traversal Interface: Provides methods to iterate templates in render order
         
     | 
| 
      
 20 
     | 
    
         
            +
              #
         
     | 
| 
      
 21 
     | 
    
         
            +
              # Key Characteristics:
         
     | 
| 
      
 22 
     | 
    
         
            +
              # - Data-Agnostic: Knows nothing about runtime context or request data
         
     | 
| 
      
 23 
     | 
    
         
            +
              # - Immutable: Once created, the composition is read-only
         
     | 
| 
      
 24 
     | 
    
         
            +
              # - Cacheable: Can be cached in production for performance
         
     | 
| 
      
 25 
     | 
    
         
            +
              class ViewComposition
         
     | 
| 
      
 26 
     | 
    
         
            +
                class TemplateNotFoundError < StandardError; end
         
     | 
| 
      
 27 
     | 
    
         
            +
                class CircularDependencyError < StandardError; end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                attr_reader :root_template_name, :templates, :dependencies
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def initialize(root_template_name, loader:)
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @root_template_name = root_template_name
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @loader             = loader
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @templates          = {}
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @dependencies       = {}
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @loading            = Set.new
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                # Resolve all template dependencies
         
     | 
| 
      
 40 
     | 
    
         
            +
                def resolve!
         
     | 
| 
      
 41 
     | 
    
         
            +
                  load_template_recursive(@root_template_name)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  freeze_composition
         
     | 
| 
      
 43 
     | 
    
         
            +
                  self
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                # Iterate through all documents in render order
         
     | 
| 
      
 47 
     | 
    
         
            +
                # Layout -> View -> Partials (depth-first)
         
     | 
| 
      
 48 
     | 
    
         
            +
                def each_document_in_render_order(&)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  return enum_for(:each_document_in_render_order) unless block_given?
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  visited = Set.new
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                  # Process layout first if specified
         
     | 
| 
      
 54 
     | 
    
         
            +
                  root_doc = @templates[@root_template_name]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  if root_doc && root_doc.layout
         
     | 
| 
      
 56 
     | 
    
         
            +
                    layout_name = root_doc.layout
         
     | 
| 
      
 57 
     | 
    
         
            +
                    if @templates[layout_name]
         
     | 
| 
      
 58 
     | 
    
         
            +
                      yield_template_recursive(layout_name, visited, &)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  # Then process the root template and its dependencies
         
     | 
| 
      
 63 
     | 
    
         
            +
                  yield_template_recursive(@root_template_name, visited, &)
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                # Get a specific template by name
         
     | 
| 
      
 67 
     | 
    
         
            +
                def template(name)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @templates[name]
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                # Check if a template exists in the composition
         
     | 
| 
      
 72 
     | 
    
         
            +
                def has_template?(name)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @templates.key?(name)
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                # Get all template names
         
     | 
| 
      
 77 
     | 
    
         
            +
                def template_names
         
     | 
| 
      
 78 
     | 
    
         
            +
                  @templates.keys
         
     | 
| 
      
 79 
     | 
    
         
            +
                end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                # Get direct dependencies of a template
         
     | 
| 
      
 82 
     | 
    
         
            +
                def dependencies_of(template_name)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  @dependencies[template_name] || []
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                private
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                def load_template_recursive(template_name, parent_path = nil)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  # Check for circular dependencies
         
     | 
| 
      
 90 
     | 
    
         
            +
                  if @loading.include?(template_name)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    raise CircularDependencyError, "Circular dependency detected: #{template_name} -> #{@loading.to_a.join(' -> ')}"
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                  # Skip if already loaded
         
     | 
| 
      
 95 
     | 
    
         
            +
                  return if @templates.key?(template_name)
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  @loading.add(template_name)
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 100 
     | 
    
         
            +
                    # Load template using the provided loader
         
     | 
| 
      
 101 
     | 
    
         
            +
                    parser = @loader.call(template_name)
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    unless parser
         
     | 
| 
      
 104 
     | 
    
         
            +
                      raise TemplateNotFoundError, "Template not found: #{template_name}"
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    # Store the template
         
     | 
| 
      
 108 
     | 
    
         
            +
                    @templates[template_name]    = parser
         
     | 
| 
      
 109 
     | 
    
         
            +
                    @dependencies[template_name] = []
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                    # Extract and load partials
         
     | 
| 
      
 112 
     | 
    
         
            +
                    extract_partials(parser).each do |partial_name|
         
     | 
| 
      
 113 
     | 
    
         
            +
                      @dependencies[template_name] << partial_name
         
     | 
| 
      
 114 
     | 
    
         
            +
                      load_template_recursive(partial_name, template_name)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                    # Load layout if specified and not already loaded
         
     | 
| 
      
 118 
     | 
    
         
            +
                    if parser.layout && !@templates.key?(parser.layout)
         
     | 
| 
      
 119 
     | 
    
         
            +
                      load_template_recursive(parser.layout, template_name)
         
     | 
| 
      
 120 
     | 
    
         
            +
                    end
         
     | 
| 
      
 121 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 122 
     | 
    
         
            +
                    @loading.delete(template_name)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                def extract_partials(parser)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  partials         = Set.new
         
     | 
| 
      
 128 
     | 
    
         
            +
                  template_content = parser.section('template')
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                  return partials unless template_content
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  # Extract partial references from template
         
     | 
| 
      
 133 
     | 
    
         
            +
                  # Looking for {{> partial_name}} patterns
         
     | 
| 
      
 134 
     | 
    
         
            +
                  template_content.scan(/\{\{>\s*([^\s}]+)\s*\}\}/) do |match|
         
     | 
| 
      
 135 
     | 
    
         
            +
                    partials.add(match[0])
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                  partials
         
     | 
| 
      
 139 
     | 
    
         
            +
                end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                def yield_template_recursive(template_name, visited, &)
         
     | 
| 
      
 142 
     | 
    
         
            +
                  return if visited.include?(template_name)
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                  visited.add(template_name)
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                  # First yield dependencies (partials)
         
     | 
| 
      
 147 
     | 
    
         
            +
                  (@dependencies[template_name] || []).each do |dep_name|
         
     | 
| 
      
 148 
     | 
    
         
            +
                    yield_template_recursive(dep_name, visited, &)
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
             
     | 
| 
      
 151 
     | 
    
         
            +
                  # Then yield the template itself
         
     | 
| 
      
 152 
     | 
    
         
            +
                  if @templates[template_name]
         
     | 
| 
      
 153 
     | 
    
         
            +
                    yield template_name, @templates[template_name]
         
     | 
| 
      
 154 
     | 
    
         
            +
                  end
         
     | 
| 
      
 155 
     | 
    
         
            +
                end
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                def freeze_composition
         
     | 
| 
      
 158 
     | 
    
         
            +
                  @templates.freeze
         
     | 
| 
      
 159 
     | 
    
         
            +
                  @dependencies.freeze
         
     | 
| 
      
 160 
     | 
    
         
            +
                  @templates.each_value(&:freeze)
         
     | 
| 
      
 161 
     | 
    
         
            +
                  @dependencies.each_value(&:freeze)
         
     | 
| 
      
 162 
     | 
    
         
            +
                  freeze
         
     | 
| 
      
 163 
     | 
    
         
            +
                end
         
     | 
| 
      
 164 
     | 
    
         
            +
              end
         
     | 
| 
      
 165 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/rhales.rb
    ADDED
    
    | 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # lib/rhales.rb
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'rhales/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative 'rhales/errors'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative 'rhales/configuration'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative 'rhales/adapters/base_auth'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require_relative 'rhales/adapters/base_session'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require_relative 'rhales/context'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require_relative 'rhales/rue_document'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require_relative 'rhales/parsers/handlebars_parser'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require_relative 'rhales/parsers/rue_format_parser'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require_relative 'rhales/template_engine'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require_relative 'rhales/hydrator'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require_relative 'rhales/view_composition'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require_relative 'rhales/hydration_data_aggregator'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require_relative 'rhales/refinements/require_refinements'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require_relative 'rhales/view'
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            # Ruby Single File Components (RSFC)
         
     | 
| 
      
 20 
     | 
    
         
            +
            #
         
     | 
| 
      
 21 
     | 
    
         
            +
            # A framework for building server-rendered components with client-side hydration
         
     | 
| 
      
 22 
     | 
    
         
            +
            # using .rue files (Ruby Single File Components). Similar to .vue files but for Ruby.
         
     | 
| 
      
 23 
     | 
    
         
            +
            #
         
     | 
| 
      
 24 
     | 
    
         
            +
            # Features:
         
     | 
| 
      
 25 
     | 
    
         
            +
            # - Server-side template rendering with Handlebars-style syntax
         
     | 
| 
      
 26 
     | 
    
         
            +
            # - Client-side data hydration with JSON injection
         
     | 
| 
      
 27 
     | 
    
         
            +
            # - Partial support for component composition
         
     | 
| 
      
 28 
     | 
    
         
            +
            # - Pluggable authentication and session adapters
         
     | 
| 
      
 29 
     | 
    
         
            +
            # - Security-first design with XSS protection and CSP support
         
     | 
| 
      
 30 
     | 
    
         
            +
            #
         
     | 
| 
      
 31 
     | 
    
         
            +
            # Usage:
         
     | 
| 
      
 32 
     | 
    
         
            +
            #   Rhales.configure do |config|
         
     | 
| 
      
 33 
     | 
    
         
            +
            #     config.default_localhas_role?e = 'en'
         
     | 
| 
      
 34 
     | 
    
         
            +
            #     config.template_paths = ['app/templates']
         
     | 
| 
      
 35 
     | 
    
         
            +
            #     config.features = { dark_mode: true }
         
     | 
| 
      
 36 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 37 
     | 
    
         
            +
            #
         
     | 
| 
      
 38 
     | 
    
         
            +
            #   view = Rhales::View.new(request, session, user)
         
     | 
| 
      
 39 
     | 
    
         
            +
            #   html = view.render('my_component')
         
     | 
| 
      
 40 
     | 
    
         
            +
            module Rhales
         
     | 
| 
      
 41 
     | 
    
         
            +
              # Convenience method to create a view with props
         
     | 
| 
      
 42 
     | 
    
         
            +
              def self.render(template_name, request: nil, session: nil, user: nil, locale: nil, **props)
         
     | 
| 
      
 43 
     | 
    
         
            +
                view = View.new(request, session, user, locale, props: props)
         
     | 
| 
      
 44 
     | 
    
         
            +
                view.render(template_name)
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              # Quick template rendering for testing/simple use cases
         
     | 
| 
      
 48 
     | 
    
         
            +
              def self.render_template(template_content, context_data = {})
         
     | 
| 
      
 49 
     | 
    
         
            +
                context = Context.minimal(props: context_data)
         
     | 
| 
      
 50 
     | 
    
         
            +
                TemplateEngine.render(template_content, context)
         
     | 
| 
      
 51 
     | 
    
         
            +
              end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
              # Create context with props (for advanced usage)
         
     | 
| 
      
 54 
     | 
    
         
            +
              def self.create_context(request: nil, session: nil, user: nil, locale: nil, **props)
         
     | 
| 
      
 55 
     | 
    
         
            +
                Context.for_view(request, session, user, locale, **props)
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
    
        data/rhales.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # rhales.gemspec
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'lib/rhales/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 6 
     | 
    
         
            +
              spec.name          = 'rhales'
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.version       = Rhales::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors       = ['delano']
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email         = ['gems@onetimesecret.com']
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              spec.summary       = 'Rhales - Server-rendered components with client-side hydration (RSFCs)'
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.description   = <<~DESC
         
     | 
| 
      
 13 
     | 
    
         
            +
                Rhales is a framework for building server-rendered components with
         
     | 
| 
      
 14 
     | 
    
         
            +
                client-side data hydration using .rue files called RSFCs (Ruby
         
     | 
| 
      
 15 
     | 
    
         
            +
                Single File Components). Similar to Vue.js single file components
         
     | 
| 
      
 16 
     | 
    
         
            +
                but for server-side Ruby applications.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                Features include Handlebars-style templating, JSON data injection, partial support,
         
     | 
| 
      
 19 
     | 
    
         
            +
                pluggable authentication adapters, and security-first design.
         
     | 
| 
      
 20 
     | 
    
         
            +
              DESC
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              spec.homepage              = 'https://github.com/onetimesecret/rhales'
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.license               = 'MIT'
         
     | 
| 
      
 24 
     | 
    
         
            +
              spec.required_ruby_version = '>= 3.4.0'
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              spec.metadata['source_code_uri']       = 'https://github.com/onetimesecret/rhales'
         
     | 
| 
      
 28 
     | 
    
         
            +
              spec.metadata['changelog_uri']         = 'https://github.com/onetimesecret/rhales/blob/main/CHANGELOG.md'
         
     | 
| 
      
 29 
     | 
    
         
            +
              spec.metadata['documentation_uri']     = 'https://github.com/onetimesecret/rhales/blob/main/README.md'
         
     | 
| 
      
 30 
     | 
    
         
            +
              spec.metadata['rubygems_mfa_required'] = 'true'
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              # Specify which files should be added to the gem
         
     | 
| 
      
 33 
     | 
    
         
            +
              spec.files = Dir.chdir(__dir__) do
         
     | 
| 
      
 34 
     | 
    
         
            +
                Dir['{lib}/**/*', '*.md', '*.txt', '*.gemspec'].select { |f| File.file?(f) }
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              spec.bindir        = 'exe'
         
     | 
| 
      
 38 
     | 
    
         
            +
              spec.executables   = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
         
     | 
| 
      
 39 
     | 
    
         
            +
              spec.require_paths = ['lib']
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
              # Runtime dependencies
         
     | 
| 
      
 42 
     | 
    
         
            +
              # (none currently - all parsing is done with manual recursive descent parsers)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              # Development dependencies should be specified in Gemfile instead of gemspec
         
     | 
| 
      
 45 
     | 
    
         
            +
              # See: https://bundler.io/guides/creating_gem.html#testing-our-gem
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,78 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: rhales
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.3.0
         
     | 
| 
      
 5 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 6 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - delano
         
     | 
| 
      
 8 
     | 
    
         
            +
            bindir: exe
         
     | 
| 
      
 9 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 10 
     | 
    
         
            +
            date: 2025-07-09 00:00:00.000000000 Z
         
     | 
| 
      
 11 
     | 
    
         
            +
            dependencies: []
         
     | 
| 
      
 12 
     | 
    
         
            +
            description: |
         
     | 
| 
      
 13 
     | 
    
         
            +
              Rhales is a framework for building server-rendered components with
         
     | 
| 
      
 14 
     | 
    
         
            +
              client-side data hydration using .rue files called RSFCs (Ruby
         
     | 
| 
      
 15 
     | 
    
         
            +
              Single File Components). Similar to Vue.js single file components
         
     | 
| 
      
 16 
     | 
    
         
            +
              but for server-side Ruby applications.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              Features include Handlebars-style templating, JSON data injection, partial support,
         
     | 
| 
      
 19 
     | 
    
         
            +
              pluggable authentication adapters, and security-first design.
         
     | 
| 
      
 20 
     | 
    
         
            +
            email:
         
     | 
| 
      
 21 
     | 
    
         
            +
            - gems@onetimesecret.com
         
     | 
| 
      
 22 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 23 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 24 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 25 
     | 
    
         
            +
            files:
         
     | 
| 
      
 26 
     | 
    
         
            +
            - CLAUDE.locale.txt
         
     | 
| 
      
 27 
     | 
    
         
            +
            - CLAUDE.md
         
     | 
| 
      
 28 
     | 
    
         
            +
            - LICENSE.txt
         
     | 
| 
      
 29 
     | 
    
         
            +
            - README.md
         
     | 
| 
      
 30 
     | 
    
         
            +
            - lib/rhales.rb
         
     | 
| 
      
 31 
     | 
    
         
            +
            - lib/rhales/adapters/base_auth.rb
         
     | 
| 
      
 32 
     | 
    
         
            +
            - lib/rhales/adapters/base_request.rb
         
     | 
| 
      
 33 
     | 
    
         
            +
            - lib/rhales/adapters/base_session.rb
         
     | 
| 
      
 34 
     | 
    
         
            +
            - lib/rhales/configuration.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            - lib/rhales/context.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            - lib/rhales/csp.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            - lib/rhales/errors.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
            - lib/rhales/errors/hydration_collision_error.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            - lib/rhales/hydration_data_aggregator.rb
         
     | 
| 
      
 40 
     | 
    
         
            +
            - lib/rhales/hydration_registry.rb
         
     | 
| 
      
 41 
     | 
    
         
            +
            - lib/rhales/hydrator.rb
         
     | 
| 
      
 42 
     | 
    
         
            +
            - lib/rhales/parsers/handlebars-grammar-review.txt
         
     | 
| 
      
 43 
     | 
    
         
            +
            - lib/rhales/parsers/handlebars_parser.rb
         
     | 
| 
      
 44 
     | 
    
         
            +
            - lib/rhales/parsers/rue_format_parser.rb
         
     | 
| 
      
 45 
     | 
    
         
            +
            - lib/rhales/refinements/require_refinements.rb
         
     | 
| 
      
 46 
     | 
    
         
            +
            - lib/rhales/rue_document.rb
         
     | 
| 
      
 47 
     | 
    
         
            +
            - lib/rhales/template_engine.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
            - lib/rhales/tilt.rb
         
     | 
| 
      
 49 
     | 
    
         
            +
            - lib/rhales/version.rb
         
     | 
| 
      
 50 
     | 
    
         
            +
            - lib/rhales/view.rb
         
     | 
| 
      
 51 
     | 
    
         
            +
            - lib/rhales/view_composition.rb
         
     | 
| 
      
 52 
     | 
    
         
            +
            - rhales.gemspec
         
     | 
| 
      
 53 
     | 
    
         
            +
            homepage: https://github.com/onetimesecret/rhales
         
     | 
| 
      
 54 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 55 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 56 
     | 
    
         
            +
            metadata:
         
     | 
| 
      
 57 
     | 
    
         
            +
              source_code_uri: https://github.com/onetimesecret/rhales
         
     | 
| 
      
 58 
     | 
    
         
            +
              changelog_uri: https://github.com/onetimesecret/rhales/blob/main/CHANGELOG.md
         
     | 
| 
      
 59 
     | 
    
         
            +
              documentation_uri: https://github.com/onetimesecret/rhales/blob/main/README.md
         
     | 
| 
      
 60 
     | 
    
         
            +
              rubygems_mfa_required: 'true'
         
     | 
| 
      
 61 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 62 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 63 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 64 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 65 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 66 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 67 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 68 
     | 
    
         
            +
                  version: 3.4.0
         
     | 
| 
      
 69 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 70 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 71 
     | 
    
         
            +
              - - ">="
         
     | 
| 
      
 72 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 73 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 74 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 75 
     | 
    
         
            +
            rubygems_version: 3.6.2
         
     | 
| 
      
 76 
     | 
    
         
            +
            specification_version: 4
         
     | 
| 
      
 77 
     | 
    
         
            +
            summary: Rhales - Server-rendered components with client-side hydration (RSFCs)
         
     | 
| 
      
 78 
     | 
    
         
            +
            test_files: []
         
     |