pineapples 0.1.0 → 0.3.34
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +1 -0
- data/.ruby-gemset +1 -0
- data/bin/pineapples +4 -9
- data/lib/pineapples/actions/apply.rb +34 -0
- data/lib/pineapples/actions/base/action.rb +72 -0
- data/lib/pineapples/actions/base/target.rb +136 -0
- data/lib/pineapples/actions/chmod.rb +28 -0
- data/lib/pineapples/actions/copy_file.rb +48 -0
- data/lib/pineapples/actions/create_file.rb +114 -0
- data/lib/pineapples/actions/directory.rb +115 -0
- data/lib/pineapples/actions/empty_directory.rb +71 -0
- data/lib/pineapples/actions/get.rb +38 -0
- data/lib/pineapples/actions/git.rb +17 -0
- data/lib/pineapples/actions/gsub_file.rb +36 -0
- data/lib/pineapples/actions/insert_into_file.rb +131 -0
- data/lib/pineapples/actions/inside.rb +69 -0
- data/lib/pineapples/actions/keep_file.rb +15 -0
- data/lib/pineapples/actions/prepend_to_class.rb +26 -0
- data/lib/pineapples/actions/rails/copy_migration.rb +67 -0
- data/lib/pineapples/actions/rails/erb_converters.rb +37 -0
- data/lib/pineapples/actions/rails/rails.rb +186 -0
- data/lib/pineapples/actions/remove_file.rb +28 -0
- data/lib/pineapples/actions/ruby.rb +49 -0
- data/lib/pineapples/actions/shell.rb +40 -0
- data/lib/pineapples/actions/template.rb +35 -0
- data/lib/pineapples/actions.rb +124 -39
- data/lib/pineapples/app_builder.rb +70 -0
- data/lib/pineapples/app_generator.rb +187 -0
- data/lib/pineapples/build_tasks/root_files.rb +23 -0
- data/lib/pineapples/error.rb +7 -0
- data/lib/pineapples/helpers.rb +34 -0
- data/lib/pineapples/parser.rb +37 -0
- data/lib/pineapples/setting.rb +155 -0
- data/lib/pineapples/settings.rb +31 -0
- data/lib/pineapples/templates/.buildpacks +2 -0
- data/lib/pineapples/templates/.editor-config +11 -0
- data/lib/pineapples/templates/.example.env.tt +11 -0
- data/lib/pineapples/templates/.example.rspec +3 -0
- data/lib/pineapples/templates/.gitignore +23 -0
- data/lib/pineapples/templates/Aptfile +0 -0
- data/lib/pineapples/templates/Gemfile.tt +89 -0
- data/lib/pineapples/templates/Guardfile +27 -0
- data/lib/pineapples/templates/Procfile +1 -0
- data/lib/pineapples/templates/README.md.tt +32 -0
- data/lib/pineapples/templates/Rakefile +6 -0
- data/lib/pineapples/templates/app/assets/javascripts/application.js +1 -0
- data/lib/pineapples/templates/app/assets/javascripts/libs.js +2 -0
- data/lib/pineapples/templates/app/assets/stylesheets/application.scss +1 -0
- data/lib/pineapples/templates/app/controllers/application_controller.rb.tt +48 -0
- data/lib/pineapples/templates/app/controllers/auth/confirmations_controller.rb +2 -0
- data/lib/pineapples/templates/app/controllers/pages_controller.rb +6 -0
- data/lib/pineapples/templates/app/helpers/application_helper.rb +59 -0
- data/lib/pineapples/templates/app/helpers/title_helper.rb +77 -0
- data/lib/pineapples/templates/app/models/user!=needs_user_model!.rb.tt +28 -0
- data/lib/pineapples/templates/app/views/common/_flashes.html.erb +16 -0
- data/lib/pineapples/templates/app/views/common/_footer.html.erb +3 -0
- data/lib/pineapples/templates/app/views/common/_header.html.erb +5 -0
- data/lib/pineapples/templates/app/views/layouts/application.html.erb.tt +33 -0
- data/lib/pineapples/templates/app/views/pages/home.html.erb +4 -0
- data/lib/pineapples/templates/bin/bundle +3 -0
- data/lib/pineapples/templates/bin/rails +8 -0
- data/lib/pineapples/templates/bin/rake +8 -0
- data/lib/pineapples/templates/bin/setup +33 -0
- data/lib/pineapples/templates/bin/spring +15 -0
- data/lib/pineapples/templates/browserlist +4 -0
- data/lib/pineapples/templates/config/application.rb.tt +43 -0
- data/lib/pineapples/templates/config/boot.rb +5 -0
- data/lib/pineapples/templates/config/database.yml.tt +20 -0
- data/lib/pineapples/templates/config/environment.rb +5 -0
- data/lib/pineapples/templates/config/environments/development.rb +64 -0
- data/lib/pineapples/templates/config/environments/production.rb +77 -0
- data/lib/pineapples/templates/config/environments/test.rb +34 -0
- data/lib/pineapples/templates/config/i18n-tasks.yml +13 -0
- data/lib/pineapples/templates/config/initializers/assets.rb +11 -0
- data/lib/pineapples/templates/config/initializers/backtrace_silencers.rb +7 -0
- data/lib/pineapples/templates/config/initializers/carrierwave.rb +22 -0
- data/lib/pineapples/templates/config/initializers/cookies_serializer.rb +3 -0
- data/lib/pineapples/templates/config/initializers/filter_parameters_logging.rb +4 -0
- data/lib/pineapples/templates/config/initializers/inflections.rb +16 -0
- data/lib/pineapples/templates/config/initializers/mime_types.rb +4 -0
- data/lib/pineapples/templates/config/initializers/pry.rb +10 -0
- data/lib/pineapples/templates/config/initializers/redis.rb +3 -0
- data/lib/pineapples/templates/config/initializers/session_store.rb.tt +3 -0
- data/lib/pineapples/templates/config/initializers/wrap_parameters.rb +14 -0
- data/lib/pineapples/templates/config/locales/en.yml +19 -0
- data/lib/pineapples/templates/config/puma.rb +21 -0
- data/lib/pineapples/templates/config/routes.rb.tt +10 -0
- data/lib/pineapples/templates/config/secrets.yml +11 -0
- data/lib/pineapples/templates/config/smtp.rb +11 -0
- data/lib/pineapples/templates/config.ru.tt +7 -0
- data/lib/pineapples/templates/db/migrate/01_enable_postgres_extensions.rb +15 -0
- data/lib/pineapples/templates/db/migrate/02_create_data_migrations.rb +14 -0
- data/lib/pineapples/templates/db/migrate/03_devise_create_users.rb +41 -0
- data/lib/pineapples/templates/db/migrate/04_add_role_field_to_users.rb +7 -0
- data/lib/pineapples/templates/lib/devise!=devise!/ajax_failure.rb +11 -0
- data/lib/pineapples/templates/lib/extensions/form_builder.rb +24 -0
- data/lib/pineapples/templates/lib/extensions/http_errors.rb +34 -0
- data/lib/pineapples/templates/lib/extensions/to_boolean.rb +45 -0
- data/lib/pineapples/templates/lib/logging/custom_rack_logger.rb +11 -0
- data/lib/pineapples/templates/lib/logging/custom_request_logger.rb +65 -0
- data/lib/pineapples/templates/lib/simple_form/components/append.rb +15 -0
- data/lib/pineapples/templates/lib/simple_form/components/prepend.rb +15 -0
- data/lib/pineapples/templates/lib/tasks/admin!=user_role_field!.rake +52 -0
- data/lib/pineapples/templates/lib/tasks/auto_annotate_models.rake +37 -0
- data/lib/pineapples/templates/lib/templates/erb/scaffold/_form.html.erb +14 -0
- data/lib/pineapples/templates/lib/virtus/virtus.rb +23 -0
- data/lib/pineapples/templates/public/404.html +67 -0
- data/lib/pineapples/templates/public/422.html +67 -0
- data/lib/pineapples/templates/public/500.html +66 -0
- data/lib/pineapples/templates/public/favicon.ico +0 -0
- data/lib/pineapples/templates/public/robots.txt +5 -0
- data/lib/pineapples/version.rb +1 -1
- data/lib/pineapples.rb +17 -2
- data/pineapples.gemspec +16 -15
- metadata +208 -2
@@ -0,0 +1,49 @@
|
|
1
|
+
require_relative 'shell'
|
2
|
+
module Pineapples
|
3
|
+
module Actions
|
4
|
+
# Executes a ruby script (taking into account WIN32 platform quirks).
|
5
|
+
#
|
6
|
+
# ==== Parameters
|
7
|
+
# command<String>:: the command to be executed.
|
8
|
+
# options<Hash>:: give :verbose => false to not log the status.
|
9
|
+
#
|
10
|
+
def ruby(command, options = {})
|
11
|
+
return if behaviour != :inboke
|
12
|
+
shell(command, options.merge(with: ruby_command))
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
# Return the path to the ruby interpreter taking into account multiple
|
17
|
+
# installations and windows extensions.
|
18
|
+
#
|
19
|
+
def ruby_command # rubocop:disable MethodLength
|
20
|
+
@ruby_command ||= begin
|
21
|
+
ruby_name = RbConfig::CONFIG['ruby_install_name']
|
22
|
+
ruby = File.join(RbConfig::CONFIG['bindir'], ruby_name)
|
23
|
+
ruby << RbConfig::CONFIG['EXEEXT']
|
24
|
+
|
25
|
+
# avoid using different name than ruby (on platforms supporting links)
|
26
|
+
if ruby_name != 'ruby' && File.respond_to?(:readlink)
|
27
|
+
begin
|
28
|
+
alternate_ruby = File.join(RbConfig::CONFIG['bindir'], 'ruby')
|
29
|
+
alternate_ruby << RbConfig::CONFIG['EXEEXT']
|
30
|
+
|
31
|
+
# ruby is a symlink
|
32
|
+
if File.symlink? alternate_ruby
|
33
|
+
linked_ruby = File.readlink alternate_ruby
|
34
|
+
|
35
|
+
# symlink points to 'ruby_install_name'
|
36
|
+
ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
|
37
|
+
end
|
38
|
+
rescue NotImplementedError # rubocop:disable HandleExceptions
|
39
|
+
# just ignore on windows
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# escape string in case path to ruby executable contain spaces.
|
44
|
+
ruby.sub!(/.*\s.*/m, '"\&"')
|
45
|
+
ruby
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Pineapples
|
2
|
+
module Actions
|
3
|
+
# Executes a command returning the contents of the command.
|
4
|
+
#
|
5
|
+
# ==== Parameters
|
6
|
+
# command<String>:: the command to be executed.
|
7
|
+
# options<Hash>:: give :verbose => false to not log the status, :capture => true to hide to output. Specify :with
|
8
|
+
# to append an executable to command execution.
|
9
|
+
#
|
10
|
+
# ==== Example
|
11
|
+
#
|
12
|
+
# inside 'vendor' do
|
13
|
+
# shell 'ln -s ~/edge rails'
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
def shell(command, options = {})
|
17
|
+
return if behavior == :revoke
|
18
|
+
|
19
|
+
verbose = options.fetch(:verbose, verbose?)
|
20
|
+
execute = !options.fetch(:pretend, pretend?)
|
21
|
+
|
22
|
+
description = "#{command} from #{current_app_dir.inspect}"
|
23
|
+
|
24
|
+
executable = options[:with].to_s
|
25
|
+
|
26
|
+
if executable.present?
|
27
|
+
description = "#{File.basename(executable)} #{desc}"
|
28
|
+
command = "#{executable} #{command}"
|
29
|
+
end
|
30
|
+
|
31
|
+
say_action(:shell, description, verbose)
|
32
|
+
|
33
|
+
if execute
|
34
|
+
config[:capture] ? `#{command}` : system("#{command}")
|
35
|
+
raise Error, "#{command} failed with status #{$CHILD_STATUS.exitstatus}." if not $CHILD_STATUS.success?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module Pineapples
|
4
|
+
module Actions
|
5
|
+
# Gets an ERB template at the relative source, executes it and makes a copy
|
6
|
+
# at the relative destination. If the destination is not given it's assumed
|
7
|
+
# to be equal to the source removing .tt from the filename.
|
8
|
+
#
|
9
|
+
# ==== Parameters
|
10
|
+
# source<String>:: the relative path to the source root.
|
11
|
+
# target<String>:: the relative path to the destination root.
|
12
|
+
# options<Hash>:: give :verbose => false to not log the status.
|
13
|
+
#
|
14
|
+
# ==== Examples
|
15
|
+
#
|
16
|
+
# template "README", "doc/README"
|
17
|
+
#
|
18
|
+
# template "doc/README"
|
19
|
+
#
|
20
|
+
def template(source, *args, &block)
|
21
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
22
|
+
target = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, '')
|
23
|
+
|
24
|
+
source = File.expand_path(find_in_source_paths(source.to_s))
|
25
|
+
context = options.delete(:context) || binding #instance_eval('binding')
|
26
|
+
|
27
|
+
create_file(target, nil, options) do
|
28
|
+
template = File.binread(source)
|
29
|
+
content = ERB.new(template, nil, '-').result(context)
|
30
|
+
content = block.call(content) if block
|
31
|
+
content
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/pineapples/actions.rb
CHANGED
@@ -1,39 +1,124 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'uri'
|
4
|
+
require 'pineapples/actions/base/action'
|
5
|
+
require 'pineapples/actions/base/target'
|
6
|
+
require 'pineapples/actions/apply'
|
7
|
+
require 'pineapples/actions/chmod'
|
8
|
+
require 'pineapples/actions/copy_file'
|
9
|
+
require 'pineapples/actions/create_file'
|
10
|
+
require 'pineapples/actions/directory'
|
11
|
+
require 'pineapples/actions/empty_directory'
|
12
|
+
require 'pineapples/actions/get'
|
13
|
+
require 'pineapples/actions/git'
|
14
|
+
require 'pineapples/actions/gsub_file'
|
15
|
+
require 'pineapples/actions/insert_into_file'
|
16
|
+
require 'pineapples/actions/inside'
|
17
|
+
require 'pineapples/actions/keep_file'
|
18
|
+
require 'pineapples/actions/prepend_to_class'
|
19
|
+
require 'pineapples/actions/remove_file'
|
20
|
+
require 'pineapples/actions/ruby'
|
21
|
+
require 'pineapples/actions/shell'
|
22
|
+
require 'pineapples/actions/template'
|
23
|
+
|
24
|
+
require 'pineapples/actions/rails/rails'
|
25
|
+
|
26
|
+
module Pineapples
|
27
|
+
module Actions
|
28
|
+
TEMPLATE_EXTNAME = '.tt'
|
29
|
+
|
30
|
+
DEFAULT_COLOR = :light_green
|
31
|
+
|
32
|
+
attr_reader :behaviour
|
33
|
+
|
34
|
+
def initialize(options)
|
35
|
+
super
|
36
|
+
|
37
|
+
@behaviour = options.behaviour || :invoke
|
38
|
+
end
|
39
|
+
|
40
|
+
# Executes instance of Action subclass depending on generator behaviour
|
41
|
+
def action(instance) #:nodoc:
|
42
|
+
return if instance.skip?
|
43
|
+
if behaviour == :invoke
|
44
|
+
instance.invoke!
|
45
|
+
else
|
46
|
+
instance.revoke!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def templates_root
|
51
|
+
@templates_root ||= File.join(__dir__, 'templates')
|
52
|
+
end
|
53
|
+
|
54
|
+
def source_paths
|
55
|
+
@source_paths ||= []
|
56
|
+
end
|
57
|
+
|
58
|
+
def source_paths_for_search
|
59
|
+
paths = []
|
60
|
+
paths += source_paths
|
61
|
+
paths << templates_root if templates_root
|
62
|
+
paths
|
63
|
+
end
|
64
|
+
|
65
|
+
# dir argument must me absolute path
|
66
|
+
def relative_to_app_root(dir)
|
67
|
+
@app_root_pathname ||= Pathname.new(app_root)
|
68
|
+
path = Pathname.new(dir)
|
69
|
+
path.relative_path_from(@app_root_pathname).to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
def relative_to_current_app_dir(dir)
|
73
|
+
current_app_path = Pathname.new(current_app_dir)
|
74
|
+
path = Pathname.new(dir)
|
75
|
+
path.relative_path_from(current_app_path).to_s
|
76
|
+
end
|
77
|
+
|
78
|
+
def find_in_source_paths(file)
|
79
|
+
files_to_search = [file, file + TEMPLATE_EXTNAME]
|
80
|
+
sources = source_paths_for_search
|
81
|
+
|
82
|
+
sources.each do |source_path|
|
83
|
+
files_to_search.each do |file|
|
84
|
+
source_file = File.expand_path(file, source_path)
|
85
|
+
return source_file if File.exist?(source_file)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
message = "Could not find #{file.inspect} in any of your source paths. "
|
90
|
+
|
91
|
+
unless self.templates_root
|
92
|
+
message << "Please set your generator instance template_root to PATH with the PATH containing your templates."
|
93
|
+
end
|
94
|
+
|
95
|
+
if sources.empty?
|
96
|
+
message << "Currently you have no source paths."
|
97
|
+
else
|
98
|
+
message << "Your current source paths are: \n#{sources.join("\n")}"
|
99
|
+
end
|
100
|
+
|
101
|
+
raise Error, message
|
102
|
+
end
|
103
|
+
|
104
|
+
def say_status(status, message, color = :light_green, log = true)
|
105
|
+
return if !log
|
106
|
+
|
107
|
+
spaces = ' ' * $terminal.indent_size * 2
|
108
|
+
|
109
|
+
status = status.to_s.rjust(12)
|
110
|
+
status = status.colorize(color)
|
111
|
+
|
112
|
+
output = "#{status}#{spaces}#{message}"
|
113
|
+
|
114
|
+
say(output)
|
115
|
+
end
|
116
|
+
|
117
|
+
def indent(verbose = true, level_increment = 1)
|
118
|
+
$terminal.indent_level += level_increment if verbose
|
119
|
+
yield
|
120
|
+
$terminal.indent_level -= level_increment if verbose
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'pineapples/actions'
|
2
|
+
#require 'pineapples/build_tasks/root_files'
|
3
|
+
|
4
|
+
module Pineapples
|
5
|
+
class AppBuilder
|
6
|
+
include Pineapples::Actions
|
7
|
+
|
8
|
+
def root_files
|
9
|
+
create_file '.ruby-version', "#{Pineapples::RUBY_VERSION}\n"
|
10
|
+
create_file '.ruby-gemset', app_name
|
11
|
+
|
12
|
+
template 'config.ru'
|
13
|
+
template 'Gemfile'
|
14
|
+
copy_file 'Guardfile'
|
15
|
+
copy_file 'Procfile'
|
16
|
+
copy_file 'Rakefile'
|
17
|
+
|
18
|
+
copy_file '.gitignore'
|
19
|
+
|
20
|
+
template 'README.md.tt'
|
21
|
+
copy_file 'browserlist'
|
22
|
+
copy_file '.editor-config'
|
23
|
+
|
24
|
+
template '.example.env.tt'
|
25
|
+
|
26
|
+
if options.heroku?
|
27
|
+
copy_file '.buildpacks'
|
28
|
+
template 'Aptfile'
|
29
|
+
end
|
30
|
+
|
31
|
+
if !options.skip_test?
|
32
|
+
copy_file '.example.rspec'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def app_files
|
37
|
+
directory 'app', except: 'user.rb'
|
38
|
+
|
39
|
+
inside 'app' do
|
40
|
+
keep_file 'assets/fonts'
|
41
|
+
keep_file 'assets/images'
|
42
|
+
if create_user_model?
|
43
|
+
template 'models/user.rb.tt'
|
44
|
+
else
|
45
|
+
keep_file 'models'
|
46
|
+
end
|
47
|
+
keep_file 'mailers'
|
48
|
+
|
49
|
+
keep_file 'controllers/concerns'
|
50
|
+
keep_file 'models/concerns'
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
def bin_files
|
56
|
+
directory 'bin' do |content|
|
57
|
+
"#{shebang}\n" + content
|
58
|
+
end
|
59
|
+
chmod 'bin', 0755 & ~File.umask, verbose: false
|
60
|
+
end
|
61
|
+
|
62
|
+
def config_files
|
63
|
+
directory 'config'
|
64
|
+
|
65
|
+
inside 'config' do
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require 'pineapples/actions'
|
2
|
+
require 'pineapples/helpers'
|
3
|
+
require 'pineapples/settings'
|
4
|
+
|
5
|
+
module Pineapples
|
6
|
+
class AppGenerator
|
7
|
+
extend Pineapples::Settings
|
8
|
+
prepend Pineapples::Actions
|
9
|
+
include Pineapples::Actions::Rails
|
10
|
+
include Pineapples::Helpers
|
11
|
+
|
12
|
+
TEMPLATING_ENGINES = [:erb, :haml, :slim]
|
13
|
+
|
14
|
+
setting :heroku, type: :boolean, default: false,
|
15
|
+
prompt: 'Wanna use Heroku?'
|
16
|
+
|
17
|
+
setting :carrierwave, type: :boolean, default: false,
|
18
|
+
prompt: 'Wanna use Carrierwave for file uploads?'
|
19
|
+
|
20
|
+
setting :devise, type: :boolean, default: true,
|
21
|
+
prompt: 'Wanna use Devise for authentication?'
|
22
|
+
|
23
|
+
setting :ajax_login, type: :boolean, default: false,
|
24
|
+
prompt: 'Wanna login via ajax using devise?'
|
25
|
+
|
26
|
+
setting :pundit, type: :boolean, default: true,
|
27
|
+
prompt: 'Wanna use Pundit for authorization?'
|
28
|
+
|
29
|
+
setting :user_role_field, type: :boolean, default: true,
|
30
|
+
prompt: 'Wanna add role attribute to users model as simple user roles solution?'
|
31
|
+
|
32
|
+
setting :template_engine, type: :symbol, default: :erb, options: TEMPLATING_ENGINES,
|
33
|
+
prompt: 'Select templating engine to be used in the app'
|
34
|
+
|
35
|
+
setting :bootstrap, type: :boolean, default: false,
|
36
|
+
prompt: 'Wanna use Bootstrap on this project?'
|
37
|
+
|
38
|
+
attr_accessor :app_name,
|
39
|
+
:app_root,
|
40
|
+
:settings
|
41
|
+
|
42
|
+
def initialize(options)
|
43
|
+
@app_name = options.app_name.gsub(/\s+/, '-')
|
44
|
+
@app_root = options.app_root || File.expand_path(app_name)
|
45
|
+
@debug = options.debug || false
|
46
|
+
@pretend = options.pretend || false
|
47
|
+
@verbose = options.verbose || true
|
48
|
+
|
49
|
+
@settings = self.class.settings
|
50
|
+
end
|
51
|
+
|
52
|
+
def start!
|
53
|
+
valid_const! && check_target!
|
54
|
+
create_app_root
|
55
|
+
|
56
|
+
# ask_user_settings
|
57
|
+
|
58
|
+
create_root_files
|
59
|
+
create_app_files
|
60
|
+
create_bin_files
|
61
|
+
create_config_files
|
62
|
+
create_db_files
|
63
|
+
create_lib_files
|
64
|
+
create_public_files
|
65
|
+
create_spec_files
|
66
|
+
|
67
|
+
create_misc_folders
|
68
|
+
|
69
|
+
#run_after_bundle_callbacks
|
70
|
+
rescue Pineapples::Error => error
|
71
|
+
(debug? || ENV['PINEAPPLES_DEBUG'] == '1') ? (raise error) : say(error.message.light_red)
|
72
|
+
exit 1
|
73
|
+
end
|
74
|
+
|
75
|
+
def ask_user_settings
|
76
|
+
settings[:heroku].ask_setting
|
77
|
+
settings[:template_engine].ask_setting
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_root_files
|
81
|
+
copy_file '.editor-config'
|
82
|
+
template '.example.env'
|
83
|
+
copy_file '.example.rspec'
|
84
|
+
copy_file '.gitignore'
|
85
|
+
copy_file 'browserlist'
|
86
|
+
template 'config.ru'
|
87
|
+
template 'Gemfile'
|
88
|
+
copy_file 'Guardfile'
|
89
|
+
copy_file 'Procfile'
|
90
|
+
copy_file 'Rakefile'
|
91
|
+
template 'README.md', 'README.md'
|
92
|
+
if heroku?
|
93
|
+
copy_file '.buildpacks'
|
94
|
+
copy_file 'Aptfile'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_app_files
|
99
|
+
directory 'app'
|
100
|
+
keep_file 'app/assets/fonts'
|
101
|
+
keep_file 'app/assets/images'
|
102
|
+
|
103
|
+
keep_file 'app/mailers'
|
104
|
+
keep_file 'app/models' if !needs_user_model?
|
105
|
+
end
|
106
|
+
|
107
|
+
def create_bin_files
|
108
|
+
directory 'bin'
|
109
|
+
# chmod 'bin', 0755 & ~File.umask, verbose: false
|
110
|
+
end
|
111
|
+
|
112
|
+
def create_config_files
|
113
|
+
directory 'config'
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_db_files
|
117
|
+
empty_directory 'db/migrate'
|
118
|
+
copy_migration 'enable_postgres_extensions'
|
119
|
+
copy_migration 'create_data_migrations'
|
120
|
+
if devise?
|
121
|
+
copy_migration 'devise_create_users'
|
122
|
+
copy_migration 'add_role_field_to_users' if user_role_field?
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def create_lib_files
|
127
|
+
directory 'lib'
|
128
|
+
keep_file 'lib/assets'
|
129
|
+
end
|
130
|
+
|
131
|
+
def create_public_files
|
132
|
+
directory 'public'
|
133
|
+
end
|
134
|
+
|
135
|
+
def create_spec_files
|
136
|
+
# directory 'spec'
|
137
|
+
end
|
138
|
+
|
139
|
+
def create_misc_folders
|
140
|
+
keep_file 'log'
|
141
|
+
|
142
|
+
empty_directory 'tmp/cache/assets'
|
143
|
+
|
144
|
+
inside 'vendor/assets' do
|
145
|
+
keep_file 'javascripts'
|
146
|
+
keep_file 'stylesheets'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def run_after_bundle_callbacks
|
151
|
+
@after_bundle_callbacks.each(&:call)
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
|
156
|
+
def debug?
|
157
|
+
@debug
|
158
|
+
end
|
159
|
+
|
160
|
+
def pretend?
|
161
|
+
@pretend
|
162
|
+
end
|
163
|
+
|
164
|
+
def execute?
|
165
|
+
!pretend?
|
166
|
+
end
|
167
|
+
|
168
|
+
def verbose?
|
169
|
+
@verbose
|
170
|
+
end
|
171
|
+
|
172
|
+
protected
|
173
|
+
|
174
|
+
def create_app_root
|
175
|
+
FileUtils::mkdir_p(app_root)
|
176
|
+
say_status :create_root, 'Created application root'
|
177
|
+
end
|
178
|
+
|
179
|
+
def check_target!
|
180
|
+
if Dir["#{app_root}/*"].present?
|
181
|
+
puts "I won't grow pineapples there, the target directory isn't empty."
|
182
|
+
exit 1
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Pineapples
|
2
|
+
module BuildTasks
|
3
|
+
module RootFiles
|
4
|
+
def readme
|
5
|
+
end
|
6
|
+
|
7
|
+
def rakefile
|
8
|
+
end
|
9
|
+
|
10
|
+
def configru
|
11
|
+
end
|
12
|
+
|
13
|
+
def gitignore
|
14
|
+
end
|
15
|
+
|
16
|
+
def gemfile
|
17
|
+
end
|
18
|
+
|
19
|
+
# build(:) if !options.skip_git?
|
20
|
+
# build(:gemfile) if !options.skip_gemfile?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Pineapples
|
2
|
+
module Helpers
|
3
|
+
RESERVED_NAMES = %w[application destroy plugin runner test]
|
4
|
+
|
5
|
+
def needs_user_model?
|
6
|
+
user_role_field? || devise?
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def app_const_base
|
12
|
+
@app_const_base ||= app_name.gsub(/\W/, '_').squeeze('_').camelize
|
13
|
+
end
|
14
|
+
|
15
|
+
def app_const
|
16
|
+
@app_const ||= "#{app_const_base}::Application"
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid_const!
|
20
|
+
if app_const =~ /^\d/
|
21
|
+
raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers."
|
22
|
+
elsif RESERVED_NAMES.include?(app_name)
|
23
|
+
raise Error, "Invalid application name #{app_name}. Please give a name which does not match one of the reserved rails words."
|
24
|
+
elsif Object.const_defined?(app_const_base)
|
25
|
+
raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def app_secret
|
30
|
+
SecureRandom.hex(64)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Pineapples
|
2
|
+
class Parser
|
3
|
+
def self.parse(args)
|
4
|
+
options = OpenStruct.new
|
5
|
+
options.app_name = nil
|
6
|
+
|
7
|
+
parser = OptionParser.new do |opts|
|
8
|
+
opts.banner = 'Usage: pineapples [options] NEW_APP_DIRECTORY'
|
9
|
+
|
10
|
+
opts.on('-h', '--help', 'Show pineapples usage') do
|
11
|
+
self.usage_and_exit(opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
15
|
+
puts Pineapples::VERSION
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
parser.parse!
|
22
|
+
options.app_name = ARGV.first
|
23
|
+
|
24
|
+
raise OptionParser::InvalidOption if options.app_name.nil?
|
25
|
+
|
26
|
+
options
|
27
|
+
rescue OptionParser::InvalidOption
|
28
|
+
self.usage_and_exit(parser)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.usage_and_exit(parser)
|
33
|
+
say parser
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|