schienenzeppelin 0.1 → 0.2

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 (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>