Class: Seams::Generators::CoreGenerator

Inherits:
Rails::Generators::Base
  • Object
show all
Includes:
EjectAware, HostInjector
Defined in:
lib/generators/seams/core/core_generator.rb

Overview

Generates a canonical Core engine on top of the generic engine scaffold. Ships the seven primitive concerns + AuditLog model other engines lean on:

- Core::Auditable          — records create/update/destroy in audit_logs
- Core::SoftDeletable      — deleted_at column + default_scope
- Core::Sluggable          — auto-generated URL slug from a configurable field
- Core::TenantScoped       — scopes records to Current.team
- Core::HasCurrentAttributes — Current.user / Current.team
- Core::EventPublisher     — convenience wrapper around Seams::Events::Publisher
- Core::EmailFormatValidator — custom validator

Run with: bin/rails generate seams:core

Constant Summary collapse

ENGINE_NAME =
"core"

Constants included from EjectAware

EjectAware::EJECT_HEADER_PREFIX

Instance Method Summary collapse

Methods included from EjectAware

#ejected?, #template_unless_ejected

Methods included from HostInjector

#host_inject_gem, #host_inject_include_in_application_controller, #host_inject_include_in_user, #host_inject_mount, #host_uninject_gem, #host_uninject_include, #host_uninject_mount, #routes_draw_anchor

Instance Method Details

#create_base_engineObject



34
35
36
# File 'lib/generators/seams/core/core_generator.rb', line 34

def create_base_engine
  EngineGenerator.start([ENGINE_NAME], destination_root: destination_root)
end

#create_concernsObject



51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/generators/seams/core/core_generator.rb', line 51

def create_concerns
  template_unless_ejected "app/models/concerns/auditable.rb.tt",
                          engine_path("app/models/concerns/core/auditable.rb")
  template_unless_ejected "app/models/concerns/soft_deletable.rb.tt",
                          engine_path("app/models/concerns/core/soft_deletable.rb")
  template_unless_ejected "app/models/concerns/sluggable.rb.tt",
                          engine_path("app/models/concerns/core/sluggable.rb")
  template_unless_ejected "app/models/concerns/tenant_scoped.rb.tt",
                          engine_path("app/models/concerns/core/tenant_scoped.rb")
  template_unless_ejected "app/controllers/concerns/has_current_attributes.rb.tt",
                          engine_path("app/controllers/concerns/core/has_current_attributes.rb")
end

#create_currentObject



71
72
73
74
# File 'lib/generators/seams/core/core_generator.rb', line 71

def create_current
  template_unless_ejected "app/models/current.rb.tt",
                          engine_path("app/models/core/current.rb")
end

#create_dummy_appObject



111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/generators/seams/core/core_generator.rb', line 111

def create_dummy_app
  # Post Wave 9: the dummy app does NOT ship a host User model.
  # The auditable spec stubs its own `Article` (via stub_const)
  # and the tenant_scoped/sluggable specs work against the
  # `articles`/`teams` tables in dummy_schema. There is no
  # remaining caller for a top-level User class.
  Seams::Generators::DummyAppWriter.write!(
    engine_path: File.join(destination_root, "engines", ENGINE_NAME),
    engine_module: "Core",
    schema: dummy_schema
  )
  template "spec/runtime/boot_spec.rb.tt",
           engine_path("spec/runtime/core_boot_spec.rb")
end

#create_migrationObject



76
77
78
79
# File 'lib/generators/seams/core/core_generator.rb', line 76

def create_migration
  template "db/migrate/create_core_audit_logs.rb.tt",
           engine_path("db/migrate/#{timestamp}_create_core_audit_logs.rb")
end

#create_modelsObject



44
45
46
47
48
49
# File 'lib/generators/seams/core/core_generator.rb', line 44

def create_models
  template_unless_ejected "app/models/application_record.rb.tt",
                          engine_path("app/models/core/application_record.rb")
  template_unless_ejected "app/models/audit_log.rb.tt",
                          engine_path("app/models/core/audit_log.rb")
end

#create_services_and_validatorsObject



64
65
66
67
68
69
# File 'lib/generators/seams/core/core_generator.rb', line 64

def create_services_and_validators
  template_unless_ejected "app/services/event_publisher.rb.tt",
                          engine_path("app/services/core/event_publisher.rb")
  template_unless_ejected "app/validators/email_format_validator.rb.tt",
                          engine_path("app/validators/core/email_format_validator.rb")
end

#create_specsObject



81
82
83
84
85
86
87
88
89
90
# File 'lib/generators/seams/core/core_generator.rb', line 81

def create_specs
  template_unless_ejected "spec/models/audit_log_spec.rb.tt",
                          engine_path("spec/models/core/audit_log_spec.rb")
  template_unless_ejected "spec/concerns/auditable_spec.rb.tt",
                          engine_path("spec/concerns/core/auditable_spec.rb")
  template_unless_ejected "spec/concerns/sluggable_spec.rb.tt",
                          engine_path("spec/concerns/core/sluggable_spec.rb")
  template_unless_ejected "spec/validators/email_format_validator_spec.rb.tt",
                          engine_path("spec/validators/core/email_format_validator_spec.rb")
end

#overwrite_engine_entry_pointObject



38
39
40
41
42
# File 'lib/generators/seams/core/core_generator.rb', line 38

def overwrite_engine_entry_point
  # engine.rb / lib/core.rb stay framework-managed.
  template "lib/engine.rb.tt", engine_path("lib/core/engine.rb"), force: true
  template "lib/core.rb.tt",   engine_path("lib/core.rb"),        force: true
end

#overwrite_readmeObject



92
93
94
# File 'lib/generators/seams/core/core_generator.rb', line 92

def overwrite_readme
  template "README.md.tt", engine_path("README.md"), force: true
end

#report_summaryObject



130
131
132
133
134
135
136
137
138
139
140
# File 'lib/generators/seams/core/core_generator.rb', line 130

def report_summary
  say ""
  say "  Core engine generated at engines/core/", :green
  say ""
  say "  Next steps:", :yellow
  say "    1. bin/rails db:migrate"
  say "    2. Mix concerns into your models as needed:"
  say "         include Core::Auditable, Core::SoftDeletable, Core::Sluggable, etc."
  say "    3. Run the engine specs: bin/rails seams:test[core]"
  say ""
end

#update_exposed_concernsObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/generators/seams/core/core_generator.rb', line 96

def update_exposed_concerns
  rubocop_path = engine_path(".rubocop.yml")
  return unless File.exist?(rubocop_path)

  contents = File.read(rubocop_path)
  replacement = "  ExposedConcerns:\n    " \
                "- Core::Auditable\n    " \
                "- Core::SoftDeletable\n    " \
                "- Core::Sluggable\n    " \
                "- Core::TenantScoped\n    " \
                "- Core::HasCurrentAttributes"
  contents.sub!(/^  ExposedConcerns: \[\]$/, replacement)
  File.write(rubocop_path, contents)
end

#wire_into_hostObject



126
127
128
# File 'lib/generators/seams/core/core_generator.rb', line 126

def wire_into_host
  host_inject_mount(engine_class: "Core::Engine", at: "/")
end