#!/usr/bin/env ruby # frozen_string_literal: true require 'thor' require 'pathname' require 'fileutils' require_relative '../<%= gem_entry_folder_path %>' class ::GenerateCommand < ::Thor include ::Thor::Actions # @return [Module] LIBRARY_MODULE = <%= root_module_name %> # @return [String] LIBRARY_NAME = '<%= gem_name %>' # @return [Pathname] ROOT_PATH = ::Pathname.new ::File.expand_path('..', __dir__) # @return [Pathname] GEM_ENTRY_FOLDER_PATH = ::Pathname.new '<%= gem_entry_folder_path %>' class << self # Define the generator's root folder # # @return [String] def source_root ::File.expand_path('..', __dir__) end end desc 'component NAME', 'Generate a new component with the specified NAME' # @param name [String] # @return [void] def component(name) name = snake_case(name) name = "#{name}_component" unless name.end_with? '_component' @name = name template 'templates/component.rb.tt', component_path component_assets_path.mkdir unless component_assets_path.exist? template 'templates/view.html.erb.tt', component_assets_path / 'view.html.erb' template 'templates/style.scss.tt', component_assets_path / 'style.scss' template 'templates/component_test.rb.tt', component_test_file_path append_file main_components_stylesheet_path, %(\n@import "../../../#{component_assets_path}/style.scss";) end private # @return [Pathname] def component_test_file_path components_test_folder_path / "#{@name}_test.rb" end # @return [Pathname] def main_components_stylesheet_path ROOT_PATH / 'assets' / 'stylesheets' / library_relative_path / 'components.scss' end # @return [Pathname] def components_test_folder_path ROOT_PATH / 'test' / library_relative_path / 'components' end # @return [Pathname] def library_relative_path @library_relative_path ||= ::Pathname.new LIBRARY_NAME.gsub('-', '/') end # @return [Pathname] def component_assets_path @component_assets_path ||= GEM_ENTRY_FOLDER_PATH / 'components' / @name end # @return [Pathname] def component_path @component_path ||= GEM_ENTRY_FOLDER_PATH / 'components' / file_name end # @return [String] def full_class_name "#{LIBRARY_MODULE}::#{class_name}" end # @return [String] def component_css_class "#{LIBRARY_NAME}--#{@name}" end # @return [String] def class_name @class_name ||= camelize(@name) end # @return [String] def file_name @file_name ||= "#{@name}.rb" end # @return [Class] def abstract_component LIBRARY_MODULE::ABSTRACT_COMPONENT end # Converts a string to camel/Pascal Case. # # camelize('some_snake_case') #=> "SomeSnakeCase" # camelize('some/snake_case') #=> "Some::SnakeCase" # # @param string [String] # @param uppercase_first_letter [Boolean] # @return [String] def camelize(string, uppercase_first_letter: true) string = if uppercase_first_letter string.sub(/^[a-z\d]*/, &:capitalize) else string.sub(/^(?:(?=\b|[A-Z_])|\w)/, &:downcase) end string.gsub!(%r{(?:_|(/))([a-z\d]*)}) do "#{::Regexp.last_match(1)}#{::Regexp.last_match(2).capitalize}" end string.gsub('/', '::') end # Converts a string in PascalCase or camelCase to snake_case. # # snake_case('SomePascalCase') => "some_pascal_case" # snake_case('Some::PascalCase') => "some/pascal_case" # # @param string [String] # @return [String] def snake_case(string) string.gsub(/([^A-Z])([A-Z]+)/, '\1_\2') .gsub(%r{::_|/_}, '/') .downcase end end ::GenerateCommand.start