Class: LcpRuby::Generators::InstallGenerator
- Inherits:
-
Rails::Generators::Base
- Object
- Rails::Generators::Base
- LcpRuby::Generators::InstallGenerator
- Includes:
- FormatSupport
- Defined in:
- lib/generators/lcp_ruby/install_generator.rb
Constant Summary
Constants included from FormatSupport
Instance Method Summary collapse
- #add_autoloader_ignore ⇒ Object
- #add_current_user_helper ⇒ Object
- #add_lcp_ruby_require ⇒ Object
-
#create_default_menu ⇒ Object
Ships a ‘config/lcp_ruby/menu.yml` with the auto-populated `top_menu:` slot plus a fully-commented user-menu block.
- #create_default_permissions ⇒ Object
- #create_directory_structure ⇒ Object
- #create_initializer ⇒ Object
- #create_sample_model ⇒ Object
- #create_sample_permissions ⇒ Object
- #create_sample_presenter ⇒ Object
- #create_sample_view_group ⇒ Object
-
#install_active_storage ⇒ Object
Active Storage backs the ‘attachment` field type and `rich_text` content, both of which are core to LCP.
- #mount_engine ⇒ Object
-
#setup_agent_affordances ⇒ Object
Agent affordances: copies the lcp-* skills and writes CLAUDE.md/AGENTS.md so AI agents (Claude Code, Codex, …) have orientation + authoring skills.
- #show_post_install_message ⇒ Object
Methods included from FormatSupport
Instance Method Details
#add_autoloader_ignore ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 41 def add_autoloader_ignore app_file = "config/application.rb" full_path = File.join(destination_root, app_file) return unless File.exist?(full_path) content = File.read(full_path) return if content.include?("ignore_lcp_services") inject_into_file app_file, before: /^ end\nend\s*\z/ do <<~RUBY.indent(4) initializer "\#{Rails.application.class.module_parent_name.underscore}.ignore_lcp_services", before: :set_autoload_paths do %w[condition_services lcp_services actions event_handlers renderers].each do |dir| path = Rails.root.join("app", dir) Rails.autoloaders.main.ignore(path) if path.directory? end end RUBY end end |
#add_current_user_helper ⇒ Object
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 213 def add_current_user_helper controller_path = "app/controllers/application_controller.rb" full_path = File.join(destination_root, controller_path) return unless File.exist?(full_path) return if File.read(full_path).include?("current_user") inject_into_class controller_path, "ApplicationController" do <<~RUBY.indent(2) # TODO: Replace with real authentication # Run: rails generate lcp_ruby:install_auth def current_user @current_user ||= OpenStruct.new(id: 1, lcp_role: ["admin"], name: "Admin User") end helper_method :current_user RUBY end end |
#add_lcp_ruby_require ⇒ Object
30 31 32 33 34 35 36 37 38 39 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 30 def add_lcp_ruby_require app_file = "config/application.rb" full_path = File.join(destination_root, app_file) return unless File.exist?(full_path) return if File.read(full_path).include?('require "lcp_ruby"') inject_into_file app_file, after: /Bundler\.require\(\*Rails\.groups\)\n/ do "require \"lcp_ruby\"\n" end end |
#create_default_menu ⇒ Object
Ships a ‘config/lcp_ruby/menu.yml` with the auto-populated `top_menu:` slot plus a fully-commented user-menu block. The block is opt-in: configurators uncomment after running `rails generate lcp_ruby:install_auth` (which wires Devise and the engine routes the block references). Without auth, the comments document the shape so the configurator discovers the capability when they need it.
113 114 115 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 113 def template "menu.yml.tt", "config/lcp_ruby/menu.yml" end |
#create_default_permissions ⇒ Object
102 103 104 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 102 def template "default_permissions.yml", "config/lcp_ruby/permissions/_default.yml" end |
#create_directory_structure ⇒ Object
66 67 68 69 70 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 66 def create_directory_structure %w[models presenters permissions views].each do |dir| empty_directory "config/lcp_ruby/#{dir}" end end |
#create_initializer ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 117 def create_initializer initializer_path = "config/initializers/lcp_ruby.rb" full_path = File.join(destination_root, initializer_path) return if File.exist?(full_path) # Parser literal MUST stay byte-identical to app_template.rb # (drift test: locale_parser_drift_spec.rb). Can't share via require — # app_template.rb runs before Bundler loads the gem's lib/. # `.present?` (not `if options[:locale]`) — Thor passes empty --locale= # through as truthy "", which would otherwise yield broken locales: []. i18n_check_locales = if [:locale].present? [:locale].split(",").map(&:strip).reject(&:empty?).uniq.map(&:to_sym) else [ :en ] end create_file initializer_path, <<~RUBY # frozen_string_literal: true LcpRuby.configure do |config| # Authentication mode: :none, :built_in, or :external # :none — no auth required; ApplicationController exposes a # stub current_user with role "admin" (see the # ApplicationController file). Suitable for prototypes. # :built_in — set automatically by `rails generate lcp_ruby:install_auth` # (Devise-based; flips this line and removes the stub). # :external — host app provides current_user (Devise, Sorcery, custom). config.authentication = :none # User class name (default: "User") # config.user_class = "User" # Role method on user object (default: :lcp_role) # config.role_method = :lcp_role # Where users land after hitting "/" (defaults to first menu item alphabetically). # String form: config.landing_page = "dashboard" # Per-role: config.landing_page = { "admin" => "admin-home", "default" => "dashboard" } # See docs/reference/engine-configuration.md#landing_page # config.landing_page = nil # Type-driven renderer defaults: when true, presenter columns # whose `renderer:` is absent get the type-driven default at # runtime (e.g. :boolean → boolean_icon, :enum → badge, # :text → truncate). Decision 14 in # docs/design/type_system_defaults.md. New apps default this to # true; existing apps upgrading should flip after auditing # their hand-written index columns. config.runtime_type_renderers = true # i18n_check (rake lcp_ruby:i18n_check) — boot-time lint that # asserts every labeled metadata element has a translation # in every locale below. See docs/reference/i18n_check.md. # # Locales: list ONLY the locales this app actually ships. # Without this, the lint walks I18n.available_locales which on # rails-i18n hosts is ~30 entries and produces unreadable # `missing in: en,ar,de,...` reports. # # Three offense kinds, each with its own severity: # * literal_in_dsl — hardcoded label paired with an # i18n key that's missing in some # locale. Real broken-UX bug → :error. # * direct_render_label — hardcoded label on a surface the # runtime renders directly without # an i18n lookup (column / filter / # view-group view labels, …). No # quick fix today → :warning. # * missing_translation — humanize-default fallback would # render in some locale → :warning # so the initial cleanup ramp # doesn't freeze every PR. config.i18n_check = { locales: #{i18n_check_locales.inspect}, severity_per_kind: { literal_in_dsl: :error, direct_render_label: :warning, missing_translation: :warning } } end # Auto-discover custom actions, event handlers, and condition services # from app/actions/, app/event_handlers/, and app/condition_services/. # `on_models_loaded` re-fires on every `LcpRuby.reload!` (autoreload # in dev), so the registries stay populated after metadata reloads; # `Rails.application.config.after_initialize` would only run once # per process boot. LcpRuby.on_models_loaded do app_path = Rails.root.join("app") LcpRuby::Actions::ActionRegistry.discover!(app_path.to_s) LcpRuby::Events::HandlerRegistry.discover!(app_path.to_s) end RUBY end |
#create_sample_model ⇒ Object
72 73 74 75 76 77 78 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 72 def create_sample_model return if [:skip_sample] copy_dsl_or_yaml "model.rb", dsl_target: "config/lcp_ruby/models/item.rb", yaml_target: "config/lcp_ruby/models/item.yml" end |
#create_sample_permissions ⇒ Object
88 89 90 91 92 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 88 def return if [:skip_sample] template "permissions.yml", "config/lcp_ruby/permissions/item.yml" end |
#create_sample_presenter ⇒ Object
80 81 82 83 84 85 86 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 80 def create_sample_presenter return if [:skip_sample] copy_dsl_or_yaml "presenter.rb", dsl_target: "config/lcp_ruby/presenters/items.rb", yaml_target: "config/lcp_ruby/presenters/items.yml" end |
#create_sample_view_group ⇒ Object
94 95 96 97 98 99 100 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 94 def create_sample_view_group return if [:skip_sample] copy_dsl_or_yaml "view_group.rb", dsl_target: "config/lcp_ruby/views/items.rb", yaml_target: "config/lcp_ruby/views/items.yml" end |
#install_active_storage ⇒ Object
Active Storage backs the ‘attachment` field type and `rich_text` content, both of which are core to LCP. Auto-invoke is idempotent: if Active Storage migrations already exist, the call is skipped.
Opt out with ‘–no-active-storage` if the host application uses external storage (e.g. a custom gem) or doesn’t need attachments at all.
238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 238 def install_active_storage return unless [:active_storage] if active_storage_already_installed? say_status :skip, "active_storage:install (migrations already present)" return end say_status :run, "active_storage:install" invoke_active_storage_install! end |
#mount_engine ⇒ Object
62 63 64 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 62 def mount_engine route 'mount LcpRuby::Engine => "/"' end |
#setup_agent_affordances ⇒ Object
Agent affordances: copies the lcp-* skills and writes CLAUDE.md/AGENTS.md so AI agents (Claude Code, Codex, …) have orientation + authoring skills. Passive — no runtime impact. Idempotent via the managed-block strategy. Invoked in-process (not a ‘generate` subprocess) so it shares this run’s destination_root and stays robust in tests/host apps alike. Explicit empty args avoid bleeding install’s options into the sibling generator.
271 272 273 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 271 def setup_agent_affordances invoke "lcp_ruby:agent_setup", [], {} end |
#show_post_install_message ⇒ Object
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/generators/lcp_ruby/install_generator.rb', line 275 def say "" say "LCP Ruby installed!", :green say "" unless [:skip_sample] say "Sample files:" say " config/lcp_ruby/models/item.#{format_extension}" say " config/lcp_ruby/presenters/items.#{format_extension}" say " config/lcp_ruby/permissions/item.yml" say " config/lcp_ruby/views/items.#{format_extension}" say "" end say "Tip: a commented user-menu block has been added to " \ "config/lcp_ruby/menu.yml. Run `rails generate lcp_ruby:install_auth` " \ "to auto-activate it (with Devise sign-out wired in), or " \ "uncomment manually after wiring up your auth routes." say "" say "Next steps:" say " 1. rails db:prepare" say " 2. rails s" say " 3. Visit http://localhost:3000/items" say "" say "Add features with generators:" say " rails generate lcp_ruby:install_auth # Devise authentication" say " rails generate lcp_ruby:auditing # Audit trail" say " rails generate lcp_ruby:export # Data export" say " rails generate lcp_ruby:import # Data import" say " rails generate lcp_ruby:custom_fields # Runtime field definitions" say " rails generate lcp_ruby:saved_filters # Saved search filters" say " rails generate lcp_ruby:monitoring # Error dashboard" say " rails generate lcp_ruby:batch_operations # Bulk operations" say " rails generate lcp_ruby:background_jobs # Job tracking" say " rails generate lcp_ruby:pages # DB-backed pages" say " rails generate lcp_ruby:groups # User groups" say " rails generate lcp_ruby:role_model # DB-backed roles" say " rails generate lcp_ruby:permission_source # Dynamic permissions" say " rails generate lcp_ruby:workflow_definition # Workflows" say " rails generate lcp_ruby:workflow_approvals # Approval processes" say " rails generate lcp_ruby:workflow_audit_log # Workflow audit" say " rails generate lcp_ruby:gapfree_sequences # Sequential numbering" say "" end |