potassium 5.2.2 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +103 -28
  3. data/.circleci/setup-rubygems.sh +3 -0
  4. data/.gitignore +2 -1
  5. data/.node-version +1 -0
  6. data/.rubocop.yml +530 -0
  7. data/.ruby-version +1 -1
  8. data/CHANGELOG.md +92 -1
  9. data/README.md +51 -45
  10. data/docs/DSL.md +5 -5
  11. data/lib/potassium/assets/.circleci/config.yml.erb +151 -0
  12. data/lib/potassium/assets/.eslintrc.json +352 -0
  13. data/lib/potassium/assets/.github/pull_request_template.md +9 -0
  14. data/lib/potassium/assets/.rubocop.yml +528 -0
  15. data/lib/potassium/assets/.stylelintrc.json +46 -0
  16. data/lib/potassium/assets/Makefile.erb +21 -32
  17. data/lib/potassium/assets/README.yml +59 -15
  18. data/lib/potassium/assets/active_admin/admin-component.vue +35 -0
  19. data/lib/potassium/assets/active_admin/admin_application.js +14 -0
  20. data/lib/potassium/assets/active_admin/init_activeadmin_vue.rb +10 -0
  21. data/lib/potassium/assets/app/graphql/graphql_controller.rb +55 -0
  22. data/lib/potassium/assets/app/graphql/mutations/login_mutation.rb +23 -0
  23. data/lib/potassium/assets/app/graphql/queries/base_query.rb +4 -0
  24. data/lib/potassium/assets/app/graphql/types/base/base_argument.rb +4 -0
  25. data/lib/potassium/assets/app/graphql/types/base/base_enum.rb +4 -0
  26. data/lib/potassium/assets/app/graphql/types/base/base_field.rb +5 -0
  27. data/lib/potassium/assets/app/graphql/types/base/base_input_object.rb +5 -0
  28. data/lib/potassium/assets/app/graphql/types/base/base_interface.rb +7 -0
  29. data/lib/potassium/assets/app/graphql/types/base/base_object.rb +5 -0
  30. data/lib/potassium/assets/app/graphql/types/base/base_scalar.rb +4 -0
  31. data/lib/potassium/assets/app/graphql/types/base/base_union.rb +4 -0
  32. data/lib/potassium/assets/app/graphql/types/mutation_type.rb +10 -0
  33. data/lib/potassium/assets/app/graphql/types/query_type.rb +13 -0
  34. data/lib/potassium/assets/app/javascript/app.spec.js +14 -0
  35. data/lib/potassium/assets/app/uploaders/base_uploader.rb +11 -0
  36. data/lib/potassium/assets/app/uploaders/image_uploader.rb +5 -0
  37. data/lib/potassium/assets/app/views/shared/_gtm_body.html.erb +4 -0
  38. data/lib/potassium/assets/app/views/shared/_gtm_head.html.erb +7 -0
  39. data/lib/potassium/assets/bin/release +1 -1
  40. data/lib/potassium/assets/bin/setup.erb +1 -1
  41. data/lib/potassium/assets/config/database_mysql.yml.erb +2 -2
  42. data/lib/potassium/assets/config/database_postgresql.yml.erb +2 -2
  43. data/lib/potassium/assets/config/graphql_playground.rb +20 -0
  44. data/lib/potassium/assets/config/puma.rb +1 -1
  45. data/lib/potassium/assets/config/shrine.rb +36 -0
  46. data/lib/potassium/assets/lib/tasks/auto_annotate_models.rake +2 -1
  47. data/lib/potassium/assets/package.json +4 -1
  48. data/lib/potassium/assets/redis.yml +1 -2
  49. data/lib/potassium/assets/testing/rails_helper.rb +2 -0
  50. data/lib/potassium/cli/commands/create.rb +12 -19
  51. data/lib/potassium/cli_options.rb +77 -26
  52. data/lib/potassium/helpers/gem-helpers.rb +1 -1
  53. data/lib/potassium/helpers/template-helpers.rb +8 -0
  54. data/lib/potassium/newest_version_ensurer.rb +19 -36
  55. data/lib/potassium/node_version_ensurer.rb +30 -0
  56. data/lib/potassium/recipes/admin.rb +3 -3
  57. data/lib/potassium/recipes/annotate.rb +1 -1
  58. data/lib/potassium/recipes/api.rb +93 -21
  59. data/lib/potassium/recipes/background_processor.rb +66 -19
  60. data/lib/potassium/recipes/ci.rb +10 -38
  61. data/lib/potassium/recipes/data_migrate.rb +44 -0
  62. data/lib/potassium/recipes/database.rb +4 -0
  63. data/lib/potassium/recipes/database_container.rb +7 -5
  64. data/lib/potassium/recipes/draper.rb +1 -10
  65. data/lib/potassium/recipes/file_storage.rb +66 -0
  66. data/lib/potassium/recipes/front_end.rb +225 -9
  67. data/lib/potassium/recipes/github.rb +93 -15
  68. data/lib/potassium/recipes/google_tag_manager.rb +90 -0
  69. data/lib/potassium/recipes/heroku.rb +42 -29
  70. data/lib/potassium/recipes/mailer.rb +18 -2
  71. data/lib/potassium/recipes/monitoring.rb +5 -0
  72. data/lib/potassium/recipes/node.rb +21 -0
  73. data/lib/potassium/recipes/rack_cors.rb +18 -15
  74. data/lib/potassium/recipes/schedule.rb +17 -2
  75. data/lib/potassium/recipes/style.rb +21 -3
  76. data/lib/potassium/recipes/vue_admin.rb +124 -0
  77. data/lib/potassium/templates/application.rb +10 -7
  78. data/lib/potassium/version.rb +7 -4
  79. data/potassium.gemspec +11 -6
  80. data/spec/features/api_spec.rb +25 -0
  81. data/spec/features/background_processor_spec.rb +19 -6
  82. data/spec/features/ci_spec.rb +7 -4
  83. data/spec/features/data_migrate_spec.rb +14 -0
  84. data/spec/features/database_container_spec.rb +1 -5
  85. data/spec/features/draper_spec.rb +1 -6
  86. data/spec/features/file_storage_spec.rb +75 -0
  87. data/spec/features/front_end_spec.rb +102 -0
  88. data/spec/features/github_spec.rb +53 -8
  89. data/spec/features/google_tag_manager_spec.rb +59 -0
  90. data/spec/features/graphql_spec.rb +71 -0
  91. data/spec/features/heroku_spec.rb +1 -1
  92. data/spec/features/mailer_spec.rb +16 -0
  93. data/spec/features/new_project_spec.rb +6 -14
  94. data/spec/features/node_spec.rb +28 -0
  95. data/spec/features/power_types_spec.rb +5 -16
  96. data/spec/features/schedule_spec.rb +11 -4
  97. data/spec/features/vue_admin_spec.rb +47 -0
  98. data/spec/spec_helper.rb +5 -0
  99. data/spec/support/fake_octokit.rb +31 -0
  100. data/spec/support/potassium_test_helpers.rb +26 -9
  101. data/tmp/.keep +0 -0
  102. metadata +152 -46
  103. data/lib/potassium/assets/.circleci/config.yml +0 -20
  104. data/lib/potassium/assets/Dockerfile.ci +0 -6
  105. data/lib/potassium/assets/active_admin/active_admin.js.coffee +0 -4
  106. data/lib/potassium/assets/active_admin/init_activeadmin_angular.rb +0 -8
  107. data/lib/potassium/assets/api/api_error_concern.rb +0 -32
  108. data/lib/potassium/assets/api/base_controller.rb +0 -9
  109. data/lib/potassium/assets/api/draper_responder.rb +0 -62
  110. data/lib/potassium/assets/api/responder.rb +0 -41
  111. data/lib/potassium/assets/aws.rb +0 -1
  112. data/lib/potassium/assets/bin/cibuild.erb +0 -100
  113. data/lib/potassium/assets/docker-compose.ci.yml +0 -11
  114. data/lib/potassium/assets/sidekiq_scheduler.yml +0 -9
  115. data/lib/potassium/assets/testing/paperclip.rb +0 -59
  116. data/lib/potassium/recipes/active_storage.rb +0 -40
  117. data/lib/potassium/recipes/angular_admin.rb +0 -56
  118. data/lib/potassium/recipes/aws_sdk.rb +0 -7
  119. data/lib/potassium/recipes/paperclip.rb +0 -47
  120. data/spec/features/active_storage_spec.rb +0 -30
  121. data/spec/features/front_end.rb +0 -30
@@ -0,0 +1,90 @@
1
+ class Recipes::GoogleTagManager < Rails::AppBuilder
2
+ def ask
3
+ use_google_tag_manager = answer(:google_tag_manager) do
4
+ Ask.confirm 'Do you want to use Google Tag Manager?'
5
+ end
6
+
7
+ set(:google_tag_manager, use_google_tag_manager)
8
+ end
9
+
10
+ def create
11
+ install if selected?(:google_tag_manager)
12
+ end
13
+
14
+ def install
15
+ add_google_tag_manager
16
+ end
17
+
18
+ def add_google_tag_manager
19
+ copy_tag_manager_files
20
+ append_to_file '.env.development', "GTM_CONTAINER_ID=\n"
21
+ include_tag_manager
22
+ add_content_security_policy
23
+ end
24
+
25
+ def add_content_security_policy
26
+ inject_into_file(
27
+ 'config/initializers/content_security_policy.rb',
28
+ content_security_policy_code
29
+ )
30
+ end
31
+
32
+ def copy_tag_manager_files
33
+ copy_file(
34
+ '../assets/app/views/shared/_gtm_head.html.erb',
35
+ 'app/views/shared/_gtm_head.html.erb',
36
+ force: true
37
+ )
38
+
39
+ copy_file(
40
+ '../assets/app/views/shared/_gtm_body.html.erb',
41
+ 'app/views/shared/_gtm_body.html.erb',
42
+ force: true
43
+ )
44
+ end
45
+
46
+ def include_tag_manager
47
+ inject_into_file(
48
+ 'app/views/layouts/application.html.erb',
49
+ render_string('shared/gtm_head'),
50
+ before: '</head>'
51
+ )
52
+
53
+ inject_into_file(
54
+ 'app/views/layouts/application.html.erb',
55
+ render_string('shared/gtm_body'),
56
+ after: '<body>'
57
+ )
58
+ end
59
+
60
+ private
61
+
62
+ def render_string(file_path)
63
+ " <%if Rails.env.production? %>
64
+ <%= render \"#{file_path}\" %>
65
+ <% end %>\n "
66
+ end
67
+
68
+ def content_security_policy_code
69
+ <<~HERE
70
+ Rails.application.config.content_security_policy do |policy|
71
+ if Rails.env.development?
72
+ policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035'
73
+ policy.script_src :self, :https, :unsafe_eval
74
+ else
75
+ policy.script_src :self, :https
76
+ # google tag manager requires to enable unsafe inline:
77
+ # https://developers.google.com/tag-manager/web/csp
78
+ policy.connect_src :self, :https, 'https://www.google-analytics.com'
79
+ policy.script_src :self,
80
+ :https,
81
+ :unsafe_inline,
82
+ 'https://www.googletagmanager.com',
83
+ 'https://www.google-analytics.com',
84
+ 'https://ssl.google-analytics.com'
85
+ policy.img_src :self, :https, 'https://www.googletagmanager.com', 'https://www.google-analytics.com'
86
+ end
87
+ end
88
+ HERE
89
+ end
90
+ end
@@ -1,13 +1,7 @@
1
1
  class Recipes::Heroku < Rails::AppBuilder
2
2
  NAME_PREFIX = 'pl'
3
-
4
- attr_accessor :app_name_staging
5
-
6
- def initialize(args)
7
- super(args)
8
- set(:heroku_app_name_staging, app_name_for('staging'))
9
- set(:heroku_app_name_production, app_name_for('production'))
10
- end
3
+ ENVIRONMENTS = ['staging', 'production']
4
+ HEROKU_NAMES_MAX_CHARS = 30
11
5
 
12
6
  def ask
13
7
  heroku = answer(:heroku) do
@@ -16,6 +10,8 @@ class Recipes::Heroku < Rails::AppBuilder
16
10
 
17
11
  if heroku
18
12
  set(:heroku, heroku)
13
+
14
+ ENVIRONMENTS.each { |environment| set_app_name_for(environment) }
19
15
  end
20
16
  end
21
17
 
@@ -47,31 +43,34 @@ class Recipes::Heroku < Rails::AppBuilder
47
43
  template "../assets/bin/setup_heroku.erb", "bin/setup_heroku", force: true
48
44
  run "chmod a+x bin/setup_heroku"
49
45
 
50
- if logged_in?
51
- %w(staging production).each do |environment|
52
- create_app_on_heroku(environment)
53
- end
54
- puts "Remember to connect the github repository to the new pipeline"
55
- open_pipeline_command = "\e[33mheroku pipelines:open #{heroku_pipeline_name}\e[0m"
56
- puts "run #{open_pipeline_command} to open the dashboard"
57
- else
58
- puts "You are not logged in into heroku"
59
- login_command = "\e[33mheroku login\e[0m"
60
- puts "Run #{login_command} and enter your credentials"
61
- puts "You can install the heroku recipe again create the app in heroku"
62
- install_command = "\e[33mpostassium install heroku --force\e[0m"
63
- puts "Just run #{install_command}"
64
- end
46
+ logged_in? ? create_apps : puts_not_logged_in_msg
65
47
 
66
48
  add_readme_header :deployment
67
49
  end
68
50
 
51
+ def create_apps
52
+ ENVIRONMENTS.each { |environment| create_app_on_heroku(environment) }
53
+ puts "Remember to connect the github repository to the new pipeline"
54
+ open_pipeline_command = "\e[33mheroku pipelines:open #{heroku_pipeline_name}\e[0m"
55
+ puts "run #{open_pipeline_command} to open the dashboard"
56
+ end
57
+
58
+ def puts_not_logged_in_msg
59
+ puts "You are not logged in into heroku"
60
+ login_command = "\e[33mheroku login\e[0m"
61
+ puts "Run #{login_command} and enter your credentials"
62
+ puts "You can install the heroku recipe again to create the app in heroku"
63
+ install_command = "\e[33mpostassium install heroku --force\e[0m"
64
+ puts "Just run #{install_command}"
65
+ end
66
+
69
67
  def heroku_pipeline_name
70
- app_name.dasherize
68
+ @heroku_pipeline_name ||= valid_heroku_name(app_name.dasherize, 'pipeline', false)
71
69
  end
72
70
 
73
- def app_name_for(environment)
74
- "#{NAME_PREFIX}-#{app_name.dasherize}-#{environment}"
71
+ def set_app_name_for(environment)
72
+ default_name = "#{NAME_PREFIX}-#{app_name.dasherize}-#{environment}"
73
+ set("heroku_app_name_#{environment}".to_sym, valid_heroku_name(default_name, environment))
75
74
  end
76
75
 
77
76
  def logged_in?
@@ -84,7 +83,7 @@ class Recipes::Heroku < Rails::AppBuilder
84
83
 
85
84
  def create_app_on_heroku(environment)
86
85
  rack_env = "RACK_ENV=production"
87
- staged_app_name = app_name_for(environment)
86
+ staged_app_name = get("heroku_app_name_#{environment}".to_sym)
88
87
 
89
88
  run_toolbelt_command "create #{staged_app_name} --remote #{environment}"
90
89
  run_toolbelt_command "labs:enable runtime-dyno-metadata", staged_app_name
@@ -99,14 +98,14 @@ class Recipes::Heroku < Rails::AppBuilder
99
98
  def set_rails_secrets(environment)
100
99
  run_toolbelt_command(
101
100
  "config:add SECRET_KEY_BASE=#{generate_secret}",
102
- app_name_for(environment)
101
+ get("heroku_app_name_#{environment}".to_sym)
103
102
  )
104
103
  end
105
104
 
106
105
  def set_app_multi_buildpack(environment)
107
106
  run_toolbelt_command(
108
107
  "buildpacks:set https://github.com/heroku/heroku-buildpack-multi.git",
109
- app_name_for(environment)
108
+ get("heroku_app_name_#{environment}".to_sym)
110
109
  )
111
110
  end
112
111
 
@@ -133,4 +132,18 @@ class Recipes::Heroku < Rails::AppBuilder
133
132
  `heroku #{command} --app #{app_env_name}`
134
133
  end
135
134
  end
135
+
136
+ def valid_heroku_name(name, element, force_suffix = true)
137
+ suffix = "-#{element}"
138
+ while name.length > HEROKU_NAMES_MAX_CHARS
139
+ puts "Heroku names must be shorter than #{HEROKU_NAMES_MAX_CHARS} chars."
140
+ if force_suffix
141
+ puts "Potassium uses the heroku-stage gem, because of that '#{suffix}' will be "\
142
+ "added to your app name. The suffix, #{suffix}, counts towards the app name length."
143
+ end
144
+ name = Ask.input("Please enter a valid name for #{element}:")
145
+ name += suffix if force_suffix && !name.end_with?(suffix)
146
+ end
147
+ name
148
+ end
136
149
  end
@@ -24,8 +24,7 @@ class Recipes::Mailer < Rails::AppBuilder
24
24
  dependencies(email_service)
25
25
  config(email_service)
26
26
 
27
- background_processor = load_recipe(:background_processor)
28
- background_processor.add_sidekiq unless background_processor.installed?
27
+ ensure_sidekiq_install_and_add_mailers_queue
29
28
  end
30
29
 
31
30
  def install
@@ -33,6 +32,10 @@ class Recipes::Mailer < Rails::AppBuilder
33
32
  create
34
33
  end
35
34
 
35
+ def add_mailer_queue
36
+ insert_into_file "config/sidekiq.yml", " - mailers", after: "- default\n"
37
+ end
38
+
36
39
  private
37
40
 
38
41
  def email_services(service_name)
@@ -99,4 +102,17 @@ class Recipes::Mailer < Rails::AppBuilder
99
102
  gather_gems(:development) { gather_gem("letter_opener") }
100
103
  application "config.action_mailer.delivery_method = :letter_opener", env: "development"
101
104
  end
105
+
106
+ def ensure_sidekiq_install_and_add_mailers_queue
107
+ background_processor_recipe = load_recipe(:background_processor)
108
+ background_processor_answer = get(:background_processor)
109
+
110
+ if background_processor_recipe.installed?
111
+ add_mailer_queue
112
+ else
113
+ recipe = self
114
+ after(:install_sidekiq) { recipe.add_mailer_queue }
115
+ background_processor_recipe.add_sidekiq unless background_processor_answer
116
+ end
117
+ end
102
118
  end
@@ -0,0 +1,5 @@
1
+ class Recipes::Monitoring < Rails::AppBuilder
2
+ def create
3
+ gather_gem('scout_apm')
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ require 'net/http'
2
+ require 'semantic'
3
+ require 'json'
4
+
5
+ class Recipes::Node < Rails::AppBuilder
6
+ def create
7
+ info "Using node version LTS #{version}"
8
+ create_file '.node-version', version, force: true
9
+ json_file = File.read(Pathname.new("package.json"))
10
+ js_package = JSON.parse(json_file)
11
+ js_package["engines"] = { "node" => "#{version}.x" }
12
+ json_string = JSON.pretty_generate(js_package)
13
+ create_file 'package.json', json_string, force: true
14
+ end
15
+
16
+ private
17
+
18
+ def version
19
+ Potassium::NODE_VERSION
20
+ end
21
+ end
@@ -4,23 +4,26 @@ class Recipes::RackCors < Rails::AppBuilder
4
4
  end
5
5
 
6
6
  def create
7
- gather_gem('rack-cors', '~> 0.4.0')
7
+ gather_gem('rack-cors', '~> 1.1')
8
+ recipe = self
8
9
  after(:gem_install) do
9
- rack_cors_config =
10
- <<~RUBY
11
- config.middleware.insert_before 0, Rack::Cors do
12
- allow do
13
- origins '*'
14
- resource '*',
15
- headers: :any,
16
- expose: ['X-Page', 'X-PageTotal'],
17
- methods: [:get, :post, :delete, :put, :options]
18
- end
19
- end
10
+ application recipe.rack_cors_config
11
+ end
12
+ end
20
13
 
21
- RUBY
14
+ def rack_cors_config
15
+ <<~RUBY
16
+ config.middleware.insert_before 0, Rack::Cors do
17
+ allow do
18
+ origins '*'
19
+ resource '/public/*', headers: :any, methods: :get
20
+ resource '/api/*',
21
+ headers: :any,
22
+ expose: ['X-Page', 'X-PageTotal'],
23
+ methods: [:get, :post, :patch, :put, :delete, :options]
24
+ end
25
+ end
22
26
 
23
- application rack_cors_config
24
- end
27
+ RUBY
25
28
  end
26
29
  end
@@ -8,10 +8,10 @@ class Recipes::Schedule < Rails::AppBuilder
8
8
 
9
9
  def create
10
10
  if selected?(:schedule)
11
- gather_gem 'sidekiq-scheduler'
11
+ gather_gem 'sidekiq-scheduler', '>= 3.0.1'
12
12
  add_readme_section :internal_dependencies, :sidekiq_scheduler
13
+ append_schedule_section_to_yml
13
14
  end
14
- template '../assets/sidekiq_scheduler.yml', 'config/sidekiq.yml', force: true
15
15
  end
16
16
 
17
17
  def install
@@ -22,4 +22,19 @@ class Recipes::Schedule < Rails::AppBuilder
22
22
  def installed?
23
23
  gem_exists?(/sidekiq-scheduler/) && file_exist?('config/sidekiq.yml')
24
24
  end
25
+
26
+ private
27
+
28
+ def append_schedule_section_to_yml
29
+ append_to_file(
30
+ 'config/sidekiq.yml',
31
+ <<-HERE.gsub(/^ {8}/, '')
32
+ # :schedule:
33
+ # an_scheduled_task:
34
+ # cron: '0 * * * * *' # Runs once per minute
35
+ # class: ExampleJob
36
+ # args: ['a', 'b']
37
+ HERE
38
+ )
39
+ end
25
40
  end
@@ -1,12 +1,30 @@
1
1
  class Recipes::Style < Rails::AppBuilder
2
2
  def create
3
- append_to_file ".gitignore", ".rubocop.yml\n"
4
- append_to_file ".gitignore", ".eslintrc.json\n"
5
- append_to_file ".gitignore", ".sscs-lint.yml\n"
3
+ add_linters
4
+ add_config_files
6
5
  add_readme_header :style_guide
7
6
  end
8
7
 
9
8
  def install
10
9
  create
11
10
  end
11
+
12
+ private
13
+
14
+ def add_linters
15
+ gather_gems(:development, :test) do
16
+ gather_gem 'rubocop', Potassium::RUBOCOP_VERSION
17
+ gather_gem 'rubocop-performance'
18
+ gather_gem 'rubocop-rails'
19
+ gather_gem 'rubocop-rspec', Potassium::RUBOCOP_RSPEC_VERSION
20
+ end
21
+ run 'bin/yarn add --dev stylelint eslint eslint-plugin-import'
22
+ run 'bin/yarn add --dev eslint-plugin-vue' if selected?(:front_end, :vue)
23
+ end
24
+
25
+ def add_config_files
26
+ copy_file '../assets/.rubocop.yml', '.rubocop.yml'
27
+ copy_file '../assets/.eslintrc.json', '.eslintrc.json'
28
+ copy_file '../assets/.stylelintrc.json', '.stylelintrc.json'
29
+ end
12
30
  end
@@ -0,0 +1,124 @@
1
+ class Recipes::VueAdmin < Rails::AppBuilder
2
+ def ask
3
+ if selected?(:admin_mode)
4
+ vue_admin = answer(:vue_admin) do
5
+ Ask.confirm "Do you want Vue support for ActiveAdmin?"
6
+ end
7
+ set(:vue_admin, vue_admin)
8
+ set(:front_end, :vue) if vue_admin
9
+ end
10
+ end
11
+
12
+ def create
13
+ recipe = self
14
+ if selected?(:vue_admin)
15
+ after(:admin_install) do
16
+ recipe.add_vue_admin
17
+ end
18
+ end
19
+ end
20
+
21
+ def install
22
+ active_admin = load_recipe(:admin)
23
+ if active_admin.installed?
24
+ add_vue_admin
25
+ info "VueAdmin installed"
26
+ else
27
+ info "VueAdmin can't be installed because Active Admin isn't installed."
28
+ end
29
+ end
30
+
31
+ def installed?
32
+ dir_exist?("app/assets/javascripts/admin")
33
+ end
34
+
35
+ def add_vue_admin
36
+ add_vue_component_library
37
+ add_component_integration
38
+ copy_file '../assets/active_admin/init_activeadmin_vue.rb',
39
+ 'config/initializers/init_activeadmin_vue.rb'
40
+ copy_file '../assets/active_admin/admin_application.js',
41
+ 'app/javascript/packs/admin_application.js',
42
+ force: true
43
+ empty_directory 'app/javascript/components'
44
+ copy_file '../assets/active_admin/admin-component.vue',
45
+ 'app/javascript/components/admin-component.vue',
46
+ force: true
47
+ end
48
+
49
+ def add_component_integration
50
+ line = "class CustomFooter < ActiveAdmin::Component"
51
+ initializer = "config/initializers/active_admin.rb"
52
+ gsub_file initializer, /(#{Regexp.escape(line)})/mi do |_match|
53
+ <<~HERE
54
+ require "vue_component.rb"
55
+ AUTO_BUILD_ELEMENTS=[:admin_component, :template, :slot]
56
+ component_creator(AUTO_BUILD_ELEMENTS)
57
+
58
+ #{line}
59
+ HERE
60
+ end
61
+ end
62
+
63
+ def add_vue_component_library
64
+ lib_component_path = "lib/vue_component.rb"
65
+ class_definitions =
66
+ <<~HERE
67
+ #{vue_component}
68
+ #{component_builder}
69
+ HERE
70
+ File.open(lib_component_path, "w") { |file| file.write(class_definitions) }
71
+ end
72
+
73
+ def vue_component
74
+ <<~HERE
75
+ class VueComponent < Arbre::Component
76
+ builder_method :root
77
+ def tag_name
78
+ :root
79
+ end
80
+
81
+ def initialize(*)
82
+ super
83
+ end
84
+
85
+ def build(attributes = {})
86
+ super(process_attributes(attributes))
87
+ end
88
+
89
+ def process_attributes(attributes)
90
+ vue_attributes = {}
91
+ attributes.each do |key, value|
92
+ dasherized_key = key.to_s.dasherize
93
+ if value.is_a?(String)
94
+ vue_attributes[dasherized_key] = value
95
+ elsif !dasherized_key.index(':').nil? && dasherized_key.index(':').zero?
96
+ vue_attributes[dasherized_key] = value.to_json
97
+ else
98
+ vue_attributes[":" + dasherized_key] = value.to_json
99
+ end
100
+ end
101
+ vue_attributes
102
+ end
103
+ end
104
+ HERE
105
+ end
106
+
107
+ def component_builder
108
+ <<~HERE
109
+ def component_creator(auto_build_elements)
110
+ auto_build_elements.each do |element|
111
+ as_string=element.to_s
112
+ camelized_element = as_string.camelize
113
+ Object.const_set(camelized_element,Class.new(VueComponent))
114
+ Object.const_get(camelized_element).class_eval do
115
+ builder_method as_string.to_sym
116
+ def tag_name
117
+ self.class.to_s.underscore
118
+ end
119
+ end
120
+ end
121
+ end
122
+ HERE
123
+ end
124
+ end