Skip to content

Commit

Permalink
Add component generator 🦾 (#97)
Browse files Browse the repository at this point in the history
* install generator working

* got it working 🦾

* js overriding is working

* moved index.js to lib/rbui/index.js

* fix a few thangs 🦾

* final commit

* remove phlex_ui refs

* fix index.js
  • Loading branch information
SethHorsley authored Sep 16, 2024
1 parent 19a1b5d commit 52898b1
Show file tree
Hide file tree
Showing 7 changed files with 177 additions and 2 deletions.
108 changes: 108 additions & 0 deletions lib/generators/rbui/component_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
module RBUI
module Generators
class ComponentGenerator < defined?(Rails::Generators::Base) ? Rails::Generators::Base : Object
namespace "rbui:component"

source_root File.expand_path("../../..", __dir__)
argument :component_name, type: :string, required: true

def copy_component
return puts "This generator can only be run in a Rails environment." unless defined?(Rails::Generators::Base)

copy_common_files
copy_component_files
end

private

def copy_common_files
template "#{template_dir}/index.js", "#{destination_path}/index.js" unless File.exist?("#{destination_path}/index.js")
copy_file File.join(source_path, "base.rb"), File.join(destination_path, "base.rb")

append_to_file "app/javascript/application.js", "\nimport \"../components/rbui\";\n"
end

def copy_component_files
puts "Component #{component} not found in rbui gem" if component_source.empty?

component_files = Dir.glob("#{component_source}/*")

component_files.each do |file|
copy_file file, File.join(destination_path, component, File.basename(file))
end
update_index_file
end

def update_index_file
index_path = File.join(destination_root, "app/components/rbui/index.js")
content = File.read(index_path)

update_last_updated_date(content)
update_controller_registration(content)

File.write(index_path, content)
end

def update_last_updated_date(content)
content.sub!(/Last updated: .*/, "Last updated: #{Time.now.strftime("%Y-%m-%d %H:%M:%S")}")
end

def update_controller_registration(content)
all_js_controllers = Dir.glob(File.join(destination_path, "**", "*_controller.js"))

# Collect all valid controller information
valid_controllers = all_js_controllers.map do |controller_file|
relative_path = Pathname.new(controller_file).relative_path_from(Pathname.new(destination_path))
file_name = relative_path.basename(".js").to_s
component_name = file_name.sub(/_controller$/, "")
new_controller = "#{component_name.camelize}Controller"
new_path = "./#{relative_path.dirname}/#{file_name}"
registration_name = "rbui--#{component_name.dasherize}"

{
import: "import #{new_controller} from \"#{new_path}\";",
registration: "RBUI.unload(\"#{registration_name}\");\napplication.register(\"#{registration_name}\", #{new_controller});",
export: "export { default as #{new_controller} } from \"#{new_path}\";"
}
end

# Update imports
imports = valid_controllers.map { |c| c[:import] }.sort
import_block = imports.join("\n")
content.sub!(/\/\/ Import all controller files.*?(?=\n\n)/m, "// Import all controller files\n#{import_block}")

# Update registrations
registrations = valid_controllers.map { |c| c[:registration] }.sort
registration_block = registrations.join("\n")
content.sub!(/\/\/ Register all controllers.*?(?=\n\n)/m, "// Register all controllers\n#{registration_block}")

# Update exports
exports = valid_controllers.map { |c| c[:export] }.sort
export_block = exports.join("\n")
content.sub!(/\/\/ Export all controllers.*?(?=\n\n)/m, "// Export all controllers so user of npm package can lazy load controllers\n#{export_block}")

content
end

def component
@component ||= component_name.downcase
end

def source_path
@source_path ||= "lib/rbui"
end

def destination_path
@destination_path ||= "app/components/rbui"
end

def component_source
@component_source ||= File.join(self.class.source_root, source_path, component)
end

def template_dir
@template_dir ||= File.join(__dir__, "templates")
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = {
darkMode: ["class"],
content: [
'./app/views/**/*.{erb,haml,html,slim,rb}',
'./app/components/rbui/**/*.rb',
'./app/helpers/**/*.rb',
'./app/assets/stylesheets/**/*.css',
'./app/javascript/**/*.js',
Expand Down
29 changes: 29 additions & 0 deletions lib/generators/rbui/templates/index.js.tt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* IMPORTANT: DO NOT EDIT THIS FILE MANUALLY
* --------------------------------------------
* This file is automatically generated and managed.
*
* Last updated: [DATE]
*/

// Load and export all of the stimulus controllers
import { Application } from "@hotwired/stimulus";

const application = Application.start();

// Configure Stimulus development experience
application.debug = false;
window.Stimulus = application;

import { application as RBUI } from "rbui-js";

// Import all controller files

// Register all controllers

// Export all controllers so user of npm package can lazy load controllers

// Export application
export { application };


1 change: 1 addition & 0 deletions lib/rbui.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,5 @@ def self.create_namespace_module
# If you need to require generators (assuming they're needed)
if defined?(Rails::Generators)
require_relative "generators/rbui/install/install_generator"
require_relative "generators/rbui/component_generator"
end
File renamed without changes.
35 changes: 35 additions & 0 deletions lib/rbui/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,41 @@ class Railtie < ::Rails::Railtie
Rails::Generators.namespace(RBUI::Generators, as: "rbui")
end
end

# Add component loading
config.to_prepare do
# Define the path to the RBUI components
rbui_components_path = Rails.root.join("app/components/rbui")

# Check if the RBUI components directory exists
if Dir.exist?(rbui_components_path)
# Find all Ruby files in the RBUI components directory and its subdirectories
Dir[rbui_components_path.join("**", "*.rb")].each do |file|
# Get the relative path of the file from the RBUI components directory
relative_path = Pathname.new(file).relative_path_from(rbui_components_path)

# Convert the file path to a component name
# e.g., "form/input.rb" becomes ["Form", "Input"]
component_name_parts = relative_path.to_s.chomp(".rb").split("/").map(&:camelize)

# Create the full component name with RBUI namespace
# e.g., "RBUI::Form::Input"
full_component_name = "RBUI::#{component_name_parts.join("::")}"

begin
# Check if the component is already defined
if defined?(full_component_name.constantize)
# If it's defined, load (or reload) the file
load file
end
rescue NameError
# If the constant isn't defined (i.e., the component doesn't exist),
# we'll skip this file and move to the next one
next
end
end
end
end
end
end
end
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"name": "rbui-js",
"version": "0.0.1-alpha.0",
"main": "lib/rbui/index.js",
"description": "Stimulus controllers for RbUI Component Library",
"main": "index.js",
"homepage": "https://rbui.dev",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand Down Expand Up @@ -35,4 +35,5 @@
"devDependencies": {
"globals": "^15.8.0"
}
}
}

0 comments on commit 52898b1

Please sign in to comment.