-
-
Notifications
You must be signed in to change notification settings - Fork 178
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add script to generate scaffolding for a new resource (#415)
* chore: add script to generate scaffolding for a new resource * chore: remove puts * chore(scaffolding): add more * chore: more scaffolding * chore: update scaffolding
- Loading branch information
Showing
12 changed files
with
481 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
# Scaffolding | ||
|
||
Generates a new model class and its associated: | ||
|
||
* migration | ||
* resource | ||
* decorator (todo) | ||
* service (todo) | ||
* repository (todo) | ||
* resource spec (todo) | ||
* decorator spec (todo) | ||
* service spec (todo) | ||
* repository spec (todo) | ||
|
||
## Usage | ||
|
||
Set `MODEL_CLASS_FULL_NAME` to the full name of the class, and run: | ||
|
||
``` | ||
bundle exec ruby scaffolding/run.rb | ||
``` | ||
|
||
Note that the class name must be in the format X::Y::Z (a class nested inside two modules). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
require 'pact_broker/string_refinements' | ||
require 'pact_broker/project_root' | ||
require 'date' | ||
require 'erb' | ||
require 'pathname' | ||
|
||
using PactBroker::StringRefinements | ||
|
||
MODEL_CLASS_FULL_NAME = "PactBroker::Foos::Foo" | ||
DRY_RUN = false | ||
|
||
TEMPLATE_DIR = Pathname.new(File.join(__dir__, "templates")) | ||
MIGRATIONS_DIR = PactBroker.project_root.join("db", "migrations") | ||
LIB_DIR = PactBroker.project_root.join("lib") | ||
SPEC_DIR = PactBroker.project_root.join("spec", "lib") | ||
|
||
def model_full_class_name | ||
MODEL_CLASS_FULL_NAME | ||
end | ||
|
||
def today | ||
DateTime.now.strftime('%Y%m%d') | ||
end | ||
|
||
def require_path_prefix | ||
model_top_module.snakecase | ||
end | ||
|
||
def migration_path | ||
MIGRATIONS_DIR.join(today + "_create_#{table_name}_table.rb") | ||
end | ||
|
||
def model_class_name | ||
model_full_class_name.split("::").last | ||
end | ||
|
||
def model_top_module | ||
model_full_class_name.split("::").first | ||
end | ||
|
||
def repository_class_full_name | ||
model_full_class_name.split("::")[0..1].join("::") + "::Repository" | ||
end | ||
|
||
# Resource | ||
|
||
def resource_top_module | ||
model_top_module | ||
end | ||
|
||
def resource_class_name | ||
model_class_name | ||
end | ||
|
||
def resource_class_full_name | ||
"#{resource_top_module}::Api::Resources::#{resource_class_name}" | ||
end | ||
|
||
def resource_url_path | ||
model_class_name_snakecase.gsub("_", "-") + "s" | ||
end | ||
|
||
# Decorator | ||
|
||
def decorator_class_name | ||
model_class_name + "Decorator" | ||
end | ||
|
||
def decorator_full_class_name | ||
"#{resource_top_module}::Api::Decorators::#{resource_class_name}Decorator" | ||
end | ||
|
||
def decorator_instance_name | ||
model_class_name_snakecase + "_decorator" | ||
end | ||
|
||
# Service | ||
|
||
def service_class_full_name | ||
model_full_class_name.split("::")[0..1].join("::") + "::Service" | ||
end | ||
|
||
def service_class_name | ||
service_class_full_name.split("::").last | ||
end | ||
|
||
def model_secondary_module | ||
model_full_class_name.split("::")[1] | ||
end | ||
|
||
def model_instance_name | ||
model_class_name.snakecase | ||
end | ||
|
||
def policy_name | ||
model_secondary_module.snakecase + "::" + model_class_name.snakecase | ||
end | ||
|
||
def service_instance_name | ||
model_class_name.snakecase + "_service" | ||
end | ||
|
||
# Repository | ||
|
||
def repository_class_full_name | ||
model_full_class_name.split("::")[0..1].join("::") + "::Repository" | ||
end | ||
|
||
def repository_class_name | ||
repository_class_full_name.split("::").last | ||
end | ||
|
||
def repository_instance_name | ||
model_class_name.snakecase + "_repository" | ||
end | ||
|
||
# Table | ||
|
||
def table_name | ||
model_class_name.snakecase | ||
end | ||
|
||
def model_class_name_snakecase | ||
model_class_name.snakecase | ||
end | ||
|
||
# File paths | ||
|
||
def migration_template_path | ||
File.join(__dir__, "templates", "migration.erb") | ||
end | ||
|
||
def model_path | ||
LIB_DIR.join(*model_full_class_name.split("::").collect(&:snakecase)).to_s.chomp("/") + ".rb" | ||
end | ||
|
||
def resource_path | ||
LIB_DIR.join(model_top_module.snakecase, "api", "resources", model_class_name_snakecase + ".rb") | ||
end | ||
|
||
def resource_spec_path | ||
resource_path.to_s.gsub(LIB_DIR.to_s, SPEC_DIR.to_s).gsub(".rb", "_spec.rb") | ||
end | ||
|
||
def resource_require_path | ||
Pathname.new(resource_path).relative_path_from(LIB_DIR).to_s.chomp(".rb") | ||
end | ||
|
||
def decorator_path | ||
LIB_DIR.join(model_top_module.snakecase, "api", "decorators", model_class_name_snakecase + "_decorator.rb") | ||
end | ||
|
||
def decorator_require_path | ||
Pathname.new(decorator_path).relative_path_from(LIB_DIR).to_s.chomp(".rb") | ||
end | ||
|
||
def service_path | ||
LIB_DIR.join(*service_class_full_name.split("::").collect(&:snakecase)).to_s.chomp("/") + ".rb" | ||
end | ||
|
||
def service_require_path | ||
Pathname.new(service_path).relative_path_from(LIB_DIR).to_s.chomp(".rb") | ||
end | ||
|
||
def service_spec_path | ||
service_path.to_s.gsub(LIB_DIR.to_s, SPEC_DIR.to_s).gsub(".rb", "_spec.rb") | ||
end | ||
|
||
def repository_path | ||
LIB_DIR.join(*repository_class_full_name.split("::").collect(&:snakecase)).to_s.chomp("/") + ".rb" | ||
end | ||
|
||
def repository_require_path | ||
Pathname.new(repository_path).relative_path_from(LIB_DIR).to_s.chomp(".rb") | ||
end | ||
|
||
def repository_spec_path | ||
repository_path.to_s.gsub(LIB_DIR.to_s, SPEC_DIR.to_s).gsub(".rb", "_spec.rb") | ||
end | ||
|
||
# Generate | ||
|
||
def generate_migration_file | ||
generate_file(migration_template_path, migration_path) | ||
end | ||
|
||
def generate_model_file | ||
generate_file(TEMPLATE_DIR.join("model.erb"), model_path) | ||
end | ||
|
||
def generate_resource_file | ||
generate_file(TEMPLATE_DIR.join("resource.erb"), resource_path) | ||
end | ||
|
||
def generate_resource_spec | ||
generate_file(TEMPLATE_DIR.join("resource_spec.rb.erb"), resource_spec_path) | ||
end | ||
|
||
def generate_decorator_file | ||
generate_file(TEMPLATE_DIR.join("decorator.rb.erb"), decorator_path) | ||
end | ||
|
||
def generate_service_file | ||
generate_file(TEMPLATE_DIR.join("service.rb.erb"), service_path) | ||
end | ||
|
||
def generate_service_spec_file | ||
generate_file(TEMPLATE_DIR.join("service_spec.rb.erb"), service_spec_path) | ||
end | ||
|
||
def generate_repository_file | ||
generate_file(TEMPLATE_DIR.join("repository.rb.erb"), repository_path) | ||
end | ||
|
||
def generate_repository_spec_file | ||
generate_file(TEMPLATE_DIR.join("repository_spec.rb.erb"), repository_spec_path) | ||
end | ||
|
||
|
||
def generate_file(template, destination) | ||
puts "Generating file #{destination}" | ||
file_content = ERB.new(File.read(template)).result(binding).tap { |it| puts it } | ||
if !DRY_RUN | ||
FileUtils.mkdir_p(File.dirname(destination)) | ||
File.open(destination, "w") { |file| file << file_content } | ||
end | ||
end | ||
|
||
generate_migration_file | ||
generate_model_file | ||
generate_resource_file | ||
generate_resource_spec | ||
generate_decorator_file | ||
generate_service_file | ||
generate_service_spec_file | ||
generate_repository_file | ||
generate_repository_spec_file |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
require 'pact_broker/api/decorators/base_decorator' | ||
|
||
module <%= resource_top_module %> | ||
module Api | ||
module Decorators | ||
class <%= decorator_class_name %> < BaseDecorator | ||
property :uuid | ||
|
||
include Timestamps | ||
end | ||
end | ||
end | ||
end |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
Sequel.migration do | ||
change do | ||
create_table(:<%= table_name %>, charset: 'utf8') do | ||
primary_key :id | ||
String :uuid, null: false | ||
|
||
DateTime :created_at, null: false | ||
DateTime :updated_at, null: false | ||
index [:uuid], unique: true, name: "<%= table_name %>_uuid_index" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
require 'sequel' | ||
require 'pact_broker/repositories/helpers' | ||
|
||
module <%= model_top_module %> | ||
module <%= model_secondary_module %> | ||
class <%= model_class_name %> < Sequel::Model | ||
plugin :timestamps, update_on_create: true | ||
|
||
dataset_module do | ||
include PactBroker::Repositories::Helpers | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
require 'pact_broker/logging' | ||
require 'pact_broker/error' | ||
|
||
module <%= model_top_module %> | ||
module <%= model_secondary_module %> | ||
class <%= repository_class_name %> | ||
include PactBroker::Logging | ||
|
||
def self.find_by_uuid(uuid) | ||
<%= model_class_name %>.where(uuid: uuid).single_record | ||
end | ||
|
||
def self.find_by_uuid!(uuid) | ||
find_by_uuid(uuid) or raise PactBroker::Error.new("<%= model_class_name %> with UUID #{uuid} does not exist") | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
require '<%= repository_require_path %>' | ||
|
||
module <%= model_top_module %> | ||
module <%= model_secondary_module %> | ||
describe <%= repository_class_name %> do | ||
|
||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
require 'pact_broker/api/resources/base_resource' | ||
require '<%= decorator_require_path %>' | ||
|
||
module <%= resource_top_module %> | ||
module Api | ||
module Resources | ||
class <%= resource_class_name %> < BaseResource | ||
def content_types_provided | ||
[["application/hal+json", :to_json]] | ||
end | ||
|
||
def allowed_methods | ||
["GET", "OPTIONS"] | ||
end | ||
|
||
def resource_exists? | ||
!!<%= model_instance_name %> | ||
end | ||
|
||
def to_json | ||
decorator_class(:<%= decorator_instance_name %>).new(<%= model_instance_name %>).to_json(decorator_options) | ||
end | ||
|
||
def policy_name | ||
:<%= policy_name %> | ||
end | ||
|
||
private | ||
|
||
attr_reader :<%= model_instance_name %> | ||
|
||
def <%= model_instance_name %> | ||
@<%= model_instance_name %> ||= <%= service_instance_name %>.find_by_uuid(uuid) | ||
end | ||
|
||
# DELETE THIS!!! It's just here so that the generated test can be run | ||
def <%= service_instance_name %> | ||
end | ||
|
||
def uuid | ||
identifier_from_path[:<%= model_instance_name %>_uuid] | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.