tsykvas_rails_template 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.
Files changed (79) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +200 -0
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +589 -0
  6. data/Rakefile +17 -0
  7. data/lib/generators/tsykvas_rails_template/companions/companions_generator.rb +273 -0
  8. data/lib/generators/tsykvas_rails_template/concept/concept_generator.rb +145 -0
  9. data/lib/generators/tsykvas_rails_template/concept/templates/component/edit.html.slim.tt +5 -0
  10. data/lib/generators/tsykvas_rails_template/concept/templates/component/edit.rb.tt +11 -0
  11. data/lib/generators/tsykvas_rails_template/concept/templates/component/index.html.slim.tt +5 -0
  12. data/lib/generators/tsykvas_rails_template/concept/templates/component/index.rb.tt +11 -0
  13. data/lib/generators/tsykvas_rails_template/concept/templates/component/new.html.slim.tt +5 -0
  14. data/lib/generators/tsykvas_rails_template/concept/templates/component/new.rb.tt +11 -0
  15. data/lib/generators/tsykvas_rails_template/concept/templates/component/show.html.slim.tt +4 -0
  16. data/lib/generators/tsykvas_rails_template/concept/templates/component/show.rb.tt +11 -0
  17. data/lib/generators/tsykvas_rails_template/concept/templates/controller.rb.tt +45 -0
  18. data/lib/generators/tsykvas_rails_template/concept/templates/operation/create.rb.tt +31 -0
  19. data/lib/generators/tsykvas_rails_template/concept/templates/operation/destroy.rb.tt +13 -0
  20. data/lib/generators/tsykvas_rails_template/concept/templates/operation/edit.rb.tt +10 -0
  21. data/lib/generators/tsykvas_rails_template/concept/templates/operation/index.rb.tt +9 -0
  22. data/lib/generators/tsykvas_rails_template/concept/templates/operation/new.rb.tt +10 -0
  23. data/lib/generators/tsykvas_rails_template/concept/templates/operation/show.rb.tt +10 -0
  24. data/lib/generators/tsykvas_rails_template/concept/templates/operation/update.rb.tt +31 -0
  25. data/lib/generators/tsykvas_rails_template/install/bootstrap_installer.rb +225 -0
  26. data/lib/generators/tsykvas_rails_template/install/install_generator.rb +298 -0
  27. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/buddy.md +157 -0
  28. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/code-reviewer.md +117 -0
  29. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/security-reviewer.md +113 -0
  30. data/lib/generators/tsykvas_rails_template/install/templates/.claude/agents/tech-lead.md +150 -0
  31. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/check.md +51 -0
  32. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/code-review.md +60 -0
  33. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/docs-create.md +102 -0
  34. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pr-review.md +81 -0
  35. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pushit.md +160 -0
  36. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/refactor.md +132 -0
  37. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/task-sum.md +47 -0
  38. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tests.md +67 -0
  39. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tsykvas-claude.md +262 -0
  40. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-docs.md +78 -0
  41. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-rules.md +102 -0
  42. data/lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-tests.md +135 -0
  43. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/architecture.md +315 -0
  44. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/authentication.md +96 -0
  45. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/background-jobs.md +135 -0
  46. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/code-style.md +101 -0
  47. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/commands.md +34 -0
  48. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/companions.md +128 -0
  49. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/concepts-refactoring.md +194 -0
  50. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/database.md +135 -0
  51. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/deployment.md +138 -0
  52. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/design-system.md +322 -0
  53. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/documentation.md +89 -0
  54. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/forms.md +174 -0
  55. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/i18n.md +165 -0
  56. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/routing-and-namespaces.md +114 -0
  57. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/security.md +122 -0
  58. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/stimulus-controllers.md +166 -0
  59. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing-examples.md +180 -0
  60. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing.md +117 -0
  61. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/tsykvas_rails_template.md +280 -0
  62. data/lib/generators/tsykvas_rails_template/install/templates/.claude/docs/ui-components.md +196 -0
  63. data/lib/generators/tsykvas_rails_template/install/templates/CLAUDE.md.tt +81 -0
  64. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/component/base.rb +6 -0
  65. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/base.rb +124 -0
  66. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/result.rb +56 -0
  67. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.html.slim +49 -0
  68. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.rb +11 -0
  69. data/lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/operation/index.rb +17 -0
  70. data/lib/generators/tsykvas_rails_template/install/templates/app/controllers/concerns/operations_methods.rb +148 -0
  71. data/lib/generators/tsykvas_rails_template/install/templates/app/controllers/home_controller.rb +10 -0
  72. data/lib/generators/tsykvas_rails_template/install/templates/app/policies/application_policy.rb +33 -0
  73. data/lib/generators/tsykvas_rails_template/install/templates/app/policies/home_policy.rb +8 -0
  74. data/lib/tasks/tsykvas.rake +11 -0
  75. data/lib/tsykvas_rails_template/probe.rb +236 -0
  76. data/lib/tsykvas_rails_template/railtie.rb +13 -0
  77. data/lib/tsykvas_rails_template/version.rb +5 -0
  78. data/lib/tsykvas_rails_template.rb +18 -0
  79. metadata +183 -0
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OperationsMethods
4
+ include ActionView::Helpers::JavaScriptHelper
5
+ extend ActiveSupport::Concern
6
+
7
+ protected
8
+
9
+ def endpoint(operation, component = nil, &block)
10
+ result = operation.call(params:, current_user: try(:current_user))
11
+
12
+ check_authorization_is_called result
13
+
14
+ # Call custom block if provided (useful for Devise sign-in, etc.)
15
+ block.call(result) if block_given?
16
+
17
+ respond_to do |format|
18
+ format.html do
19
+ if action_name == "create" || action_name == "update" || action_name.include?("destroy")
20
+ if result.success? || (result.failure? && action_name.include?("destroy"))
21
+ flash[:notice] = result.message if result.message.present?
22
+ flash[:alert] = result.error_message if result.error_message.present?
23
+ path = result.redirect_path || public_send("#{controller_name}_path")
24
+ redirect_to path
25
+ else
26
+ flash[:alert] = result.error_message if result.error_message.present?
27
+ params = if result.model.is_a?(::OpenStruct)
28
+ result.model.to_h
29
+ else
30
+ key = operation.to_s.split("::").first.underscore
31
+ { "#{key}": result.model }
32
+ end
33
+
34
+ render component.new(**params), status: :unprocessable_content
35
+ end
36
+ elsif action_name == "index"
37
+ flash[:notice] = result.message if result.message.present?
38
+ flash[:alert] = result.error_message if result.error_message.present?
39
+ params = if result.model.is_a?(::OpenStruct)
40
+ result.model.to_h
41
+ else
42
+ key = operation.to_s.split("::").first.underscore.pluralize
43
+ { "#{key}": result.model }
44
+ end
45
+
46
+ render component.new(**params)
47
+ elsif action_name == "show"
48
+ flash[:notice] = result.message if result.message.present?
49
+ flash[:alert] = result.error_message if result.error_message.present?
50
+ params = if result.model.is_a?(::OpenStruct)
51
+ result.model.to_h
52
+ else
53
+ key = operation.to_s.split("::").first.underscore
54
+ { "#{key}": result.model }
55
+ end
56
+
57
+ render component.new(**params)
58
+ elsif action_name == "edit" || action_name == "new"
59
+ flash[:notice] = result.message if result.message.present?
60
+ flash[:alert] = result.error_message if result.error_message.present?
61
+ params = if result.model.is_a?(::OpenStruct)
62
+ result.model.to_h
63
+ else
64
+ key = operation.to_s.split("::").first.underscore
65
+ { "#{key}": result.model }
66
+ end
67
+
68
+ render component.new(**params)
69
+ end
70
+ end
71
+
72
+ # Used for rendering new/edit modals via JS.
73
+ #
74
+ # Assumes Bootstrap modals are available globally as `window.bootstrap.Modal`.
75
+ # If your app uses a different modal library (or none), the inline JS below
76
+ # gracefully no-ops on the dismiss step. Replace this branch entirely if
77
+ # you ship your own modal stack.
78
+ format.js do
79
+ params = if result.model.is_a?(::OpenStruct)
80
+ result.model.to_h
81
+ else
82
+ key = operation.to_s.split("::").first.underscore
83
+ { "#{key}": result.model }
84
+ end
85
+
86
+ if result.success? && (action_name == "create" || action_name == "update" || action_name.include?("destroy"))
87
+ flash[:notice] = result.message if result.message.present?
88
+ flash[:alert] = result.error_message if result.error_message.present?
89
+ path = result.redirect_path || public_send("#{controller_name}_path")
90
+ render js: "window.location.href='#{path}'"
91
+ else
92
+ modal = render_to_string(component.new(**params), layout: false)
93
+ render js: <<~JS
94
+ var activeModal = document.querySelector('.modal.show');
95
+ if (activeModal && window.bootstrap && window.bootstrap.Modal) {
96
+ window.bootstrap.Modal.getOrCreateInstance(activeModal).hide();
97
+ }
98
+ var modalsContainer = document.getElementById('modals');
99
+ if (modalsContainer) {
100
+ modalsContainer.innerHTML = "";
101
+ var renderedHtml = "#{escape_javascript(modal)}";
102
+ var tempContainer = document.createElement("div");
103
+ tempContainer.innerHTML = renderedHtml;
104
+ if (tempContainer.firstElementChild) {
105
+ modalsContainer.appendChild(tempContainer.firstElementChild);
106
+ }
107
+ }
108
+ JS
109
+ end
110
+ end
111
+
112
+ # Used for select2 search results.
113
+ format.json do
114
+ collection = if result.model.is_a?(::OpenStruct)
115
+ key = operation.to_s.split("::").first.underscore.pluralize
116
+ result.model[key]
117
+ else
118
+ result.model
119
+ end
120
+ render json: {
121
+ result: collection.map(&:select2_search_result),
122
+ pagination: {
123
+ more: collection.respond_to?(:next_page) && collection.next_page.present?
124
+ }
125
+ }
126
+ end
127
+
128
+ # Fallback for auto-submit controllers that send null requests.
129
+ format.any do
130
+ flash[:notice] = result.message if result.message.present?
131
+ flash[:alert] = result.error_message if result.error_message.present?
132
+ params = if result.model.is_a?(::OpenStruct)
133
+ result.model.to_h
134
+ else
135
+ key = operation.to_s.split("::").first.underscore.pluralize
136
+ { "#{key}": result.model }
137
+ end
138
+ render component.new(**params)
139
+ end
140
+ end
141
+ end
142
+
143
+ def check_authorization_is_called(result)
144
+ skip_authorization if result[:pundit] || result["policy.run"] || result.failure?
145
+ skip_policy_scope if result[:pundit_scope] || result.failure?
146
+ result[:model]
147
+ end
148
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Generated by tsykvas_rails_template:install. Canonical example of the
4
+ # `endpoint` DSL: controllers stay one-liners, business logic lives in the
5
+ # operation, presentation in the component, authorization in the policy.
6
+ class HomeController < ApplicationController
7
+ def index
8
+ endpoint Home::Operation::Index, Home::Component::Index
9
+ end
10
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationPolicy
4
+ attr_reader :user, :record
5
+
6
+ def initialize(user, record)
7
+ @user = user
8
+ @record = record
9
+ end
10
+
11
+ def index? = false
12
+ def show? = false
13
+ def create? = false
14
+ def new? = create?
15
+ def update? = false
16
+ def edit? = update?
17
+ def destroy? = false
18
+
19
+ class Scope
20
+ def initialize(user, scope)
21
+ @user = user
22
+ @scope = scope
23
+ end
24
+
25
+ def resolve
26
+ raise NotImplementedError, "You must define #resolve in #{self.class}"
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :user, :scope
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Canonical example policy paired with Home::Operation::Index. The home
4
+ # page is public, so `index?` returns true unconditionally. Replace with
5
+ # real authorization rules when the home page is no longer a placeholder.
6
+ class HomePolicy < ApplicationPolicy
7
+ def index? = true
8
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "tsykvas_rails_template/probe"
5
+
6
+ namespace :tsykvas do
7
+ desc "Print a deterministic JSON inventory of the host project (consumed by /tsykvas-claude)"
8
+ task :probe do
9
+ puts JSON.pretty_generate(TsykvasRailsTemplate::Probe.run)
10
+ end
11
+ end
@@ -0,0 +1,236 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+ require "yaml"
5
+
6
+ module TsykvasRailsTemplate
7
+ # Deterministic project inventory for `/tsykvas-claude`.
8
+ #
9
+ # Reads files from a Rails app root and returns a structured Hash that the
10
+ # slash command can consume verbatim — keeps the LLM out of the inventory
11
+ # step so what's "true about the project" is testable and stable run-to-run.
12
+ class Probe
13
+ SCHEMA_VERSION = 2
14
+
15
+ def self.run(root: Dir.pwd)
16
+ new(root).run
17
+ end
18
+
19
+ def initialize(root)
20
+ @root = Pathname(root)
21
+ end
22
+
23
+ def run
24
+ {
25
+ schema_version: SCHEMA_VERSION,
26
+ gem_version: TsykvasRailsTemplate::VERSION,
27
+ root: root.to_s,
28
+ ruby_version: detect_ruby_version,
29
+ rails_version: detect_rails_version,
30
+ default_branch: detect_default_branch,
31
+ api_only: detect_api_only,
32
+ engine_host: detect_engine_host,
33
+ template_engine: detect_template_engine,
34
+ auth: detect_auth,
35
+ authorization: detect_authorization,
36
+ has_api_v1: detect_api_v1,
37
+ has_bootstrap: detect_bootstrap,
38
+ test_framework: detect_test_framework,
39
+ background_jobs: detect_background_jobs,
40
+ databases: detect_databases,
41
+ concept_folders: detect_concept_folders,
42
+ application_controller_includes: detect_application_controller_includes
43
+ }
44
+ end
45
+
46
+ private
47
+
48
+ attr_reader :root
49
+
50
+ def gemfile_lock
51
+ @gemfile_lock ||= read("Gemfile.lock").to_s
52
+ end
53
+
54
+ def routes_rb
55
+ @routes_rb ||= read("config/routes.rb").to_s
56
+ end
57
+
58
+ def application_rb
59
+ @application_rb ||= read("config/application.rb").to_s
60
+ end
61
+
62
+ def application_controller_rb
63
+ @application_controller_rb ||= read("app/controllers/application_controller.rb").to_s
64
+ end
65
+
66
+ def detect_ruby_version
67
+ ruby_file = read(".ruby-version")
68
+ return ruby_file.strip.sub(/^ruby[ \t-]+/, "") if ruby_file
69
+
70
+ gemfile_lock[/RUBY VERSION\s+ruby (\S+)/, 1]
71
+ end
72
+
73
+ def detect_rails_version
74
+ gemfile_lock[/^\s+rails \((\S+)\)/, 1]
75
+ end
76
+
77
+ def detect_default_branch
78
+ head = read(".git/HEAD")
79
+ return head[%r{ref: refs/heads/(\S+)}, 1] if head
80
+
81
+ nil
82
+ end
83
+
84
+ # config.api_only = true → host is API-only (no template engine, no AssetPipeline)
85
+ def detect_api_only
86
+ application_rb.match?(/config\.api_only\s*=\s*true/)
87
+ end
88
+
89
+ # `class XxxApplication < Rails::Engine` instead of `< Rails::Application` → host is an engine
90
+ def detect_engine_host
91
+ application_rb.match?(/<\s*Rails::Engine\b/)
92
+ end
93
+
94
+ def detect_template_engine
95
+ return nil if detect_api_only
96
+ return :slim if gem?("slim-rails") || gem?("slim")
97
+ return :haml if gem?("haml-rails") || gem?("haml")
98
+
99
+ :erb
100
+ end
101
+
102
+ # Returns a structured Hash with detected auth signals.
103
+ #
104
+ # `method` is a coarse classification: :devise, :devise_omniauth, :custom,
105
+ # :basic_auth, :jwt, :warden, or :none. Multiple flags can be true.
106
+ def detect_auth
107
+ flags = auth_flags
108
+ flags[:method] = classify_auth_method(flags)
109
+ flags
110
+ end
111
+
112
+ AUTH_METHOD_PRIORITY = %i[devise warden jwt basic_auth custom_current_user].freeze
113
+ private_constant :AUTH_METHOD_PRIORITY
114
+
115
+ def auth_flags
116
+ ac = application_controller_rb
117
+ {
118
+ devise: gem?("devise"),
119
+ omniauth: gem?("omniauth"),
120
+ omniauth_openid_connect: gem?("omniauth_openid_connect"),
121
+ warden: gem?("warden") || ac.include?("Warden::"),
122
+ jwt: gem?("jwt") || ac.include?("JsonWebToken") || ac.include?("decode_jwt"),
123
+ basic_auth: ac.include?("authenticate_or_request_with_http_basic"),
124
+ custom_current_user: ac.match?(/^\s*def\s+current_user\b/) ||
125
+ ac.match?(/helper_method\s+.*:current_user/)
126
+ }
127
+ end
128
+
129
+ def classify_auth_method(flags)
130
+ return :devise_omniauth if flags[:devise] && flags[:omniauth_openid_connect]
131
+
132
+ hit = AUTH_METHOD_PRIORITY.find { |key| flags[key] }
133
+ return :none unless hit
134
+
135
+ hit == :custom_current_user ? :custom : hit
136
+ end
137
+
138
+ def detect_authorization
139
+ return :pundit if gem?("pundit")
140
+ return :action_policy if gem?("action_policy")
141
+ return :cancancan if gem?("cancancan") || gem?("cancan")
142
+
143
+ :none
144
+ end
145
+
146
+ def detect_api_v1
147
+ return true if routes_rb.match?(/namespace\s+:api\b/) &&
148
+ routes_rb.match?(/namespace\s+:v1\b/)
149
+ return true if routes_rb.match?(%r{["']/?api/v1["']})
150
+
151
+ Dir.glob(root.join("app/controllers/api/v1/**/*.rb").to_s).any?
152
+ end
153
+
154
+ def detect_bootstrap
155
+ return true if gem?("bootstrap") || gem?("bootstrap-rubygem")
156
+ return true if file_contains?("config/importmap.rb", /bootstrap/i)
157
+
158
+ file_contains?("package.json", /"bootstrap"\s*:/)
159
+ end
160
+
161
+ def detect_test_framework
162
+ return :rspec if gem?("rspec-rails") || gem?("rspec")
163
+
164
+ :minitest
165
+ end
166
+
167
+ def detect_background_jobs
168
+ [
169
+ (:solid_queue if gem?("solid_queue")),
170
+ (:sidekiq if gem?("sidekiq")),
171
+ (:good_job if gem?("good_job")),
172
+ (:delayed_job if gem?("delayed_job")),
173
+ (:resque if gem?("resque")),
174
+ (:que if gem?("que"))
175
+ ].compact
176
+ end
177
+
178
+ # Detect databases from config/database.yml top-level keys (multi-DB-aware).
179
+ # Returns a list of names like ["primary", "queue", "cache", "cable"]; falls
180
+ # back to ["primary"] when only the legacy single-DB shape is present.
181
+ def detect_databases
182
+ raw = read("config/database.yml")
183
+ return [] unless raw
184
+
185
+ parsed = safe_yaml(raw)
186
+ return [] unless parsed.is_a?(Hash)
187
+
188
+ env = parsed["development"] || parsed[parsed.keys.first]
189
+ return ["primary"] unless env.is_a?(Hash)
190
+
191
+ keys = env.keys
192
+ keys.all? { |k| env[k].is_a?(Hash) } ? keys.sort : ["primary"]
193
+ end
194
+
195
+ def detect_concept_folders
196
+ base = root.join("app/concepts")
197
+ return [] unless base.directory?
198
+
199
+ base.children
200
+ .select(&:directory?)
201
+ .map { |p| p.basename.to_s }
202
+ .reject { |n| n == "base" }
203
+ .sort
204
+ end
205
+
206
+ def detect_application_controller_includes
207
+ application_controller_rb.scan(/^\s*include\s+([\w:]+)/).flatten
208
+ end
209
+
210
+ def gem?(name)
211
+ gemfile_lock.match?(/^\s+#{Regexp.escape(name)} \(/)
212
+ end
213
+
214
+ def file_contains?(rel, pattern)
215
+ contents = read(rel)
216
+ !!contents && contents.match?(pattern)
217
+ end
218
+
219
+ def read(rel)
220
+ path = root.join(rel)
221
+ return nil unless path.file?
222
+
223
+ path.read
224
+ rescue Errno::ENOENT
225
+ nil
226
+ end
227
+
228
+ def safe_yaml(raw)
229
+ # Strip ERB so YAML.safe_load doesn't choke on `<%= ENV[...] %>` etc.
230
+ stripped = raw.gsub(/<%=?.*?%>/m, "''")
231
+ YAML.safe_load(stripped, aliases: true) || {}
232
+ rescue Psych::SyntaxError, ArgumentError
233
+ {}
234
+ end
235
+ end
236
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/railtie"
4
+
5
+ module TsykvasRailsTemplate
6
+ class Railtie < ::Rails::Railtie
7
+ railtie_name :tsykvas_rails_template
8
+
9
+ rake_tasks do
10
+ load File.expand_path("../tasks/tsykvas.rake", __dir__)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TsykvasRailsTemplate
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "tsykvas_rails_template/version"
4
+ require_relative "tsykvas_rails_template/probe"
5
+
6
+ # Eager-require runtime deps so the host's `Bundler.require` (which only loads
7
+ # gems listed directly in its Gemfile) still picks them up transitively. Without
8
+ # this, `include Pundit::Authorization` and the ViewComponent/Slim references
9
+ # blow up at boot inside the host app.
10
+ require "pundit"
11
+ require "view_component"
12
+ require "slim-rails"
13
+
14
+ module TsykvasRailsTemplate
15
+ class Error < StandardError; end
16
+ end
17
+
18
+ require_relative "tsykvas_rails_template/railtie" if defined?(::Rails::Railtie)
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tsykvas_rails_template
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Yurii Tsykvas
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: pundit
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.3'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.3'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rails
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.1'
40
+ - !ruby/object:Gem::Dependency
41
+ name: slim-rails
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '3.6'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '3.6'
54
+ - !ruby/object:Gem::Dependency
55
+ name: view_component
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ description: |
69
+ Installs an opinionated Rails skeleton: thin `endpoint Operation, Component`
70
+ controllers, plain-Ruby `Base::Operation::Base` + `Result` classes, a
71
+ ViewComponent-based `app/concepts/<feature>/{operation,component}/` layout,
72
+ and a `.claude/` directory pre-loaded with battle-tested slash commands,
73
+ subagents, and architecture docs. Ships generators to scaffold the host app
74
+ and to create new concept directories.
75
+ email:
76
+ - tsykvasyurii@gmail.com
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - CHANGELOG.md
82
+ - CODE_OF_CONDUCT.md
83
+ - LICENSE.txt
84
+ - README.md
85
+ - Rakefile
86
+ - lib/generators/tsykvas_rails_template/companions/companions_generator.rb
87
+ - lib/generators/tsykvas_rails_template/concept/concept_generator.rb
88
+ - lib/generators/tsykvas_rails_template/concept/templates/component/edit.html.slim.tt
89
+ - lib/generators/tsykvas_rails_template/concept/templates/component/edit.rb.tt
90
+ - lib/generators/tsykvas_rails_template/concept/templates/component/index.html.slim.tt
91
+ - lib/generators/tsykvas_rails_template/concept/templates/component/index.rb.tt
92
+ - lib/generators/tsykvas_rails_template/concept/templates/component/new.html.slim.tt
93
+ - lib/generators/tsykvas_rails_template/concept/templates/component/new.rb.tt
94
+ - lib/generators/tsykvas_rails_template/concept/templates/component/show.html.slim.tt
95
+ - lib/generators/tsykvas_rails_template/concept/templates/component/show.rb.tt
96
+ - lib/generators/tsykvas_rails_template/concept/templates/controller.rb.tt
97
+ - lib/generators/tsykvas_rails_template/concept/templates/operation/create.rb.tt
98
+ - lib/generators/tsykvas_rails_template/concept/templates/operation/destroy.rb.tt
99
+ - lib/generators/tsykvas_rails_template/concept/templates/operation/edit.rb.tt
100
+ - lib/generators/tsykvas_rails_template/concept/templates/operation/index.rb.tt
101
+ - lib/generators/tsykvas_rails_template/concept/templates/operation/new.rb.tt
102
+ - lib/generators/tsykvas_rails_template/concept/templates/operation/show.rb.tt
103
+ - lib/generators/tsykvas_rails_template/concept/templates/operation/update.rb.tt
104
+ - lib/generators/tsykvas_rails_template/install/bootstrap_installer.rb
105
+ - lib/generators/tsykvas_rails_template/install/install_generator.rb
106
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/agents/buddy.md
107
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/agents/code-reviewer.md
108
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/agents/security-reviewer.md
109
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/agents/tech-lead.md
110
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/check.md
111
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/code-review.md
112
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/docs-create.md
113
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pr-review.md
114
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/pushit.md
115
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/refactor.md
116
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/task-sum.md
117
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tests.md
118
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/tsykvas-claude.md
119
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-docs.md
120
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-rules.md
121
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/commands/update-tests.md
122
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/architecture.md
123
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/authentication.md
124
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/background-jobs.md
125
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/code-style.md
126
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/commands.md
127
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/companions.md
128
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/concepts-refactoring.md
129
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/database.md
130
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/deployment.md
131
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/design-system.md
132
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/documentation.md
133
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/forms.md
134
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/i18n.md
135
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/routing-and-namespaces.md
136
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/security.md
137
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/stimulus-controllers.md
138
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing-examples.md
139
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/testing.md
140
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/tsykvas_rails_template.md
141
+ - lib/generators/tsykvas_rails_template/install/templates/.claude/docs/ui-components.md
142
+ - lib/generators/tsykvas_rails_template/install/templates/CLAUDE.md.tt
143
+ - lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/component/base.rb
144
+ - lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/base.rb
145
+ - lib/generators/tsykvas_rails_template/install/templates/app/concepts/base/operation/result.rb
146
+ - lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.html.slim
147
+ - lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/component/index.rb
148
+ - lib/generators/tsykvas_rails_template/install/templates/app/concepts/home/operation/index.rb
149
+ - lib/generators/tsykvas_rails_template/install/templates/app/controllers/concerns/operations_methods.rb
150
+ - lib/generators/tsykvas_rails_template/install/templates/app/controllers/home_controller.rb
151
+ - lib/generators/tsykvas_rails_template/install/templates/app/policies/application_policy.rb
152
+ - lib/generators/tsykvas_rails_template/install/templates/app/policies/home_policy.rb
153
+ - lib/tasks/tsykvas.rake
154
+ - lib/tsykvas_rails_template.rb
155
+ - lib/tsykvas_rails_template/probe.rb
156
+ - lib/tsykvas_rails_template/railtie.rb
157
+ - lib/tsykvas_rails_template/version.rb
158
+ homepage: https://github.com/tsykvas/tsykvas_rails_template
159
+ licenses:
160
+ - MIT
161
+ metadata:
162
+ homepage_uri: https://github.com/tsykvas/tsykvas_rails_template
163
+ source_code_uri: https://github.com/tsykvas/tsykvas_rails_template
164
+ changelog_uri: https://github.com/tsykvas/tsykvas_rails_template/blob/main/CHANGELOG.md
165
+ rdoc_options: []
166
+ require_paths:
167
+ - lib
168
+ required_ruby_version: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: 3.2.0
173
+ required_rubygems_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ requirements: []
179
+ rubygems_version: 4.0.8
180
+ specification_version: 4
181
+ summary: 'Rails template: thin controllers, Operation/Component architecture, and
182
+ Claude tooling.'
183
+ test_files: []