Class: Seams::Generators::EngineGenerator

Inherits:
Rails::Generators::NamedBase
  • Object
show all
Includes:
HostInjector
Defined in:
lib/generators/seams/engine/engine_generator.rb

Overview

Generates a new Rails engine under engines/<name>/, fully isolated via ‘isolate_namespace`, with the Seams boundary cops pre-wired in the engine’s own .rubocop.yml. After generating the new engine, the cop config of every existing sibling engine is updated so boundary enforcement covers the new engine without manual edits.

Run with: bin/rails generate seams:engine billing

Constant Summary collapse

NAME_PATTERN =
/\A[a-z][a-z0-9_]*\z/

Instance Method Summary collapse

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_appObject



53
54
55
56
57
58
59
# File 'lib/generators/seams/engine/engine_generator.rb', line 53

def create_app
  template "app/application_controller.rb.tt",
           "engines/#{name}/app/controllers/#{name}/application_controller.rb"
  # Phase 1.6 — engine-scoped abstract AR base.
  template "app/application_record.rb.tt",
           "engines/#{name}/app/models/#{name}/application_record.rb"
end

#create_configObject



49
50
51
# File 'lib/generators/seams/engine/engine_generator.rb', line 49

def create_config
  template "config/routes.rb.tt", "engines/#{name}/config/routes.rb"
end

#create_dummy_appObject

Phase 1.6 — per-engine dummy app via the shared DummyAppWriter. Generic engines start with an empty schema; canonical generators (auth/billing/etc) overwrite this with their own schema by calling DummyAppWriter.write! again with the right SCHEMA body. Runs AFTER create_spec_helper so DummyAppWriter’s File.write silently overwrites the lightweight Thor template rather than tripping a Thor “conflict” prompt.



100
101
102
103
104
105
106
107
# File 'lib/generators/seams/engine/engine_generator.rb', line 100

def create_dummy_app
  Seams::Generators::DummyAppWriter.write!(
    engine_path: File.join(destination_root, "engines", name),
    engine_module: module_name,
    mount_at: "/#{name}",
    schema: "# generic engine — no schema yet"
  )
end

#create_engine_gemfileObject



68
69
70
# File 'lib/generators/seams/engine/engine_generator.rb', line 68

def create_engine_gemfile
  template "Gemfile.tt", "engines/#{name}/Gemfile"
end

#create_engine_rakefileObject



72
73
74
# File 'lib/generators/seams/engine/engine_generator.rb', line 72

def create_engine_rakefile
  template "Rakefile.tt", "engines/#{name}/Rakefile"
end

#create_gemspecObject



39
40
41
# File 'lib/generators/seams/engine/engine_generator.rb', line 39

def create_gemspec
  template "gemspec.tt", "engines/#{name}/#{name}.gemspec"
end

#create_libObject



43
44
45
46
47
# File 'lib/generators/seams/engine/engine_generator.rb', line 43

def create_lib
  template "lib/engine.rb.tt",  "engines/#{name}/lib/#{name}/engine.rb"
  template "lib/version.rb.tt", "engines/#{name}/lib/#{name}/version.rb"
  template "lib/root.rb.tt",    "engines/#{name}/lib/#{name}.rb"
end

#create_licenseObject



85
86
87
# File 'lib/generators/seams/engine/engine_generator.rb', line 85

def create_license
  template "LICENSE.tt", "engines/#{name}/LICENSE"
end

#create_localesObject

Phase 1.6 — i18n stub + standalone Gemfile + Rakefile so the engine can be tested in isolation (cd engines/<name> && rake).



63
64
65
66
# File 'lib/generators/seams/engine/engine_generator.rb', line 63

def create_locales
  template "config/locales/en.yml.tt",
           "engines/#{name}/config/locales/en.yml"
end

#create_readmeObject



89
90
91
# File 'lib/generators/seams/engine/engine_generator.rb', line 89

def create_readme
  template "README.md.tt", "engines/#{name}/README.md"
end

#create_rubocop_configObject



76
77
78
# File 'lib/generators/seams/engine/engine_generator.rb', line 76

def create_rubocop_config
  template "rubocop.yml.tt", "engines/#{name}/.rubocop.yml"
end

#create_spec_helperObject



80
81
82
83
# File 'lib/generators/seams/engine/engine_generator.rb', line 80

def create_spec_helper
  template "spec/spec_helper.rb.tt",   "engines/#{name}/spec/spec_helper.rb"
  template "spec/example_spec.rb.tt",  "engines/#{name}/spec/#{name}_spec.rb"
end

#reportObject



138
139
140
141
142
143
# File 'lib/generators/seams/engine/engine_generator.rb', line 138

def report
  say ""
  say "  Engine `#{name}` generated at engines/#{name}/", :green
  say "  Run its specs with: bin/rails seams:test[#{name}]"
  say ""
end

#update_sibling_enginesObject



126
127
128
129
130
131
132
133
134
135
136
# File 'lib/generators/seams/engine/engine_generator.rb', line 126

def update_sibling_engines
  sibling_dirs = sibling_engine_dirs
  return if sibling_dirs.empty?

  Seams::Generators::SiblingRubocopWriter.rewrite!(
    engines_root: engines_root,
    dirs: (sibling_dirs + [name]).sort
  )

  say "  update  .rubocop.yml of #{sibling_dirs.size} sibling engine(s)", :green
end

#validate_nameObject



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/generators/seams/engine/engine_generator.rb', line 26

def validate_name
  unless NAME_PATTERN.match?(name)
    raise Seams::GeneratorError,
          "Engine name #{name.inspect} must be lowercase letters, digits, " \
          "and underscores, starting with a letter."
  end

  engine_root = File.join(destination_root, "engines", name)
  return unless File.exist?(engine_root)

  raise Seams::GeneratorError, "Engine #{name.inspect} already exists at #{engine_root}"
end

#wire_into_hostObject



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

def wire_into_host
  # Mount the engine into the host's routes (idempotent — skips
  # if the line already exists, so canonical generators that
  # call this and ALSO mount themselves are safe).
  host_inject_mount(engine_class: "#{module_name}::Engine", at: "/#{name}")

  # Drop a host-side initializer stub the user can fill in.
  # Skipped if a canonical generator (or the host) has already
  # created one.
  initializer_path = File.join(destination_root, "config/initializers/#{name}.rb")
  if File.exist?(initializer_path)
    say "  exist   config/initializers/#{name}.rb (kept)", :blue
  elsif File.directory?(File.join(destination_root, "config/initializers"))
    template "host_initializer.rb.tt", "config/initializers/#{name}.rb"
  end
end