seams 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +335 -0
- data/LICENSE +21 -0
- data/README.md +104 -0
- data/lib/generators/seams/accounts/accounts_generator.rb +272 -0
- data/lib/generators/seams/accounts/templates/README.md.tt +219 -0
- data/lib/generators/seams/accounts/templates/app/models/account.rb.tt +124 -0
- data/lib/generators/seams/accounts/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/accounts/templates/app/models/current.rb.tt +38 -0
- data/lib/generators/seams/accounts/templates/app/models/membership.rb.tt +114 -0
- data/lib/generators/seams/accounts/templates/config/routes.rb.tt +8 -0
- data/lib/generators/seams/accounts/templates/db/migrate/create_accounts.rb.tt +29 -0
- data/lib/generators/seams/accounts/templates/db/migrate/create_accounts_memberships.rb.tt +49 -0
- data/lib/generators/seams/accounts/templates/lib/accounts.rb.tt +21 -0
- data/lib/generators/seams/accounts/templates/lib/concerns/account_scoped.rb.tt +97 -0
- data/lib/generators/seams/accounts/templates/lib/concerns/authorization.rb.tt +105 -0
- data/lib/generators/seams/accounts/templates/lib/configuration.rb.tt +26 -0
- data/lib/generators/seams/accounts/templates/lib/engine.rb.tt +55 -0
- data/lib/generators/seams/accounts/templates/spec/factories/accounts.rb.tt +49 -0
- data/lib/generators/seams/accounts/templates/spec/models/accounts/account_spec.rb.tt +64 -0
- data/lib/generators/seams/accounts/templates/spec/models/accounts/membership_spec.rb.tt +99 -0
- data/lib/generators/seams/accounts/templates/spec/runtime/accounts_boot_spec.rb.tt +181 -0
- data/lib/generators/seams/admin/admin_generator.rb +852 -0
- data/lib/generators/seams/admin/templates/README.md.tt +266 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/accounts_controller.rb.tt +16 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/accounts_memberships_controller.rb.tt +16 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/application_controller.rb.tt +282 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/identities_controller.rb.tt +26 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/invitations_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/invoices_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/lifetime_passes_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/notification_preferences_controller.rb.tt +15 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/notifications_controller.rb.tt +18 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/plans_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/subscriptions_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/teams_controller.rb.tt +14 -0
- data/lib/generators/seams/admin/templates/app/controllers/admin/teams_memberships_controller.rb.tt +16 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/account_dashboard.rb.tt +50 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/accounts_membership_dashboard.rb.tt +58 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/identity_dashboard.rb.tt +48 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/invitation_dashboard.rb.tt +51 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/invoice_dashboard.rb.tt +67 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/lifetime_pass_dashboard.rb.tt +65 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/notification_dashboard.rb.tt +58 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/notification_preference_dashboard.rb.tt +43 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/plan_dashboard.rb.tt +72 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/subscription_dashboard.rb.tt +59 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/team_dashboard.rb.tt +39 -0
- data/lib/generators/seams/admin/templates/app/dashboards/admin/teams_membership_dashboard.rb.tt +43 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/account_policy.rb.tt +10 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/accounts_membership_policy.rb.tt +10 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/application_policy.rb.tt +85 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/identity_policy.rb.tt +18 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/invitation_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/invoice_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/lifetime_pass_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/notification_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/notification_preference_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/plan_policy.rb.tt +11 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/subscription_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/team_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/platform/teams_membership_policy.rb.tt +9 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/account_policy.rb.tt +33 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/accounts_membership_policy.rb.tt +24 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/application_policy.rb.tt +169 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/identity_policy.rb.tt +67 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/invitation_policy.rb.tt +24 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/invoice_policy.rb.tt +21 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/lifetime_pass_policy.rb.tt +21 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/notification_policy.rb.tt +25 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/notification_preference_policy.rb.tt +23 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/plan_policy.rb.tt +47 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/subscription_policy.rb.tt +22 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/team_policy.rb.tt +28 -0
- data/lib/generators/seams/admin/templates/app/policies/admin/tenant/teams_membership_policy.rb.tt +24 -0
- data/lib/generators/seams/admin/templates/config/routes.rb.tt +38 -0
- data/lib/generators/seams/admin/templates/lib/admin.rb.tt +36 -0
- data/lib/generators/seams/admin/templates/lib/concerns/authenticator.rb.tt +66 -0
- data/lib/generators/seams/admin/templates/lib/configuration.rb.tt +90 -0
- data/lib/generators/seams/admin/templates/lib/context.rb.tt +44 -0
- data/lib/generators/seams/admin/templates/lib/engine.rb.tt +68 -0
- data/lib/generators/seams/admin/templates/spec/factories/admin.rb.tt +10 -0
- data/lib/generators/seams/admin/templates/spec/runtime/admin_boot_spec.rb.tt +604 -0
- data/lib/generators/seams/auth/add_oauth_provider/add_oauth_provider_generator.rb +157 -0
- data/lib/generators/seams/auth/add_oauth_provider/templates/adapter.rb.tt +95 -0
- data/lib/generators/seams/auth/add_oauth_provider/templates/adapter_spec.rb.tt +58 -0
- data/lib/generators/seams/auth/auth_generator.rb +311 -0
- data/lib/generators/seams/auth/templates/README.md.tt +289 -0
- data/lib/generators/seams/auth/templates/app/controllers/oauth/callbacks_controller.rb.tt +80 -0
- data/lib/generators/seams/auth/templates/app/controllers/password_resets_controller.rb.tt +44 -0
- data/lib/generators/seams/auth/templates/app/controllers/registrations_controller.rb.tt +34 -0
- data/lib/generators/seams/auth/templates/app/controllers/sessions_controller.rb.tt +49 -0
- data/lib/generators/seams/auth/templates/app/jobs/application_job.rb.tt +7 -0
- data/lib/generators/seams/auth/templates/app/jobs/cleanup_expired_sessions_job.rb.tt +30 -0
- data/lib/generators/seams/auth/templates/app/mailers/passwords_mailer.rb.tt +15 -0
- data/lib/generators/seams/auth/templates/app/models/api_token.rb.tt +62 -0
- data/lib/generators/seams/auth/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/auth/templates/app/models/current.rb.tt +15 -0
- data/lib/generators/seams/auth/templates/app/models/identity.rb.tt +74 -0
- data/lib/generators/seams/auth/templates/app/models/oauth/provider.rb.tt +48 -0
- data/lib/generators/seams/auth/templates/app/models/session.rb.tt +28 -0
- data/lib/generators/seams/auth/templates/app/services/authenticate_identity.rb.tt +31 -0
- data/lib/generators/seams/auth/templates/app/services/generate_api_token.rb.tt +35 -0
- data/lib/generators/seams/auth/templates/app/services/oauth/authenticator.rb.tt +94 -0
- data/lib/generators/seams/auth/templates/app/services/register_identity.rb.tt +57 -0
- data/lib/generators/seams/auth/templates/app/services/reset_password.rb.tt +41 -0
- data/lib/generators/seams/auth/templates/app/services/revoke_api_token.rb.tt +38 -0
- data/lib/generators/seams/auth/templates/app/views/password_resets/edit.html.erb.tt +12 -0
- data/lib/generators/seams/auth/templates/app/views/password_resets/new.html.erb.tt +11 -0
- data/lib/generators/seams/auth/templates/app/views/passwords_mailer/reset_email.html.erb.tt +7 -0
- data/lib/generators/seams/auth/templates/app/views/registrations/new.html.erb.tt +26 -0
- data/lib/generators/seams/auth/templates/app/views/sessions/_oauth_buttons.html.erb.tt +18 -0
- data/lib/generators/seams/auth/templates/app/views/sessions/new.html.erb.tt +17 -0
- data/lib/generators/seams/auth/templates/config/routes.rb.tt +21 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_api_tokens.rb.tt +26 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_identities.rb.tt +29 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_oauth_providers.rb.tt +35 -0
- data/lib/generators/seams/auth/templates/db/migrate/create_auth_sessions.rb.tt +19 -0
- data/lib/generators/seams/auth/templates/lib/auth.rb.tt +39 -0
- data/lib/generators/seams/auth/templates/lib/concerns/api_authenticatable.rb.tt +58 -0
- data/lib/generators/seams/auth/templates/lib/concerns/authenticatable.rb.tt +32 -0
- data/lib/generators/seams/auth/templates/lib/concerns/authentication.rb.tt +60 -0
- data/lib/generators/seams/auth/templates/lib/configuration.rb.tt +45 -0
- data/lib/generators/seams/auth/templates/lib/engine.rb.tt +46 -0
- data/lib/generators/seams/auth/templates/lib/oauth/abstract.rb.tt +87 -0
- data/lib/generators/seams/auth/templates/lib/oauth/github.rb.tt +112 -0
- data/lib/generators/seams/auth/templates/lib/oauth/google.rb.tt +78 -0
- data/lib/generators/seams/auth/templates/lib/tasks/auth_pii.rake.tt +68 -0
- data/lib/generators/seams/auth/templates/spec/factories/auth.rb.tt +38 -0
- data/lib/generators/seams/auth/templates/spec/mailers/passwords_mailer_spec.rb.tt +37 -0
- data/lib/generators/seams/auth/templates/spec/models/api_token_spec.rb.tt +84 -0
- data/lib/generators/seams/auth/templates/spec/models/identity_spec.rb.tt +56 -0
- data/lib/generators/seams/auth/templates/spec/models/oauth/provider_spec.rb.tt +64 -0
- data/lib/generators/seams/auth/templates/spec/models/session_spec.rb.tt +34 -0
- data/lib/generators/seams/auth/templates/spec/runtime/boot_spec.rb.tt +30 -0
- data/lib/generators/seams/auth/templates/spec/runtime/event_payload_spec.rb.tt +29 -0
- data/lib/generators/seams/auth/templates/spec/runtime/login_flow_spec.rb.tt +45 -0
- data/lib/generators/seams/billing/billing_generator.rb +476 -0
- data/lib/generators/seams/billing/templates/README.md.tt +355 -0
- data/lib/generators/seams/billing/templates/app/controllers/admin/lifetime_passes_controller.rb.tt +84 -0
- data/lib/generators/seams/billing/templates/app/controllers/checkout_controller.rb.tt +92 -0
- data/lib/generators/seams/billing/templates/app/controllers/invoices_controller.rb.tt +63 -0
- data/lib/generators/seams/billing/templates/app/controllers/plans_controller.rb.tt +14 -0
- data/lib/generators/seams/billing/templates/app/controllers/portal_controller.rb.tt +45 -0
- data/lib/generators/seams/billing/templates/app/controllers/subscriptions_controller.rb.tt +119 -0
- data/lib/generators/seams/billing/templates/app/controllers/webhooks_controller.rb.tt +98 -0
- data/lib/generators/seams/billing/templates/app/helpers/currency_helper.rb.tt +44 -0
- data/lib/generators/seams/billing/templates/app/jobs/application_job.rb.tt +6 -0
- data/lib/generators/seams/billing/templates/app/jobs/cancel_subscription_job.rb.tt +39 -0
- data/lib/generators/seams/billing/templates/app/jobs/start_subscription_job.rb.tt +32 -0
- data/lib/generators/seams/billing/templates/app/jobs/webhooks/process_event_job.rb.tt +37 -0
- data/lib/generators/seams/billing/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/billing/templates/app/models/invoice.rb.tt +35 -0
- data/lib/generators/seams/billing/templates/app/models/lifetime_pass.rb.tt +60 -0
- data/lib/generators/seams/billing/templates/app/models/plan.rb.tt +95 -0
- data/lib/generators/seams/billing/templates/app/models/subscription.rb.tt +31 -0
- data/lib/generators/seams/billing/templates/app/models/webhook_event.rb.tt +13 -0
- data/lib/generators/seams/billing/templates/app/services/checkout_session_service.rb.tt +25 -0
- data/lib/generators/seams/billing/templates/app/services/customers/find_or_create_service.rb.tt +73 -0
- data/lib/generators/seams/billing/templates/app/services/invoices/sync_service.rb.tt +50 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/create_lifetime_session_service.rb.tt +82 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/create_pass_from_checkout_service.rb.tt +88 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/grant_pass_service.rb.tt +80 -0
- data/lib/generators/seams/billing/templates/app/services/lifetime/revoke_pass_service.rb.tt +59 -0
- data/lib/generators/seams/billing/templates/app/services/portal_session_service.rb.tt +23 -0
- data/lib/generators/seams/billing/templates/app/services/service_result.rb.tt +38 -0
- data/lib/generators/seams/billing/templates/app/services/stripe_service.rb.tt +67 -0
- data/lib/generators/seams/billing/templates/app/services/subscriptions/cancel_service.rb.tt +42 -0
- data/lib/generators/seams/billing/templates/app/services/subscriptions/change_plan_service.rb.tt +48 -0
- data/lib/generators/seams/billing/templates/app/services/subscriptions/reactivate_service.rb.tt +28 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/event_router.rb.tt +54 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handler.rb.tt +93 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/charge_refunded_handler.rb.tt +18 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/checkout_session_completed_handler.rb.tt +58 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_created_handler.rb.tt +16 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_finalized_handler.rb.tt +14 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_handler_base.rb.tt +80 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_paid_handler.rb.tt +12 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_payment_failed_handler.rb.tt +12 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/invoice_voided_handler.rb.tt +12 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/payment_failed_handler.rb.tt +15 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/payment_succeeded_handler.rb.tt +19 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_created_handler.rb.tt +11 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_deleted_handler.rb.tt +15 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_handler_base.rb.tt +92 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_trial_will_end_handler.rb.tt +15 -0
- data/lib/generators/seams/billing/templates/app/services/webhooks/handlers/subscription_updated_handler.rb.tt +11 -0
- data/lib/generators/seams/billing/templates/app/views/admin/lifetime_passes/index.html.erb.tt +36 -0
- data/lib/generators/seams/billing/templates/app/views/admin/lifetime_passes/new.html.erb.tt +37 -0
- data/lib/generators/seams/billing/templates/app/views/checkout/success.html.erb.tt +5 -0
- data/lib/generators/seams/billing/templates/app/views/invoices/index.html.erb.tt +22 -0
- data/lib/generators/seams/billing/templates/app/views/invoices/show.html.erb.tt +14 -0
- data/lib/generators/seams/billing/templates/app/views/plans/index.html.erb.tt +51 -0
- data/lib/generators/seams/billing/templates/app/views/subscriptions/index.html.erb.tt +16 -0
- data/lib/generators/seams/billing/templates/app/views/subscriptions/show.html.erb.tt +25 -0
- data/lib/generators/seams/billing/templates/config/routes.rb.tt +39 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_invoices.rb.tt +32 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_lifetime_passes.rb.tt +43 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_plans.rb.tt +31 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_subscriptions.rb.tt +33 -0
- data/lib/generators/seams/billing/templates/db/migrate/create_billing_webhook_events.rb.tt +24 -0
- data/lib/generators/seams/billing/templates/lib/billing.rb.tt +34 -0
- data/lib/generators/seams/billing/templates/lib/concerns/billable.rb.tt +100 -0
- data/lib/generators/seams/billing/templates/lib/configuration.rb.tt +52 -0
- data/lib/generators/seams/billing/templates/lib/engine.rb.tt +72 -0
- data/lib/generators/seams/billing/templates/lib/gateways/abstract.rb.tt +65 -0
- data/lib/generators/seams/billing/templates/lib/gateways/adyen.rb.tt +16 -0
- data/lib/generators/seams/billing/templates/lib/gateways/paddle.rb.tt +22 -0
- data/lib/generators/seams/billing/templates/lib/gateways/stripe.rb.tt +155 -0
- data/lib/generators/seams/billing/templates/lib/stripe/client.rb.tt +101 -0
- data/lib/generators/seams/billing/templates/lib/stripe/webhook_signature.rb.tt +43 -0
- data/lib/generators/seams/billing/templates/lib/tasks/billing_check.rake.tt +34 -0
- data/lib/generators/seams/billing/templates/spec/factories/billing.rb.tt +65 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/charge_refunded.json.tt +19 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/checkout_session_completed.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_created.json.tt +25 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_deleted.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_trial_will_end.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/customer_subscription_updated.json.tt +28 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_created.json.tt +18 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_finalized.json.tt +18 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_paid.json.tt +19 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_payment_failed.json.tt +20 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/invoice_voided.json.tt +18 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/payment_intent_payment_failed.json.tt +21 -0
- data/lib/generators/seams/billing/templates/spec/fixtures/stripe/payment_intent_succeeded.json.tt +17 -0
- data/lib/generators/seams/billing/templates/spec/gateways/contract_spec.rb.tt +11 -0
- data/lib/generators/seams/billing/templates/spec/gateways/stripe_spec.rb.tt +53 -0
- data/lib/generators/seams/billing/templates/spec/models/plan_spec.rb.tt +81 -0
- data/lib/generators/seams/billing/templates/spec/models/subscription_spec.rb.tt +43 -0
- data/lib/generators/seams/billing/templates/spec/runtime/boot_spec.rb.tt +38 -0
- data/lib/generators/seams/billing/templates/spec/runtime/webhook_handlers_spec.rb.tt +382 -0
- data/lib/generators/seams/billing/templates/spec/support/shared_examples/a_billing_gateway.rb.tt +100 -0
- data/lib/generators/seams/billing/templates/spec/support/stripe_helpers.rb.tt +59 -0
- data/lib/generators/seams/core/core_generator.rb +191 -0
- data/lib/generators/seams/core/templates/README.md.tt +45 -0
- data/lib/generators/seams/core/templates/app/controllers/concerns/has_current_attributes.rb.tt +71 -0
- data/lib/generators/seams/core/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/core/templates/app/models/audit_log.rb.tt +19 -0
- data/lib/generators/seams/core/templates/app/models/concerns/auditable.rb.tt +64 -0
- data/lib/generators/seams/core/templates/app/models/concerns/sluggable.rb.tt +53 -0
- data/lib/generators/seams/core/templates/app/models/concerns/soft_deletable.rb.tt +37 -0
- data/lib/generators/seams/core/templates/app/models/concerns/tenant_scoped.rb.tt +39 -0
- data/lib/generators/seams/core/templates/app/models/current.rb.tt +16 -0
- data/lib/generators/seams/core/templates/app/services/event_publisher.rb.tt +23 -0
- data/lib/generators/seams/core/templates/app/validators/email_format_validator.rb.tt +21 -0
- data/lib/generators/seams/core/templates/db/migrate/create_core_audit_logs.rb.tt +29 -0
- data/lib/generators/seams/core/templates/lib/core.rb.tt +8 -0
- data/lib/generators/seams/core/templates/lib/engine.rb.tt +28 -0
- data/lib/generators/seams/core/templates/spec/concerns/auditable_spec.rb.tt +39 -0
- data/lib/generators/seams/core/templates/spec/concerns/sluggable_spec.rb.tt +29 -0
- data/lib/generators/seams/core/templates/spec/models/audit_log_spec.rb.tt +22 -0
- data/lib/generators/seams/core/templates/spec/runtime/boot_spec.rb.tt +25 -0
- data/lib/generators/seams/core/templates/spec/validators/email_format_validator_spec.rb.tt +29 -0
- data/lib/generators/seams/engine/engine_generator.rb +165 -0
- data/lib/generators/seams/engine/templates/Gemfile.tt +19 -0
- data/lib/generators/seams/engine/templates/LICENSE.tt +21 -0
- data/lib/generators/seams/engine/templates/README.md.tt +40 -0
- data/lib/generators/seams/engine/templates/Rakefile.tt +14 -0
- data/lib/generators/seams/engine/templates/app/application_controller.rb.tt +6 -0
- data/lib/generators/seams/engine/templates/app/application_record.rb.tt +16 -0
- data/lib/generators/seams/engine/templates/config/locales/en.yml.tt +14 -0
- data/lib/generators/seams/engine/templates/config/routes.rb.tt +4 -0
- data/lib/generators/seams/engine/templates/gemspec.tt +20 -0
- data/lib/generators/seams/engine/templates/host_initializer.rb.tt +13 -0
- data/lib/generators/seams/engine/templates/lib/engine.rb.tt +27 -0
- data/lib/generators/seams/engine/templates/lib/root.rb.tt +7 -0
- data/lib/generators/seams/engine/templates/lib/version.rb.tt +5 -0
- data/lib/generators/seams/engine/templates/rubocop.yml.tt +55 -0
- data/lib/generators/seams/engine/templates/spec/example_spec.rb.tt +16 -0
- data/lib/generators/seams/engine/templates/spec/spec_helper.rb.tt +23 -0
- data/lib/generators/seams/install/install_generator.rb +211 -0
- data/lib/generators/seams/install/templates/Dockerfile.tt +52 -0
- data/lib/generators/seams/install/templates/Procfile.tt +14 -0
- data/lib/generators/seams/install/templates/bin_seams.tt +107 -0
- data/lib/generators/seams/install/templates/ci.yml.tt +123 -0
- data/lib/generators/seams/install/templates/deploy.yml.tt +63 -0
- data/lib/generators/seams/install/templates/doc/ARCHITECTURE.md.tt +86 -0
- data/lib/generators/seams/install/templates/docker-entrypoint.tt +27 -0
- data/lib/generators/seams/install/templates/rubocop.yml.tt +33 -0
- data/lib/generators/seams/install/templates/ruby-version.tt +1 -0
- data/lib/generators/seams/install/templates/script/collate_coverage.rb.tt +33 -0
- data/lib/generators/seams/install/templates/script/run_affected_tests.sh.tt +64 -0
- data/lib/generators/seams/install/templates/seams.rake.tt +65 -0
- data/lib/generators/seams/install/templates/seams.rb.tt +9 -0
- data/lib/generators/seams/install/templates/seams_engines.rb.tt +15 -0
- data/lib/generators/seams/notifications/notifications_generator.rb +395 -0
- data/lib/generators/seams/notifications/templates/README.md.tt +269 -0
- data/lib/generators/seams/notifications/templates/app/channels/notification_channel.rb.tt +36 -0
- data/lib/generators/seams/notifications/templates/app/controllers/notifications_controller.rb.tt +58 -0
- data/lib/generators/seams/notifications/templates/app/controllers/preferences_controller.rb.tt +54 -0
- data/lib/generators/seams/notifications/templates/app/javascript/controllers/notification_bell_controller.js.tt +34 -0
- data/lib/generators/seams/notifications/templates/app/jobs/application_job.rb.tt +6 -0
- data/lib/generators/seams/notifications/templates/app/jobs/create_notification_job.rb.tt +31 -0
- data/lib/generators/seams/notifications/templates/app/jobs/send_due_notifications_job.rb.tt +22 -0
- data/lib/generators/seams/notifications/templates/app/jobs/send_notification_job.rb.tt +13 -0
- data/lib/generators/seams/notifications/templates/app/mailers/application_mailer.rb.tt +12 -0
- data/lib/generators/seams/notifications/templates/app/mailers/notification_mailer.rb.tt +23 -0
- data/lib/generators/seams/notifications/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/notifications/templates/app/models/delivery.rb.tt +13 -0
- data/lib/generators/seams/notifications/templates/app/models/notification.rb.tt +218 -0
- data/lib/generators/seams/notifications/templates/app/models/notification_preference.rb.tt +29 -0
- data/lib/generators/seams/notifications/templates/app/models/strategies/email.rb.tt +38 -0
- data/lib/generators/seams/notifications/templates/app/models/strategies/in_app.rb.tt +26 -0
- data/lib/generators/seams/notifications/templates/app/models/strategies/sms.rb.tt +33 -0
- data/lib/generators/seams/notifications/templates/app/subscribers/auth_subscriber.rb.tt +71 -0
- data/lib/generators/seams/notifications/templates/app/subscribers/billing_subscriber.rb.tt +127 -0
- data/lib/generators/seams/notifications/templates/app/views/layouts/notifications/mailer.html.erb.tt +22 -0
- data/lib/generators/seams/notifications/templates/app/views/layouts/notifications/mailer.text.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/notifications/_bell.html.erb.tt +15 -0
- data/lib/generators/seams/notifications/templates/app/views/notifications/index.html.erb.tt +15 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_failed.html.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_failed.text.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_paid.html.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/invoice_paid.text.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_granted.html.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_granted.text.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_purchased.html.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/lifetime_purchased.text.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_canceled.html.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_canceled.text.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_started.html.erb.tt +4 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_started.text.erb.tt +5 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_updated.html.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/billing/subscription_updated.text.erb.tt +3 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/default.html.erb.tt +10 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/default.text.erb.tt +11 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/welcome.html.erb.tt +6 -0
- data/lib/generators/seams/notifications/templates/app/views/templates/welcome.text.erb.tt +6 -0
- data/lib/generators/seams/notifications/templates/config/initializers/notifications.rb.tt +58 -0
- data/lib/generators/seams/notifications/templates/config/routes.rb.tt +17 -0
- data/lib/generators/seams/notifications/templates/db/migrate/create_notification_deliveries.rb.tt +16 -0
- data/lib/generators/seams/notifications/templates/db/migrate/create_notification_preferences.rb.tt +25 -0
- data/lib/generators/seams/notifications/templates/db/migrate/create_notifications.rb.tt +35 -0
- data/lib/generators/seams/notifications/templates/lib/adapters/abstract.rb.tt +20 -0
- data/lib/generators/seams/notifications/templates/lib/adapters/action_mailer.rb.tt +17 -0
- data/lib/generators/seams/notifications/templates/lib/adapters/null_sms.rb.tt +23 -0
- data/lib/generators/seams/notifications/templates/lib/concerns/notifiable.rb.tt +135 -0
- data/lib/generators/seams/notifications/templates/lib/configuration.rb.tt +24 -0
- data/lib/generators/seams/notifications/templates/lib/engine.rb.tt +35 -0
- data/lib/generators/seams/notifications/templates/lib/notifications.rb.tt +75 -0
- data/lib/generators/seams/notifications/templates/lib/type_registry.rb.tt +74 -0
- data/lib/generators/seams/notifications/templates/spec/factories/notifications.rb.tt +53 -0
- data/lib/generators/seams/notifications/templates/spec/models/delivery_spec.rb.tt +28 -0
- data/lib/generators/seams/notifications/templates/spec/models/notification_preference_spec.rb.tt +46 -0
- data/lib/generators/seams/notifications/templates/spec/models/notification_spec.rb.tt +60 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/bell_broadcast_spec.rb.tt +59 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/billing_subscriber_skip_spec.rb.tt +87 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/boot_spec.rb.tt +39 -0
- data/lib/generators/seams/notifications/templates/spec/runtime/schedule_round_trip_spec.rb.tt +55 -0
- data/lib/generators/seams/remove/remove_generator.rb +259 -0
- data/lib/generators/seams/teams/teams_generator.rb +298 -0
- data/lib/generators/seams/teams/templates/README.md.tt +88 -0
- data/lib/generators/seams/teams/templates/app/controllers/invitations_controller.rb.tt +102 -0
- data/lib/generators/seams/teams/templates/app/controllers/memberships_controller.rb.tt +54 -0
- data/lib/generators/seams/teams/templates/app/controllers/teams_controller.rb.tt +68 -0
- data/lib/generators/seams/teams/templates/app/jobs/application_job.rb.tt +6 -0
- data/lib/generators/seams/teams/templates/app/mailers/invitation_mailer.rb.tt +34 -0
- data/lib/generators/seams/teams/templates/app/models/application_record.rb.tt +7 -0
- data/lib/generators/seams/teams/templates/app/models/current.rb.tt +30 -0
- data/lib/generators/seams/teams/templates/app/models/invitation.rb.tt +36 -0
- data/lib/generators/seams/teams/templates/app/models/membership.rb.tt +36 -0
- data/lib/generators/seams/teams/templates/app/models/team.rb.tt +32 -0
- data/lib/generators/seams/teams/templates/app/subscribers/invitation_subscriber.rb.tt +36 -0
- data/lib/generators/seams/teams/templates/app/views/invitation_mailer/invite.text.erb.tt +8 -0
- data/lib/generators/seams/teams/templates/app/views/invitations/index.html.erb.tt +44 -0
- data/lib/generators/seams/teams/templates/app/views/memberships/index.html.erb.tt +32 -0
- data/lib/generators/seams/teams/templates/app/views/teams/edit.html.erb.tt +28 -0
- data/lib/generators/seams/teams/templates/app/views/teams/index.html.erb.tt +15 -0
- data/lib/generators/seams/teams/templates/app/views/teams/new.html.erb.tt +24 -0
- data/lib/generators/seams/teams/templates/app/views/teams/show.html.erb.tt +17 -0
- data/lib/generators/seams/teams/templates/config/routes.rb.tt +19 -0
- data/lib/generators/seams/teams/templates/db/migrate/create_team_invitations.rb.tt +24 -0
- data/lib/generators/seams/teams/templates/db/migrate/create_team_memberships.rb.tt +25 -0
- data/lib/generators/seams/teams/templates/db/migrate/create_teams.rb.tt +18 -0
- data/lib/generators/seams/teams/templates/lib/concerns/account_scoped.rb.tt +79 -0
- data/lib/generators/seams/teams/templates/lib/concerns/authorization.rb.tt +55 -0
- data/lib/generators/seams/teams/templates/lib/configuration.rb.tt +45 -0
- data/lib/generators/seams/teams/templates/lib/engine.rb.tt +51 -0
- data/lib/generators/seams/teams/templates/lib/teams.rb.tt +22 -0
- data/lib/generators/seams/teams/templates/spec/factories/teams.rb.tt +47 -0
- data/lib/generators/seams/teams/templates/spec/models/invitation_spec.rb.tt +25 -0
- data/lib/generators/seams/teams/templates/spec/models/membership_spec.rb.tt +29 -0
- data/lib/generators/seams/teams/templates/spec/models/team_spec.rb.tt +23 -0
- data/lib/generators/seams/teams/templates/spec/runtime/boot_spec.rb.tt +32 -0
- data/lib/seams/cli/list.rb +111 -0
- data/lib/seams/cli/quality.rb +99 -0
- data/lib/seams/cli/resolve.rb +276 -0
- data/lib/seams/cli/test_changed.rb +116 -0
- data/lib/seams/cli.rb +48 -0
- data/lib/seams/configuration.rb +19 -0
- data/lib/seams/cops/known_queue_names.rb +42 -0
- data/lib/seams/cops/migration_comments.rb +68 -0
- data/lib/seams/cops/no_cross_engine_dependency.rb +58 -0
- data/lib/seams/cops/no_cross_engine_model_access.rb +153 -0
- data/lib/seams/cops.rb +18 -0
- data/lib/seams/event_registry.rb +49 -0
- data/lib/seams/events/adapter.rb +24 -0
- data/lib/seams/events/adapters/active_support.rb +31 -0
- data/lib/seams/events/publisher.rb +178 -0
- data/lib/seams/events.rb +39 -0
- data/lib/seams/generators/dummy_app_writer.rb +424 -0
- data/lib/seams/generators/eject_aware.rb +102 -0
- data/lib/seams/generators/follow_up_generator.rb +148 -0
- data/lib/seams/generators/host_injector.rb +124 -0
- data/lib/seams/generators/sibling_rubocop_writer.rb +77 -0
- data/lib/seams/generators/splicer.rb +217 -0
- data/lib/seams/observability/adapter.rb +33 -0
- data/lib/seams/observability/adapters/rails_logger.rb +59 -0
- data/lib/seams/observability.rb +34 -0
- data/lib/seams/runtime.rb +23 -0
- data/lib/seams/version.rb +5 -0
- data/lib/seams.rb +23 -0
- metadata +493 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Core::Auditable do
|
|
6
|
+
# Stub a named ActiveRecord class. The polymorphic `auditable_type`
|
|
7
|
+
# column needs `self.class.name` to be non-nil; `Class.new(...)`
|
|
8
|
+
# returns an anonymous class whose `.name` is nil, which breaks the
|
|
9
|
+
# `dependent: :nullify` cleanup on destroy.
|
|
10
|
+
before do
|
|
11
|
+
stub_const("Article", Class.new(ActiveRecord::Base) {
|
|
12
|
+
self.table_name = "articles"
|
|
13
|
+
include Core::Auditable
|
|
14
|
+
})
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
let(:model_class) { Article }
|
|
18
|
+
|
|
19
|
+
it "creates an audit log on create" do
|
|
20
|
+
expect { model_class.create!(title: "Hi") }
|
|
21
|
+
.to change(Core::AuditLog, :count).by(1)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "records the changed attributes on update" do
|
|
25
|
+
article = model_class.create!(title: "Hi")
|
|
26
|
+
expect { article.update!(title: "Bye") }
|
|
27
|
+
.to change(Core::AuditLog, :count).by(1)
|
|
28
|
+
|
|
29
|
+
last = Core::AuditLog.recent.first
|
|
30
|
+
expect(last.action).to eq("update")
|
|
31
|
+
expect(last.payload).to include("title" => "Bye")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "creates an audit log on destroy" do
|
|
35
|
+
article = model_class.create!(title: "Hi")
|
|
36
|
+
expect { article.destroy }
|
|
37
|
+
.to change(Core::AuditLog, :count).by(1)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Core::Sluggable do
|
|
6
|
+
let(:model_class) do
|
|
7
|
+
Class.new(ActiveRecord::Base) do
|
|
8
|
+
self.table_name = "teams"
|
|
9
|
+
include Core::Sluggable
|
|
10
|
+
sluggable_from :name
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "auto-assigns a slug from the source attribute" do
|
|
15
|
+
record = model_class.create!(name: "Acme Corp!")
|
|
16
|
+
expect(record.slug).to eq("acme-corp")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "appends a numeric suffix on collision" do
|
|
20
|
+
model_class.create!(name: "Acme")
|
|
21
|
+
second = model_class.create!(name: "Acme")
|
|
22
|
+
expect(second.slug).to eq("acme-2")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "respects an explicitly-set slug" do
|
|
26
|
+
record = model_class.create!(name: "Whatever", slug: "my-custom")
|
|
27
|
+
expect(record.slug).to eq("my-custom")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Core::AuditLog do
|
|
6
|
+
it "rejects unknown actions" do
|
|
7
|
+
log = described_class.new(action: "made_up", auditable_type: "Article", auditable_id: 1)
|
|
8
|
+
expect(log).not_to be_valid
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe ".for" do
|
|
12
|
+
it "filters audit logs to a specific record" do
|
|
13
|
+
article = double(class: double(name: "Article"), id: "7")
|
|
14
|
+
described_class.create!(action: "create", auditable_type: "Article", auditable_id: "7")
|
|
15
|
+
described_class.create!(action: "create", auditable_type: "Article", auditable_id: "8")
|
|
16
|
+
|
|
17
|
+
# auditable_id is string-typed (polymorphic over both bigint-PK
|
|
18
|
+
# and UUID-PK auditables — see the migration's comment).
|
|
19
|
+
expect(described_class.for(article).pluck(:auditable_id)).to eq(["7"])
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "Core engine boot", type: :integration do
|
|
6
|
+
it "loads the engine" do
|
|
7
|
+
expect(defined?(Core::Engine)).to eq("constant")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "registers record.audited.core in Seams::EventRegistry on boot" do
|
|
11
|
+
expect(Seams::EventRegistry.registered?("record.audited.core")).to be(true)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "exposes the canonical concerns as constants" do
|
|
15
|
+
expect(defined?(Core::Auditable)).to eq("constant")
|
|
16
|
+
expect(defined?(Core::SoftDeletable)).to eq("constant")
|
|
17
|
+
expect(defined?(Core::Sluggable)).to eq("constant")
|
|
18
|
+
expect(defined?(Core::TenantScoped)).to eq("constant")
|
|
19
|
+
expect(defined?(Core::HasCurrentAttributes)).to eq("constant")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "creates the core_audit_logs table from the dummy schema" do
|
|
23
|
+
expect(ActiveRecord::Base.connection.table_exists?(:core_audit_logs)).to be(true)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe Core::EmailFormatValidator do
|
|
6
|
+
let(:model_class) do
|
|
7
|
+
Class.new do
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
attr_accessor :email
|
|
10
|
+
validates :email, "core/email_format": true
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "accepts a normal email" do
|
|
15
|
+
expect(model_class.new.tap { |o| o.email = "x@y.com" }).to be_valid
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "rejects an email without @" do
|
|
19
|
+
expect(model_class.new.tap { |o| o.email = "no-at" }).not_to be_valid
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "rejects emails with consecutive dots" do
|
|
23
|
+
expect(model_class.new.tap { |o| o.email = "x..y@z.com" }).not_to be_valid
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "rejects emails without a TLD" do
|
|
27
|
+
expect(model_class.new.tap { |o| o.email = "x@y" }).not_to be_valid
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "rails/generators"
|
|
5
|
+
require "seams"
|
|
6
|
+
require "seams/generators/host_injector"
|
|
7
|
+
require "seams/generators/sibling_rubocop_writer"
|
|
8
|
+
require "seams/generators/dummy_app_writer"
|
|
9
|
+
|
|
10
|
+
module Seams
|
|
11
|
+
module Generators
|
|
12
|
+
# Generates a new Rails engine under engines/<name>/, fully isolated
|
|
13
|
+
# via `isolate_namespace`, with the Seams boundary cops pre-wired in
|
|
14
|
+
# the engine's own .rubocop.yml. After generating the new engine,
|
|
15
|
+
# the cop config of every existing sibling engine is updated so
|
|
16
|
+
# boundary enforcement covers the new engine without manual edits.
|
|
17
|
+
#
|
|
18
|
+
# Run with: bin/rails generate seams:engine billing
|
|
19
|
+
class EngineGenerator < Rails::Generators::NamedBase
|
|
20
|
+
include Seams::Generators::HostInjector
|
|
21
|
+
|
|
22
|
+
source_root File.expand_path("templates", __dir__)
|
|
23
|
+
|
|
24
|
+
NAME_PATTERN = /\A[a-z][a-z0-9_]*\z/
|
|
25
|
+
|
|
26
|
+
def validate_name
|
|
27
|
+
unless NAME_PATTERN.match?(name)
|
|
28
|
+
raise Seams::GeneratorError,
|
|
29
|
+
"Engine name #{name.inspect} must be lowercase letters, digits, " \
|
|
30
|
+
"and underscores, starting with a letter."
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
engine_root = File.join(destination_root, "engines", name)
|
|
34
|
+
return unless File.exist?(engine_root)
|
|
35
|
+
|
|
36
|
+
raise Seams::GeneratorError, "Engine #{name.inspect} already exists at #{engine_root}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_gemspec
|
|
40
|
+
template "gemspec.tt", "engines/#{name}/#{name}.gemspec"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_lib
|
|
44
|
+
template "lib/engine.rb.tt", "engines/#{name}/lib/#{name}/engine.rb"
|
|
45
|
+
template "lib/version.rb.tt", "engines/#{name}/lib/#{name}/version.rb"
|
|
46
|
+
template "lib/root.rb.tt", "engines/#{name}/lib/#{name}.rb"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def create_config
|
|
50
|
+
template "config/routes.rb.tt", "engines/#{name}/config/routes.rb"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def create_app
|
|
54
|
+
template "app/application_controller.rb.tt",
|
|
55
|
+
"engines/#{name}/app/controllers/#{name}/application_controller.rb"
|
|
56
|
+
# Phase 1.6 — engine-scoped abstract AR base.
|
|
57
|
+
template "app/application_record.rb.tt",
|
|
58
|
+
"engines/#{name}/app/models/#{name}/application_record.rb"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Phase 1.6 — i18n stub + standalone Gemfile + Rakefile so the
|
|
62
|
+
# engine can be tested in isolation (cd engines/<name> && rake).
|
|
63
|
+
def create_locales
|
|
64
|
+
template "config/locales/en.yml.tt",
|
|
65
|
+
"engines/#{name}/config/locales/en.yml"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def create_engine_gemfile
|
|
69
|
+
template "Gemfile.tt", "engines/#{name}/Gemfile"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def create_engine_rakefile
|
|
73
|
+
template "Rakefile.tt", "engines/#{name}/Rakefile"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def create_rubocop_config
|
|
77
|
+
template "rubocop.yml.tt", "engines/#{name}/.rubocop.yml"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def create_spec_helper
|
|
81
|
+
template "spec/spec_helper.rb.tt", "engines/#{name}/spec/spec_helper.rb"
|
|
82
|
+
template "spec/example_spec.rb.tt", "engines/#{name}/spec/#{name}_spec.rb"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def create_license
|
|
86
|
+
template "LICENSE.tt", "engines/#{name}/LICENSE"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def create_readme
|
|
90
|
+
template "README.md.tt", "engines/#{name}/README.md"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Phase 1.6 — per-engine dummy app via the shared DummyAppWriter.
|
|
94
|
+
# Generic engines start with an empty schema; canonical
|
|
95
|
+
# generators (auth/billing/etc) overwrite this with their own
|
|
96
|
+
# schema by calling DummyAppWriter.write! again with the right
|
|
97
|
+
# SCHEMA body. Runs AFTER create_spec_helper so DummyAppWriter's
|
|
98
|
+
# File.write silently overwrites the lightweight Thor template
|
|
99
|
+
# rather than tripping a Thor "conflict" prompt.
|
|
100
|
+
def create_dummy_app
|
|
101
|
+
Seams::Generators::DummyAppWriter.write!(
|
|
102
|
+
engine_path: File.join(destination_root, "engines", name),
|
|
103
|
+
engine_module: module_name,
|
|
104
|
+
mount_at: "/#{name}",
|
|
105
|
+
schema: "# generic engine — no schema yet"
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def wire_into_host
|
|
110
|
+
# Mount the engine into the host's routes (idempotent — skips
|
|
111
|
+
# if the line already exists, so canonical generators that
|
|
112
|
+
# call this and ALSO mount themselves are safe).
|
|
113
|
+
host_inject_mount(engine_class: "#{module_name}::Engine", at: "/#{name}")
|
|
114
|
+
|
|
115
|
+
# Drop a host-side initializer stub the user can fill in.
|
|
116
|
+
# Skipped if a canonical generator (or the host) has already
|
|
117
|
+
# created one.
|
|
118
|
+
initializer_path = File.join(destination_root, "config/initializers/#{name}.rb")
|
|
119
|
+
if File.exist?(initializer_path)
|
|
120
|
+
say " exist config/initializers/#{name}.rb (kept)", :blue
|
|
121
|
+
elsif File.directory?(File.join(destination_root, "config/initializers"))
|
|
122
|
+
template "host_initializer.rb.tt", "config/initializers/#{name}.rb"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def update_sibling_engines
|
|
127
|
+
sibling_dirs = sibling_engine_dirs
|
|
128
|
+
return if sibling_dirs.empty?
|
|
129
|
+
|
|
130
|
+
Seams::Generators::SiblingRubocopWriter.rewrite!(
|
|
131
|
+
engines_root: engines_root,
|
|
132
|
+
dirs: (sibling_dirs + [name]).sort
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
say " update .rubocop.yml of #{sibling_dirs.size} sibling engine(s)", :green
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def report
|
|
139
|
+
say ""
|
|
140
|
+
say " Engine `#{name}` generated at engines/#{name}/", :green
|
|
141
|
+
say " Run its specs with: bin/rails seams:test[#{name}]"
|
|
142
|
+
say ""
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
private
|
|
146
|
+
|
|
147
|
+
def module_name
|
|
148
|
+
name.split("_").map(&:capitalize).join
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def engines_root
|
|
152
|
+
File.join(destination_root, "engines")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def sibling_engine_dirs
|
|
156
|
+
return [] unless Dir.exist?(engines_root)
|
|
157
|
+
|
|
158
|
+
Dir.children(engines_root)
|
|
159
|
+
.select { |child| File.directory?(File.join(engines_root, child)) }
|
|
160
|
+
.reject { |child| child.start_with?(".") || child == name }
|
|
161
|
+
.sort
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Engine-local Gemfile. Mostly redundant in the in-tree layout — the
|
|
2
|
+
# host's Gemfile already loads the engine via path-resolution from
|
|
3
|
+
# seams_engines.rb. This file exists so the engine can ALSO be
|
|
4
|
+
# extracted and bundle-installed standalone (CI matrix run, future
|
|
5
|
+
# gem release, etc.) without rewriting the dependency surface.
|
|
6
|
+
#
|
|
7
|
+
# Keep this file aligned with the engine's gemspec — runtime deps
|
|
8
|
+
# go there, dev/test-only tools go here.
|
|
9
|
+
source "https://rubygems.org"
|
|
10
|
+
|
|
11
|
+
# Specify your gem's dependencies in <%= name %>.gemspec.
|
|
12
|
+
gemspec
|
|
13
|
+
|
|
14
|
+
group :development, :test do
|
|
15
|
+
gem "rspec-rails", "~> 7.1"
|
|
16
|
+
gem "rubocop", require: false
|
|
17
|
+
gem "rubocop-rails", require: false
|
|
18
|
+
gem "rubocop-rspec", require: false
|
|
19
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) <%= Time.now.year %> TODO
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# <%= module_name %>
|
|
2
|
+
|
|
3
|
+
> TODO: one-line summary of this engine.
|
|
4
|
+
|
|
5
|
+
## Events emitted
|
|
6
|
+
|
|
7
|
+
| Event name | Payload | Emitted when |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| _none yet_ | | |
|
|
10
|
+
|
|
11
|
+
Register every event in `lib/<%= name %>/engine.rb` so it shows up in
|
|
12
|
+
`bin/rails seams:list`.
|
|
13
|
+
|
|
14
|
+
## Events consumed
|
|
15
|
+
|
|
16
|
+
| Event name | Subscriber | What it does |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| _none yet_ | | |
|
|
19
|
+
|
|
20
|
+
## Exposed concerns
|
|
21
|
+
|
|
22
|
+
Modules in this list are intentionally part of the engine's public
|
|
23
|
+
contract. Other engines may `include` them; `Seams/NoCrossEngineModelAccess`
|
|
24
|
+
will not flag them.
|
|
25
|
+
|
|
26
|
+
| Concern | Purpose |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| _none yet_ | |
|
|
29
|
+
|
|
30
|
+
## Adapters
|
|
31
|
+
|
|
32
|
+
| Interface | Default | Override via |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| _none yet_ | | |
|
|
35
|
+
|
|
36
|
+
## Running the specs
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bin/rails seams:test[<%= name %>]
|
|
40
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Engine-local Rakefile. Like the Gemfile, this is mostly redundant
|
|
4
|
+
# in-tree — the host's `rake` invokes the engine's specs via
|
|
5
|
+
# seams:test[<name>]. It exists so the engine can be tested
|
|
6
|
+
# standalone:
|
|
7
|
+
#
|
|
8
|
+
# cd engines/<%= name %> && bundle exec rake
|
|
9
|
+
require "bundler/setup"
|
|
10
|
+
require "rspec/core/rake_task"
|
|
11
|
+
|
|
12
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
13
|
+
|
|
14
|
+
task default: :spec
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module <%= module_name %>
|
|
4
|
+
# Engine-scoped abstract Active Record base. Every <%= module_name %>::*
|
|
5
|
+
# AR model inherits from this rather than from
|
|
6
|
+
# ::ApplicationRecord so the engine remains usable in a host that
|
|
7
|
+
# has its own ApplicationRecord with conflicting concerns.
|
|
8
|
+
#
|
|
9
|
+
# Hosts that want shared behaviour across all engines can include
|
|
10
|
+
# a concern here — but only behaviour the engine itself needs.
|
|
11
|
+
# Cross-engine domain logic belongs in the host's ApplicationRecord
|
|
12
|
+
# or in a Core engine concern.
|
|
13
|
+
class ApplicationRecord < ActiveRecord::Base
|
|
14
|
+
self.abstract_class = true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Engine-scoped i18n. Every translation key SHOULD start with
|
|
2
|
+
# `<%= name %>.` so two engines can never collide on a key (the host's
|
|
3
|
+
# I18n.load_path picks up engines/*/config/locales/*.yml automatically
|
|
4
|
+
# via Rails::Engine).
|
|
5
|
+
#
|
|
6
|
+
# Usage from inside the engine:
|
|
7
|
+
#
|
|
8
|
+
# I18n.t("<%= name %>.welcome", name: "Ada")
|
|
9
|
+
#
|
|
10
|
+
# Override in the host by dropping a file at
|
|
11
|
+
# config/locales/<%= name %>.en.yml — keys merge top-down, host wins.
|
|
12
|
+
en:
|
|
13
|
+
<%= name %>:
|
|
14
|
+
placeholder: "Translate me — engines/<%= name %>/config/locales/en.yml"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/<%= name %>/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "<%= name %>"
|
|
7
|
+
spec.version = <%= module_name %>::VERSION
|
|
8
|
+
spec.authors = ["TODO"]
|
|
9
|
+
spec.email = ["TODO"]
|
|
10
|
+
spec.summary = "TODO: short summary of the <%= name %> engine"
|
|
11
|
+
spec.description = "TODO: longer description"
|
|
12
|
+
spec.license = "MIT"
|
|
13
|
+
|
|
14
|
+
spec.files = Dir["{app,config,db,lib}/**/*", "LICENSE", "README.md"]
|
|
15
|
+
|
|
16
|
+
spec.required_ruby_version = ">= 3.2.0"
|
|
17
|
+
|
|
18
|
+
spec.add_dependency "rails", ">= 7.1"
|
|
19
|
+
spec.add_dependency "seams"
|
|
20
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Configuration for the <%= module_name %> engine. Uncomment and edit
|
|
4
|
+
# the values you need to override; everything is set to a sensible
|
|
5
|
+
# default in the engine's `Configuration` class.
|
|
6
|
+
#
|
|
7
|
+
# This file is created by `bin/rails generate seams:engine <%= name %>`
|
|
8
|
+
# only on first run; subsequent runs leave it alone.
|
|
9
|
+
|
|
10
|
+
# <%= module_name %>.configure do |config|
|
|
11
|
+
# # Add your settings here. Run `bin/rails console` and inspect
|
|
12
|
+
# # `<%= module_name %>.configuration` to see the available options.
|
|
13
|
+
# end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module <%= module_name %>
|
|
4
|
+
class Engine < ::Rails::Engine
|
|
5
|
+
isolate_namespace <%= module_name %>
|
|
6
|
+
|
|
7
|
+
config.generators do |g|
|
|
8
|
+
g.test_framework :rspec
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
initializer "<%= name %>.register_events" do
|
|
12
|
+
# Declare events that this engine emits. Other engines look these
|
|
13
|
+
# up via Seams::EventRegistry to know what to subscribe to.
|
|
14
|
+
#
|
|
15
|
+
# Example:
|
|
16
|
+
# Seams::EventRegistry.register("<%= name %>.something_happened.<%= name %>", emitted_by: "<%= module_name %>")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
initializer "<%= name %>.append_migrations" do |app|
|
|
20
|
+
unless app.root == root
|
|
21
|
+
config.paths["db/migrate"].expanded.each do |expanded_path|
|
|
22
|
+
app.config.paths["db/migrate"] << expanded_path
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Self-contained — engines do not inherit from the host's .rubocop.yml
|
|
2
|
+
# so a host using `rubocop-rails-omakase` (or any other style) doesn't
|
|
3
|
+
# force engine code to follow rules written for application code.
|
|
4
|
+
# Engine code is gem-shaped and uses default RuboCop styles.
|
|
5
|
+
|
|
6
|
+
require:
|
|
7
|
+
- seams/cops
|
|
8
|
+
|
|
9
|
+
AllCops:
|
|
10
|
+
TargetRubyVersion: 4.0
|
|
11
|
+
NewCops: enable
|
|
12
|
+
SuggestExtensions: false
|
|
13
|
+
Exclude:
|
|
14
|
+
- "spec/dummy/**/*"
|
|
15
|
+
- "db/migrate/**/*_create_*.rb"
|
|
16
|
+
- "tmp/**/*"
|
|
17
|
+
- "vendor/**/*"
|
|
18
|
+
|
|
19
|
+
Style/Documentation:
|
|
20
|
+
Enabled: false
|
|
21
|
+
|
|
22
|
+
Style/StringLiterals:
|
|
23
|
+
EnforcedStyle: double_quotes
|
|
24
|
+
|
|
25
|
+
Layout/LineLength:
|
|
26
|
+
Max: 120
|
|
27
|
+
|
|
28
|
+
Metrics/MethodLength:
|
|
29
|
+
Max: 25
|
|
30
|
+
|
|
31
|
+
# Engine-scoped boundary enforcement. List every other engine in your
|
|
32
|
+
# host application here so this engine cannot reach into them
|
|
33
|
+
# accidentally. Add concerns the other engines expose (e.g.
|
|
34
|
+
# `Billing::Billable`) to ExposedConcerns to allow `include` calls.
|
|
35
|
+
Seams/NoCrossEngineModelAccess:
|
|
36
|
+
Enabled: true
|
|
37
|
+
OwnEngine: <%= module_name %>
|
|
38
|
+
OtherEngines: []
|
|
39
|
+
ExposedConcerns: []
|
|
40
|
+
|
|
41
|
+
Seams/NoCrossEngineDependency:
|
|
42
|
+
Enabled: true
|
|
43
|
+
OwnEngine: <%= name %>
|
|
44
|
+
OtherEngines: []
|
|
45
|
+
|
|
46
|
+
Seams/KnownQueueNames:
|
|
47
|
+
Enabled: true
|
|
48
|
+
KnownQueues:
|
|
49
|
+
- default
|
|
50
|
+
- <%= name %>
|
|
51
|
+
|
|
52
|
+
Seams/MigrationComments:
|
|
53
|
+
Enabled: true
|
|
54
|
+
Include:
|
|
55
|
+
- "db/migrate/**/*.rb"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Force-load this engine's lib/ so the constant resolves whether rspec
|
|
4
|
+
# is run from the host root (`bundle exec rspec engines/<%= name %>/spec`)
|
|
5
|
+
# or from inside the engine. The host's spec_helper does not require us.
|
|
6
|
+
# Rails must load before lib/<%= name %>.rb because engine.rb references
|
|
7
|
+
# Rails::Engine.
|
|
8
|
+
require "rails"
|
|
9
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
10
|
+
require "<%= name %>"
|
|
11
|
+
|
|
12
|
+
RSpec.describe <%= module_name %> do
|
|
13
|
+
it "defines a VERSION constant" do
|
|
14
|
+
expect(<%= module_name %>::VERSION).to match(/\A\d+\.\d+\.\d+\z/)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
ENV["RAILS_ENV"] ||= "test"
|
|
4
|
+
|
|
5
|
+
# This engine isn't a published gem; force-load its lib/ so the
|
|
6
|
+
# constant resolves whether rspec is invoked from the engine or from
|
|
7
|
+
# the host root (`bundle exec rspec engines/<%= name %>/spec`).
|
|
8
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
|
9
|
+
require "<%= name %>"
|
|
10
|
+
|
|
11
|
+
RSpec.configure do |config|
|
|
12
|
+
config.expect_with :rspec do |expectations|
|
|
13
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
config.mock_with :rspec do |mocks|
|
|
17
|
+
mocks.verify_partial_doubles = true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
config.disable_monkey_patching!
|
|
21
|
+
config.order = :random
|
|
22
|
+
Kernel.srand config.seed
|
|
23
|
+
end
|