roda-project 0.1.11 → 0.1.13

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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/roda/project/bin/generators/migration.rb +1 -1
  3. data/lib/roda/project/bin/generators/model.rb +2 -2
  4. data/lib/roda/project/bin/generators/routes.rb +25 -9
  5. data/lib/roda/project/bin/generators/service.rb +120 -0
  6. data/lib/roda/project/bin/generators.rb +9 -0
  7. data/lib/roda/project/cli.rb +18 -8
  8. data/lib/roda/project/generator.rb +2 -2
  9. data/lib/roda/project/jeremy_template_creator.rb +32 -0
  10. data/lib/roda/project/main_context.rb +3 -3
  11. data/lib/roda/project/templates/base/app/app.rb.erb +1 -2
  12. data/lib/roda/project/templates/base/minimal/AGENTS.md +15 -6
  13. data/lib/roda/project/templates/base/minimal/bin/roda.erb +4 -0
  14. data/lib/roda/project/templates/base/scaffold/AGENTS.md.erb +47 -0
  15. data/lib/roda/project/templates/base/scaffold/Gemfile.erb +2 -1
  16. data/lib/roda/project/templates/base/scaffold/app/config/config.rb.erb +14 -1
  17. data/lib/roda/project/templates/base/scaffold/app/routes/foo.rb.erb +2 -1
  18. data/lib/roda/project/templates/base/scaffold/bin/roda.erb +5 -1
  19. data/lib/roda/project/templates/base/scaffold/boot.rb.erb +7 -1
  20. data/lib/roda/project/version.rb +1 -1
  21. data/lib/roda/project.rb +3 -0
  22. metadata +8 -6
  23. data/lib/roda/project/templates/base/scaffold/AGENTS.md +0 -9
  24. /data/lib/roda/project/templates/{base/scaffold → front-end}/app/config/locales/en.yml +0 -0
  25. /data/lib/roda/project/templates/{base/scaffold → front-end}/app/config/locales/foo/en.yml +0 -0
  26. /data/lib/roda/project/templates/{base/scaffold → front-end}/app/config/locales/foo/pt-br.yml +0 -0
  27. /data/lib/roda/project/templates/{base/scaffold → front-end}/app/config/locales/pt-br.yml +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fceab0441f37da52ca87b8c028d4fa72573854e2a1adc25f34f76ac6e7b4e2a
4
- data.tar.gz: 24c9c54923283bee8394d0597206feed0d1a914cbf30caa1368bef696a2ffa3a
3
+ metadata.gz: 3156e8ffc1fbf7c48c30c1224bfccd2bf66c775b90cb802ada325c2ef2a5607e
4
+ data.tar.gz: 02e04e9cb18a32f82cad2fceb59f1d567d33fe61330f1f0a26bb6e38ebf3b618
5
5
  SHA512:
6
- metadata.gz: 7aa0cc8165bd3a515e8e06a625e0621ffd9257fa276431fd1babfd2ba1f3a4fd8336dc595c4a56d41f09c18505a8809870e1369612e46c810204ad65d9511c71
7
- data.tar.gz: 9cf9d5bda0e6f992d820b20ec16647df888bcf36246500669a828efac54b1c091ddf73d628a54706af50bdd9b466b027076765755e74d00aa4fee6ea05fdf06b
6
+ metadata.gz: b2a91d0af7f801951d65f288a3fcbc0012b3779e6736dfdd94d7703377834cad15d8a8680293b1800a8293e90cfb59d8d3f971e1e67abedf682b32a432e9920a
7
+ data.tar.gz: b80916d58cdd4a167f8be8a9e5e43f4c56730457818b6cfee081ac4946d1e353284c7b6d087f9d030a03d7a705426e78fe871610dd5438dfe3c1c9bb1d426563
@@ -29,7 +29,7 @@ class Roda
29
29
 
30
30
  File.write(filename, content)
31
31
 
32
- puts_create_message(filename)
32
+ action_success_message(filename)
33
33
  end
34
34
 
35
35
  def migrations_path
@@ -22,7 +22,7 @@ class Roda
22
22
  filename = File.join("spec/app/models", *name_segments[0..-2], "#{model_file_basename}_spec.rb")
23
23
  File.write(filename, spec_code)
24
24
 
25
- puts_create_message(filename)
25
+ action_success_message(filename)
26
26
  end
27
27
 
28
28
  def create_model
@@ -30,7 +30,7 @@ class Roda
30
30
  filename = File.join("app/models", *name_segments[0..-2], "#{model_file_basename}.rb")
31
31
  File.write(filename, code)
32
32
 
33
- puts_create_message(filename)
33
+ action_success_message(filename)
34
34
  end
35
35
 
36
36
  def spec_code
@@ -23,8 +23,15 @@ class Roda
23
23
  filename = File.join(ensure_and_get_path("app/routes", branch_name), "#{branch_name}.rb")
24
24
  route_definitions = routes_list.map do |route_str|
25
25
  method, name = parse_route_string(route_str)
26
- view_line = (method == "get" && must_generate_views?) ? "\n view('#{name}')" : ""
27
- " r.#{method} \"#{name}\" do#{view_line}\n end"
26
+ view_name = name
27
+ view_name = "index" if view_name == ""
28
+ view_line = (method == "get" && must_generate_views?) ? "\n view('#{view_name}')" : ""
29
+
30
+ if name != ""
31
+ " r.#{method} \"#{name}\" do#{view_line}\n end"
32
+ else
33
+ " r.#{method} do#{view_line}\n end"
34
+ end
28
35
  end.join("\n\n")
29
36
 
30
37
  hash_branch_header = if branch_name.include?("/")
@@ -45,7 +52,7 @@ class Roda
45
52
  end
46
53
  RUBY
47
54
  File.write(filename, content)
48
- puts_create_message(filename)
55
+ action_success_message(filename)
49
56
  end
50
57
 
51
58
  def generate_views
@@ -55,9 +62,10 @@ class Roda
55
62
  routes_list.each do |route_str|
56
63
  method, name = parse_route_string(route_str)
57
64
  if method == "get"
65
+ name = "index" if name == ""
58
66
  view_filename = File.join(branch_views_dir, "#{name}.erb")
59
67
  File.write(view_filename, "")
60
- puts_create_message(view_filename)
68
+ action_success_message(view_filename)
61
69
  end
62
70
  end
63
71
  end
@@ -70,10 +78,18 @@ class Roda
70
78
 
71
79
  test_route_definitions = routes_list.map do |route_str|
72
80
  method, name = parse_route_string(route_str)
73
- " it \"responds to #{method.upcase} /#{branch_name}/#{name}\" do\n" \
74
- " #{method} \"/#{branch_name}/#{name}\"\n" \
75
- " expect(last_response.status).to eq(200)\n" \
76
- " end"
81
+
82
+ if name != ""
83
+ " it \"responds to #{method.upcase} /#{branch_name}/#{name}\" do\n" \
84
+ " #{method} \"/#{branch_name}/#{name}\"\n" \
85
+ " expect(last_response.status).to eq(200)\n" \
86
+ " end"
87
+ else
88
+ " it \"responds to #{method.upcase} /#{branch_name} do\n" \
89
+ " #{method} \"/#{branch_name}\n" \
90
+ " expect(last_response.status).to eq(200)\n" \
91
+ " end"
92
+ end
77
93
  end.join("\n")
78
94
 
79
95
  test_content = <<~RUBY
@@ -84,7 +100,7 @@ class Roda
84
100
  end
85
101
  RUBY
86
102
  File.write(test_filename, test_content)
87
- puts_create_message(test_filename)
103
+ action_success_message(test_filename)
88
104
  end
89
105
 
90
106
  def must_generate_views?
@@ -0,0 +1,120 @@
1
+ class Roda
2
+ module Project
3
+ module Bin
4
+ class Generators < ::Thor
5
+ class Service < Roda::Project::Bin::Generator
6
+ include Roda::Project::Helpers::Inflections
7
+
8
+ def call
9
+ unless valid_args?
10
+ puts "Usage: bin/roda g service <module|class> <name>"
11
+ exit 1
12
+ end
13
+
14
+ puts "* creating service"
15
+ create_service
16
+ create_service_spec
17
+ end
18
+
19
+ def create_service
20
+ ensure_and_get_path("app/services", service_relative_path)
21
+ filename = File.join("app/services", *name_segments[0..-2], "#{service_file_basename}.rb")
22
+ File.write(filename, code)
23
+
24
+ action_success_message(filename)
25
+ end
26
+
27
+ def create_service_spec
28
+ ensure_and_get_path("spec/app/services", service_relative_path)
29
+ filename = File.join("spec/app/services", *name_segments[0..-2], "#{service_file_basename}_spec.rb")
30
+ File.write(filename, spec_code)
31
+
32
+ action_success_message(filename)
33
+ end
34
+
35
+ def spec_code
36
+ depth = 2 + name_segments.length - 1
37
+ relative_prefix = "../" * depth
38
+ <<~RUBY
39
+ require_relative "#{relative_prefix}spec_helper"
40
+
41
+ describe #{qualified_class_name} do
42
+ end
43
+ RUBY
44
+ end
45
+
46
+ def code
47
+ leaf_keyword = service_type
48
+ if name_segments.length == 1
49
+ <<~RUBY
50
+ #{leaf_keyword} #{camelize(name_segments.last)}
51
+ end
52
+ RUBY
53
+ else
54
+ depth = name_segments.length - 1
55
+ leaf_indent = " " * depth
56
+ lines = [
57
+ "#{leaf_indent}#{leaf_keyword} #{camelize(name_segments.last)}",
58
+ "#{leaf_indent}end"
59
+ ]
60
+
61
+ name_segments[0..-2].map { |s| camelize(s) }.reverse.each_with_index do |mod, idx|
62
+ mod_indent = " " * (depth - 1 - idx)
63
+ lines = ["#{mod_indent}module #{mod}"] + lines + ["#{mod_indent}end"]
64
+ end
65
+
66
+ lines.join("\n") + "\n"
67
+ end
68
+ end
69
+
70
+ def name_segments
71
+ @name_segments ||= service_name.split("/")
72
+ end
73
+
74
+ def qualified_class_name
75
+ @qualified_class_name ||= name_segments.map { |s| camelize(s) }.join("::")
76
+ end
77
+
78
+ def service_relative_path
79
+ @service_relative_path ||= if name_segments.length > 1
80
+ File.join(*name_segments[0..-2], service_file_basename)
81
+ else
82
+ service_file_basename
83
+ end
84
+ end
85
+
86
+ def service_file_basename
87
+ @service_file_basename ||= underscore(name_segments.last)
88
+ end
89
+
90
+ def service_type
91
+ @service_type ||= parse_args[:type]
92
+ end
93
+
94
+ def service_name
95
+ @service_name ||= parse_args[:name]
96
+ end
97
+
98
+ def parse_args
99
+ @parse_args ||= begin
100
+ if %w[module class].include?(@args[0].to_s.downcase)
101
+ { type: @args[0].to_s.downcase, name: @args[1].to_s }
102
+ else
103
+ { type: "class", name: @args[0].to_s }
104
+ end
105
+ end
106
+ end
107
+
108
+ def valid_args?
109
+ return false unless %w[module class].include?(service_type)
110
+ return false if service_name.empty?
111
+ return false if service_name.include?(" ")
112
+ return false if service_name.match?(/\A\d/)
113
+
114
+ true
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -20,6 +20,15 @@ class Roda
20
20
  Model.new(context:, args:, options:).call
21
21
  end
22
22
 
23
+ desc "service", "Create service module or class and test scaffold"
24
+ def service(*args)
25
+ Service.new(context:, args:, options:).call
26
+ end
27
+
28
+ def self.exit_on_failure?
29
+ true
30
+ end
31
+
23
32
  private
24
33
 
25
34
  def context
@@ -10,8 +10,8 @@ class Roda
10
10
  puts pastel.italic("#{Roda::Project.messages.sample.first}\n")
11
11
 
12
12
  get_user_context
13
-
14
13
  puts pastel.bright_black("\n[project: #{@context.project_name}]\n")
14
+ return JeremyTemplateCreator.new(context: @context).call if jeremy?
15
15
 
16
16
  create_base_project
17
17
  add_front_end
@@ -26,14 +26,16 @@ class Roda
26
26
  puts "\n* create your database\n"
27
27
  puts "$ bin/roda db create"
28
28
  end
29
- puts "\nmigrate the database (use RACK_ENV to migrate 'test' or 'production' environments):\n\n"
30
- puts "$ bin/roda db migrate"
29
+ if @context.rodauth?
30
+ puts "\nmigrate the database (use RACK_ENV to migrate 'test' or 'production' environments):\n\n"
31
+ puts "$ bin/roda db migrate"
32
+ end
31
33
  end
32
34
  puts "\nrun and watch the project in dev mode:\n"
33
35
  puts "\n$ bin/roda dev"
34
36
  if @context.fullstack?
35
37
  puts "\ncompile and watch assets:\n"
36
- puts "\n$ bin/roda assets:dev"
38
+ puts "\n$ bin/roda assets -w"
37
39
  end
38
40
  puts "\nrun 'bin/roda' inside #{@context.project_name} to see all available tasks\n\n"
39
41
  rescue TTY::Reader::InputInterrupt
@@ -44,6 +46,8 @@ class Roda
44
46
 
45
47
  def get_user_context
46
48
  retry_on_error { @context.project_name = read_line("Project name › ", "project") }
49
+ return if jeremy?
50
+
47
51
  retry_on_error { @context.base = read_line("(#{fullstack_id}) Fullstack (#{api_id}) API (#{minimal_id}) Minimal › ", fullstack_id).to_i }
48
52
  retry_on_error { @context.tests = read_line("(#{rspec_id}) RSpec (#{minitest_id}) Minitest › ", rspec_id).to_i }
49
53
 
@@ -63,6 +67,10 @@ class Roda
63
67
  end
64
68
  end
65
69
 
70
+ def jeremy?
71
+ @jeremy ||= ARGV[0] == "--jeremy"
72
+ end
73
+
66
74
  def create_base_project
67
75
  puts "* creating base project"
68
76
  if @context.minimal?
@@ -96,12 +104,14 @@ class Roda
96
104
  erb_cp_dir("front-end", "app/assets")
97
105
  erb_cp_file("front-end", "esbuild.js")
98
106
  erb_cp_file("front-end", "package.json")
107
+ cp_dir("front-end", "app/config/locales")
108
+ action_success_message("app/config/locales")
99
109
  cp_dir("front-end", "app/views")
100
- puts_create_message("app/views")
110
+ action_success_message("app/views")
101
111
  cp_dir("front-end", "public/assets")
102
- puts_create_message("public/assets")
112
+ action_success_message("public/assets")
103
113
  cp_dir("front-end", "public/images")
104
- puts_create_message("public/images")
114
+ action_success_message("public/images")
105
115
  end
106
116
  end
107
117
 
@@ -121,7 +131,7 @@ class Roda
121
131
  erb_cp_file("rodauth", "db/migrations/001_add_rodauth.rb")
122
132
  if @context.fullstack?
123
133
  cp_file("rodauth", "app/views/create-account.erb")
124
- puts_create_message("app/views/create-account.erb")
134
+ action_success_message("app/views/create-account.erb")
125
135
  end
126
136
  end
127
137
  end
@@ -20,8 +20,8 @@ class Roda
20
20
 
21
21
  protected
22
22
 
23
- def puts_create_message(path)
24
- puts(pastel.green(" create ") + path)
23
+ def action_success_message(path, action = "create")
24
+ puts(pastel.green(" #{action} ") + path)
25
25
  end
26
26
  end
27
27
  end
@@ -0,0 +1,32 @@
1
+ require "fileutils"
2
+
3
+ class Roda
4
+ module Project
5
+ class JeremyTemplateCreator < Generator
6
+ include Helpers::Inflections
7
+
8
+ def call
9
+ repo_url = "https://github.com/jeremyevans/roda-sequel-stack"
10
+ puts "* Downloading template with git...\n\n"
11
+
12
+ success = system("git clone --depth 1 #{repo_url} #{@context.project_name}")
13
+ abort("\nCould not download the template.") unless success
14
+
15
+ git_dir = File.join(@context.project_name, ".git")
16
+ if Dir.exist?(git_dir)
17
+ FileUtils.rm_rf(git_dir)
18
+ puts "\n* Cleaned up template git history.\n\n"
19
+ end
20
+
21
+ action_success_message("./#{@context.project_name}")
22
+
23
+ setup_command = "cd #{@context.project_name} && rake setup[#{camelize(@context.project_name)}]"
24
+ system(setup_command)
25
+
26
+ action_success_message(setup_command, "run")
27
+ puts "\nSetup is done! follow the link below to learn about this template:"
28
+ puts "\n#{repo_url}"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -23,9 +23,9 @@ class Roda
23
23
  option :main_context, type: :hash, default: {
24
24
  project_name: "#{project_name}",
25
25
  base: #{id_to_string(base, :base)},
26
- rodauth: #{rodauth},
26
+ rodauth: #{rodauth || false},
27
27
  tests: #{id_to_string(tests, :tests)},
28
- database: #{database},
28
+ database: #{database || false},
29
29
  RUBY
30
30
  if database?
31
31
  option << " database_type: #{id_to_string(database_type, :database)},"
@@ -108,7 +108,7 @@ class Roda
108
108
  def root_example
109
109
  return 'view("index")' if fullstack?
110
110
 
111
- '{ message: "#{t.hello.message}" }'
111
+ '{ message: "hello world" }'
112
112
  end
113
113
  # rubocop:enable Lint/InterpolationCheck
114
114
 
@@ -8,7 +8,7 @@ class <%= context.const_project_name %> < Roda
8
8
  <% if context.fullstack? %>
9
9
  # Views
10
10
  plugin :partials, views: "app/views"
11
- plugin :render, layout: "./layout"
11
+ plugin :render, **Config.get[:render]
12
12
  plugin :content_for, append: false
13
13
  plugin :flash
14
14
  plugin :assets_manifest
@@ -69,7 +69,6 @@ class <%= context.const_project_name %> < Roda
69
69
  # r.i18n_set_locale_from(:session)<% end %>
70
70
  <% if context.rodauth? %>
71
71
  r.rodauth
72
- rodauth.require_authentication
73
72
  <% end %>
74
73
  r.root do
75
74
  <%= context.root_example %>
@@ -1,9 +1,18 @@
1
- Act as a Ruby specialist.
1
+ # Project Code Generation Rules
2
2
 
3
- This is a web application written using the Roda web framework
3
+ ## Core Stack
4
+ - **Web Framework**: Roda (STRICT: Do NOT use Rails, ActionController, or Sinatra conventions).
5
+ - **Autoloader**: Zeitwerk (Do NOT manually `require` files located in the `app/` directory. Only require standard libraries or gems).
6
+ - **No Rails Magic:** Do not use `ActiveSupport` methods (like `.present?` or `.blank?`) unless the gem is explicitly in the Gemfile.
4
7
 
5
- ## Project guidelines
8
+ ## Code Style & Conventions
6
9
 
7
- - **Never** deliver code without tests validating the code (execute with `rake test`)
8
- - **Never** write long comments in the code
9
- - **Always** use clean code
10
+ ### 1. Types
11
+ - Rely on standard Ruby 3.x patterns. Use explicit YARD docs for method signatures.
12
+
13
+ ### 2. Routing (Roda)
14
+ - Do not create deep routing blocks. Use Roda's tree routing efficiently (`r.on`, `r.is`, `r.get`, `r.post`).
15
+
16
+ ### 3. Boot Sequence & Initialization
17
+ - **`boot.rb`**: The absolute starting point. It sets up `Bundler` and boots `Zeitwerk`.
18
+ - **`config.ru`**: The Rack entrypoint. It defines middleware and mounts the primary Roda application class defined in `app.rb`.
@@ -42,6 +42,10 @@ class CLI < Thor
42
42
  end
43
43
  end
44
44
  map "s" => "server"
45
+
46
+ def self.exit_on_failure?
47
+ true
48
+ end
45
49
  end
46
50
 
47
51
  CLI.start(ARGV)
@@ -0,0 +1,47 @@
1
+ # Project Code Generation Rules
2
+
3
+ ## Core Stack
4
+ - **Web Framework**: Roda (STRICT: Do NOT use Rails, ActionController, or Sinatra conventions).
5
+ - **No Rails Magic:** Do not use `ActiveSupport` methods (like `.present?` or `.blank?`) unless the gem is explicitly in the Gemfile.<% if context.database %>
6
+ - **ORM**: Sequel (STRICT: Do NOT use ActiveRecord. Use Sequel Models, Datasets, and Migrations).<% end %>
7
+ - **Autoloader**: Zeitwerk (Do NOT manually `require` files located in the `app/` directory. Only require standard libraries or gems).<% if context.fullstack? %>
8
+ - **Frontend**: esbuild + ERB (Fullstack mode).<% end %>
9
+
10
+ ## Code Style & Conventions
11
+
12
+ ### 1. Types
13
+ - Rely on standard Ruby 3.x patterns. Use explicit YARD docs for method signatures.
14
+
15
+ ### 2. Routing (Roda)
16
+ - The main app resides in `app/[project_name].rb`.
17
+ - Sub-routes MUST be implemented using Roda **Hash Branches** (`hash_branches` plugin) and placed in `app/routes/`.
18
+ - Do not create deep routing blocks. Use Roda's tree routing efficiently (`r.on`, `r.is`, `r.get`, `r.post`).<% if context.database %>
19
+
20
+ ### 3. Database & Models (Sequel)
21
+ - Models reside in `app/models/`.
22
+ - Migrations reside in `db/migrations/` and MUST use sequential numbering (e.g., `001_...`).
23
+ - When writing database queries, use Sequel's dataset methods (e.g., `where`, `select`, `exclude`, `join`). Do not use string interpolation for SQL queries.
24
+
25
+ <% end %><% if context.fullstack? %>### 4. Views & Presentation
26
+ - ERB templates go in `app/views/`.
27
+
28
+ <% end %>### 5. Testing
29
+ - Specs reside in `spec/app/`.
30
+ - Use `rack-test` for route testing.
31
+ - Ensure database transactions are rolled back after each test block.
32
+ - Mirror the file structure of `app/` inside `spec/app/` (e.g., `app/models/user.rb` -> `spec/app/models/user_spec.rb`).
33
+
34
+ ### 6. Boot Sequence & Initialization
35
+ - **`boot.rb`**: The absolute starting point. It sets up `Bundler`, boots `Zeitwerk` for autoloading the `app/` directory, and loads service providers from `app/config/providers/`.
36
+ - **`config.ru`**: The Rack entrypoint. It defines middleware (like `Rack::LiveReload` in development) and mounts the primary Roda application class defined in `app/[project_name].rb`.
37
+
38
+ ### 7. Tooling
39
+ - Do NOT run `bundle exec rake` for scaffolding/servers. The project uses a custom CLI: `bin/roda`. Suggest commands using `bin/roda` (e.g., generators, running the server).
40
+
41
+ #### Generators
42
+ - To maintain consistency and avoid manual boilerplate, the project uses custom generators for scaffolding new features. These automatically hook into Zeitwerk's expectations, Sequel's DSL, and Roda's Hash Branches.
43
+ - **`bin/roda g routes <branch> [options]`**: Scaffolds a Roda hash branch file in `app/routes/`, matching spec files, and ERB views (for GET routes). Supports nested paths (e.g., `api/v1`) and bare verbs (e.g., `books :get :post`).<% if context.database %>
44
+ - **`bin/roda g model <name> [fields]`**: Generates a Sequel ORM model class, a matching model spec, and a timestamped Sequel migration. Supports namespacing (`Admin/User`) and auto-pluralizes table names.
45
+ - **`bin/roda g migration <name> [fields]`**: Creates a timestamped Sequel migration. It automatically detects intent from the name (e.g., `add_status_to_users` generates the `alter_table` block) and maps Rails-like field types (e.g., `user:references`, `body:text`) to Sequel schema methods.
46
+ <% end %>- **`bin/roda g service <type> <name>`**: Scaffolds a class or module service in `app/services/` and a matching spec. Defaults to `class` if type is omitted.
47
+
@@ -48,5 +48,6 @@ group :development do
48
48
  gem "minitest"
49
49
  gem "minitest-hooks"
50
50
  <% else %>
51
- gem "rspec"<% end %>
51
+ gem "rspec"<% end %><% if context.database? %>
52
+ gem "sequel-annotate"<% end %>
52
53
  end
@@ -5,13 +5,26 @@ module Config
5
5
  secret: ENV["SESSION_SECRET"] || 'DEV-ONLY-8<FQF8HiF)>l0hbPk£vBQ#IrYsoO}14k\l+-/gIU[j}l0hbPk£vBQ#IrY',
6
6
  environment:,<% if context.rodauth? %>
7
7
  hmac_secret: ENV["RODAUTH_HMAC_SECRET"] || 'DEV-ONLY',
8
- jwt_secret: ENV["JWT_SECRET"] || 'DEV-ONLY',<% end %><% if context.fullstack? %>
8
+ jwt_secret: ENV["JWT_SECRET"] || 'DEV-ONLY'<% end %><% if context.fullstack? %>,
9
9
  i18n: {
10
10
  translations: ["app/config/locales", "app/config/locales/foo"],
11
11
  locale: ["en", "pt-br"]
12
12
  }<% end %><% if context.database? %>,
13
13
  db: {
14
14
  url: not_production? ? <%= context.default_db_url %> : ENV["DATABASE_URL"]
15
+ }<% end %><% if context.fullstack? %>,
16
+ render: {
17
+ layout: "./layout",
18
+ assume_fixed_locals: true, # Optimize plugin by assuming all templates use fixed locals
19
+ template_opts: {
20
+ scope_class: self, # Always uses current class as scope class for compiled templates
21
+ freeze: true, # Freeze string literals in templates
22
+ extract_fixed_locals: true, # Support fixed locals in templates
23
+ default_fixed_locals: '()', # Default to templates not supporting local variables
24
+ escape: true, # For Erubi templates, escapes %= by default (use %== for unescaped
25
+ chain_appends: true, # For Erubi templates, improves performance
26
+ skip_compiled_encoding_detection: true, # Unless you need encodings explicitly specified
27
+ }
15
28
  }<% end %>
16
29
  }
17
30
  end
@@ -1,5 +1,6 @@
1
1
  class <%= context.const_project_name %>
2
- hash_branch "foo" do |r|
2
+ hash_branch "foo" do |r|<% if context.rodauth? %>
3
+ rodauth.require_authentication<% end %>
3
4
  r.get "bar" do
4
5
  <%= context.foo_bar_example %>
5
6
  end
@@ -3,7 +3,7 @@ require "thor"
3
3
  require "roda/project/bin/generators"
4
4
  <% if context.database? %>
5
5
  class Db < Thor
6
- desc "migrate", "Migrate the database. Optional: provide target version, e.g., 'roda db:migrate 1'"
6
+ desc "migrate", "Migrate the database (use RACK_ENV to migrate 'test' or 'production' environments). Optional: provide target version, e.g., 'roda db:migrate 1'"
7
7
  option :target, type: :numeric, aliases: "-t", desc: "provide target version"
8
8
  def migrate
9
9
  require_db_deps
@@ -148,6 +148,10 @@ class CLI < Thor
148
148
  desc "generate", "Commands to generate code"
149
149
  <%= context.to_thor_option %>
150
150
  subcommand "generate", Roda::Project::Bin::Generators
151
+
152
+ def self.exit_on_failure?
153
+ true
154
+ end
151
155
  end
152
156
 
153
157
  CLI.start(ARGV)
@@ -32,4 +32,10 @@ Providers::Mailer.boot
32
32
  Providers::Logger.boot
33
33
 
34
34
  # Consts<% if context.database %>
35
- DB = Providers::DB::Conn.get<% end %>
35
+ DB = Providers::DB::Conn.get
36
+
37
+ # Automatic models annotations in dev environment
38
+ if Config.not_production?
39
+ require 'sequel/annotate'
40
+ Sequel::Annotate.annotate(Dir['app/models/*.rb'], position: :before, border: true) rescue nil
41
+ end<% end %>
@@ -2,6 +2,6 @@
2
2
 
3
3
  class Roda
4
4
  module Project
5
- VERSION = "0.1.11"
5
+ VERSION = "0.1.13"
6
6
  end
7
7
  end
data/lib/roda/project.rb CHANGED
@@ -59,6 +59,7 @@ require_relative "project/helpers/inflections"
59
59
  # Base
60
60
  require_relative "project/main_context"
61
61
  require_relative "project/generator"
62
+ require_relative "project/jeremy_template_creator"
62
63
  require_relative "project/cli"
63
64
  require_relative "project/bin/generator"
64
65
  # Generators/migration
@@ -70,6 +71,8 @@ require_relative "project/bin/generators/migration/code_builder"
70
71
  require_relative "project/bin/generators/model"
71
72
  # Generators/routes
72
73
  require_relative "project/bin/generators/routes"
74
+ # Generators/service
75
+ require_relative "project/bin/generators/service"
73
76
  # Generators/base
74
77
  require_relative "project/bin/generators"
75
78
  # Version
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda-project
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henrique F. Teixeira
@@ -85,12 +85,14 @@ files:
85
85
  - lib/roda/project/bin/generators/migration/field_parser.rb
86
86
  - lib/roda/project/bin/generators/model.rb
87
87
  - lib/roda/project/bin/generators/routes.rb
88
+ - lib/roda/project/bin/generators/service.rb
88
89
  - lib/roda/project/cli.rb
89
90
  - lib/roda/project/generator.rb
90
91
  - lib/roda/project/helpers/ids.rb
91
92
  - lib/roda/project/helpers/inflections.rb
92
93
  - lib/roda/project/helpers/interactive_input.rb
93
94
  - lib/roda/project/helpers/template.rb
95
+ - lib/roda/project/jeremy_template_creator.rb
94
96
  - lib/roda/project/main_context.rb
95
97
  - lib/roda/project/templates/base/app/app.rb.erb
96
98
  - lib/roda/project/templates/base/minimal/AGENTS.md
@@ -103,15 +105,11 @@ files:
103
105
  - lib/roda/project/templates/base/minimal/boot.rb
104
106
  - lib/roda/project/templates/base/minimal/config.ru
105
107
  - lib/roda/project/templates/base/minimal/public/exception_page.css
106
- - lib/roda/project/templates/base/scaffold/AGENTS.md
108
+ - lib/roda/project/templates/base/scaffold/AGENTS.md.erb
107
109
  - lib/roda/project/templates/base/scaffold/Gemfile.erb
108
110
  - lib/roda/project/templates/base/scaffold/Guardfile
109
111
  - lib/roda/project/templates/base/scaffold/README.md
110
112
  - lib/roda/project/templates/base/scaffold/app/config/config.rb.erb
111
- - lib/roda/project/templates/base/scaffold/app/config/locales/en.yml
112
- - lib/roda/project/templates/base/scaffold/app/config/locales/foo/en.yml
113
- - lib/roda/project/templates/base/scaffold/app/config/locales/foo/pt-br.yml
114
- - lib/roda/project/templates/base/scaffold/app/config/locales/pt-br.yml
115
113
  - lib/roda/project/templates/base/scaffold/app/config/providers/logger.rb
116
114
  - lib/roda/project/templates/base/scaffold/app/config/providers/mailer.rb
117
115
  - lib/roda/project/templates/base/scaffold/app/routes/foo.rb.erb
@@ -124,6 +122,10 @@ files:
124
122
  - lib/roda/project/templates/front-end/app/assets/css/app.css
125
123
  - lib/roda/project/templates/front-end/app/assets/js/app.js
126
124
  - lib/roda/project/templates/front-end/app/assets/js/some/foo.js
125
+ - lib/roda/project/templates/front-end/app/config/locales/en.yml
126
+ - lib/roda/project/templates/front-end/app/config/locales/foo/en.yml
127
+ - lib/roda/project/templates/front-end/app/config/locales/foo/pt-br.yml
128
+ - lib/roda/project/templates/front-end/app/config/locales/pt-br.yml
127
129
  - lib/roda/project/templates/front-end/app/views/foo/bar.erb
128
130
  - lib/roda/project/templates/front-end/app/views/index.erb
129
131
  - lib/roda/project/templates/front-end/app/views/layout.erb
@@ -1,9 +0,0 @@
1
- Act as a Ruby specialist.
2
-
3
- This is a web application written using the Roda web framework
4
-
5
- ## Project guidelines
6
-
7
- - **Never** deliver code without tests validating the code (execute with `rake test`)
8
- - **Never** write long comments in the code
9
- - **Always** use clean code