michel 0.1.0
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 +7 -0
- data/.github/workflows/dynamic-security.yml +19 -0
- data/.github/workflows/main.yml +92 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.standard.yml +5 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +6 -0
- data/CONTRIBUTING.md +38 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +325 -0
- data/LICENSE +19 -0
- data/README.md +76 -0
- data/RELEASING.md +43 -0
- data/Rakefile +10 -0
- data/SECURITY.md +2 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/lib/generators/michel/install/install_generator.rb +13 -0
- data/lib/generators/michel/install/templates/michel.rb +5 -0
- data/lib/generators/michel/view/templates/belongs_to_associations.erb +6 -0
- data/lib/generators/michel/view/templates/has_many_associations.erb +2 -0
- data/lib/generators/michel/view/templates/index_migration.erb +15 -0
- data/lib/generators/michel/view/templates/view.erb +95 -0
- data/lib/generators/michel/view/templates/view_migration.rb +8 -0
- data/lib/generators/michel/view/view_generator.rb +59 -0
- data/lib/michel/version.rb +5 -0
- data/lib/michel.rb +60 -0
- data/michel.gemspec +33 -0
- data/sig/michel.rbs +4 -0
- data/spec/example-app/.ruby-version +1 -0
- data/spec/example-app/Rakefile +6 -0
- data/spec/example-app/app/controllers/application_controller.rb +2 -0
- data/spec/example-app/app/controllers/concerns/.keep +0 -0
- data/spec/example-app/app/models/application_record.rb +3 -0
- data/spec/example-app/app/models/appointment.rb +3 -0
- data/spec/example-app/app/models/concerns/.keep +0 -0
- data/spec/example-app/app/models/physician.rb +4 -0
- data/spec/example-app/app/models/physician_availability.rb +3 -0
- data/spec/example-app/bin/bundle +109 -0
- data/spec/example-app/bin/dev +2 -0
- data/spec/example-app/bin/rails +4 -0
- data/spec/example-app/bin/rake +4 -0
- data/spec/example-app/bin/setup +34 -0
- data/spec/example-app/config/application.rb +44 -0
- data/spec/example-app/config/boot.rb +3 -0
- data/spec/example-app/config/credentials.yml.enc +1 -0
- data/spec/example-app/config/database.yml +85 -0
- data/spec/example-app/config/environment.rb +5 -0
- data/spec/example-app/config/environments/development.rb +49 -0
- data/spec/example-app/config/environments/production.rb +64 -0
- data/spec/example-app/config/environments/test.rb +42 -0
- data/spec/example-app/config/initializers/cors.rb +16 -0
- data/spec/example-app/config/initializers/filter_parameter_logging.rb +8 -0
- data/spec/example-app/config/initializers/inflections.rb +16 -0
- data/spec/example-app/config/locales/en.yml +31 -0
- data/spec/example-app/config/puma.rb +38 -0
- data/spec/example-app/config/routes.rb +10 -0
- data/spec/example-app/config.ru +6 -0
- data/spec/example-app/db/migrate/20250829205200_create_physicians.rb +8 -0
- data/spec/example-app/db/migrate/20250829205205_create_appointments.rb +10 -0
- data/spec/example-app/db/migrate/20250829205257_create_availabilities.rb +12 -0
- data/spec/example-app/db/schema.rb +42 -0
- data/spec/example-app/db/seeds.rb +9 -0
- data/spec/example-app/lib/tasks/.keep +0 -0
- data/spec/example-app/log/.keep +0 -0
- data/spec/example-app/public/robots.txt +1 -0
- data/spec/example-app/script/.keep +0 -0
- data/spec/example-app/tmp/.keep +0 -0
- data/spec/example-app/tmp/pids/.keep +0 -0
- data/spec/example-app/vendor/.keep +0 -0
- data/spec/generators/michel/install/install_generator_spec.rb +18 -0
- data/spec/generators/michel/view/view_generator_spec.rb +63 -0
- data/spec/lib/michel_spec.rb +60 -0
- data/spec/spec_helper.rb +27 -0
- metadata +158 -0
data/SECURITY.md
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "michel"
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
require "irb"
|
|
11
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require "rails/generators/base"
|
|
2
|
+
require "scenic"
|
|
3
|
+
module Michel
|
|
4
|
+
module Generators
|
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("../templates", __FILE__)
|
|
7
|
+
|
|
8
|
+
def create_initializer
|
|
9
|
+
copy_file "michel.rb", "config/initializers/michel.rb"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
reversible do |direction|
|
|
3
|
+
direction.up do
|
|
4
|
+
execute <<-SQL
|
|
5
|
+
CREATE EXTENSION IF NOT EXISTS btree_gist;
|
|
6
|
+
CREATE INDEX on <%=Michel.booking_class_table_name%> using gist (<%=Michel.resource_class_foreign_id%>, tsrange(start_time, start_time + interval '1 minute' * duration, '()'));
|
|
7
|
+
SQL
|
|
8
|
+
end
|
|
9
|
+
direction.down do
|
|
10
|
+
execute <<-SQL
|
|
11
|
+
DROP INDEX <%=Michel.booking_class_table_name%>_<%=Michel.resource_class_foreign_id%>_tsrange_idx;
|
|
12
|
+
DROP EXTENSION IF EXISTS btree_gist;
|
|
13
|
+
SQL
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
WITH RECURSIVE time_slots AS (
|
|
2
|
+
-- Generate a series of dates for the next year, starting from tomorrow
|
|
3
|
+
SELECT
|
|
4
|
+
p.id AS <%=Michel.availability_class_foreign_id%>,
|
|
5
|
+
p.<%=Michel.resource_class_foreign_id%>,
|
|
6
|
+
-- what is DATE_TRUNC?
|
|
7
|
+
-- DATE_TRUNC('week', CURRENT_DATE) returns the first day of the week
|
|
8
|
+
(DATE_TRUNC('week', CURRENT_DATE) + (p.weekday - 1 || ' days')::interval) AS start_date,
|
|
9
|
+
CURRENT_DATE + INTERVAL '6 months' AS end_date,
|
|
10
|
+
p.start_time,
|
|
11
|
+
p.end_time,
|
|
12
|
+
p.timezone
|
|
13
|
+
FROM
|
|
14
|
+
<%=Michel.availability_class_table_name%> p
|
|
15
|
+
UNION ALL
|
|
16
|
+
-- Recursively generate dates for all instances of the given weekday
|
|
17
|
+
SELECT
|
|
18
|
+
ts.<%=Michel.availability_class_foreign_id%>,
|
|
19
|
+
ts.<%=Michel.resource_class_foreign_id%>,
|
|
20
|
+
ts.start_date + INTERVAL '1 week' AS start_date, -- Explicitly alias the column
|
|
21
|
+
ts.end_date,
|
|
22
|
+
ts.start_time,
|
|
23
|
+
ts.end_time,
|
|
24
|
+
ts.timezone
|
|
25
|
+
FROM
|
|
26
|
+
time_slots ts
|
|
27
|
+
WHERE
|
|
28
|
+
ts.start_date + INTERVAL '1 week' <= ts.end_date
|
|
29
|
+
),
|
|
30
|
+
-- Generate time slots for each day, every 15 minutes
|
|
31
|
+
slot_intervals AS (
|
|
32
|
+
SELECT
|
|
33
|
+
ts.<%=Michel.availability_class_foreign_id%>,
|
|
34
|
+
ts.<%=Michel.resource_class_foreign_id%>,
|
|
35
|
+
ts.start_date,
|
|
36
|
+
|
|
37
|
+
-- Create proper timestamps for start and end times with timezone handling
|
|
38
|
+
(make_timestamptz(
|
|
39
|
+
date_part('year', ts.start_date)::integer,
|
|
40
|
+
date_part('month', ts.start_date)::integer,
|
|
41
|
+
date_part('day', ts.start_date)::integer,
|
|
42
|
+
split_part(ts.start_time, ':', 1)::int,
|
|
43
|
+
split_part(ts.start_time, ':', 2)::int,
|
|
44
|
+
0,
|
|
45
|
+
ts.timezone
|
|
46
|
+
)) AT TIME ZONE 'UTC' AS slot_start_time,
|
|
47
|
+
|
|
48
|
+
(make_timestamptz(
|
|
49
|
+
date_part('year', ts.start_date)::integer,
|
|
50
|
+
date_part('month', ts.start_date)::integer,
|
|
51
|
+
date_part('day', ts.start_date)::integer,
|
|
52
|
+
split_part(ts.end_time, ':', 1)::int,
|
|
53
|
+
split_part(ts.end_time, ':', 2)::int,
|
|
54
|
+
0,
|
|
55
|
+
ts.timezone
|
|
56
|
+
)) AT TIME ZONE 'UTC' AS slot_end_time
|
|
57
|
+
FROM
|
|
58
|
+
time_slots ts
|
|
59
|
+
),
|
|
60
|
+
time_slots_every_15_min AS (
|
|
61
|
+
SELECT
|
|
62
|
+
si.<%=Michel.availability_class_foreign_id%>,
|
|
63
|
+
si.<%=Michel.resource_class_foreign_id%>,
|
|
64
|
+
si.start_date,
|
|
65
|
+
|
|
66
|
+
-- Generate the series for time slots every 15 minutes
|
|
67
|
+
generate_series(
|
|
68
|
+
GREATEST(si.slot_start_time, CURRENT_DATE + INTERVAL '1 day'),
|
|
69
|
+
-- Ensure it starts from tomorrow
|
|
70
|
+
si.slot_end_time - INTERVAL '30 minutes',
|
|
71
|
+
INTERVAL '15 minutes'
|
|
72
|
+
) AS slot_start_time
|
|
73
|
+
FROM
|
|
74
|
+
slot_intervals si
|
|
75
|
+
)
|
|
76
|
+
SELECT
|
|
77
|
+
concat(<%=Michel.availability_class_foreign_id%>, slot_start_time) AS id,
|
|
78
|
+
<%=Michel.availability_class_foreign_id%>,
|
|
79
|
+
<%=Michel.resource_class_foreign_id%>,
|
|
80
|
+
slot_start_time as start_time,
|
|
81
|
+
slot_start_time + INTERVAL '30 minutes' AS end_time
|
|
82
|
+
FROM
|
|
83
|
+
time_slots_every_15_min
|
|
84
|
+
EXCEPT
|
|
85
|
+
SELECT
|
|
86
|
+
concat(<%=Michel.availability_class_foreign_id%>, slot_start_time) AS id,
|
|
87
|
+
time_slots_every_15_min.<%=Michel.availability_class_foreign_id%>,
|
|
88
|
+
time_slots_every_15_min.<%=Michel.resource_class_foreign_id%>,
|
|
89
|
+
time_slots_every_15_min.slot_start_time as start_time,
|
|
90
|
+
time_slots_every_15_min.slot_start_time + INTERVAL '30 minutes' AS end_time
|
|
91
|
+
FROM time_slots_every_15_min
|
|
92
|
+
CROSS JOIN <%=Michel.booking_class_table_name%>
|
|
93
|
+
WHERE tsrange(<%=Michel.booking_class_table_name%>.start_time, <%=Michel.booking_class_table_name%>.start_time + interval '1 minute' * <%=Michel.booking_class_table_name%>.duration, '()')
|
|
94
|
+
&& tsrange(time_slots_every_15_min.slot_start_time, time_slots_every_15_min.slot_start_time + INTERVAL '30 minutes', '()')
|
|
95
|
+
AND <%=Michel.booking_class_table_name%>.<%=Michel.resource_class_foreign_id%> = time_slots_every_15_min.<%=Michel.resource_class_foreign_id%>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "scenic"
|
|
3
|
+
module Michel
|
|
4
|
+
module Generators
|
|
5
|
+
class ViewGenerator < Rails::Generators::Base
|
|
6
|
+
source_root File.expand_path("templates", __dir__)
|
|
7
|
+
include Scenic
|
|
8
|
+
|
|
9
|
+
def create_index_in_migration
|
|
10
|
+
self.destination_root = Rails.root
|
|
11
|
+
|
|
12
|
+
puts "Generating #{Michel.booking_class_table_name} index migration"
|
|
13
|
+
invoke "migration", ["add_index_to_#{Michel.booking_class_table_name}"]
|
|
14
|
+
index_migration_content = template_content("index_migration.erb")
|
|
15
|
+
Dir.glob(Rails.root.join("db/migrate/*add_index_to_#{Michel.booking_class_table_name}.rb")).each do |file|
|
|
16
|
+
inject_into_file file, index_migration_content, after: "def change"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def create_scenic_model
|
|
21
|
+
self.destination_root = Rails.root
|
|
22
|
+
puts "Creating scenic model available_time_slot"
|
|
23
|
+
|
|
24
|
+
invoke "scenic:model", ["available_time_slots"], {"materialized" => true, "test_framework" => false}
|
|
25
|
+
|
|
26
|
+
Dir.glob(Rails.root.join("db/migrate/*create_available_time_slots.rb")).each do |file|
|
|
27
|
+
gsub_file file, /change/, "up"
|
|
28
|
+
inject_into_class file, "CreateAvailableTimeSlots", template_content("view_migration.rb")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def create_sql_file
|
|
33
|
+
puts "Creating materialized view SQL at db/views/available_time_slots_v01.sql"
|
|
34
|
+
template "view.erb", "db/views/available_time_slots_v01.sql", {force: true}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def add_associations_to_models
|
|
38
|
+
has_many_associations = template_content("has_many_associations.erb")
|
|
39
|
+
|
|
40
|
+
inject_into_class "app/models/#{Michel.availability_class_underscore}.rb", Michel.availability_class_name,
|
|
41
|
+
has_many_associations
|
|
42
|
+
inject_into_class "app/models/#{Michel.resource_class_underscore}.rb", Michel.resource_class_name,
|
|
43
|
+
has_many_associations
|
|
44
|
+
belongs_to_associations = template_content("belongs_to_associations.erb")
|
|
45
|
+
case behavior
|
|
46
|
+
when :invoke
|
|
47
|
+
inject_into_class "app/models/available_time_slot.rb", "AvailableTimeSlot", belongs_to_associations
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def template_content(filename)
|
|
54
|
+
template = File.read(File.join(self.class.source_root, filename))
|
|
55
|
+
ERB.new(template).result(binding)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/michel.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require "zeitwerk"
|
|
2
|
+
|
|
3
|
+
loader = Zeitwerk::Loader.for_gem
|
|
4
|
+
loader.ignore("#{__dir__}/generators")
|
|
5
|
+
loader.setup
|
|
6
|
+
module Michel
|
|
7
|
+
class Error < StandardError; end
|
|
8
|
+
|
|
9
|
+
mattr_accessor :resource_class_name
|
|
10
|
+
mattr_accessor :booking_class_name
|
|
11
|
+
mattr_accessor :availability_class_name
|
|
12
|
+
|
|
13
|
+
def self.setup
|
|
14
|
+
yield self
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.resource_class_symbol
|
|
18
|
+
@@resource_class_name.underscore.to_sym
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.resource_class_foreign_id
|
|
22
|
+
@@resource_class_name.foreign_key
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.resource_class_underscore
|
|
26
|
+
@@resource_class_name.underscore
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.booking_class_symbol
|
|
30
|
+
@@booking_class_name.underscore.to_sym
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.booking_class_table_name
|
|
34
|
+
@@booking_class_name.tableize
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.booking_class_foreign_id
|
|
38
|
+
@@booking_class_name.foreign_key
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.booking_class_underscore
|
|
42
|
+
@@booking_class_name.underscore
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.availability_class_symbol
|
|
46
|
+
@@availability_class_name.underscore.to_sym
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.availability_class_table_name
|
|
50
|
+
@@availability_class_name.tableize
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.availability_class_foreign_id
|
|
54
|
+
@@availability_class_name.foreign_key
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.availability_class_underscore
|
|
58
|
+
@@availability_class_name.underscore
|
|
59
|
+
end
|
|
60
|
+
end
|
data/michel.gemspec
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/michel/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "michel"
|
|
7
|
+
spec.version = Michel::VERSION
|
|
8
|
+
spec.authors = ["Sally Hall", "Aji Slater"]
|
|
9
|
+
spec.email = ["sally@thoughtbot.com", "aji.slater@gmail.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Generator to help with appointment scheduling"
|
|
12
|
+
spec.homepage = "https://github.com/thoughtbot/michel/"
|
|
13
|
+
spec.required_ruby_version = ">= 3.0.0"
|
|
14
|
+
|
|
15
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
16
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
|
17
|
+
|
|
18
|
+
# Specify which files should be added to the gem when it is released.
|
|
19
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
20
|
+
|
|
21
|
+
spec.files = `git ls-files`.split("\n")
|
|
22
|
+
spec.bindir = "exe"
|
|
23
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
24
|
+
spec.require_paths = ["lib"]
|
|
25
|
+
|
|
26
|
+
# Uncomment to register a new dependency of your gem
|
|
27
|
+
spec.add_dependency "activerecord", ">= 7.0.0"
|
|
28
|
+
spec.add_dependency "pg", "~> 1.0"
|
|
29
|
+
spec.add_dependency "scenic", "~>1.9"
|
|
30
|
+
|
|
31
|
+
# For more information and examples about making a new gem, check out our
|
|
32
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
|
33
|
+
end
|
data/sig/michel.rbs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ruby-3.3.5
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'bundle' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require "rubygems"
|
|
12
|
+
|
|
13
|
+
m = Module.new do
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def invoked_as_script?
|
|
17
|
+
File.expand_path($0) == File.expand_path(__FILE__)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def env_var_version
|
|
21
|
+
ENV["BUNDLER_VERSION"]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def cli_arg_version
|
|
25
|
+
return unless invoked_as_script? # don't want to hijack other binstubs
|
|
26
|
+
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
|
|
27
|
+
bundler_version = nil
|
|
28
|
+
update_index = nil
|
|
29
|
+
ARGV.each_with_index do |a, i|
|
|
30
|
+
if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
|
|
31
|
+
bundler_version = a
|
|
32
|
+
end
|
|
33
|
+
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/o
|
|
34
|
+
bundler_version = $1
|
|
35
|
+
update_index = i
|
|
36
|
+
end
|
|
37
|
+
bundler_version
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def gemfile
|
|
41
|
+
gemfile = ENV["BUNDLE_GEMFILE"]
|
|
42
|
+
return gemfile if gemfile && !gemfile.empty?
|
|
43
|
+
|
|
44
|
+
File.expand_path("../../../Gemfile", __dir__)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def lockfile
|
|
48
|
+
lockfile =
|
|
49
|
+
case File.basename(gemfile)
|
|
50
|
+
when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
|
|
51
|
+
else "#{gemfile}.lock"
|
|
52
|
+
end
|
|
53
|
+
File.expand_path(lockfile)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def lockfile_version
|
|
57
|
+
return unless File.file?(lockfile)
|
|
58
|
+
lockfile_contents = File.read(lockfile)
|
|
59
|
+
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/o
|
|
60
|
+
Regexp.last_match(1)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def bundler_requirement
|
|
64
|
+
@bundler_requirement ||=
|
|
65
|
+
env_var_version ||
|
|
66
|
+
cli_arg_version ||
|
|
67
|
+
bundler_requirement_for(lockfile_version)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def bundler_requirement_for(version)
|
|
71
|
+
return "#{Gem::Requirement.default}.a" unless version
|
|
72
|
+
|
|
73
|
+
bundler_gem_version = Gem::Version.new(version)
|
|
74
|
+
|
|
75
|
+
bundler_gem_version.approximate_recommendation
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def load_bundler!
|
|
79
|
+
ENV["BUNDLE_GEMFILE"] ||= gemfile
|
|
80
|
+
|
|
81
|
+
activate_bundler
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def activate_bundler
|
|
85
|
+
gem_error = activation_error_handling do
|
|
86
|
+
gem "bundler", bundler_requirement
|
|
87
|
+
end
|
|
88
|
+
return if gem_error.nil?
|
|
89
|
+
require_error = activation_error_handling do
|
|
90
|
+
require "bundler/version"
|
|
91
|
+
end
|
|
92
|
+
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
|
|
93
|
+
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
|
|
94
|
+
exit 42
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def activation_error_handling
|
|
98
|
+
yield
|
|
99
|
+
nil
|
|
100
|
+
rescue StandardError, LoadError => e
|
|
101
|
+
e
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
m.load_bundler!
|
|
106
|
+
|
|
107
|
+
if m.invoked_as_script?
|
|
108
|
+
load Gem.bin_path("bundler", "bundle")
|
|
109
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require "fileutils"
|
|
3
|
+
|
|
4
|
+
APP_ROOT = File.expand_path("..", __dir__)
|
|
5
|
+
|
|
6
|
+
def system!(*args)
|
|
7
|
+
system(*args, exception: true)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
FileUtils.chdir APP_ROOT do
|
|
11
|
+
# This script is a way to set up or update your development environment automatically.
|
|
12
|
+
# This script is idempotent, so that you can run it at any time and get an expectable outcome.
|
|
13
|
+
# Add necessary setup steps to this file.
|
|
14
|
+
|
|
15
|
+
puts "== Installing dependencies =="
|
|
16
|
+
system("bundle check") || system!("bundle install")
|
|
17
|
+
|
|
18
|
+
# puts "\n== Copying sample files =="
|
|
19
|
+
# unless File.exist?("config/database.yml")
|
|
20
|
+
# FileUtils.cp "config/database.yml.sample", "config/database.yml"
|
|
21
|
+
# end
|
|
22
|
+
|
|
23
|
+
puts "\n== Preparing database =="
|
|
24
|
+
system! "bin/rails db:prepare"
|
|
25
|
+
|
|
26
|
+
puts "\n== Removing old logs and tempfiles =="
|
|
27
|
+
system! "bin/rails log:clear tmp:clear"
|
|
28
|
+
|
|
29
|
+
unless ARGV.include?("--skip-server")
|
|
30
|
+
puts "\n== Starting development server =="
|
|
31
|
+
$stdout.flush # flush the output before exec(2) so that it displays
|
|
32
|
+
exec "bin/dev"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require_relative "boot"
|
|
2
|
+
|
|
3
|
+
require "rails"
|
|
4
|
+
# Pick the frameworks you want:
|
|
5
|
+
require "active_model/railtie"
|
|
6
|
+
# require "active_job/railtie"
|
|
7
|
+
require "active_record/railtie"
|
|
8
|
+
# require "active_storage/engine"
|
|
9
|
+
require "action_controller/railtie"
|
|
10
|
+
# require "action_mailer/railtie"
|
|
11
|
+
# require "action_mailbox/engine"
|
|
12
|
+
# require "action_text/engine"
|
|
13
|
+
require "action_view/railtie"
|
|
14
|
+
# require "action_cable/engine"
|
|
15
|
+
# require "rails/test_unit/railtie"
|
|
16
|
+
|
|
17
|
+
# Require the gems listed in Gemfile, including any gems
|
|
18
|
+
# you've limited to :test, :development, or :production.
|
|
19
|
+
Bundler.require(*Rails.groups)
|
|
20
|
+
|
|
21
|
+
module ExampleApp
|
|
22
|
+
class Application < Rails::Application
|
|
23
|
+
# Initialize configuration defaults for originally generated Rails version.
|
|
24
|
+
config.load_defaults 8.0
|
|
25
|
+
|
|
26
|
+
# Please, add to the `ignore` list any other `lib` subdirectories that do
|
|
27
|
+
# not contain `.rb` files, or that should not be reloaded or eager loaded.
|
|
28
|
+
# Common ones are `templates`, `generators`, or `middleware`, for example.
|
|
29
|
+
config.autoload_lib(ignore: %w[assets tasks])
|
|
30
|
+
|
|
31
|
+
# Configuration for the application, engines, and railties goes here.
|
|
32
|
+
#
|
|
33
|
+
# These settings can be overridden in specific environments using the files
|
|
34
|
+
# in config/environments, which are processed later.
|
|
35
|
+
#
|
|
36
|
+
# config.time_zone = "Central Time (US & Canada)"
|
|
37
|
+
# config.eager_load_paths << Rails.root.join("extras")
|
|
38
|
+
|
|
39
|
+
# Only loads a smaller set of middleware suitable for API only apps.
|
|
40
|
+
# Middleware like session, flash, cookies can be added back manually.
|
|
41
|
+
# Skip views, helpers and assets when generating a new resource.
|
|
42
|
+
config.api_only = true
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bPcLj+RUYOcXjiYTK/tVFqiUjCdvnCrBcVyybZ8age2+5F5tTftPfpHy+As4XBK2AiVooOQHs8lcm2PNAsRUOoTOMG9Y+edynBb1Af0TsYfMq0vKJwJz1D/1TT6Ddf+MCvbxUqA6NvJQpQy4x5pNP2tAX29YeWKr2XsggtvwZJ4C78DMhoL8fqgich+iIsBF86QXU7XBj64L2cEsVIpm/s4KFqeig0s6XGl0m0/euy8NKysMj3jBw4LrokvYbG7BsN3meBjVupFkeI+BGxpH8+2LXeevVtTDKq+bx+rfe8n5FMXH7DPMwQMZt/6ggRlMFvW/JUxGwZt8l24Rmw6yXZelw7pGqG0MxbPOe6MIL5gxAjM7Oyk+Sb3Km6ilW0D2ZKAnXUKw5rj3Xo8l4xn2ZUf51P6/JhnYy53rFiIP1ByMUEBq6ON1GqQ+pkGJYAHCCcDifLZUuIaNULcVkizrfJKOOtz0h0y5NZWLB/yT+EkfmyjiYrD5uS/o--IUEzH9/T2+Rx416h--1A4772sIfBvMfSKf9NL7wQ==
|