tramway 2.0.4.1 → 2.1
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 +4 -4
- data/docs/AGENTS.md +162 -0
- data/lib/generators/tramway/install/install_generator.rb +91 -48
- data/lib/tramway/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08ab219884f2a424e7adce93a5733871510a88193f31a36999994340585a7a34'
|
|
4
|
+
data.tar.gz: 3fe496c333ffc32c8d1d4aaf979766ed767256f6ba80b86fc9a527edecdf24ec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3bd350c148342fcc1e199eb94164d548e3732f889ae4a5c843907c4b668e9870285cfc63090b8ce68751b96028a52d0aad41c5d82fe140751ca950f8f40ae36d
|
|
7
|
+
data.tar.gz: 3cbad4c74dcb1f1418d4ab04f2b4795f2a6c2d39963873e311e69e97db127bd739b07272c70129c56ed0d3c095a1ab180847bcc74579d90681ec1b0a5e859240
|
data/docs/AGENTS.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# AGENTS.md: Tramway Code Generation Standards
|
|
2
|
+
|
|
3
|
+
This document guides AI-assisted code generation for Rails applications built with **Tramway**. It is designed for founders, designers, PMs, and engineers who rely on AI tools (ChatGPT/Copilot/etc.) to build maintainable Rails code that fits Tramway’s conventions without a senior engineer reworking everything.
|
|
4
|
+
|
|
5
|
+
**Core Principle:** Generated code should feel like curated documentation—simple, explicit, and aligned with Tramway’s defaults. Prefer composable ViewComponents, Tailwind-friendly markup, and Rails-native patterns over bespoke architectures.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Project Overview
|
|
10
|
+
|
|
11
|
+
Tramway extends Rails with:
|
|
12
|
+
- **CRUD** actions that can be configured in `config/initializers/tramway.rb`.
|
|
13
|
+
- **Generators** that wire Tailwind, ViewComponent, and pagination defaults (`bin/rails g tramway:install`).
|
|
14
|
+
- **ViewComponents** for reusable UI pieces.
|
|
15
|
+
- **Tailwind safelist** utilities to keep dynamic classes in the build.
|
|
16
|
+
|
|
17
|
+
Generated code should:
|
|
18
|
+
- Lean on Rails conventions and Tramway generators instead of hand-rolled setup.
|
|
19
|
+
- Use domain language (e.g., `Participant`, `Dashboard`) over generic terms.
|
|
20
|
+
- Keep logic in the right layer: models for data/validations, controllers for HTTP, components for repeatable UI, views for simple rendering.
|
|
21
|
+
- Be readable without comments; short methods, guard clauses, and clear naming.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Quick Start Workflow (Preferred)
|
|
26
|
+
|
|
27
|
+
1) **Install Tramway defaults**
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
bin/rails g tramway:install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
- The install generator appends missing gems, copies Tailwind safelist config, ensures `app/assets/tailwind/application.css` imports Tailwind, and writes an `AGENTS.md` guide in the project root.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Technology Stack & Gems
|
|
38
|
+
|
|
39
|
+
Tramway expects and installs:
|
|
40
|
+
- `rails` (7+), `kaminari`, `view_component`, `haml-rails`, `dry-initializer`, `tailwindcss-rails`.
|
|
41
|
+
- Prefer Haml for views unless a component template uses ERB.
|
|
42
|
+
- Keep JavaScript minimal; use Stimulus if needed, avoid SPAs.
|
|
43
|
+
|
|
44
|
+
Do **not** introduce alternative architectures (contexts/operation gems) unless explicitly requested.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## File Structure & Organization
|
|
49
|
+
|
|
50
|
+
Follow Rails defaults. When extracting logic, namespace under the owning model or component:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
app/
|
|
54
|
+
components/ # ViewComponent classes and templates
|
|
55
|
+
participants/
|
|
56
|
+
card_component.rb
|
|
57
|
+
card_component.html.erb
|
|
58
|
+
controllers/
|
|
59
|
+
participants_controller.rb
|
|
60
|
+
decorators/ # Tramway Decorator pattern
|
|
61
|
+
participant_decorator.rb
|
|
62
|
+
forms/ # Tramway Form pattern
|
|
63
|
+
participant_form.rb
|
|
64
|
+
models/
|
|
65
|
+
participant.rb
|
|
66
|
+
views/
|
|
67
|
+
participants/
|
|
68
|
+
show.html.haml
|
|
69
|
+
config/
|
|
70
|
+
initializers/
|
|
71
|
+
tramway.rb # Tramway configuration
|
|
72
|
+
tailwind.config.js # Safelist managed by tramway:install
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Rules
|
|
78
|
+
|
|
79
|
+
- Use Tramway Entities and Tramway actions (index, show, create) by default unless custom behavior is needed. Configure in `config/initializers/tramway.rb`.
|
|
80
|
+
- Normalize input with `normalizes` (from Tramway) for attributes like email, phone, etc.
|
|
81
|
+
- Use Tramway Navbar for navigation
|
|
82
|
+
- Use Tramway Flash for user notifications.
|
|
83
|
+
- Use Tramway Table for tabular data display.
|
|
84
|
+
- Use Tramway Button for buttons.
|
|
85
|
+
- Use `tramway_form_for` and provided inputs in forms.
|
|
86
|
+
- Inherit all components from Tramway::BaseComponent
|
|
87
|
+
|
|
88
|
+
## Controller Patterns
|
|
89
|
+
|
|
90
|
+
- Keep actions short and explicit with guard clauses.
|
|
91
|
+
- Delegate heavy lifting to models, jobs, or components.
|
|
92
|
+
- Render components for complex UI rather than partials with logic.
|
|
93
|
+
|
|
94
|
+
Example:
|
|
95
|
+
```ruby
|
|
96
|
+
class ParticipantsController < ApplicationController
|
|
97
|
+
def index
|
|
98
|
+
@participants = tramway_decorate Participant.all.page(params[:page])
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def new
|
|
102
|
+
@participant_form = tramway_form Participant.new
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def create
|
|
106
|
+
@participant_form = tramway_form Participant.new
|
|
107
|
+
|
|
108
|
+
if @participant_form.submit params[:participant]
|
|
109
|
+
redirect_to participants_path, notice: 'Participant created successfully.'
|
|
110
|
+
else
|
|
111
|
+
render :new, status: :unprocessable_entity
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def show
|
|
116
|
+
@participant = tramway_decorate Participant.find(params[:id])
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def edit
|
|
120
|
+
@participant_form = tramway_form Participant.find(params[:id])
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def update
|
|
124
|
+
@participant_form = tramway_form Participant.find(params[:id])
|
|
125
|
+
|
|
126
|
+
if @participant_form.submit params[:participant]
|
|
127
|
+
redirect_to participant_path(@participant_form), notice: 'Participant updated successfully.'
|
|
128
|
+
else
|
|
129
|
+
render :edit, status: :unprocessable_entity
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def destroy
|
|
134
|
+
participant = Participant.find(params[:id])
|
|
135
|
+
participant.destroy
|
|
136
|
+
|
|
137
|
+
redirect_to participants_path, notice: 'Participant deleted successfully.'
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Tailwind Practices
|
|
145
|
+
|
|
146
|
+
- Keep `config/tailwind.config.js` managed by the generator. If you add dynamic classes, update the `safelist` via the generator template rather than rewriting the config.
|
|
147
|
+
- Add imports to `app/assets/tailwind/application.css`; avoid inline `<style>` blocks.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Configuration
|
|
152
|
+
|
|
153
|
+
- Use `anyway_config` (installed by Tramway) for configuration, not direct `ENV` reads.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Checklist (Before Shipping)
|
|
158
|
+
|
|
159
|
+
- [ ] Used Tramway generators instead of manual setup where available.
|
|
160
|
+
- [ ] Controller actions are concise with guard clauses.
|
|
161
|
+
- [ ] Reusable UI is a ViewComponent using Tailwind utilities and accessible semantics.
|
|
162
|
+
- [ ] Tailwind safelist covers dynamic classes.
|
|
@@ -5,54 +5,8 @@ require 'fileutils'
|
|
|
5
5
|
|
|
6
6
|
module Tramway
|
|
7
7
|
module Generators
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
class InstallGenerator < Rails::Generators::Base
|
|
11
|
-
desc 'Installs Tramway dependencies and Tailwind safelist configuration.'
|
|
12
|
-
|
|
13
|
-
def ensure_dependencies
|
|
14
|
-
missing_dependencies = gem_dependencies.reject do |dependency|
|
|
15
|
-
gemfile_contains?(dependency[:name])
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
return if missing_dependencies.empty?
|
|
19
|
-
|
|
20
|
-
append_to_file 'Gemfile', <<~GEMS
|
|
21
|
-
|
|
22
|
-
# Tramway dependencies
|
|
23
|
-
#{missing_dependencies.pluck(:declaration).join("\n")}
|
|
24
|
-
|
|
25
|
-
GEMS
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def ensure_tailwind_safelist
|
|
29
|
-
return create_tailwind_config unless File.exist?(tailwind_config_path)
|
|
30
|
-
|
|
31
|
-
source_entries = extract_safelist_entries(File.read(gem_tailwind_config_path))
|
|
32
|
-
target_content = File.read(tailwind_config_path)
|
|
33
|
-
target_entries = extract_safelist_entries(target_content)
|
|
34
|
-
|
|
35
|
-
missing_entries = source_entries - target_entries
|
|
36
|
-
return if missing_entries.empty?
|
|
37
|
-
|
|
38
|
-
File.write(tailwind_config_path, insert_entries(target_content, missing_entries))
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def ensure_tailwind_application_stylesheet
|
|
42
|
-
path = tailwind_application_stylesheet_path
|
|
43
|
-
FileUtils.mkdir_p(File.dirname(path))
|
|
44
|
-
|
|
45
|
-
return create_file(path, "#{tailwind_css_import_line}\n") unless File.exist?(path)
|
|
46
|
-
|
|
47
|
-
content = File.read(path)
|
|
48
|
-
return if content.include?(tailwind_css_import_line)
|
|
49
|
-
|
|
50
|
-
File.open(path, 'a') do |file|
|
|
51
|
-
file.write("\n") unless content.empty? || content.end_with?("\n")
|
|
52
|
-
file.write("#{tailwind_css_import_line}\n")
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
8
|
+
# nodoc
|
|
9
|
+
module InstallGeneratorHelpers
|
|
56
10
|
private
|
|
57
11
|
|
|
58
12
|
def gem_dependencies
|
|
@@ -91,6 +45,22 @@ module Tramway
|
|
|
91
45
|
'@import "tailwindcss";'
|
|
92
46
|
end
|
|
93
47
|
|
|
48
|
+
def agents_file_path
|
|
49
|
+
@agents_file_path ||= File.join(destination_root, 'AGENTS.md')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def gem_agents_file_path
|
|
53
|
+
@gem_agents_file_path ||= File.expand_path('../../../../docs/AGENTS.md', __dir__)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def agents_template
|
|
57
|
+
@agents_template ||= File.read(gem_agents_file_path)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def agents_section_heading
|
|
61
|
+
@agents_section_heading ||= agents_template.lines.first&.strip
|
|
62
|
+
end
|
|
63
|
+
|
|
94
64
|
def create_tailwind_config
|
|
95
65
|
create_file tailwind_config_path, File.read(gem_tailwind_config_path)
|
|
96
66
|
end
|
|
@@ -128,6 +98,79 @@ module Tramway
|
|
|
128
98
|
line = content[line_start..index]
|
|
129
99
|
line[/^\s*/] || ' '
|
|
130
100
|
end
|
|
101
|
+
|
|
102
|
+
def append_agents_template(content)
|
|
103
|
+
separator = agents_separator(content)
|
|
104
|
+
File.open(agents_file_path, 'a') do |file|
|
|
105
|
+
file.write("#{separator}#{agents_template}")
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def agents_separator(content)
|
|
110
|
+
return '' if content.empty?
|
|
111
|
+
|
|
112
|
+
content.end_with?("\n") ? "\n" : "\n\n"
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Running `rails generate tramway:install` will invoke this generator
|
|
117
|
+
#
|
|
118
|
+
class InstallGenerator < Rails::Generators::Base
|
|
119
|
+
include InstallGeneratorHelpers
|
|
120
|
+
|
|
121
|
+
desc 'Installs Tramway dependencies and Tailwind safelist configuration.'
|
|
122
|
+
|
|
123
|
+
def ensure_agents_file
|
|
124
|
+
return create_file(agents_file_path, agents_template) unless File.exist?(agents_file_path)
|
|
125
|
+
|
|
126
|
+
content = File.read(agents_file_path)
|
|
127
|
+
return if content.include?(agents_section_heading)
|
|
128
|
+
|
|
129
|
+
append_agents_template(content)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def ensure_dependencies
|
|
133
|
+
missing_dependencies = gem_dependencies.reject do |dependency|
|
|
134
|
+
gemfile_contains?(dependency[:name])
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
return if missing_dependencies.empty?
|
|
138
|
+
|
|
139
|
+
append_to_file 'Gemfile', <<~GEMS
|
|
140
|
+
|
|
141
|
+
# Tramway dependencies
|
|
142
|
+
#{missing_dependencies.pluck(:declaration).join("\n")}
|
|
143
|
+
|
|
144
|
+
GEMS
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def ensure_tailwind_safelist
|
|
148
|
+
return create_tailwind_config unless File.exist?(tailwind_config_path)
|
|
149
|
+
|
|
150
|
+
source_entries = extract_safelist_entries(File.read(gem_tailwind_config_path))
|
|
151
|
+
target_content = File.read(tailwind_config_path)
|
|
152
|
+
target_entries = extract_safelist_entries(target_content)
|
|
153
|
+
|
|
154
|
+
missing_entries = source_entries - target_entries
|
|
155
|
+
return if missing_entries.empty?
|
|
156
|
+
|
|
157
|
+
File.write(tailwind_config_path, insert_entries(target_content, missing_entries))
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def ensure_tailwind_application_stylesheet
|
|
161
|
+
path = tailwind_application_stylesheet_path
|
|
162
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
163
|
+
|
|
164
|
+
return create_file(path, "#{tailwind_css_import_line}\n") unless File.exist?(path)
|
|
165
|
+
|
|
166
|
+
content = File.read(path)
|
|
167
|
+
return if content.include?(tailwind_css_import_line)
|
|
168
|
+
|
|
169
|
+
File.open(path, 'a') do |file|
|
|
170
|
+
file.write("\n") unless content.empty? || content.end_with?("\n")
|
|
171
|
+
file.write("#{tailwind_css_import_line}\n")
|
|
172
|
+
end
|
|
173
|
+
end
|
|
131
174
|
end
|
|
132
175
|
end
|
|
133
176
|
end
|
data/lib/tramway/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tramway
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: '2.1'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- kalashnikovisme
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-01-
|
|
12
|
+
date: 2026-01-07 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: anyway_config
|
|
@@ -234,6 +234,7 @@ files:
|
|
|
234
234
|
- config/locales/en.yml
|
|
235
235
|
- config/routes.rb
|
|
236
236
|
- config/tailwind.config.js
|
|
237
|
+
- docs/AGENTS.md
|
|
237
238
|
- lib/generators/tramway/install/install_generator.rb
|
|
238
239
|
- lib/kaminari/helpers/tag.rb
|
|
239
240
|
- lib/rules/turbo_html_attributes_rules.rb
|