schienenzeppelin 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +5 -1
  4. data/.tool-versions +1 -1
  5. data/CHANGELOG.md +1 -0
  6. data/Gemfile +1 -0
  7. data/Gemfile.lock +78 -71
  8. data/TODO.md +37 -25
  9. data/lib/schienenzeppelin.rb +5 -2
  10. data/lib/schienenzeppelin/add_on.rb +68 -0
  11. data/lib/schienenzeppelin/{helpers → addons}/annotate.rb +4 -2
  12. data/lib/schienenzeppelin/{helpers → addons}/capistrano.rb +2 -2
  13. data/lib/schienenzeppelin/{helpers → addons}/continuous_integration.rb +2 -2
  14. data/lib/schienenzeppelin/{helpers → addons}/credentials.rb +2 -2
  15. data/lib/schienenzeppelin/{helpers → addons}/devise.rb +6 -3
  16. data/lib/schienenzeppelin/addons/docker.rb +12 -0
  17. data/lib/schienenzeppelin/addons/docker_compose.rb +11 -0
  18. data/lib/schienenzeppelin/addons/dotenv.rb +11 -0
  19. data/lib/schienenzeppelin/{helpers → addons}/errors.rb +5 -2
  20. data/lib/schienenzeppelin/{helpers → addons}/factory_bot.rb +6 -2
  21. data/lib/schienenzeppelin/addons/foreman.rb +13 -0
  22. data/lib/schienenzeppelin/addons/generators.rb +30 -0
  23. data/lib/schienenzeppelin/{helpers → addons}/high_voltage.rb +4 -2
  24. data/lib/schienenzeppelin/addons/inline_svg.rb +9 -0
  25. data/lib/schienenzeppelin/{helpers/scaffold.rb → addons/irbrc.rb} +3 -3
  26. data/lib/schienenzeppelin/addons/jb.rb +9 -0
  27. data/lib/schienenzeppelin/{helpers/hotwire.rb → addons/lograge.rb} +3 -3
  28. data/lib/schienenzeppelin/addons/oj.rb +9 -0
  29. data/lib/schienenzeppelin/{helpers → addons}/pundit.rb +2 -2
  30. data/lib/schienenzeppelin/{helpers → addons}/rspec.rb +4 -2
  31. data/lib/schienenzeppelin/{helpers → addons}/rubocop.rb +2 -2
  32. data/lib/schienenzeppelin/addons/ruby_version.rb +11 -0
  33. data/lib/schienenzeppelin/addons/scaffold.rb +13 -0
  34. data/lib/schienenzeppelin/{helpers → addons}/services.rb +2 -2
  35. data/lib/schienenzeppelin/addons/shoulda.rb +13 -0
  36. data/lib/schienenzeppelin/{helpers → addons}/sidekiq.rb +3 -4
  37. data/lib/schienenzeppelin/{helpers → addons}/stimulus.rb +4 -2
  38. data/lib/schienenzeppelin/{helpers → addons}/stimulus_components.rb +4 -2
  39. data/lib/schienenzeppelin/{helpers → addons}/tailwind.rb +4 -2
  40. data/lib/schienenzeppelin/{helpers/home.rb → addons/views.rb} +5 -3
  41. data/lib/schienenzeppelin/app_builder.rb +2 -50
  42. data/lib/schienenzeppelin/app_generator.rb +53 -61
  43. data/lib/schienenzeppelin/context.rb +26 -0
  44. data/lib/schienenzeppelin/dependencies.rb +33 -0
  45. data/lib/schienenzeppelin/generator_utils.rb +77 -0
  46. data/lib/schienenzeppelin/version.rb +2 -2
  47. data/schienenzeppelin.gemspec +0 -1
  48. data/templates/.irbrc.erb +2 -2
  49. data/templates/Dockerfile.erb +1 -1
  50. data/templates/Gemfile.erb +39 -10
  51. data/templates/Procfile.dev.erb +5 -1
  52. data/templates/Procfile.erb +2 -0
  53. data/templates/app/views/shared/_navbar.html.erb.tt +19 -4
  54. data/templates/app/workers/application_worker.rb +5 -0
  55. data/templates/docker-compose.yml.erb +2 -2
  56. data/templates/spec/rails_helper.rb +1 -1
  57. metadata +41 -27
  58. data/.rspec_status +0 -3
  59. data/lib/schienenzeppelin/helper_base.rb +0 -28
  60. data/lib/schienenzeppelin/helpers/generators.rb +0 -26
@@ -2,84 +2,76 @@
2
2
 
3
3
  module Schienenzeppelin
4
4
  class AppGenerator < Rails::Generators::AppGenerator
5
- class_option :database,
6
- type: :string,
7
- aliases: '-d',
8
- default: 'postgresql',
9
- desc: "Preconfigure for selected database (options: #{DATABASES.join('/')})"
10
-
11
- class_option :skip_active_job,
12
- type: :boolean, default: true,
13
- desc: 'Skip Active Job'
14
-
15
- class_option :skip_jbuilder,
16
- type: :boolean,
17
- default: true,
18
- desc: 'Skip jbuilder gem'
19
-
20
- class_option :skip_test,
21
- type: :boolean,
22
- aliases: '-T', default: true,
23
- desc: 'Skip test files'
24
-
25
- class_option :skip_sidekiq,
26
- type: :boolean, default: false,
27
- desc: 'Skip sidekiq'
28
-
29
- class_option :skip_rspec,
30
- type: :boolean,
31
- aliases: '-T', default: false,
32
- desc: 'Skip rspec'
33
-
34
- def create_config_files
5
+ include GeneratorUtils
6
+ overwrite_default_options!
7
+
8
+ generate_addon_options!
9
+
10
+ generate_addon_skips!
11
+
12
+ def initialize(*args)
35
13
  super
36
- Schienenzeppelin::Helpers::Generators.apply
14
+
15
+ return unless options[:api]
16
+
17
+ self.options = options.merge(
18
+ skip_errors: true,
19
+ skip_high_voltage: true,
20
+ skip_stimulus: true,
21
+ skip_tailwind: true,
22
+ skip_views: true
23
+ ).freeze
37
24
  end
38
25
 
39
26
  def create_root_files
40
27
  super
41
28
 
42
- build(:irbrc)
43
- build(:foreman)
44
- build(:dotenv)
45
- build(:docker)
46
- build(:docker_compose)
47
- # TODO: Make optional
48
- # Schienenzeppelin::Helpers::Rubocop.apply
29
+ add(:irbrc)
30
+ add(:foreman)
31
+ add(:dotenv)
32
+ add(:docker)
33
+ add(:docker_compose)
34
+ add(:rubocop)
49
35
  end
50
36
 
51
37
  def create_test_files
52
- build(:test) unless options[:skip_test]
53
- build(:rspec) unless options[:skip_rspec]
54
- build(:factory_bot) unless options[:skip_factory_bot]
55
- build(:shoulda) unless options[:skip_shoulda]
38
+ return if options[:skip_test]
39
+
40
+ super if options[:testing_framework] == 'minitest'
41
+
42
+ add(:rspec) if options[:testing_framework] == 'rspec'
56
43
  end
57
44
 
58
45
  def finish_template
59
46
  super
60
47
  # These require the presence of config/controllers, so they must be done after everything else
61
- Schienenzeppelin::Helpers::Annotate.apply
62
- build(:lograge)
63
- build(:high_voltage)
64
- build(:pundit)
65
- Schienenzeppelin::Helpers::Services.apply unless options[:skip_services]
66
- build(:sidekiq)
48
+ add(:annotate)
49
+ add(:continuous_integration)
50
+ add(:high_voltage)
51
+ add(:generators)
52
+ add(:lograge)
53
+ add(:pundit)
54
+ add(:services)
55
+ add(:sidekiq)
56
+ add(:views, :errors, :scaffold)
57
+
58
+ add(:factory_bot)
59
+ add(:shoulda)
67
60
  end
68
61
 
69
62
  def after_install
70
- Schienenzeppelin::Helpers::Devise.apply
71
- Schienenzeppelin::Helpers::Stimulus.apply
72
- # TODO: Re-enable with Rails 6.2
73
- # Schienenzeppelin::Helpers::Hotwire.apply
74
- Schienenzeppelin::Helpers::Tailwind.apply
75
- Schienenzeppelin::Helpers::StimulusComponents.apply
76
-
77
- Schienenzeppelin::Helpers::Home.apply
78
- Schienenzeppelin::Helpers::Errors.apply
79
- Schienenzeppelin::Helpers::Scaffold.apply
80
-
81
- Schienenzeppelin::Helpers::ContinuousIntegration.apply
82
- Schienenzeppelin::Helpers::Capistrano.apply
63
+ add(:tailwind, :stimulus, :stimulus_components)
64
+ add(:devise)
65
+ add(:capistrano)
66
+ end
67
+
68
+ no_tasks do
69
+ def uses?(addon)
70
+ return false if options["skip_#{addon}".to_sym]
71
+
72
+ addon = AddOn.get(addon)
73
+ Dependencies.new(addon, context).satisfied?
74
+ end
83
75
  end
84
76
 
85
77
  def self.banner
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schienenzeppelin
4
+ class Context
5
+ attr_reader :options, :callbacks
6
+
7
+ def initialize(options = {})
8
+ @options = options
9
+ @callbacks = []
10
+ end
11
+
12
+ def addons
13
+ AddOns.constants
14
+ .select { |clazz| AddOns.const_get(clazz).is_a?(Class) }
15
+ .map(&:name)
16
+ .map(&:underscore)
17
+ end
18
+
19
+ # Skippable parts of the default Rails generator, e.g. active_record, active_job...
20
+ def default_addons
21
+ addon_options = addons.map { |option| "skip_#{option}".to_sym }
22
+ skip_options = Schienenzeppelin::AppGenerator.class_options.keys.select { |key| key =~ /skip_/ }
23
+ (skip_options - addon_options).map { |option| option.to_s.delete_prefix('skip_').to_sym }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schienenzeppelin
4
+ class Dependencies
5
+ def initialize(addon, context)
6
+ @addon = addon
7
+ @context = context
8
+ @options = context.options
9
+ end
10
+
11
+ def satisfied?
12
+ @addon.dependencies.each do |dependency|
13
+ return false unless dependencies_satisfied?(dependency)
14
+ end
15
+
16
+ true
17
+ end
18
+
19
+ private
20
+
21
+ def dependencies_satisfied?(addon, visited = [])
22
+ return false if @options["skip_#{addon}".to_sym]
23
+
24
+ return true if @context.default_addons.include?(addon)
25
+
26
+ visited << addon
27
+ dependencies = AddOn.get(addon).dependencies - visited
28
+ dependencies.each do |dependency|
29
+ return false unless dependencies_satisfied?(dependency, visited)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Schienenzeppelin
4
+ module GeneratorUtils
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ protected
10
+
11
+ def context
12
+ @context ||= Context.new(options)
13
+ end
14
+
15
+ private
16
+
17
+ def add(*addons)
18
+ addons.each do |addon|
19
+ addon = addon.to_s.capitalize.camelize
20
+ "Schienenzeppelin::AddOns::#{addon}"
21
+ .constantize
22
+ .apply(context)
23
+ end
24
+ end
25
+
26
+ module ClassMethods
27
+ def overwrite_default_options!
28
+ databases = Rails::Generators::Database::DATABASES
29
+ class_option :database,
30
+ type: :string,
31
+ aliases: '-d',
32
+ default: 'postgresql',
33
+ desc: "Preconfigure for selected database (options: #{databases.join('/')})"
34
+
35
+ class_option :skip_active_job,
36
+ type: :boolean,
37
+ default: true,
38
+ desc: 'Skip Active Job'
39
+ end
40
+
41
+ def generate_addon_options!
42
+ test_frameworks = %w[minitest rspec]
43
+ class_option :test_framework,
44
+ type: :string,
45
+ default: 'rspec',
46
+ desc: "Select a testing framework (options: #{test_frameworks.join('/')})"
47
+
48
+ background_jobs = %w[sidekiq].freeze
49
+ class_option :background_jobs,
50
+ type: :string,
51
+ default: 'sidekiq',
52
+ desc: "Select a background processing (options: #{background_jobs.join('/')})"
53
+
54
+ deployments = %w[capistrano].freeze
55
+ class_option :deployment,
56
+ type: :string,
57
+ default: 'capistrano',
58
+ desc: "Select a deployment option (options: #{deployments.join('/')})"
59
+
60
+ version_managers = %w[asdf].freeze
61
+ class_option :version_manger,
62
+ type: :string,
63
+ default: 'asdf',
64
+ desc: "Select your Version Manager (options: #{version_managers.join('/')})"
65
+ end
66
+
67
+ def generate_addon_skips!
68
+ Context.new.addons.each do |addon|
69
+ class_option "skip_#{addon}".to_sym,
70
+ type: :boolean,
71
+ default: false,
72
+ desc: "Skip #{addon.underscore.titleize}"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Schienenzeppelin
4
- VERSION = '0.1'
5
- RAILS_VERSION = '~> 6.1.2'
4
+ VERSION = '0.2'
5
+ RAILS_VERSION = '~> 6.1.3'
6
6
  RUBY_VERSION = '3.0.0'
7
7
  end
@@ -8,7 +8,6 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Schienenzeppelin::VERSION
9
9
  spec.authors = ['Hans-Jörg Schnedlitz']
10
10
  spec.email = ['hans.schnedlitz@gmail.com']
11
- spec.date = Date.today.strftime('%Y-%m-%d')
12
11
 
13
12
  spec.summary = 'The Rails app generator that gets you started quickly'
14
13
  spec.description = <<~HEREDOC
data/templates/.irbrc.erb CHANGED
@@ -7,6 +7,6 @@ IRB.conf[:SAVE_HISTORY] = 1000
7
7
  IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-history"
8
8
  IRB.conf[:PROMPT_MODE] = :SIMPLE
9
9
 
10
- <% unless options[:skip_factory_bot] %>
10
+ <% if uses?(:factory_bot) -%>
11
11
  include FactoryBot::Syntax::Methods
12
- <% end %>
12
+ <% end -%>
@@ -22,7 +22,7 @@ RUN bundle install --without development
22
22
  RUN yarn install
23
23
 
24
24
  FROM cache
25
- COPY . /bookstore
25
+ COPY . /<%= app_name %>
26
26
 
27
27
  ARG DATABASE_HOST=db
28
28
  ARG RAILS_ENV=production
@@ -26,30 +26,49 @@ ruby <%= "'#{RUBY_VERSION}'" -%>
26
26
  # gem 'image_processing', '~> 1.2'
27
27
  <% end -%>
28
28
 
29
+ # Schienenzeppelin
30
+ gem 'schienenzeppelin', '<%= Gem::Version.new(Schienenzeppelin::VERSION).approximate_recommendation %>'
31
+ <% if uses?(:jb) -%>
29
32
  # Jb is a faster alternative to jbuilder"
30
33
  gem 'jb', '~> 0.8'
34
+ <% end -%>
35
+ <% if uses?(:oj) -%>
31
36
  # A fast JSON parser and Object marshaller
32
37
  gem 'oj', '~> 3.11'
38
+ <% end -%>
39
+ <% if uses?(:lograge) -%>
33
40
  # An attempt to tame noisy Rails logs
34
41
  gem "lograge"
42
+ <% end -%>
43
+ <% if uses?(:pundit) -%>
35
44
  # Minimal and simple authorization through OO
36
45
  gem 'pundit', '~> 2.1'
46
+ <% end -%>
47
+ <% if uses?(:devise) -%>
37
48
  # Flexible authentication solution for Rails with Warden
38
49
  gem 'devise', '~> 4.7'
50
+ <% end -%>
39
51
 
52
+ <% if uses?(:high_voltage) -%>
40
53
  # A Rails engine for static pages
41
54
  gem 'high_voltage', '~> 3.1'
42
- # Hotwire is an alternative approach to building modern web applications
43
- gem 'hotwire-rails'
55
+ <% end -%>
56
+ <% if uses?(:stimulus) -%>
44
57
  # Add javascript sprinkles to your views
45
58
  gem 'stimulus-rails'
59
+ <% end -%>
60
+ <% if uses?(:tailwind) -%>
46
61
  # Tailwind CSS for Rails
47
62
  gem 'tailwindcss-rails'
63
+ <% end -%>
64
+ <% if uses?(:inline_svg) -%>
48
65
  # Embedded SVGs for easy styling
49
66
  gem 'inline_svg'
50
-
67
+ <% end -%>
68
+ <% if uses?(:sidekiq) -%>
51
69
  # Simple, efficient background processing alternative to ActiveJob
52
70
  gem 'sidekiq', '~> 6.1'
71
+ <% end -%>
53
72
 
54
73
  <% if depend_on_bootsnap? -%>
55
74
  # Reduces boot times through caching; required in config/boot.rb
@@ -65,21 +84,24 @@ gem 'bootsnap', '>= 1.4.4', require: false
65
84
  group :development, :test do
66
85
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
67
86
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
87
+ <% if uses?(:dotenv) -%>
68
88
  # A convenient way to manage environment variables
69
89
  gem 'dotenv-rails'
70
- gem 'rubocop', '~> 1.10', require: false
71
- <%- unless options[:skip_rspec] -%>
72
- gem "rspec-rails"
73
90
  <% end -%>
74
- <%- unless options[:skip_factory_bot] -%>
91
+
92
+ <% if uses?(:factory_bot) -%>
75
93
  gem "factory_bot_rails"
76
94
  <% end -%>
95
+ <% if uses?(:rspec) -%>
96
+ gem "rspec-rails"
97
+ <% end -%>
98
+ <% if uses?(:rubocop) -%>
99
+ gem 'rubocop', '~> 1.10', require: false
100
+ <% end -%>
77
101
  end
78
102
 
79
103
  <% end -%>
80
104
  group :development do
81
- # Add a comment summarizing the current schema to your code
82
- gem 'annotate', '~> 3.1'
83
105
  <%- unless options.api? || options.skip_dev_gems? -%>
84
106
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
85
107
  <%- if options.dev? || options.edge? || options.main? -%>
@@ -98,15 +120,22 @@ group :development do
98
120
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
99
121
  gem 'spring'
100
122
  <% end -%>
123
+
124
+ <%if uses?(:annotate) -%>
125
+ # Add a comment summarizing the current schema to your code
126
+ gem 'annotate', '~> 3.1'
127
+ <%end -%>
128
+ <% if uses?(:capistrano) -%>
101
129
  # Capistrano is used to deploy your application
102
130
  gem "capistrano", "~> 3.15", require: false
103
131
  gem "capistrano-rails", "~> 1.6", require: false
104
132
  gem 'capistrano-passenger', '~> 0.2.0', require: false
105
133
  gem 'capistrano-rbenv', '~> 2.2', '>= 2.1.4', require: false
134
+ <% end -%>
106
135
  end
107
136
 
108
137
  group :test do
109
- <%- unless options[:skip_shoulda] -%>
138
+ <% if uses?(:shoulda) -%>
110
139
  gem "shoulda-matchers"
111
140
  <% end -%>
112
141
  <%- if depends_on_system_test? -%>
@@ -1,6 +1,10 @@
1
+ <% if uses?(:docker_compose) -%>
1
2
  docker: docker-compose up --scale <%= app_name %>=0
2
- <%- unless options[:skip_sidekiq] -%>
3
+ <% end -%>
4
+ <% if uses?(:sidekiq) -%>
3
5
  sidekiq: bundle exec sidekiq
4
6
  <% end -%>
7
+ <% if uses?(:webpack_install) -%>
5
8
  webpack: bundle exec bin/webpack-dev-server
9
+ <% end -%>
6
10
  web: bundle exec rails server -p 3000
@@ -1,2 +1,4 @@
1
1
  web: rails server
2
+ <% if uses?(:sidekiq) -%>
2
3
  worker: sidekiq
4
+ <% end -%>
@@ -1,19 +1,30 @@
1
1
  <header class="shadow">
2
2
  <nav
3
+ <%-if uses?(:stimulus_components) -%>
3
4
  data-controller="dropdown"
5
+ <%- end -%>
4
6
  class="container mx-auto flex flex-wrap justify-between items-center p-5">
5
7
  <div>
6
8
  <a
7
9
  class="flex items-center mr-2"
8
- href="<%%= root_path %>">
10
+ <%- if uses?(:high_voltage) -%>
11
+ href="<%%= root_path %>"
12
+ <%- else -%>
13
+ href="/"
14
+ <%- end -%>
15
+ >
16
+ <%- if uses?(:inline_svg) -%>
9
17
  <%%= inline_svg_pack_tag('media/images/logo.svg', class: "rounded mx-2", size: "3rem * 3rem") %>
18
+ <%- end -%>
10
19
  <p class="font-bold text-lg"><%= app_name.capitalize %> </p>
11
20
  </a>
12
21
  </div>
13
22
  <div class="flex md:hidden">
14
- <button data-action="click->dropdown#toggle click@window->dropdown#hide"
15
- class="px-3 py-2 border border-gray-500 rounded text-grey hover:text-gray-600 hover:border-gray-600"
16
- >
23
+ <button
24
+ <%- if uses?(:stimulus_components) -%>
25
+ data-action="click->dropdown#toggle click@window->dropdown#hide"
26
+ <%- end -%>
27
+ class="px-3 py-2 border border-gray-500 rounded text-grey hover:text-gray-600 hover:border-gray-600" >
17
28
  <svg class="w-3 h-3 fill-current" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
18
29
  <title>Menu</title>
19
30
  <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"/>
@@ -21,11 +32,14 @@
21
32
  </button>
22
33
  </div>
23
34
  <div
35
+ <%-if uses?(:stimulus_components) -%>
24
36
  data-dropdown-target="menu"
37
+ <%- end -%>
25
38
  class="hidden md:flex-grow md:flex w-full md:w-auto text-right md:text-left text-bold mt-5 md:mt-0 border-t-2 border-gray-200 md:border-none">
26
39
  <div class="justify-start flex-grow">
27
40
  <!-- SZ Link Placeholder -->
28
41
  </div>
42
+ <%-if uses?(:devise) -%>
29
43
  <ul class="w-full flex-col md:flex md:flex-row items-center justify-end md:w-auto">
30
44
  <%% if user_signed_in? %>
31
45
  <li><%%= link_to "Edit account", edit_user_registration_path, class: "btn btn-default md:mr-2 my-2 md:my-0 " %></li>
@@ -35,6 +49,7 @@
35
49
  <li><%%= link_to "Sign Up", new_user_registration_path, class: "btn btn-blue" %></li>
36
50
  <%% end %>
37
51
  </ul>
52
+ <%- end -%>
38
53
  </div>
39
54
  </nav>
40
55
  </header>