Class: Suspenders::AppBuilder

Inherits:
Rails::AppBuilder
  • Object
show all
Extended by:
Forwardable
Includes:
Actions
Defined in:
lib/voyage/app_builder.rb,
lib/suspenders/app_builder.rb

Instance Method Summary collapse

Methods included from Actions

#action_mailer_host, #configure_application_file, #configure_environment, #replace_in_file

Instance Method Details

#accept_defaultsObject



10
11
12
13
14
15
16
# File 'lib/voyage/app_builder.rb', line 10

def accept_defaults
  if agree?('Would you like to accept all defaults? [slim, devise w/ first & last name, refills nav & footer] (Y/n)')
    @@accept_defaults = true
  else
    @@accept_defaults = false
  end
end


703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'lib/voyage/app_builder.rb', line 703

def add_admin_links_to_navigation
  return unless @@use_devise
  inject_into_file 'app/views/refills/_navigation.html.erb', after: '        <li class="nav-link"><a href="javascript:void(0)">Contact</a></li>'  do <<-RUBY

    <% if current_user && true_user.admin? %>
      <% if current_user != true_user %>
        <li class='nav-link'><%= link_to 'Stop Impersonating', stop_impersonating_admin_users_path %></li>
      <% else %>
        <li class="nav-link"><a href="/admin/users">Admin</a></li>
      <% end %>
    <% end %>

    <% if current_user %>
      <li class='nav-link'><%= link_to 'Sign Out', sign_out_path %></li>
    <% else %>
      <li class='nav-link'><%= link_to 'Sign In', sign_in_path %></li>
    <% end %>
    RUBY
  end
end

#add_admin_views_for_devise_resource(adding_first_and_last_name) ⇒ Object



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/voyage/app_builder.rb', line 316

def add_admin_views_for_devise_resource(adding_first_and_last_name)
  config = { adding_first_and_last_name: adding_first_and_last_name }
  template '../templates/users_index.html.erb', 'app/views/admin/users/index.html.erb', config

  if @@use_slim
    inside('lib') do # arbitrary, run in context of newly generated app
      run "erb2slim '../app/views/users' '../app/views/users'"
      run "erb2slim -d '../app/views/users'"

      run "erb2slim '../app/views/admin/users' '../app/views/admin/users'"
      run "erb2slim -d '../app/views/admin/users'"
    end
  end

  template '../templates/admin_users_controller.rb', 'app/controllers/admin/users_controller.rb'
  template '../templates/admin_controller.rb', 'app/controllers/admin/admin_controller.rb'
end

#add_analytics_initializerObject



294
295
296
297
# File 'lib/voyage/app_builder.rb', line 294

def add_analytics_initializer
  template '../templates/analytics_ruby_initializer.rb', 'config/initializers/analytics_ruby.rb'
  template '../templates/analytics_alias.html.erb.erb', 'app/views/users/analytics_alias.html.erb'
end

#add_api_foundationObject



563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
# File 'lib/voyage/app_builder.rb', line 563

def add_api_foundation
  # Create /app/api/base_api_controller.rb
  template '../templates/api_base_controller.rb', 'app/controllers/api/base_api_controller.rb', force: true

  # Create /app/api/v1/users_controller.rb
  template '../templates/api_users_controller.rb', 'app/controllers/api/v1/users_controller.rb', force: true

  # Update routes to include namespaced API
  inject_into_file 'config/routes.rb', before: /^end/ do <<-RUBY.gsub(/^ {6}/, '')

    # API-specific routes
    namespace 'api' do
      namespace 'v1' do
        resources :users, except: [:new, :edit]
      end
    end
    RUBY
  end
end

#add_app_css_fileObject



666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
# File 'lib/voyage/app_builder.rb', line 666

def add_app_css_file
  create_file "app/assets/stylesheets/#{app_name}.sass" do <<-RUBY.gsub(/^ {8}/, '')
    .outer-wrapper
      position: relative
      min-height: 100%

    .navigation-wrapper
      @include outer-container

    .main
      padding: 18px
      @include outer-container
      padding-bottom: 450px

    .footer
      min-height: 420px
      position: absolute
      bottom: 0
      left: 0
    RUBY
  end
end

#add_auto_annotate_models_rake_taskObject



769
770
771
# File 'lib/voyage/app_builder.rb', line 769

def add_auto_annotate_models_rake_task
  template '../templates/auto_annotate_models.rake', 'lib/tasks/auto_annotate_models.rake', force: true
end

#add_bullet_gem_configurationObject



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/suspenders/app_builder.rb', line 63

def add_bullet_gem_configuration
  config = <<-RUBY
  config.after_initialize do
Bullet.enable = true
Bullet.bullet_logger = true
Bullet.rails_logger = true
  end

  RUBY

  inject_into_file(
    "config/environments/development.rb",
    config,
    after: "config.action_mailer.raise_delivery_errors = true\n",
  )
end

#add_canard_roles_to_devise_resourceObject



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
# File 'lib/voyage/app_builder.rb', line 365

def add_canard_roles_to_devise_resource
  inject_into_file 'app/models/user.rb', before: /^end/ do <<-RUBY.gsub(/^ {6}/, '')

    before_create :generate_uuid

    # Permissions cascade/inherit through the roles listed below. The order of
    # this list is important, it should progress from least to most privelage
    ROLES = [:admin].freeze
    acts_as_user roles: ROLES
    roles ROLES

    validates :email,
              presence: true,
              format: /\\A[-a-z0-9_+\\.]+\\@([-a-z0-9]+\\.)+[a-z0-9]{2,8}\\z/i,
              uniqueness: true

    # NOTE: these password validations won't run if the user has an invite token
    validates :password,
              presence: true,
              length: { within: 8..72 },
              confirmation: true,
              on: :create
    validates :password_confirmation,
              presence: true,
              on: :create

    def tester?
      (email =~ /(example.com|headway.io)$/).present?
    end

    private

    def generate_uuid
      loop do
        uuid = SecureRandom.uuid
        self.uuid = uuid
        break unless User.exists?(uuid: uuid)
      end
    end
    RUBY
  end
end

#add_custom_routes_for_deviseObject



417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
# File 'lib/voyage/app_builder.rb', line 417

def add_custom_routes_for_devise
  find = <<-RUBY.gsub(/^ {6}/, '')
    devise_for :users
    resources :users
  RUBY

  replace = <<-RUBY.gsub(/^ {6}/, '')
    devise_for :users, controllers: {
      registrations: 'devise_customizations/registrations',
    }

    resources :users do
      member do
        get 'analytics_alias'
      end
    end

    namespace :admin do
      resources :users do
        member do
          get 'impersonate'
        end

        collection do
          get 'stop_impersonating'
        end
      end
    end

    authenticated :user do
      # root to: 'dashboard#show', as: :authenticated_root
      root to: 'high_voltage/pages#show', id: 'welcome', as: :authenticated_root
    end

    devise_scope :user do
      get 'sign-in',  to: 'devise/sessions#new'
      get 'sign-out', to: 'devise/sessions#destroy'
    end
  RUBY

  replace_in_file 'config/routes.rb', find, replace
end

#add_devise_registrations_controllerObject



288
289
290
291
# File 'lib/voyage/app_builder.rb', line 288

def add_devise_registrations_controller
  template '../templates/devise_registrations_controller.rb',
           'app/controllers/devise_customizations/registrations_controller.rb'
end

#add_faviconObject



773
774
775
# File 'lib/voyage/app_builder.rb', line 773

def add_favicon
  template '../templates/favicon.ico', 'app/assets/images/favicon.ico', force: true
end

#add_high_voltage_static_pagesObject



615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
# File 'lib/voyage/app_builder.rb', line 615

def add_high_voltage_static_pages
  template '../templates/about.html.erb', "app/views/pages/about.html.#{@@use_slim ? 'slim' : 'erb'}"
  template '../templates/welcome.html.erb', "app/views/pages/welcome.html.erb"

  inject_into_file 'config/routes.rb', before: /^end/ do <<-RUBY.gsub(/^ {6}/, '')
    root 'high_voltage/pages#show', id: 'welcome'
    RUBY
  end

  create_file 'config/initializers/high_voltage.rb' do <<-RUBY.gsub(/^ {8}/, '')
    HighVoltage.configure do |config|
      config.route_drawer = HighVoltage::RouteDrawers::Root
    end
    RUBY
  end
end

#add_refills_to_stylesheetsObject



724
725
726
727
728
729
730
731
732
# File 'lib/voyage/app_builder.rb', line 724

def add_refills_to_stylesheets
  inject_into_file 'app/assets/stylesheets/application.scss', after: '@import "refills/flashes";'  do <<-RUBY.gsub(/^ {8}/, '')
    \n@import "refills/navigation";
    @import "refills/footer";

    @import "#{app_name}";
    RUBY
  end
end

#add_rubocop_configObject



765
766
767
# File 'lib/voyage/app_builder.rb', line 765

def add_rubocop_config
  template '../templates/rubocop.yml', '.rubocop.yml', force: true
end

#add_specsObject



781
782
783
784
785
786
787
788
789
# File 'lib/voyage/app_builder.rb', line 781

def add_specs
  inject_into_file 'app/jobs/application_job.rb', before: "class ApplicationJob < ActiveJob::Base" do <<-RUBY.gsub(/^ {8}/, '')
    # :nocov:
    RUBY
  end

  template '../templates/specs/controllers/admin/users_controller_spec.rb', 'spec/controllers/admin/users_controller_spec.rb', force: true
  template '../templates/specs/controllers/application_controller_spec.rb', 'spec/controllers/application_controller_spec.rb', force: true
end

#add_to_gitignoreObject



822
823
824
825
826
827
828
829
830
831
832
# File 'lib/voyage/app_builder.rb', line 822

def add_to_gitignore
  inject_into_file '.gitignore', after: '/tmp/*' do <<-RUBY.gsub(/^ {8}/, '')

    .env
    .zenflow-log
    errors.err
    .ctags
    .cadre/coverage.vim
    RUBY
  end
end

#add_token_authObject



541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
# File 'lib/voyage/app_builder.rb', line 541

def add_token_auth
  inject_into_file 'app/models/user.rb', after: "class User < ApplicationRecord" do <<-'RUBY'.gsub(/^ {6}/, '')

    acts_as_token_authenticatable
    RUBY
  end

  generate 'migration add_authentication_token_to_users "authentication_token:string{30}:uniq"'

  # specs
  template '../templates/specs/features/user_impersonation_spec.rb', 'spec/features/user_impersonation_spec.rb', force: true
  template '../templates/specs/features/user_list_spec.rb', 'spec/features/user_list_spec.rb', force: true
  template '../templates/specs/features/user_signup_spec.rb', 'spec/features/user_signup_spec.rb', force: true
  template '../templates/specs/requests/user_api_spec.rb', 'spec/requests/user_api_spec.rb', force: true
  template '../templates/specs/support/api/schemas/user.json', 'spec/support/api/schemas/user.json', force: true
  template '../templates/config_initializers_ams.rb', 'config/initializers/ams.rb', force: true
  template '../templates/specs/support/matchers/api_schema_matcher.rb', 'spec/support/matchers/api_schema_matcher.rb', force: true
  template '../templates/specs/mailers/application_mailer_spec.rb.erb', 'spec/mailers/application_mailer_spec.rb', force: true
  template '../templates/specs/support/features/session_helpers.rb', 'spec/support/features/session_helpers.rb', force: true
  template '../templates/specs/support/request_spec_helper.rb', 'spec/support/request_spec_helper.rb', force: true
end

#agree?(prompt) ⇒ Boolean

Returns:

  • (Boolean)


3
4
5
6
7
8
# File 'lib/voyage/app_builder.rb', line 3

def agree?(prompt)
  puts prompt
  response = STDIN.gets.chomp

  response.empty? || %w(y yes).include?(response.downcase.strip)
end

#authorize_devise_resource_for_index_actionObject



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# File 'lib/voyage/app_builder.rb', line 334

def authorize_devise_resource_for_index_action
  generate 'canard:ability user can:manage:user cannot:destroy:user'
  generate 'canard:ability admin can:destroy:user'

  %w(admins users).each do |resource_name|
    replace_in_file "spec/abilities/#{resource_name}_spec.rb", "require 'cancan/matchers'", "require_relative '../support/matchers/custom_cancan'"
  end

  find = <<-RUBY.gsub(/^ {4}/, '')
    it { is_expected.to be_able_to(:manage, user) }
  RUBY
  replace = <<-RUBY.gsub(/^ {4}/, '')
    it { is_expected.to be_able_to(:manage, acting_user) }
    it { is_expected.to_not be_able_to(:manage, user) }
  RUBY
  replace_in_file 'spec/abilities/users_spec.rb', find, replace

  find = <<-RUBY.gsub(/^ {6}/, '')
    can [:manage], User
  RUBY
  replace = <<-RUBY.gsub(/^ {6}/, '')
    can [:manage], User do |u|
      u == user
    end
  RUBY
  replace_in_file 'app/abilities/users.rb', find, replace

  generate 'migration add_roles_mask_to_users roles_mask:integer'
  template '../templates/custom_cancan_matchers.rb', 'spec/support/matchers/custom_cancan.rb'
end

#bundle_without_productionObject



25
26
27
# File 'lib/voyage/app_builder.rb', line 25

def bundle_without_production
  template '../templates/bundle_config', '.bundle/config'
end

#configure_action_mailerObject



312
313
314
315
316
# File 'lib/suspenders/app_builder.rb', line 312

def configure_action_mailer
  action_mailer_host "development", %{"localhost:3000"}
  action_mailer_host "test", %{"www.example.com"}
  action_mailer_host "production", %{ENV.fetch("APPLICATION_HOST")}
end

#configure_action_mailer_in_specsObject



287
288
289
# File 'lib/suspenders/app_builder.rb', line 287

def configure_action_mailer_in_specs
  copy_file 'action_mailer.rb', 'spec/support/action_mailer.rb'
end

#configure_active_jobObject



892
893
894
# File 'lib/voyage/app_builder.rb', line 892

def configure_active_job
  # NOTE: (2017-06-02) jon => don't want this
end

#configure_automatic_deploymentObject



382
383
384
385
386
387
388
389
390
391
392
# File 'lib/suspenders/app_builder.rb', line 382

def configure_automatic_deployment
  deploy_command = <<-YML.strip_heredoc
  deployment:
    staging:
      branch: master
      commands:
        - bin/deploy staging
  YML

  append_file "circle.yml", deploy_command
end

#configure_background_jobs_for_rspecObject



888
889
890
# File 'lib/voyage/app_builder.rb', line 888

def configure_background_jobs_for_rspec
  # NOTE: (2017-05-31) jon => don't want this
end

#configure_capybara_webkitObject



896
897
898
# File 'lib/voyage/app_builder.rb', line 896

def configure_capybara_webkit
  # NOTE: (2016-02-03) jonk => don't want this
end

#configure_ciObject



884
885
886
# File 'lib/voyage/app_builder.rb', line 884

def configure_ci
  template "../templates/circle.yml.erb", "circle.yml"
end

#configure_generatorsObject

OVERRIDE SUSPENDERS METHODS #



842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
# File 'lib/voyage/app_builder.rb', line 842

def configure_generators
  config = <<-RUBY.gsub(/^ {4}/, '')

    config.generators do |g|
      g.helper false
      g.javascript_engine false
      g.request_specs false
      g.routing_specs false
      g.stylesheets false
      g.test_framework :rspec
      g.view_specs false
      g.fixture_replacement :factory_girl, dir: 'spec/factories'
    end

  RUBY

  inject_into_class 'config/application.rb', 'Application', config
end

#configure_i18n_for_missing_translationsObject



278
279
280
281
# File 'lib/suspenders/app_builder.rb', line 278

def configure_i18n_for_missing_translations
  raise_on_missing_translations_in("development")
  raise_on_missing_translations_in("test")
end

#configure_i18n_for_test_environmentObject



274
275
276
# File 'lib/suspenders/app_builder.rb', line 274

def configure_i18n_for_test_environment
  copy_file "i18n.rb", "spec/support/i18n.rb"
end

#configure_quiet_assetsObject



88
89
90
91
92
93
94
# File 'lib/suspenders/app_builder.rb', line 88

def configure_quiet_assets
  config = <<-RUBY
config.assets.quiet = true
  RUBY

  inject_into_class "config/application.rb", "Application", config
end

#configure_rack_timeoutObject



300
301
302
303
304
305
306
# File 'lib/suspenders/app_builder.rb', line 300

def configure_rack_timeout
  rack_timeout_config = <<-RUBY
Rack::Timeout.timeout = (ENV["RACK_TIMEOUT"] || 10).to_i
  RUBY

  append_file "config/environments/production.rb", rack_timeout_config
end

#configure_rspecObject



263
264
265
266
267
268
# File 'lib/suspenders/app_builder.rb', line 263

def configure_rspec
  remove_file "spec/rails_helper.rb"
  remove_file "spec/spec_helper.rb"
  copy_file "rails_helper.rb", "spec/rails_helper.rb"
  copy_file "spec_helper.rb", "spec/spec_helper.rb"
end

#configure_rvm_prepend_bin_to_pathObject



797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
# File 'lib/voyage/app_builder.rb', line 797

def configure_rvm_prepend_bin_to_path
  run "rm -f $rvm_path/hooks/after_cd_bundler"

  run "touch $rvm_path/hooks/after_cd_bundler"

  git_safe_dir = <<-RUBY.gsub(/^ {8}/, '')
    #!/usr/bin/env bash
    export PATH=".git/safe/../../bin:$PATH"
    RUBY

  run "echo '#{git_safe_dir}' >> $rvm_path/hooks/after_cd_bundler"

  run 'chmod +x $rvm_path/hooks/after_cd_bundler'

  run 'mkdir -p .git/safe'
end

#configure_simple_formObject



308
309
310
# File 'lib/suspenders/app_builder.rb', line 308

def configure_simple_form
  bundle_command "exec rails generate simple_form:install"
end

#configure_smtpObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/suspenders/app_builder.rb', line 135

def configure_smtp
  copy_file 'smtp.rb', 'config/smtp.rb'

  prepend_file 'config/environments/production.rb',
    %{require Rails.root.join("config/smtp")\n}

  config = <<-RUBY

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = SMTP_SETTINGS
  RUBY

  inject_into_file 'config/environments/production.rb', config,
    after: "config.action_mailer.raise_delivery_errors = false"
end

#configure_spec_support_featuresObject



258
259
260
261
# File 'lib/suspenders/app_builder.rb', line 258

def configure_spec_support_features
  empty_directory_with_keep_file 'spec/features'
  empty_directory_with_keep_file 'spec/support/features'
end

#configure_time_formatsObject



295
296
297
298
# File 'lib/suspenders/app_builder.rb', line 295

def configure_time_formats
  remove_file "config/locales/en.yml"
  template "config_locales_en.yml.erb", "config/locales/en.yml"
end

#copy_dotfilesObject



351
352
353
# File 'lib/suspenders/app_builder.rb', line 351

def copy_dotfiles
  directory("dotfiles", ".")
end

#copy_env_to_exampleObject



818
819
820
# File 'lib/voyage/app_builder.rb', line 818

def copy_env_to_example
  run 'cp .env .env.example'
end

#copy_miscellaneous_filesObject



412
413
414
415
416
# File 'lib/suspenders/app_builder.rb', line 412

def copy_miscellaneous_files
  copy_file "browserslist", "browserslist"
  copy_file "errors.rb", "config/initializers/errors.rb"
  copy_file "json_encoding.rb", "config/initializers/json_encoding.rb"
end

#create_application_layoutObject



218
219
220
221
222
# File 'lib/suspenders/app_builder.rb', line 218

def create_application_layout
  template 'suspenders_layout.html.erb.erb',
    'app/views/layouts/application.html.erb',
    force: true
end

#create_databaseObject



872
873
874
875
# File 'lib/voyage/app_builder.rb', line 872

def create_database
  # Suspenders version also migrates, we don't want that yet... we migrate in the rake_db_setup method
  bundle_command 'exec rake db:create'
end

#create_deploy_scriptObject



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
# File 'lib/suspenders/app_builder.rb', line 364

def create_deploy_script
  copy_file "bin_deploy", "bin/deploy"

  instructions = <<-MARKDOWN

## Deploying

If you have previously run the `./bin/setup` script,
you can deploy to staging and production with:

% ./bin/deploy staging
% ./bin/deploy production
  MARKDOWN

  append_file "README.md", instructions
  run "chmod a+x bin/deploy"
end

#create_github_repo(repo_name) ⇒ Object



394
395
396
# File 'lib/suspenders/app_builder.rb', line 394

def create_github_repo(repo_name)
  run "hub create #{repo_name}"
end

#create_heroku_apps(flags) ⇒ Object



359
360
361
362
# File 'lib/suspenders/app_builder.rb', line 359

def create_heroku_apps(flags)
  create_staging_heroku_app(flags)
  create_production_heroku_app(flags)
end

#create_partials_directoryObject



198
199
200
# File 'lib/suspenders/app_builder.rb', line 198

def create_partials_directory
  empty_directory 'app/views/application'
end

#create_shared_css_overridesObject



211
212
213
214
215
216
# File 'lib/suspenders/app_builder.rb', line 211

def create_shared_css_overrides
  copy_file(
    "_css_overrides.html.erb",
    "app/views/application/_css_overrides.html.erb",
  )
end

#create_shared_flashesObject



202
203
204
205
# File 'lib/suspenders/app_builder.rb', line 202

def create_shared_flashes
  copy_file "_flashes.html.erb", "app/views/application/_flashes.html.erb"
  copy_file "flashes_helper.rb", "app/helpers/flashes_helper.rb"
end

#create_shared_javascriptsObject



207
208
209
# File 'lib/suspenders/app_builder.rb', line 207

def create_shared_javascripts
  copy_file '_javascript.html.erb', 'app/views/application/_javascript.html.erb'
end

#customize_application_controller_for_devise(adding_first_and_last_name, devise_token_auth) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/voyage/app_builder.rb', line 163

def customize_application_controller_for_devise(adding_first_and_last_name, devise_token_auth)
  inject_into_file 'app/controllers/application_controller.rb', before: "class ApplicationController < ActionController::Base" do <<-RUBY.gsub(/^ {8}/, '')
    # rubocop:disable Metrics/ClassLength, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/LineLength
    RUBY
  end

  inject_into_file 'app/controllers/application_controller.rb', after: "  protect_from_forgery with: :exception" do <<-RUBY.gsub(/^ {6}/, '')

    check_authorization unless: :devise_or_pages_controller?
    impersonates :user
    #{'acts_as_token_authentication_handler_for User' if devise_token_auth}

    before_action :configure_permitted_parameters, if: :devise_controller?
    before_action :authenticate_user!, unless: -> { is_a?(HighVoltage::PagesController) }
    before_action :add_layout_name_to_gon
    before_action :detect_device_type

    rescue_from CanCan::AccessDenied do |exception|
      redirect_to root_path, alert: exception.message
    end

    # Example Traditional Event: analytics_track(user, 'Created Widget', { widget_name: 'foo' })
    # Example Page View:         analytics_track(user, 'Page Viewed', { page_name: 'Terms and Conditions', url: '/terms' })
    #
    # NOTE: setup some defaults that we want to track on every event mixpanel_track
    # NOTE: the identify step happens on every page load to keep intercom.io and mixpanel people up to date
    def analytics_track(user, event_name, options = {})
      return if user.tester?

      sanitized_options = sanitize_hash_javascript(options)

      segment_attributes = {
        user_id: user.uuid,
        event: event_name,
        properties: {
          browser:         "\#{browser.name rescue 'unknown'}",
          browser_id:      "\#{browser.id rescue 'unknown'}",
          browser_version: "\#{browser.version rescue 'unknown'}",
          platform:        "\#{browser.platform rescue 'unknown'}",
          roles:           "\#{user.roles.map(&:to_s).join(',') rescue ''}",
          rails_env:       Rails.env.to_s,
        }.merge(sanitized_options),
      }

      Analytics.track(segment_attributes)
    end

    protected

    def devise_or_pages_controller?
      devise_controller? == true || is_a?(HighVoltage::PagesController)
    end

    def sanitize_hash_javascript(hash)
      hash.deep_stringify_keys
          .deep_transform_keys { |k| sanitize_javascript(k) }
          .transform_values    { |v| sanitize_javascript(v) }
    end

    def sanitize_javascript(value)
      value.is_a?(String) ? ActionView::Base.new.escape_javascript(value) : value
    end

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(
        :sign_up,
        keys: [
          #{':first_name,' if adding_first_and_last_name}
          #{':last_name,' if adding_first_and_last_name}
          :email,
          :password,
          :password_confirmation,
          :remember_me,
        ],
      )

      devise_parameter_sanitizer.permit(
        :sign_in,
        keys: [
          :login, :email, :password, :remember_me
        ],
      )

      devise_parameter_sanitizer.permit(
        :account_update,
        keys: [
          #{':first_name,' if adding_first_and_last_name}
          #{':last_name,' if adding_first_and_last_name}
          :email,
          :password,
          :password_confirmation,
          :current_password,
        ],
      )
    end

    def add_layout_name_to_gon
      gon.layout =
        case devise_controller?
        when true
          'devise'
        else
          'application'
        end
    end

    def detect_device_type
      request.variant =
        case request.user_agent
        when /iPad/i
          :tablet
        when /iPhone/i
          :phone
        when /Android/i && /mobile/i
          :phone
        when /Android/i
          :tablet
        when /Windows Phone/i
          :phone
        end
    end
    RUBY
  end
end

#customize_application_jsObject



583
584
585
586
587
588
589
590
591
# File 'lib/voyage/app_builder.rb', line 583

def customize_application_js
  template '../templates/application.js', 'app/assets/javascripts/application.js', force: true

  inject_into_file 'app/views/application/_javascript.html.erb', after: '<%= render "analytics" %>' do <<-RUBY.gsub(/^ {8}/, '')

    <%= render "analytics_identify" %>
  RUBY
  end
end

#customize_application_mailerObject



777
778
779
# File 'lib/voyage/app_builder.rb', line 777

def customize_application_mailer
  template '../templates/application_mailer.rb.erb', 'app/mailers/application_mailer.rb', force: true
end

#customize_devise_viewsObject



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/voyage/app_builder.rb', line 143

def customize_devise_views
  %w(edit new).each do |file|
    if @@use_slim
      file_path = "app/views/devise/registrations/#{file}.html.slim"
      inject_into_file file_path, before: "    = f.input :email, required: true, autofocus: true" do <<-'RUBY'.gsub(/^ {8}/, '')
        = f.input :first_name, required: true, autofocus: true
        = f.input :last_name, required: true
        RUBY
      end
    else
      file_path = "app/views/devise/registrations/#{file}.html.erb"
      inject_into_file file_path, before: "    <%= f.input :email, required: true, autofocus: true %>" do <<-'RUBY'.gsub(/^ {8}/, '')
        <%= f.input :first_name, required: true, autofocus: true %>
        <%= f.input :last_name, required: true %>
        RUBY
      end
    end
  end
end

#customize_error_pagesObject



418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/suspenders/app_builder.rb', line 418

def customize_error_pages
  meta_tags =<<-EOS
  <meta charset="utf-8" />
  <meta name="ROBOTS" content="NOODP" />
  <meta name="viewport" content="initial-scale=1" />
  EOS

  %w(500 404 422).each do |page|
    inject_into_file "public/#{page}.html", meta_tags, after: "<head>\n"
    replace_in_file "public/#{page}.html", /<!--.+-->\n/, ''
  end
end

#customize_resource_controller_for_devise(adding_first_and_last_name) ⇒ Object



299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
# File 'lib/voyage/app_builder.rb', line 299

def customize_resource_controller_for_devise(adding_first_and_last_name)
  bundle_command 'exec rails generate controller users'
  run 'rm spec/controllers/users_controller_spec.rb'

  inject_into_class 'app/controllers/users_controller.rb', 'UsersController' do <<-RUBY.gsub(/^ {6}/, '')
    # https://github.com/CanCanCommunity/cancancan/wiki/authorizing-controller-actions
    # load_and_authorize_resource only: []
    skip_authorization_check only: [:analytics_alias]

    def analytics_alias
      # view file has JS that will identify the anonymous user through segment
      # after registration via "after devise registration path"
    end
    RUBY
  end
end

#customize_user_factory(adding_first_and_last_name) ⇒ Object



460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# File 'lib/voyage/app_builder.rb', line 460

def customize_user_factory(adding_first_and_last_name)
  inject_into_file 'spec/factories/users.rb', before: /^  end/ do <<-'RUBY'.gsub(/^ {4}/, '')
    password 'asdfjkl123'
    password_confirmation 'asdfjkl123'
    sequence(:email) { |n| "user_#{n}@example.com" }

    trait :admin do
      roles [:admin]
      email '[email protected]'
    end
    RUBY
  end

  if adding_first_and_last_name
    inject_into_file 'spec/factories/users.rb', after: /roles \[:admin\]\n/ do <<-'RUBY'.gsub(/^ {4}/, '')
      first_name 'Admin'
      last_name 'User'
      RUBY
    end
  end
end

#customize_user_specObject



491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
# File 'lib/voyage/app_builder.rb', line 491

def customize_user_spec
  find = <<-RUBY.gsub(/^ {6}/, '')
    pending "add some examples to (or delete) \#{__FILE__}"
  RUBY

  replace = <<-RUBY.gsub(/^ {6}/, '')
    describe 'constants' do
      context 'roles' do
        it 'has the admin role' do
          expect(User::ROLES).to eq([:admin])
        end
      end
    end

    describe 'validations' do
      it { is_expected.to validate_presence_of(:email) }
      it { is_expected.to validate_presence_of(:password) }
      it { is_expected.to validate_presence_of(:password_confirmation) }
    end

    context '#tester?' do
      ['example.com', 'headway.io'].each do |domain|
        it "an email including the \#{domain} domain is a tester" do
          user = build(:user, email: "asdf@\#{domain}")
          expect(user.tester?).to eq(true)
        end
      end

      it 'an email including the gmail.com domain is NOT a tester' do
        user = build(:user, email: '[email protected]')
        expect(user.tester?).to eq(false)
      end
    end

    context 'new user creation' do
      it 'ensures uniqueness of the uuid' do
        allow(User).to receive(:exists?).and_return(true, false)

        expect do
          create(:user)
        end.to change { User.count }.by(1)

        expect(User).to have_received(:exists?).exactly(2).times
      end
    end
  RUBY

  replace_in_file 'spec/models/user_spec.rb', find, replace
end

#disallow_wrapping_parametersObject



194
195
196
# File 'lib/suspenders/app_builder.rb', line 194

def disallow_wrapping_parameters
  remove_file "config/initializers/wrap_parameters.rb"
end

#downgrade_neat_1_8_so_refills_media_mixin_worksObject


TEMP FIX

https://github.com/thoughtbot/bourbon/issues/993
https://github.com/thoughtbot/refills/issues/400



638
639
640
641
642
# File 'lib/voyage/app_builder.rb', line 638

def downgrade_neat_1_8_so_refills_media_mixin_works
  replace_in_file 'Gemfile', "gem 'neat', '~> 2.0.0.beta.1'", "gem 'neat', '~> 1.8.0'"
  run 'gem uninstall -x neat -v2.0.0'
  run 'bundle'
end

#enable_database_cleanerObject



247
248
249
# File 'lib/suspenders/app_builder.rb', line 247

def enable_database_cleaner
  copy_file 'database_cleaner_rspec.rb', 'spec/support/database_cleaner.rb'
end

#enable_rack_canonical_hostObject



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/suspenders/app_builder.rb', line 151

def enable_rack_canonical_host
  config = <<-RUBY

  if ENV.fetch("HEROKU_APP_NAME", "").include?("staging-pr-")
ENV["APPLICATION_HOST"] = ENV["HEROKU_APP_NAME"] + ".herokuapp.com"
  end

  config.middleware.use Rack::CanonicalHost, ENV.fetch("APPLICATION_HOST")
  RUBY

  inject_into_file(
    "config/environments/production.rb",
    config,
    after: "Rails.application.configure do",
  )
end

#enable_rack_deflaterObject



168
169
170
# File 'lib/suspenders/app_builder.rb', line 168

def enable_rack_deflater
  configure_environment "production", "config.middleware.use Rack::Deflater"
end

#gemfileObject



27
28
29
# File 'lib/suspenders/app_builder.rb', line 27

def gemfile
  template "Gemfile.erb", "Gemfile"
end

#generate_data_migrationsObject



606
607
608
609
610
611
612
613
# File 'lib/voyage/app_builder.rb', line 606

def generate_data_migrations
  generate 'data_migrations:install'

  file = Dir['db/migrate/*_create_data_migrations.rb'].first
  replace_in_file file, 'class CreateDataMigrations < ActiveRecord::Migration', "class CreateDataMigrations < ActiveRecord::Migration[4.2]"

  empty_directory_with_keep_file 'db/data_migrate'
end

#generate_factories_fileObject


setup_test_environment overrides




880
881
882
# File 'lib/voyage/app_builder.rb', line 880

def generate_factories_file
  # NOTE: (2016-02-03) jonk => don't want this, we use individual factories
end

#generate_refillsObject


ADDING REFILLS COMPONENTS




651
652
653
654
655
656
657
658
659
660
661
662
663
664
# File 'lib/voyage/app_builder.rb', line 651

def generate_refills
  if @@accept_defaults || agree?('Would you like to install default Refill components? (Y/n)')
    @@add_refills = true

    bundle_command 'exec rails generate refills:import navigation'
    bundle_command 'exec rails generate refills:import footer'

    add_admin_links_to_navigation

    add_refills_to_stylesheets
  else
    @@add_refills = false
  end
end

#generate_rspecObject



325
326
327
# File 'lib/suspenders/app_builder.rb', line 325

def generate_rspec
  generate 'rspec:install'
end

#generate_ruby_version_and_gemsetObject



602
603
604
# File 'lib/voyage/app_builder.rb', line 602

def generate_ruby_version_and_gemset
  create_file '.ruby-gemset', "#{app_name}\n"
end

#generate_seeder_templates(using_devise:) ⇒ Object


END DEVISE SETUP




485
486
487
488
489
# File 'lib/voyage/app_builder.rb', line 485

def generate_seeder_templates(using_devise:)
  config = { force: true, using_devise: using_devise }
  template '../templates/seeder.rb.erb', 'lib/seeder.rb', config
  template '../templates/seeds.rb.erb', 'db/seeds.rb', config
end

#generate_test_environmentObject


END ADDING REFILLS COMPONENTS




737
738
739
740
# File 'lib/voyage/app_builder.rb', line 737

def generate_test_environment
  template '../templates/controller_helpers.rb', 'spec/support/controller_helpers.rb'
  template '../templates/simplecov.rb', '.simplecov'
end

#gitignoreObject



23
24
25
# File 'lib/suspenders/app_builder.rb', line 23

def gitignore
  copy_file "suspenders_gitignore", ".gitignore"
end

#init_gitObject



355
356
357
# File 'lib/suspenders/app_builder.rb', line 355

def init_git
  run 'git init'
end

#install_deviseObject


DEVISE SETUP




90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/voyage/app_builder.rb', line 90

def install_devise
  if @@accept_defaults || agree?('Would you like to install Devise? (Y/n)')
    @@use_devise = true

    if @@accept_defaults || agree?('Would you like to install Devise token authentication? (Y/n)')
      devise_token_auth = true
    end

    bundle_command 'exec rails generate devise:install'

    if @@accept_defaults || agree?("Would you like to add first_name and last_name to the devise model? (Y/n)")
      adding_first_and_last_name = true

      bundle_command "exec rails generate resource user first_name:string last_name:string uuid:string"

      replace_in_file 'spec/factories/users.rb',
        'first_name "MyString"', 'first_name { Faker::Name.first_name }'
      replace_in_file 'spec/factories/users.rb',
        'last_name "MyString"', 'last_name { Faker::Name.last_name }'
      replace_in_file 'spec/factories/users.rb',
        'uuid "MyString"', 'uuid { SecureRandom.uuid }'
    end

    bundle_command "exec rails generate devise user"
    bundle_command 'exec rails generate devise:views'

    if @@use_slim
      inside('lib') do # arbitrary, run in context of newly generated app
        run "erb2slim '../app/views/devise' '../app/views/devise'"
        run "erb2slim -d '../app/views/devise'"
      end
    end

    customize_devise_views if adding_first_and_last_name
    customize_application_controller_for_devise(adding_first_and_last_name, devise_token_auth)
    add_devise_registrations_controller
    customize_resource_controller_for_devise(adding_first_and_last_name)
    add_admin_views_for_devise_resource(adding_first_and_last_name)
    add_analytics_initializer
    authorize_devise_resource_for_index_action
    add_canard_roles_to_devise_resource
    update_devise_initializer
    add_custom_routes_for_devise
    customize_user_factory(adding_first_and_last_name)
    generate_seeder_templates(using_devise: true)
    customize_user_spec
    add_token_auth
  else
    @@use_devise = false
    generate_seeder_templates(using_devise: false)
  end
end

#overwrite_application_layoutObject



865
866
867
868
869
870
# File 'lib/voyage/app_builder.rb', line 865

def overwrite_application_layout
  template '../templates/voyage_layout.html.erb.erb', 'app/views/layouts/application.html.erb', force: true, add_refills: @@add_refills
  update_application_layout_for_slim if @@use_slim

  template '../templates/analytics_identify.html.erb.erb', 'app/views/application/_analytics_identify.html.erb', force: true
end

#provide_dev_prime_taskObject



101
102
103
# File 'lib/suspenders/app_builder.rb', line 101

def provide_dev_prime_task
  copy_file 'dev.rake', 'lib/tasks/dev.rake'
end

#provide_setup_scriptObject



96
97
98
99
# File 'lib/suspenders/app_builder.rb', line 96

def provide_setup_script
  template "bin_setup", "bin/setup", force: true
  run "chmod a+x bin/setup"
end

#provide_shoulda_matchers_configObject



251
252
253
254
255
256
# File 'lib/suspenders/app_builder.rb', line 251

def provide_shoulda_matchers_config
  copy_file(
    "shoulda_matchers_config_rspec.rb",
    "spec/support/shoulda_matchers.rb"
  )
end

#raise_on_delivery_errorsObject



42
43
44
45
# File 'lib/suspenders/app_builder.rb', line 42

def raise_on_delivery_errors
  replace_in_file 'config/environments/development.rb',
    'raise_delivery_errors = false', 'raise_delivery_errors = true'
end

#raise_on_missing_assets_in_testObject



38
39
40
# File 'lib/suspenders/app_builder.rb', line 38

def raise_on_missing_assets_in_test
  configure_environment "test", "config.assets.raise_runtime_errors = true"
end

#raise_on_unpermitted_parametersObject



80
81
82
83
84
85
86
# File 'lib/suspenders/app_builder.rb', line 80

def raise_on_unpermitted_parameters
  config = <<-RUBY
config.action_controller.action_on_unpermitted_parameters = :raise
  RUBY

  inject_into_class "config/application.rb", "Application", config
end

#rake_db_setupObject

Do this last



792
793
794
795
# File 'lib/voyage/app_builder.rb', line 792

def rake_db_setup
  rake 'db:migrate'
  rake 'db:seed' if File.exist?('config/initializers/devise.rb')
end

#readmeObject



19
20
21
# File 'lib/suspenders/app_builder.rb', line 19

def readme
  template 'README.md.erb', 'README.md'
end

#remove_config_comment_linesObject


End setup_test_environment overrides




903
904
905
# File 'lib/voyage/app_builder.rb', line 903

def remove_config_comment_lines
  # NOTE: (2016-02-09) jonk => don't want this
end

#remove_routes_comment_linesObject



453
454
455
456
457
# File 'lib/suspenders/app_builder.rb', line 453

def remove_routes_comment_lines
  replace_in_file 'config/routes.rb',
    /Rails\.application\.routes\.draw do.*end/m,
    "Rails.application.routes.draw do\nend"
end


47
48
49
50
51
52
53
# File 'lib/suspenders/app_builder.rb', line 47

def remove_turbolinks
  replace_in_file(
    "app/assets/javascripts/application.js",
    "//= require turbolinks",
    ""
  )
end

#replace_default_puma_configurationObject



329
330
331
# File 'lib/suspenders/app_builder.rb', line 329

def replace_default_puma_configuration
  copy_file "puma.rb", "config/puma.rb", force: true
end

#replace_gemfile(path) ⇒ Object



233
234
235
236
237
238
239
240
241
# File 'lib/suspenders/app_builder.rb', line 233

def replace_gemfile(path)
  template 'Gemfile.erb', 'Gemfile', force: true do |content|
    if path
      content.gsub(%r{gem .suspenders.}) { |s| %{#{s}, path: "#{path}"} }
    else
      content
    end
  end
end

#require_files_in_libObject



593
594
595
596
597
598
599
600
# File 'lib/voyage/app_builder.rb', line 593

def require_files_in_lib
  create_file 'config/initializers/require_files_in_lib.rb' do <<-RUBY.gsub(/^ {8}/, '')
    # rubocop:disable Rails/FilePath
    Dir[File.join(Rails.root, 'lib', '**', '*.rb')].each { |l| require l }
    # rubocop:enable Rails/FilePath
    RUBY
  end
end

#run_rubocop_auto_correctObject



814
815
816
# File 'lib/voyage/app_builder.rb', line 814

def run_rubocop_auto_correct
  run 'rubocop --auto-correct'
end

#set_ruby_to_version_being_usedObject



861
862
863
# File 'lib/voyage/app_builder.rb', line 861

def set_ruby_to_version_being_used
  create_file '.ruby-version', "#{Voyage::RUBY_VERSION}\n"
end

#set_test_delivery_methodObject



55
56
57
58
59
60
61
# File 'lib/suspenders/app_builder.rb', line 55

def set_test_delivery_method
  inject_into_file(
    "config/environments/development.rb",
    "\n  config.action_mailer.delivery_method = :file",
    after: "config.action_mailer.raise_delivery_errors = true",
  )
end

#set_up_factory_girl_for_rspecObject



123
124
125
# File 'lib/suspenders/app_builder.rb', line 123

def set_up_factory_girl_for_rspec
  copy_file 'factory_girl_rspec.rb', 'spec/support/factory_girl.rb'
end

#set_up_foregoObject



333
334
335
# File 'lib/suspenders/app_builder.rb', line 333

def set_up_forego
  copy_file "Procfile", "Procfile"
end

#set_up_houndObject



131
132
133
# File 'lib/suspenders/app_builder.rb', line 131

def set_up_hound
  copy_file "hound.yml", ".hound.yml"
end

#setup_asset_hostObject



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/suspenders/app_builder.rb', line 172

def setup_asset_host
  replace_in_file 'config/environments/production.rb',
    "# config.action_controller.asset_host = 'http://assets.example.com'",
    'config.action_controller.asset_host = ENV.fetch("ASSET_HOST", ENV.fetch("APPLICATION_HOST"))'

  replace_in_file 'config/initializers/assets.rb',
    "config.assets.version = '1.0'",
    'config.assets.version = (ENV["ASSETS_VERSION"] || "1.0")'

  config = <<-EOD
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=31557600",
  }
  EOD

  configure_environment("production", config)
end

#setup_bundler_auditObject



403
404
405
406
# File 'lib/suspenders/app_builder.rb', line 403

def setup_bundler_audit
  copy_file "bundler_audit.rake", "lib/tasks/bundler_audit.rake"
  append_file "Rakefile", %{\ntask default: "bundle:audit"\n}
end

#setup_default_directoriesObject



337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/suspenders/app_builder.rb', line 337

def setup_default_directories
  [
    'app/views/pages',
    'spec/lib',
    'spec/controllers',
    'spec/helpers',
    'spec/support/matchers',
    'spec/support/mixins',
    'spec/support/shared_examples'
  ].each do |dir|
    empty_directory_with_keep_file dir
  end
end

#setup_default_rake_taskObject



459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
# File 'lib/suspenders/app_builder.rb', line 459

def setup_default_rake_task
  append_file 'Rakefile' do
    <<-EOS
task(:default).clear
task default: [:spec]

if defined? RSpec
  task(:spec).clear
  RSpec::Core::RakeTask.new(:spec) do |t|
t.verbose = false
  end
end
    EOS
  end
end

#setup_rack_mini_profilerObject



31
32
33
34
35
36
# File 'lib/suspenders/app_builder.rb', line 31

def setup_rack_mini_profiler
  copy_file(
    "rack_mini_profiler.rb",
    "config/initializers/rack_mini_profiler.rb",
  )
end

#setup_secret_tokenObject



190
191
192
# File 'lib/suspenders/app_builder.rb', line 190

def setup_secret_token
  template 'secrets.yml', 'config/secrets.yml', force: true
end

#setup_segmentObject



398
399
400
401
# File 'lib/suspenders/app_builder.rb', line 398

def setup_segment
  copy_file '_analytics.html.erb',
    'app/views/application/_analytics.html.erb'
end

#setup_springObject



408
409
410
# File 'lib/suspenders/app_builder.rb', line 408

def setup_spring
  bundle_command "exec spring binstub --all"
end

#spin_up_webpackerObject



834
835
836
837
# File 'lib/voyage/app_builder.rb', line 834

def spin_up_webpacker
  rake 'webpacker:install'
  rake 'webpacker:install:react'
end

#update_application_css_fileObject



693
694
695
696
697
698
699
700
701
# File 'lib/voyage/app_builder.rb', line 693

def update_application_css_file
  inject_into_file 'app/assets/stylesheets/application.scss', before: '@import "neat";'  do <<-RUBY.gsub(/^ {8}/, '')
    $visual-grid: true;
    $visual-grid-color: #9cf !default;
    $visual-grid-index: front !default;
    $visual-grid-opacity: 0.1 !default;
    RUBY
  end
end

#update_application_layout_for_slimObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/voyage/app_builder.rb', line 40

def update_application_layout_for_slim
  find = <<-RUBY.gsub(/^ {4}/, '')
    <%#
      Configure default and controller-, and view-specific titles in
      config/locales/en.yml. For more see:
      https://github.com/calebthompson/title#usage
    %>
  RUBY

  replace = <<-RUBY.gsub(/^ {8}/, '')
      <% # Configure default and controller-, and view-specific titles in
    # config/locales/en.yml. For more see:
    # https://github.com/calebthompson/title#usage %>
  RUBY

  replace_in_file 'app/views/layouts/application.html.erb', find, replace

  inside('lib') do # arbitrary, run in context of newly generated app
    run "erb2slim '../app/views/layouts' '../app/views/layouts'"
    run "erb2slim -d '../app/views/layouts'"
  end

  # strip trailing space after closing "> in application layout before
  # trying to find and replace it
  replace_in_file 'app/views/layouts/application.html.slim', '| "> ', '| ">'

  find = <<-RUBY.gsub(/^ {6}/, '')
    |  <body class="
    = devise_controller? ? 'devise' : 'application'
    = body_class
    | ">
  RUBY

  replace = <<-RUBY.gsub(/^ {6}/, '')
    body class="\#{devise_controller? ? 'devise' : 'application'} \#{body_class}"
  RUBY

  replace_in_file 'app/views/layouts/application.html.slim', find, replace
end

#update_application_rb_for_slimObject



80
81
82
83
84
85
# File 'lib/voyage/app_builder.rb', line 80

def update_application_rb_for_slim
  inject_into_file "config/application.rb", after: "     g.fixture_replacement :factory_girl, dir: 'spec/factories'\n" do <<-'RUBY'.gsub(/^ {2}/, '')
    g.template_engine :slim
    RUBY
  end
end

#update_devise_initializerObject



408
409
410
411
412
413
414
415
# File 'lib/voyage/app_builder.rb', line 408

def update_devise_initializer
  replace_in_file 'config/initializers/devise.rb',
    'config.sign_out_via = :delete', 'config.sign_out_via = :get'

  replace_in_file 'config/initializers/devise.rb',
    "config.mailer_sender = '[email protected]'",
    "config.mailer_sender = '[email protected]'"
end

#update_flashes_css_fileObject



689
690
691
# File 'lib/voyage/app_builder.rb', line 689

def update_flashes_css_file
  replace_in_file 'app/assets/stylesheets/refills/_flashes.scss', "margin-bottom: $base-spacing / 2;", "// margin-bottom: $base-spacing / 2;"
end

#update_gemset_in_gemfileObject



18
19
20
21
22
23
# File 'lib/voyage/app_builder.rb', line 18

def update_gemset_in_gemfile
  replace_in_file 'Gemfile', '#ruby-gemset', "#ruby-gemset=#{app_name}"

  # Remove commented out lines from template
  gsub_file('Gemfile', /^\s{2}\n/, '')
end

#update_test_environmentObject



742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
# File 'lib/voyage/app_builder.rb', line 742

def update_test_environment
  inject_into_file 'spec/support/factory_girl.rb', before: /^end/ do <<-RUBY.gsub(/^ {6}/, '')

    # Spring doesn't reload factory_girl
    config.before(:all) do
      FactoryGirl.reload
    end
    RUBY
  end

  template "../templates/rails_helper.rb.erb", "spec/rails_helper.rb", force: true

  %w(test development).each do |environment|
    inject_into_file "config/environments/#{environment}.rb", after: /^end/ do <<-RUBY.gsub(/^ {10}/, '')

      # NOTE: console can use create(:factory_name), or build(:factory_name) without
      # needing to use FactoryGirl.create(:factory_name).
      include FactoryGirl::Syntax::Methods
      RUBY
    end
  end
end

#use_postgres_config_templateObject



224
225
226
227
# File 'lib/suspenders/app_builder.rb', line 224

def use_postgres_config_template
  template 'postgresql_database.yml.erb', 'config/database.yml',
    force: true
end

#use_slimObject



29
30
31
32
33
34
35
36
37
38
# File 'lib/voyage/app_builder.rb', line 29

def use_slim
  if @@accept_defaults || agree?('Would you like to use slim? (Y/n)')
    @@use_slim = true
    run 'gem install html2slim'
    update_application_rb_for_slim
  else
    @@use_slim = false
    gsub_file('Gemfile', /^gem 'slim-rails'\n/, '')
  end
end