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,155 @@
|
|
1
|
+
module Pineapples
|
2
|
+
class Setting
|
3
|
+
attr_reader :name, :type, :default, :question, :options
|
4
|
+
attr_accessor :value
|
5
|
+
|
6
|
+
VALID_TYPES = [:boolean, :numeric, :string, :symbol]
|
7
|
+
|
8
|
+
def initialize(name, options = {})
|
9
|
+
raise ArgumentError, "option name can't be nil" if name.nil?
|
10
|
+
raise ArgumentError, "type can't be nil" if options[:type].nil?
|
11
|
+
|
12
|
+
type = options[:type].to_sym
|
13
|
+
|
14
|
+
raise ArgumentError, "Type :#{type} is not valid for options." if type && !valid_type?(type)
|
15
|
+
|
16
|
+
@name = name
|
17
|
+
@type = type || :string
|
18
|
+
@default = options[:default]
|
19
|
+
@value = @default if @default
|
20
|
+
@question = options[:prompt]
|
21
|
+
@options = Array(options[:options])
|
22
|
+
|
23
|
+
validate_options_type!
|
24
|
+
validate_type!(default)
|
25
|
+
validate_value_in_options!(default)
|
26
|
+
end
|
27
|
+
|
28
|
+
def value=(setting)
|
29
|
+
validate_type!(setting)
|
30
|
+
validate_value_in_options!(setting)
|
31
|
+
@value = setting
|
32
|
+
end
|
33
|
+
|
34
|
+
def valid_type?(type)
|
35
|
+
VALID_TYPES.include?(type)
|
36
|
+
end
|
37
|
+
|
38
|
+
def has_default?
|
39
|
+
@default || (@default == false)
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_options?
|
43
|
+
@options.present?
|
44
|
+
end
|
45
|
+
|
46
|
+
VALID_TYPES.each do |type|
|
47
|
+
define_method :"#{type}?" do
|
48
|
+
self.type == type
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def ask_setting
|
53
|
+
if has_options?
|
54
|
+
ask_with_options
|
55
|
+
else
|
56
|
+
if boolean?
|
57
|
+
ask_boolean
|
58
|
+
else
|
59
|
+
ask
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def ask_with_options
|
67
|
+
puts
|
68
|
+
index = Ask.list(question_string, options_with_color, inquirer_options)
|
69
|
+
puts
|
70
|
+
answer = options[index]
|
71
|
+
self.value = cast_to_type(answer)
|
72
|
+
end
|
73
|
+
|
74
|
+
def ask_boolean
|
75
|
+
puts
|
76
|
+
answer = Ask.confirm(question_string, inquirer_options)
|
77
|
+
puts
|
78
|
+
self.value = cast_to_type(answer)
|
79
|
+
end
|
80
|
+
|
81
|
+
def ask
|
82
|
+
puts
|
83
|
+
answer = Ask.input(question_string, inquirer_options)
|
84
|
+
puts
|
85
|
+
|
86
|
+
self.value = cast_to_type(answer)
|
87
|
+
end
|
88
|
+
|
89
|
+
def question_string
|
90
|
+
result = ' ' * $terminal.indent_size
|
91
|
+
result << question.light_yellow
|
92
|
+
result << default_string if has_default?
|
93
|
+
end
|
94
|
+
|
95
|
+
def options_with_color
|
96
|
+
options.map{ |option| option.to_s.light_blue }
|
97
|
+
end
|
98
|
+
|
99
|
+
def default_string
|
100
|
+
" (default: #{default})".light_green
|
101
|
+
end
|
102
|
+
|
103
|
+
def cast_to_type(setting)
|
104
|
+
case type
|
105
|
+
when :numeric
|
106
|
+
setting.to_f
|
107
|
+
when :string
|
108
|
+
setting.to_s
|
109
|
+
when :symbol
|
110
|
+
setting.to_sym
|
111
|
+
else
|
112
|
+
setting
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def validate_type(setting)
|
117
|
+
value_type = case setting
|
118
|
+
when nil
|
119
|
+
return true
|
120
|
+
when TrueClass, FalseClass
|
121
|
+
:boolean
|
122
|
+
when Numeric, Hash, Array, String, Symbol
|
123
|
+
setting.class.name.downcase.to_sym
|
124
|
+
end
|
125
|
+
type == value_type
|
126
|
+
end
|
127
|
+
|
128
|
+
def validate_type!(setting)
|
129
|
+
if !validate_type(setting)
|
130
|
+
raise ArgumentError, "Setting's value must match its type."
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def validate_value_in_options!(setting)
|
135
|
+
if has_options? && !options.include?(setting)
|
136
|
+
raise ArgumentError, "New setting value must be one of the options"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def validate_options_type!
|
141
|
+
if options.any?{ |option| !validate_type(option) }
|
142
|
+
raise ArgumentError, "Option #{option} value doesn't match setting type"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def get_type_class
|
147
|
+
Object.const_get(type.to_s.capitalize)
|
148
|
+
end
|
149
|
+
|
150
|
+
def inquirer_options
|
151
|
+
{clear: false, response: false}
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'pineapples/setting'
|
2
|
+
|
3
|
+
module Pineapples
|
4
|
+
module Settings
|
5
|
+
def settings
|
6
|
+
@settings
|
7
|
+
end
|
8
|
+
|
9
|
+
def setting(name, opts)
|
10
|
+
raw_setting = Pineapples::Setting.new(name, opts)
|
11
|
+
|
12
|
+
@settings ||= {}
|
13
|
+
|
14
|
+
self.settings[name] = raw_setting
|
15
|
+
|
16
|
+
define_method name do
|
17
|
+
self.settings[name].value
|
18
|
+
end
|
19
|
+
|
20
|
+
define_method :"#{name}=" do |value|
|
21
|
+
self.settings[name].value = value
|
22
|
+
end
|
23
|
+
|
24
|
+
define_method :"#{name}?" do
|
25
|
+
value = self.send(name)
|
26
|
+
value.present?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# Copy this file into a new file called ".env" in the root of the project.
|
2
|
+
# The dotenv gem will load the contents of .env into the environment when
|
3
|
+
# Rails starts. Access values like this: ENV["RAILS_SECRET_KEY_BASE"]
|
4
|
+
#
|
5
|
+
# The purpose of this file is to keep secrets out of source control.
|
6
|
+
# For more information, see: https://github.com/bkeepers/dotenv
|
7
|
+
|
8
|
+
SECRET_KEY_BASE=<%= app_secret %>
|
9
|
+
SIDEKIQ_WEB_USERNAME=admin
|
10
|
+
SIDEKIQ_WEB_PASSWORD=password
|
11
|
+
LOG_ASSETS = false
|
@@ -0,0 +1,23 @@
|
|
1
|
+
*.DS_Store
|
2
|
+
|
3
|
+
/.bundle
|
4
|
+
/.ruby-gemset
|
5
|
+
/.rvmrc
|
6
|
+
/.rspec
|
7
|
+
|
8
|
+
/.env
|
9
|
+
/.foreman
|
10
|
+
|
11
|
+
/coverage/*
|
12
|
+
|
13
|
+
/log
|
14
|
+
|
15
|
+
/vendor/assets/bower_components
|
16
|
+
*.bowerrc
|
17
|
+
bower.json
|
18
|
+
|
19
|
+
/public/system
|
20
|
+
/public/assets
|
21
|
+
|
22
|
+
/spec/tmp
|
23
|
+
/tmp
|
File without changes
|
@@ -0,0 +1,89 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
ruby '<%= RUBY_VERSION %>'
|
4
|
+
|
5
|
+
gem 'dotenv-rails', groups: [:development, :test]
|
6
|
+
|
7
|
+
gem 'rails', '<%= RAILS_VERSION %>'
|
8
|
+
|
9
|
+
gem 'pg'
|
10
|
+
gem 'postgres_ext'
|
11
|
+
gem 'schema_plus'
|
12
|
+
|
13
|
+
gem 'date_validator'
|
14
|
+
<% if devise? -%>
|
15
|
+
gem 'devise'
|
16
|
+
<% end -%>
|
17
|
+
gem 'email_validator'
|
18
|
+
gem 'fast_blank'
|
19
|
+
gem 'fixme', github: 'henrik/fixme'
|
20
|
+
<% if user_role_field? -%>
|
21
|
+
gem 'highline', require: false
|
22
|
+
<% end -%>
|
23
|
+
gem 'hiredis'
|
24
|
+
gem 'pry-byebug'
|
25
|
+
gem 'pry-rails'
|
26
|
+
gem 'rack-cache'
|
27
|
+
gem 'redis', require: ['redis', 'redis/connection/hiredis']
|
28
|
+
gem 'redis-rails'
|
29
|
+
gem 'require_all'
|
30
|
+
gem 'responders'
|
31
|
+
gem 'seed_migration'
|
32
|
+
gem 'show_data'
|
33
|
+
gem 'simple_enum'
|
34
|
+
gem 'simple_form'
|
35
|
+
gem 'sidekiq'
|
36
|
+
gem 'virtus'
|
37
|
+
|
38
|
+
# Front-end gems
|
39
|
+
gem 'autoprefixer-rails'
|
40
|
+
<% if bootstrap? -%>
|
41
|
+
gem 'bootstrap-sass', '~> 3.3.5'
|
42
|
+
<% end -%>
|
43
|
+
gem 'coffee-rails', '~> 4.1.0'
|
44
|
+
<% if bootstrap? -%>
|
45
|
+
gem 'font-awesome-rails'
|
46
|
+
<% end -%>
|
47
|
+
gem 'jquery-rails'
|
48
|
+
gem 'sassc-rails'
|
49
|
+
gem 'momentjs-rails'
|
50
|
+
gem 'uglifier', '>= 1.3.0'
|
51
|
+
|
52
|
+
<% if heroku? -%>
|
53
|
+
group :production do
|
54
|
+
gem 'heroku-deflater'
|
55
|
+
gem 'rack-timeout'
|
56
|
+
gem 'rails_12factor'
|
57
|
+
end
|
58
|
+
<% end -%>
|
59
|
+
|
60
|
+
group :production, :development do
|
61
|
+
gem 'puma'
|
62
|
+
end
|
63
|
+
|
64
|
+
group :development do
|
65
|
+
gem 'annotate', '~> 2.6.6'
|
66
|
+
gem 'better_errors'
|
67
|
+
gem 'binding_of_caller'
|
68
|
+
gem 'guard-livereload', '~> 2.4', require: false
|
69
|
+
gem 'rack-livereload', github: 'johnbintz/rack-livereload'
|
70
|
+
gem 'rb-fsevent', group: :darwin, require: false
|
71
|
+
gem 'rb-inotify', group: :linux, require: false
|
72
|
+
gem 'quiet_assets'
|
73
|
+
end
|
74
|
+
|
75
|
+
group :test do
|
76
|
+
gem 'capybara'
|
77
|
+
gem 'database_cleaner'
|
78
|
+
gem 'factory_girl_rails'
|
79
|
+
gem 'rspec-rails', '~> 3.2'
|
80
|
+
gem 'shoulda'
|
81
|
+
end
|
82
|
+
|
83
|
+
group :development, :test do
|
84
|
+
gem 'spring'
|
85
|
+
gem 'web-console', '~> 2.0'
|
86
|
+
end
|
87
|
+
|
88
|
+
# bundle exec rake doc:rails generates the API under doc/api.
|
89
|
+
gem 'sdoc', '~> 0.4.0', group: :doc
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
# Run just the livereload monitor with: `guard -P livereload`
|
5
|
+
guard :livereload do
|
6
|
+
watch(%r{app/views/.+\.(erb|haml|slim)$})
|
7
|
+
watch(%r{app/helpers/.+\.rb})
|
8
|
+
watch(%r{public/.+\.(css|js|html)})
|
9
|
+
watch(%r{config/locales/.+\.yml})
|
10
|
+
# Rails Assets Pipeline
|
11
|
+
watch(%r{(app|lib|vendor)(/assets/\w+/(.+\.(css|js))).*}) { |m| "/assets/#{m[3]}" }
|
12
|
+
watch(%r{(app|lib|vendor)(/assets/\w+/(.+)\.(scss))}) { |m| "/assets/#{m[3]}.css" }
|
13
|
+
watch(%r{(app/assets/stylesheets/shared/)(\w+/(.+)\.(scss))}) { |m| "/assets/application.css" }
|
14
|
+
end
|
15
|
+
|
16
|
+
# guard :minitest, spring: true do
|
17
|
+
# # Rails 4
|
18
|
+
# watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
|
19
|
+
# watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
|
20
|
+
# watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
|
21
|
+
# watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
|
22
|
+
# watch(%r{^app/workers/(.+)\.rb$}) { |m| "test/unit/workers/#{m[1]}_test.rb" }
|
23
|
+
# watch(%r{^lib/(.+)\.rb$}) { |m| "test/unit/lib/#{m[1]}_test.rb" }
|
24
|
+
# watch(%r{^lib/tasks/(.+)\.rake$}) { |m| "test/unit/lib/tasks/#{m[1]}_test.rb" }
|
25
|
+
# watch(%r{^test/.+_test\.rb$})
|
26
|
+
# watch(%r{^test/test_helper\.rb$}) { 'test' }
|
27
|
+
# end
|
@@ -0,0 +1 @@
|
|
1
|
+
web: bundle exec puma -C config/puma.rb
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# <%= app_name.humanize %>
|
2
|
+
|
3
|
+
## Getting Started
|
4
|
+
|
5
|
+
After you have cloned this repo, run this setup script to set up your machine
|
6
|
+
with the necessary dependencies to run and test this app:
|
7
|
+
|
8
|
+
% ./bin/setup
|
9
|
+
|
10
|
+
It assumes you have a machine equipped with Ruby, Postgres, etc. If not, provision
|
11
|
+
your machine with [this script].
|
12
|
+
|
13
|
+
[this script]: https://github.com/thoughtbot/laptop
|
14
|
+
|
15
|
+
After setting up, you can run the application using [foreman]:
|
16
|
+
|
17
|
+
% foreman start
|
18
|
+
|
19
|
+
If you don't have `foreman`, see [Foreman's install instructions][foreman]. It
|
20
|
+
is [purposefully excluded from the project's `Gemfile`][exclude].
|
21
|
+
|
22
|
+
[foreman]: https://github.com/ddollar/foreman
|
23
|
+
[exclude]: https://github.com/ddollar/foreman/pull/437#issuecomment-41110407
|
24
|
+
|
25
|
+
## Guidelines
|
26
|
+
|
27
|
+
Use the following guides for getting things done, programming well, and
|
28
|
+
programming in style.
|
29
|
+
|
30
|
+
* [Protocol](http://github.com/thoughtbot/guides/blob/master/protocol)
|
31
|
+
* [Best Practices](http://github.com/thoughtbot/guides/blob/master/best-practices)
|
32
|
+
* [Style](http://github.com/thoughtbot/guides/blob/master/style)
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_tree .
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_self
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_dependency 'application_responder'
|
2
|
+
require_dependency 'ipaddr'
|
3
|
+
|
4
|
+
class ApplicationController < ActionController::Base
|
5
|
+
<% if pundit? -%>
|
6
|
+
include Pundit
|
7
|
+
|
8
|
+
<% end -%>
|
9
|
+
# Prevent CSRF attacks by raising an exception.
|
10
|
+
# For APIs, you may want to use :null_session instead.
|
11
|
+
protect_from_forgery with: :exception
|
12
|
+
<% if pundit? -%>
|
13
|
+
|
14
|
+
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
15
|
+
|
16
|
+
<% end -%>
|
17
|
+
def self.responder
|
18
|
+
ApplicationResponder
|
19
|
+
end
|
20
|
+
<% if devise? -%>
|
21
|
+
|
22
|
+
def guest_user?
|
23
|
+
!current_user
|
24
|
+
end
|
25
|
+
|
26
|
+
<% end -%>
|
27
|
+
<% if user_role_field? -%>
|
28
|
+
def guest_user
|
29
|
+
User.guest
|
30
|
+
end
|
31
|
+
<% end -%>
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def local_request?
|
38
|
+
local_network = IPAddr.new('192.168.0.0/8')
|
39
|
+
request.local? || local_network === request.remote_ip
|
40
|
+
end
|
41
|
+
<% if pundit? -%>
|
42
|
+
|
43
|
+
def user_not_authorized(exception)
|
44
|
+
flash[:error] = 'You are not authorized to perform this action.'
|
45
|
+
redirect_to(request.referrer || root_path)
|
46
|
+
end
|
47
|
+
<% end -%>
|
48
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module ApplicationHelper
|
2
|
+
def parent_layout(layout)
|
3
|
+
layout = layout.to_s
|
4
|
+
layout = "layouts/#{layout}" unless layout.include?('/')
|
5
|
+
|
6
|
+
@view_flow.set(:layout, output_buffer)
|
7
|
+
|
8
|
+
output = render file: layout
|
9
|
+
|
10
|
+
self.output_buffer = ActionView::OutputBuffer.new(output)
|
11
|
+
end
|
12
|
+
|
13
|
+
def modal_for(id, modal_title = nil, &block)
|
14
|
+
modal_id = id + '-modal'
|
15
|
+
modal_body = capture(&block)
|
16
|
+
render partial: 'common/modal', locals: {modal_id: modal_id,
|
17
|
+
modal_title: modal_title,
|
18
|
+
modal_body: modal_body}
|
19
|
+
end
|
20
|
+
|
21
|
+
def svg_tag(filename, options = {})
|
22
|
+
options[:width], options[:height] = extract_dimensions(options.delete(:size)) if options[:size]
|
23
|
+
|
24
|
+
assets = Rails.application.assets
|
25
|
+
file = assets.find_asset(filename + '.svg').body.force_encoding('UTF-8')
|
26
|
+
doc = Nokogiri::HTML::DocumentFragment.parse file
|
27
|
+
|
28
|
+
svg = doc.at_css 'svg'
|
29
|
+
|
30
|
+
svg["class"] = options[:class] if options[:class]
|
31
|
+
svg["id"] = options[:id] if options[:id]
|
32
|
+
svg["width"] = options[:width] if options[:width]
|
33
|
+
svg["height"] = options[:height] if options[:height]
|
34
|
+
|
35
|
+
raw doc
|
36
|
+
end
|
37
|
+
|
38
|
+
def close_button_tag(options = {})
|
39
|
+
options = Hash(options).reverse_merge!({type: 'button', class: 'close', aria: {label: 'Close'}})
|
40
|
+
content_tag :button, options do
|
41
|
+
content_tag :span, aria: {hidden: 'true'} do
|
42
|
+
'×'.html_safe
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def icon_tag(name)
|
48
|
+
content_tag :i, nil, class: "icon icon-#{name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def flash_class(level)
|
52
|
+
case level.to_sym
|
53
|
+
when :notice then 'alert alert-success'
|
54
|
+
when :error then 'alert alert-danger'
|
55
|
+
when :alert then 'alert alert-danger'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module TitleHelper
|
2
|
+
|
3
|
+
def title(additional_context = {}, opts = {})
|
4
|
+
if content_for?(:title)
|
5
|
+
provide(:title)
|
6
|
+
else
|
7
|
+
context = controller.view_assigns.merge(additional_context).symbolize_keys
|
8
|
+
PageTitle.new(controller_path, action_name, context, opts)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class PageTitle
|
13
|
+
attr_reader :controller_path, :action_name, :context,
|
14
|
+
:application_name, :include_application_name, :separator
|
15
|
+
|
16
|
+
def initialize(controller_path, action_name, context, opts)
|
17
|
+
@controller_path = controller_path
|
18
|
+
@action_name = action_name
|
19
|
+
@context = context
|
20
|
+
@application_name = opts[:application_name] || humanized_application_name
|
21
|
+
@include_application_name = opts[:include_application_name] || true
|
22
|
+
@separator = opts[:separator] || ' – '
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
title = translate_action
|
27
|
+
if include_application_name
|
28
|
+
title << "#{separator}#{application_name}" if title != application_name
|
29
|
+
end
|
30
|
+
title
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def translate_application_name
|
38
|
+
return application_name if application_name.present?
|
39
|
+
I18n.t(application_title, default: humanized_application_name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def humanized_application_name
|
43
|
+
guess_title_key.underscore.humanize.gsub(/\S+/, &:capitalize)
|
44
|
+
end
|
45
|
+
|
46
|
+
def translate_action
|
47
|
+
I18n.t("titles.#{controller_i18n_key_lookup_path}.#{action_name}",
|
48
|
+
context.merge(default: defaults))
|
49
|
+
end
|
50
|
+
|
51
|
+
def application_title_key
|
52
|
+
:'titles.application'
|
53
|
+
end
|
54
|
+
|
55
|
+
def guess_title_key
|
56
|
+
Rails.application.class.to_s.split('::').first
|
57
|
+
end
|
58
|
+
|
59
|
+
def controller_i18n_key_lookup_path
|
60
|
+
controller_path.gsub('/', '.')
|
61
|
+
end
|
62
|
+
|
63
|
+
def defaults
|
64
|
+
default_keys_in_lookup_path + [application_title_key, guess_title_key]
|
65
|
+
end
|
66
|
+
|
67
|
+
def default_keys_in_lookup_path
|
68
|
+
defaults = []
|
69
|
+
lookup_path = controller_i18n_key_lookup_path.split('.')
|
70
|
+
while lookup_path.length > 0
|
71
|
+
defaults << ['titles', *lookup_path, 'default'].join('.').to_sym
|
72
|
+
lookup_path.pop
|
73
|
+
end
|
74
|
+
defaults.reverse
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
<% if user_role_field? -%>
|
3
|
+
as_enum :role, [:guest, :regular, :trusted, :moderator, :admin],
|
4
|
+
source: :role, map: :string, accessor: :whiny
|
5
|
+
|
6
|
+
before_create do
|
7
|
+
self.role = :regular
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.guest
|
11
|
+
User.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def guest?
|
15
|
+
new_record?
|
16
|
+
end
|
17
|
+
|
18
|
+
def regular?
|
19
|
+
persisted? && role == :regular
|
20
|
+
end
|
21
|
+
<% end -%>
|
22
|
+
|
23
|
+
<% if devise? -%>
|
24
|
+
def send_devise_notification(notification, *args)
|
25
|
+
devise_mailer.send(notification, self, *args).deliver_later
|
26
|
+
end
|
27
|
+
<% end -%>
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% if flash.any? %>
|
2
|
+
<div class="flashes">
|
3
|
+
<% flash.each do |key, messages| %>
|
4
|
+
<div class="<%= flash_class(key) %>">
|
5
|
+
<% close_button_tag(data: {dismiss: 'alert'}) %>
|
6
|
+
<ul>
|
7
|
+
<% Array(messages).each do |message| %>
|
8
|
+
<li>
|
9
|
+
<%= message %>
|
10
|
+
</li>
|
11
|
+
<% end %>
|
12
|
+
</ul>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
</div>
|
16
|
+
<% end %>
|