jets-fs 1.6.10
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/.circleci/bin/commit_docs.sh +26 -0
- data/.circleci/config.yml +126 -0
- data/.codebuild/README.md +68 -0
- data/.codebuild/bin/jets +3 -0
- data/.codebuild/buildspec-base.yml +14 -0
- data/.codebuild/integration.sh +72 -0
- data/.codebuild/jets.postman_collection.json +323 -0
- data/.codebuild/scripts/install-docker.sh +12 -0
- data/.codebuild/scripts/install-dynamodb-local.sh +22 -0
- data/.codebuild/scripts/install-java.sh +22 -0
- data/.codebuild/scripts/install-node.sh +4 -0
- data/.github/ISSUE_TEMPLATE.md +7 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +73 -0
- data/.github/ISSUE_TEMPLATE/documentation.md +27 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +64 -0
- data/.github/ISSUE_TEMPLATE/question.md +16 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +42 -0
- data/.gitignore +24 -0
- data/.gitmodules +6 -0
- data/.python-version +1 -0
- data/.rspec +4 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +533 -0
- data/Dockerfile +16 -0
- data/Dockerfile.base +53 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +190 -0
- data/Guardfile +22 -0
- data/LICENSE.txt +22 -0
- data/Procfile +2 -0
- data/README.md +203 -0
- data/Rakefile +21 -0
- data/backers.md +16 -0
- data/bin/release +9 -0
- data/buildspec.yml +18 -0
- data/exe/jets +14 -0
- data/jets.gemspec +61 -0
- data/lib/jets.rb +71 -0
- data/lib/jets/application.rb +308 -0
- data/lib/jets/aws_info.rb +111 -0
- data/lib/jets/aws_services.rb +60 -0
- data/lib/jets/aws_services/stack_status.rb +59 -0
- data/lib/jets/booter.rb +130 -0
- data/lib/jets/builders.rb +16 -0
- data/lib/jets/builders/code_builder.rb +379 -0
- data/lib/jets/builders/code_size.rb +57 -0
- data/lib/jets/builders/gem_replacer.rb +76 -0
- data/lib/jets/builders/handler_generator.rb +172 -0
- data/lib/jets/builders/lambda_layer.rb +69 -0
- data/lib/jets/builders/md5.rb +60 -0
- data/lib/jets/builders/md5_zip.rb +61 -0
- data/lib/jets/builders/purger.rb +35 -0
- data/lib/jets/builders/rack_packager.rb +51 -0
- data/lib/jets/builders/rackup_wrappers/rackup +19 -0
- data/lib/jets/builders/rackup_wrappers/rackup.rb +7 -0
- data/lib/jets/builders/reconfigure_rails.rb +114 -0
- data/lib/jets/builders/reconfigure_rails/config/initializers/jets.rb +16 -0
- data/lib/jets/builders/ruby_packager.rb +207 -0
- data/lib/jets/builders/shim_vars.rb +5 -0
- data/lib/jets/builders/shim_vars/app.rb +78 -0
- data/lib/jets/builders/shim_vars/base.rb +25 -0
- data/lib/jets/builders/shim_vars/shared.rb +37 -0
- data/lib/jets/builders/templates/handler.rb +12 -0
- data/lib/jets/builders/tidy.rb +107 -0
- data/lib/jets/builders/util.rb +31 -0
- data/lib/jets/camelizer.rb +67 -0
- data/lib/jets/cfn.rb +6 -0
- data/lib/jets/cfn/builders.rb +20 -0
- data/lib/jets/cfn/builders/api_deployment_builder.rb +58 -0
- data/lib/jets/cfn/builders/api_gateway_builder.rb +80 -0
- data/lib/jets/cfn/builders/base_child_builder.rb +82 -0
- data/lib/jets/cfn/builders/controller_builder.rb +42 -0
- data/lib/jets/cfn/builders/function_builder.rb +14 -0
- data/lib/jets/cfn/builders/interface.rb +127 -0
- data/lib/jets/cfn/builders/job_builder.rb +14 -0
- data/lib/jets/cfn/builders/parent_builder.rb +93 -0
- data/lib/jets/cfn/builders/rule_builder.rb +24 -0
- data/lib/jets/cfn/builders/shared_builder.rb +14 -0
- data/lib/jets/cfn/ship.rb +189 -0
- data/lib/jets/cfn/status.rb +212 -0
- data/lib/jets/cfn/upload.rb +139 -0
- data/lib/jets/cli.rb +189 -0
- data/lib/jets/commands.rb +27 -0
- data/lib/jets/commands/base.rb +164 -0
- data/lib/jets/commands/build.rb +217 -0
- data/lib/jets/commands/call.rb +174 -0
- data/lib/jets/commands/call/anonymous_guesser.rb +96 -0
- data/lib/jets/commands/call/autoload_guesser.rb +112 -0
- data/lib/jets/commands/call/base_guesser.rb +33 -0
- data/lib/jets/commands/call/guesser.rb +48 -0
- data/lib/jets/commands/clean.rb +23 -0
- data/lib/jets/commands/clean/base.rb +24 -0
- data/lib/jets/commands/clean/build.rb +13 -0
- data/lib/jets/commands/clean/log.rb +107 -0
- data/lib/jets/commands/console.rb +13 -0
- data/lib/jets/commands/db.rb +15 -0
- data/lib/jets/commands/db/environment-task.rake +3 -0
- data/lib/jets/commands/db/tasks.rb +44 -0
- data/lib/jets/commands/dbconsole.rb +131 -0
- data/lib/jets/commands/delete.rb +143 -0
- data/lib/jets/commands/deploy.rb +131 -0
- data/lib/jets/commands/dynamodb.rb +22 -0
- data/lib/jets/commands/dynamodb/migrate.rb +9 -0
- data/lib/jets/commands/dynamodb/migrator.rb +36 -0
- data/lib/jets/commands/gems.rb +21 -0
- data/lib/jets/commands/help.rb +9 -0
- data/lib/jets/commands/help/build.md +6 -0
- data/lib/jets/commands/help/call.md +61 -0
- data/lib/jets/commands/help/clean/build.md +5 -0
- data/lib/jets/commands/help/clean/log.md +5 -0
- data/lib/jets/commands/help/console.md +18 -0
- data/lib/jets/commands/help/db/generate.md +8 -0
- data/lib/jets/commands/help/dbconsole.md +9 -0
- data/lib/jets/commands/help/delete.md +22 -0
- data/lib/jets/commands/help/deploy.md +32 -0
- data/lib/jets/commands/help/dynamodb/generate.md +52 -0
- data/lib/jets/commands/help/dynamodb/migrate.md +4 -0
- data/lib/jets/commands/help/gems/check.md +8 -0
- data/lib/jets/commands/help/generate.md +22 -0
- data/lib/jets/commands/help/import/rack.md +13 -0
- data/lib/jets/commands/help/import/rails.md +11 -0
- data/lib/jets/commands/help/new.md +42 -0
- data/lib/jets/commands/help/routes.md +16 -0
- data/lib/jets/commands/help/runner.md +17 -0
- data/lib/jets/commands/help/server.md +15 -0
- data/lib/jets/commands/help/status.md +14 -0
- data/lib/jets/commands/help/upgrade.md +5 -0
- data/lib/jets/commands/help/url.md +6 -0
- data/lib/jets/commands/import.rb +18 -0
- data/lib/jets/commands/import/base.rb +49 -0
- data/lib/jets/commands/import/cheatsheet.rb +35 -0
- data/lib/jets/commands/import/rack.rb +16 -0
- data/lib/jets/commands/import/rail.rb +74 -0
- data/lib/jets/commands/import/sequence.rb +90 -0
- data/lib/jets/commands/import/templates/config/database.yml +26 -0
- data/lib/jets/commands/import/templates/submodules-cheatsheet.md +89 -0
- data/lib/jets/commands/main.rb +152 -0
- data/lib/jets/commands/markdown.rb +8 -0
- data/lib/jets/commands/markdown/creator.rb +58 -0
- data/lib/jets/commands/markdown/index.rb +27 -0
- data/lib/jets/commands/markdown/page.rb +125 -0
- data/lib/jets/commands/markdown/shell.rb +11 -0
- data/lib/jets/commands/new.rb +157 -0
- data/lib/jets/commands/rake_command.rb +61 -0
- data/lib/jets/commands/rake_tasks.rb +45 -0
- data/lib/jets/commands/runner.rb +18 -0
- data/lib/jets/commands/sequence.rb +99 -0
- data/lib/jets/commands/stack_info.rb +30 -0
- data/lib/jets/commands/templates/skeleton/.gitignore +12 -0
- data/lib/jets/commands/templates/skeleton/.jetskeep +1 -0
- data/lib/jets/commands/templates/skeleton/.rspec +3 -0
- data/lib/jets/commands/templates/skeleton/Gemfile.tt +35 -0
- data/lib/jets/commands/templates/skeleton/Procfile +7 -0
- data/lib/jets/commands/templates/skeleton/README.md +11 -0
- data/lib/jets/commands/templates/skeleton/Rakefile +2 -0
- data/lib/jets/commands/templates/skeleton/app/controllers/application_controller.rb +2 -0
- data/lib/jets/commands/templates/skeleton/app/helpers/application_helper.rb +2 -0
- data/lib/jets/commands/templates/skeleton/app/jobs/application_job.rb +4 -0
- data/lib/jets/commands/templates/skeleton/app/models/application_item.rb +2 -0
- data/lib/jets/commands/templates/skeleton/app/models/application_record.rb +3 -0
- data/lib/jets/commands/templates/skeleton/app/views/layouts/application.html.erb.tt +25 -0
- data/lib/jets/commands/templates/skeleton/config.ru +5 -0
- data/lib/jets/commands/templates/skeleton/config/application.rb.tt +66 -0
- data/lib/jets/commands/templates/skeleton/config/database.yml.tt +26 -0
- data/lib/jets/commands/templates/skeleton/config/dynamodb.yml +22 -0
- data/lib/jets/commands/templates/skeleton/config/environments/development.rb +4 -0
- data/lib/jets/commands/templates/skeleton/config/environments/production.rb +4 -0
- data/lib/jets/commands/templates/skeleton/config/routes.rb +9 -0
- data/lib/jets/commands/templates/skeleton/db/.gitkeep +0 -0
- data/lib/jets/commands/templates/skeleton/public/404.html +67 -0
- data/lib/jets/commands/templates/skeleton/public/422.html +67 -0
- data/lib/jets/commands/templates/skeleton/public/500.html +66 -0
- data/lib/jets/commands/templates/skeleton/public/favicon.ico +0 -0
- data/lib/jets/commands/templates/skeleton/public/index.html.tt +91 -0
- data/lib/jets/commands/templates/skeleton/spec/controllers/posts_controller_spec.rb +15 -0
- data/lib/jets/commands/templates/skeleton/spec/fixtures/payloads/posts-index.json +51 -0
- data/lib/jets/commands/templates/skeleton/spec/fixtures/payloads/posts-show.json +53 -0
- data/lib/jets/commands/templates/skeleton/spec/spec_helper.rb.tt +30 -0
- data/lib/jets/commands/templates/webpacker/app/javascript/packs/application.js.tt +14 -0
- data/lib/jets/commands/templates/webpacker/app/javascript/packs/theme.scss.tt +24 -0
- data/lib/jets/commands/templates/webpacker/app/javascript/src/jets/crud.js +87 -0
- data/lib/jets/commands/upgrade.rb +146 -0
- data/lib/jets/commands/upgrade/templates/bin/webpack +19 -0
- data/lib/jets/commands/upgrade/templates/bin/webpack-dev-server +19 -0
- data/lib/jets/commands/url.rb +68 -0
- data/lib/jets/commands/webpacker_template.rb +18 -0
- data/lib/jets/controller.rb +16 -0
- data/lib/jets/controller/base.rb +103 -0
- data/lib/jets/controller/callbacks.rb +62 -0
- data/lib/jets/controller/cookies.rb +40 -0
- data/lib/jets/controller/cookies/jar.rb +269 -0
- data/lib/jets/controller/layout.rb +17 -0
- data/lib/jets/controller/middleware.rb +5 -0
- data/lib/jets/controller/middleware/cors.rb +60 -0
- data/lib/jets/controller/middleware/local.rb +119 -0
- data/lib/jets/controller/middleware/local/api_gateway.rb +93 -0
- data/lib/jets/controller/middleware/local/mimic_aws_call.rb +38 -0
- data/lib/jets/controller/middleware/local/route_matcher.rb +97 -0
- data/lib/jets/controller/middleware/main.rb +46 -0
- data/lib/jets/controller/middleware/webpacker_setup.rb +6 -0
- data/lib/jets/controller/params.rb +87 -0
- data/lib/jets/controller/rack.rb +5 -0
- data/lib/jets/controller/rack/adapter.rb +63 -0
- data/lib/jets/controller/rack/env.rb +105 -0
- data/lib/jets/controller/redirection.rb +55 -0
- data/lib/jets/controller/rendering.rb +84 -0
- data/lib/jets/controller/rendering/rack_renderer.rb +238 -0
- data/lib/jets/controller/request.rb +29 -0
- data/lib/jets/controller/response.rb +61 -0
- data/lib/jets/core.rb +211 -0
- data/lib/jets/core_ext/kernel.rb +56 -0
- data/lib/jets/db.rb +15 -0
- data/lib/jets/dotenv.rb +39 -0
- data/lib/jets/erb.rb +51 -0
- data/lib/jets/generator.rb +41 -0
- data/lib/jets/generator/templates/erb/controller/view.html.erb +2 -0
- data/lib/jets/generator/templates/erb/scaffold/_form.html.erb +39 -0
- data/lib/jets/generator/templates/erb/scaffold/edit.html.erb +6 -0
- data/lib/jets/generator/templates/erb/scaffold/index.html.erb +29 -0
- data/lib/jets/generator/templates/erb/scaffold/new.html.erb +5 -0
- data/lib/jets/generator/templates/erb/scaffold/show.html.erb +9 -0
- data/lib/jets/generator/templates/rails/assets/javascript.js +2 -0
- data/lib/jets/generator/templates/rails/assets/stylesheet.css +4 -0
- data/lib/jets/generator/templates/rails/controller/controller.rb +13 -0
- data/lib/jets/generator/templates/rails/helper/helper.rb +4 -0
- data/lib/jets/generator/templates/rails/scaffold/scaffold.css +80 -0
- data/lib/jets/generator/templates/rails/scaffold_controller/api_controller.rb +62 -0
- data/lib/jets/generator/templates/rails/scaffold_controller/controller.rb +79 -0
- data/lib/jets/inflections.rb +32 -0
- data/lib/jets/internal/app/controllers/jets/public_controller.rb +31 -0
- data/lib/jets/internal/app/controllers/jets/rack_controller.rb +25 -0
- data/lib/jets/internal/app/functions/jets/base_path.rb +153 -0
- data/lib/jets/internal/app/jobs/jets/preheat_job.rb +62 -0
- data/lib/jets/io.rb +14 -0
- data/lib/jets/job.rb +4 -0
- data/lib/jets/job/base.rb +29 -0
- data/lib/jets/job/dsl.rb +108 -0
- data/lib/jets/klass.rb +109 -0
- data/lib/jets/lambda.rb +18 -0
- data/lib/jets/lambda/dsl.rb +384 -0
- data/lib/jets/lambda/function.rb +29 -0
- data/lib/jets/lambda/function_constructor.rb +55 -0
- data/lib/jets/lambda/functions.rb +34 -0
- data/lib/jets/lambda/task.rb +111 -0
- data/lib/jets/logger.rb +24 -0
- data/lib/jets/mega.rb +7 -0
- data/lib/jets/mega/hash_converter.rb +25 -0
- data/lib/jets/mega/request.rb +140 -0
- data/lib/jets/mega/request/source.rb +21 -0
- data/lib/jets/middleware.rb +38 -0
- data/lib/jets/middleware/configurator.rb +84 -0
- data/lib/jets/middleware/default_stack.rb +49 -0
- data/lib/jets/middleware/layer.rb +34 -0
- data/lib/jets/middleware/stack.rb +77 -0
- data/lib/jets/naming.rb +49 -0
- data/lib/jets/overrides/lambda.rb +1 -0
- data/lib/jets/overrides/lambda/marshaller.rb +31 -0
- data/lib/jets/overrides/rails.rb +4 -0
- data/lib/jets/overrides/rails/asset_tag_helper.rb +114 -0
- data/lib/jets/overrides/rails/common_methods.rb +20 -0
- data/lib/jets/overrides/rails/rendering_helper.rb +26 -0
- data/lib/jets/overrides/rails/url_helper.rb +25 -0
- data/lib/jets/poly_fun.rb +82 -0
- data/lib/jets/poly_fun/base_executor.rb +125 -0
- data/lib/jets/poly_fun/lambda_executor.rb +16 -0
- data/lib/jets/poly_fun/node_error.rb +8 -0
- data/lib/jets/poly_fun/node_executor.rb +54 -0
- data/lib/jets/poly_fun/python_error.rb +8 -0
- data/lib/jets/poly_fun/python_executor.rb +23 -0
- data/lib/jets/preheat.rb +117 -0
- data/lib/jets/processors.rb +4 -0
- data/lib/jets/processors/deducer.rb +65 -0
- data/lib/jets/processors/main_processor.rb +59 -0
- data/lib/jets/rack_server.rb +80 -0
- data/lib/jets/rdoc.rb +30 -0
- data/lib/jets/resource.rb +74 -0
- data/lib/jets/resource/api_gateway.rb +9 -0
- data/lib/jets/resource/api_gateway/base_path.rb +5 -0
- data/lib/jets/resource/api_gateway/base_path/function.rb +42 -0
- data/lib/jets/resource/api_gateway/base_path/mapping.rb +44 -0
- data/lib/jets/resource/api_gateway/base_path/role.rb +76 -0
- data/lib/jets/resource/api_gateway/cors.rb +61 -0
- data/lib/jets/resource/api_gateway/deployment.rb +78 -0
- data/lib/jets/resource/api_gateway/domain_name.rb +59 -0
- data/lib/jets/resource/api_gateway/method.rb +98 -0
- data/lib/jets/resource/api_gateway/resource.rb +78 -0
- data/lib/jets/resource/api_gateway/rest_api.rb +60 -0
- data/lib/jets/resource/api_gateway/rest_api/change_detection.rb +42 -0
- data/lib/jets/resource/api_gateway/rest_api/logical_id.rb +63 -0
- data/lib/jets/resource/api_gateway/rest_api/routes.rb +11 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/change.rb +12 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/change/base.rb +130 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/change/to.rb +29 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/change/variable.rb +39 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/collision.rb +123 -0
- data/lib/jets/resource/api_gateway/rest_api/routes/collision/variable_exception.rb +7 -0
- data/lib/jets/resource/associated.rb +26 -0
- data/lib/jets/resource/base.rb +28 -0
- data/lib/jets/resource/child_stack.rb +7 -0
- data/lib/jets/resource/child_stack/api_deployment.rb +56 -0
- data/lib/jets/resource/child_stack/api_gateway.rb +29 -0
- data/lib/jets/resource/child_stack/app_class.rb +112 -0
- data/lib/jets/resource/child_stack/base.rb +24 -0
- data/lib/jets/resource/child_stack/shared.rb +90 -0
- data/lib/jets/resource/config.rb +4 -0
- data/lib/jets/resource/config/config_rule.rb +74 -0
- data/lib/jets/resource/config/managed_rule.rb +15 -0
- data/lib/jets/resource/events.rb +3 -0
- data/lib/jets/resource/events/rule.rb +31 -0
- data/lib/jets/resource/iam.rb +8 -0
- data/lib/jets/resource/iam/application_role.rb +27 -0
- data/lib/jets/resource/iam/base_role_definition.rb +47 -0
- data/lib/jets/resource/iam/class_role.rb +74 -0
- data/lib/jets/resource/iam/function_role.rb +54 -0
- data/lib/jets/resource/iam/managed_policy.rb +22 -0
- data/lib/jets/resource/iam/policy_document.rb +41 -0
- data/lib/jets/resource/lambda.rb +5 -0
- data/lib/jets/resource/lambda/function.rb +216 -0
- data/lib/jets/resource/lambda/function/environment.rb +61 -0
- data/lib/jets/resource/lambda/gem_layer.rb +17 -0
- data/lib/jets/resource/lambda/layer_version.rb +44 -0
- data/lib/jets/resource/permission.rb +45 -0
- data/lib/jets/resource/replacer.rb +77 -0
- data/lib/jets/resource/route53.rb +3 -0
- data/lib/jets/resource/route53/record_set.rb +70 -0
- data/lib/jets/resource/s3.rb +17 -0
- data/lib/jets/resource/sns.rb +3 -0
- data/lib/jets/resource/sqs.rb +3 -0
- data/lib/jets/resource/standardizer.rb +42 -0
- data/lib/jets/route.rb +166 -0
- data/lib/jets/router.rb +175 -0
- data/lib/jets/router/scope.rb +30 -0
- data/lib/jets/rule.rb +4 -0
- data/lib/jets/rule/base.rb +19 -0
- data/lib/jets/rule/dsl.rb +110 -0
- data/lib/jets/spec_helpers.rb +52 -0
- data/lib/jets/spec_helpers/params.rb +10 -0
- data/lib/jets/spec_helpers/request.rb +98 -0
- data/lib/jets/spec_helpers/response.rb +5 -0
- data/lib/jets/stack.rb +103 -0
- data/lib/jets/stack/builder.rb +38 -0
- data/lib/jets/stack/definition.rb +50 -0
- data/lib/jets/stack/function.rb +60 -0
- data/lib/jets/stack/main.rb +5 -0
- data/lib/jets/stack/main/dsl.rb +33 -0
- data/lib/jets/stack/main/extensions/base.rb +45 -0
- data/lib/jets/stack/main/extensions/cloudwatch.rb +19 -0
- data/lib/jets/stack/main/extensions/lambda.rb +71 -0
- data/lib/jets/stack/main/extensions/sns.rb +12 -0
- data/lib/jets/stack/main/extensions/sqs.rb +36 -0
- data/lib/jets/stack/output.rb +38 -0
- data/lib/jets/stack/output/dsl.rb +19 -0
- data/lib/jets/stack/output/lookup.rb +36 -0
- data/lib/jets/stack/parameter.rb +38 -0
- data/lib/jets/stack/parameter/dsl.rb +42 -0
- data/lib/jets/stack/resource.rb +32 -0
- data/lib/jets/stack/resource/dsl.rb +19 -0
- data/lib/jets/tmp_loader.rb +52 -0
- data/lib/jets/turbine.rb +30 -0
- data/lib/jets/turbo.rb +47 -0
- data/lib/jets/turbo/database_yaml.rb +41 -0
- data/lib/jets/turbo/project/.gitignore +12 -0
- data/lib/jets/turbo/project/.jetskeep +1 -0
- data/lib/jets/turbo/project/Gemfile +16 -0
- data/lib/jets/turbo/project/Rakefile +2 -0
- data/lib/jets/turbo/project/app/controllers/application_controller.rb +2 -0
- data/lib/jets/turbo/project/app/helpers/application_helper.rb +2 -0
- data/lib/jets/turbo/project/app/jobs/application_job.rb +4 -0
- data/lib/jets/turbo/project/config.ru +5 -0
- data/lib/jets/turbo/project/config/application.rb +4 -0
- data/lib/jets/turbo/project/config/routes.rb +4 -0
- data/lib/jets/turbo/rail.rb +113 -0
- data/lib/jets/turbo/templates/config/database.yml +26 -0
- data/lib/jets/util.rb +38 -0
- data/lib/jets/version.rb +3 -0
- data/readme/prerelease.md +6 -0
- data/readme/testing.md +60 -0
- metadata +859 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
class Jets::Resource
|
|
2
|
+
class Replacer
|
|
3
|
+
extend Memoist
|
|
4
|
+
|
|
5
|
+
def initialize(replacements={})
|
|
6
|
+
@replacements = replacements
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Replace placeholder hash values with replacements. This does a deep replacement
|
|
10
|
+
# to the hash values. The replacement "key" is the string value within the value.
|
|
11
|
+
#
|
|
12
|
+
# Example:
|
|
13
|
+
#
|
|
14
|
+
# attributes = {whatever: "foo REPLACE_KEY bar" }
|
|
15
|
+
# replace_placeholders(attributes, REPLACE_KEY: "blah:arn")
|
|
16
|
+
# => {whatever: "foo blah:arn bar" }
|
|
17
|
+
#
|
|
18
|
+
# Also, we always replace the special {namespace} value in the hash values. Example:
|
|
19
|
+
#
|
|
20
|
+
# attributes = {whatever: "{namespace}LambdaFunction" }
|
|
21
|
+
# replace_placeholders(attributes, {})
|
|
22
|
+
# => {whatever: "foo PostsControllerIndexLambdaFunction bar" }
|
|
23
|
+
#
|
|
24
|
+
def replace_placeholders(attributes)
|
|
25
|
+
update_values(attributes)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def update_values(original)
|
|
29
|
+
case original
|
|
30
|
+
when Array
|
|
31
|
+
original.map { |v| update_values(v) }
|
|
32
|
+
when Hash
|
|
33
|
+
initializer = original.map do |k, v|
|
|
34
|
+
[k, update_values(v)]
|
|
35
|
+
end
|
|
36
|
+
Hash[initializer]
|
|
37
|
+
else
|
|
38
|
+
replace_value(original)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def replace_value(value)
|
|
43
|
+
# Dont perform replacement on Integers
|
|
44
|
+
return value if value.is_a?(Integer)
|
|
45
|
+
# return value unless value.is_a?(String) or value.is_a?(Symbol)
|
|
46
|
+
|
|
47
|
+
value = value.to_s # normalize to String
|
|
48
|
+
@replacements.each do |k,v|
|
|
49
|
+
# IE: Replaces {namespace} => SecurityJobCheck
|
|
50
|
+
value = value.gsub("{#{k}}", v)
|
|
51
|
+
end
|
|
52
|
+
value
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class << self
|
|
56
|
+
# Examples:
|
|
57
|
+
# "AWS::Events::Rule" => "events.amazonaws.com",
|
|
58
|
+
# "AWS::Config::ConfigRule" => "config.amazonaws.com",
|
|
59
|
+
# "AWS::ApiGateway::Method" => "apigateway.amazonaws.com"
|
|
60
|
+
def principal_map(type)
|
|
61
|
+
service = type.split('::')[1].downcase
|
|
62
|
+
"#{service}.amazonaws.com"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# From AWS docs: https://amzn.to/2N0QXQL
|
|
66
|
+
# source_arn is "not supported by all event sources"
|
|
67
|
+
#
|
|
68
|
+
# When it is not available the resource definition should add it.
|
|
69
|
+
def source_arn_map(type)
|
|
70
|
+
map = {
|
|
71
|
+
"AWS::ApiGateway::Method" => "!Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApi}/*/*",
|
|
72
|
+
}
|
|
73
|
+
map[type]
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# CloudFormation Docs AWS::Route53::RecordSet: https://amzn.to/2BtP9s5
|
|
2
|
+
#
|
|
3
|
+
# Example:
|
|
4
|
+
#
|
|
5
|
+
# DnsRecord:
|
|
6
|
+
# Type: AWS::Route53::RecordSet
|
|
7
|
+
# Properties:
|
|
8
|
+
# HostedZoneName: !Ref 'HostedZoneResource'
|
|
9
|
+
# Comment: DNS name for my instance.
|
|
10
|
+
# Name: !Join ['', [!Ref 'Ec2Instance', ., !Ref 'AWS::Region', ., !Ref 'HostedZone', .]]
|
|
11
|
+
# Type: A
|
|
12
|
+
# TTL: '900'
|
|
13
|
+
# ResourceRecords:
|
|
14
|
+
# - !GetAtt Ec2Instance.PublicIp
|
|
15
|
+
module Jets::Resource::Route53
|
|
16
|
+
class RecordSet < Jets::Resource::Base
|
|
17
|
+
def definition
|
|
18
|
+
{
|
|
19
|
+
dns_record: {
|
|
20
|
+
type: "AWS::Route53::RecordSet",
|
|
21
|
+
properties: {
|
|
22
|
+
hosted_zone_name: hosted_zone_name,
|
|
23
|
+
comment: "DNS record managed by Jets",
|
|
24
|
+
name: name,
|
|
25
|
+
type: "CNAME",
|
|
26
|
+
ttl: "60",
|
|
27
|
+
resource_records: [
|
|
28
|
+
cname,
|
|
29
|
+
],
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def cname
|
|
36
|
+
if endpoint_types.include?("REGIONAL")
|
|
37
|
+
"!GetAtt DomainName.RegionalDomainName"
|
|
38
|
+
else
|
|
39
|
+
"!GetAtt DomainName.DistributionDomainName"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def domain_name
|
|
44
|
+
Jets::Resource::ApiGateway::DomainName.new
|
|
45
|
+
end
|
|
46
|
+
memoize :domain_name
|
|
47
|
+
|
|
48
|
+
def endpoint_types
|
|
49
|
+
domain_name.endpoint_types
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# IE: demo-dev.mydomain.com
|
|
53
|
+
def name
|
|
54
|
+
# Weird looking but correct: domain_name is object and domain_name is also method
|
|
55
|
+
domain_name.domain_name
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# IE: mydomain.com
|
|
59
|
+
def hosted_zone_name
|
|
60
|
+
name = Jets.config.domain.hosted_zone_name
|
|
61
|
+
name.ends_with?('.') ? name : "#{name}." # add trailing period if missing
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def outputs
|
|
65
|
+
{
|
|
66
|
+
"DnsRecord" => "!Ref DnsRecord",
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class Jets::Resource
|
|
2
|
+
class Standardizer
|
|
3
|
+
attr_reader :definition
|
|
4
|
+
def initialize(*definition)
|
|
5
|
+
@definition = definition.flatten
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def template
|
|
9
|
+
camelize(standarize(@definition))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def camelize(attributes)
|
|
13
|
+
Jets::Camelizer.transform(attributes)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def standarize(definition)
|
|
17
|
+
first, second, third, _ = definition
|
|
18
|
+
if definition.size == 1 && first.is_a?(Hash) # long form
|
|
19
|
+
first # pass through
|
|
20
|
+
elsif definition.size == 2 && second.is_a?(Hash) # medium form
|
|
21
|
+
logical_id, attributes = first, second
|
|
22
|
+
attributes.delete(:properties) if attributes[:properties].nil? || attributes[:properties].empty?
|
|
23
|
+
{ logical_id => attributes }
|
|
24
|
+
elsif definition.size == 2 && second.is_a?(String) # short form
|
|
25
|
+
logical_id, type = first, second
|
|
26
|
+
{ logical_id => {
|
|
27
|
+
type: type
|
|
28
|
+
}}
|
|
29
|
+
elsif definition.size == 3 && (second.is_a?(String) || second.is_a?(NilClass))# short form
|
|
30
|
+
logical_id, type, properties = first, second, third
|
|
31
|
+
template = { logical_id => {
|
|
32
|
+
type: type
|
|
33
|
+
}}
|
|
34
|
+
attributes = template.values.first
|
|
35
|
+
attributes[:properties] = properties unless properties.empty?
|
|
36
|
+
template
|
|
37
|
+
else # Dont understand this form
|
|
38
|
+
raise "Invalid form provided. definition #{definition.inspect}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/jets/route.rb
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# route = Jets::Route.new(
|
|
2
|
+
# path: "posts",
|
|
3
|
+
# method: :get,
|
|
4
|
+
# to: "posts#index",
|
|
5
|
+
# )
|
|
6
|
+
class Jets::Route
|
|
7
|
+
CAPTURE_REGEX = "([^/]*)" # as string
|
|
8
|
+
|
|
9
|
+
def initialize(options)
|
|
10
|
+
@options = options
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# IE: standard: posts/:id/edit
|
|
14
|
+
# api_gateway: posts/{id}/edit
|
|
15
|
+
def path(format=:jets)
|
|
16
|
+
case format
|
|
17
|
+
when :api_gateway
|
|
18
|
+
api_gateway_format(@options[:path])
|
|
19
|
+
when :raw
|
|
20
|
+
@options[:path]
|
|
21
|
+
else # jets format
|
|
22
|
+
ensure_jets_format(@options[:path])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def method
|
|
27
|
+
@options[:method].to_s.upcase
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# IE: posts#index
|
|
31
|
+
def to
|
|
32
|
+
@options[:to]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def internal?
|
|
36
|
+
!!@options[:internal]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def homepage?
|
|
40
|
+
path == ''
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# IE: PostsController
|
|
44
|
+
def controller_name
|
|
45
|
+
to.sub(/#.*/,'').camelize + "Controller"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# IE: index
|
|
49
|
+
def action_name
|
|
50
|
+
to.sub(/.*#/,'')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Checks to see if the corresponding controller exists. Useful to validate routes
|
|
54
|
+
# before deploying to CloudFormation and then rolling back.
|
|
55
|
+
def valid?
|
|
56
|
+
controller_class = begin
|
|
57
|
+
controller_name.constantize
|
|
58
|
+
rescue NameError
|
|
59
|
+
return false
|
|
60
|
+
end
|
|
61
|
+
controller_class.lambda_functions.include?(action_name.to_sym)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Extracts the path parameters from the actual path
|
|
65
|
+
# Only supports extracting 1 parameter. So:
|
|
66
|
+
#
|
|
67
|
+
# actual_path: posts/tung/edit
|
|
68
|
+
# route.path: posts/:id/edit
|
|
69
|
+
#
|
|
70
|
+
# Returns:
|
|
71
|
+
# { id: "tung" }
|
|
72
|
+
def extract_parameters(actual_path)
|
|
73
|
+
if path.include?(':')
|
|
74
|
+
extract_parameters_capture(actual_path)
|
|
75
|
+
elsif path.include?('*')
|
|
76
|
+
extract_parameters_proxy(actual_path)
|
|
77
|
+
else
|
|
78
|
+
# Lambda AWS_PROXY sets null to the input request when there are no path parmeters
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def extract_parameters_proxy(actual_path)
|
|
84
|
+
# changes path to a string used for a regexp
|
|
85
|
+
# others/*proxy => others\/(.*)
|
|
86
|
+
# nested/others/*proxy => nested/others\/(.*)
|
|
87
|
+
if path.include?('/')
|
|
88
|
+
leading_path = path.split('/')[0..-2].join('/') # drop last segment
|
|
89
|
+
# leading_path: nested/others
|
|
90
|
+
# capture everything after the leading_path as the value
|
|
91
|
+
regexp = Regexp.new("#{leading_path}/(.*)")
|
|
92
|
+
value = actual_path.match(regexp)[1]
|
|
93
|
+
else
|
|
94
|
+
value = actual_path
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# the last segment without the '*' is the key
|
|
98
|
+
proxy_segment = path.split('/').last # last segment is the proxy segment
|
|
99
|
+
# proxy_segment: *proxy
|
|
100
|
+
key = proxy_segment.sub('*','')
|
|
101
|
+
|
|
102
|
+
{ key => value }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def extract_parameters_capture(actual_path)
|
|
106
|
+
# changes path to a string used for a regexp
|
|
107
|
+
# posts/:id/edit => posts\/(.*)\/edit
|
|
108
|
+
labels = []
|
|
109
|
+
regexp_string = path.split('/').map do |s|
|
|
110
|
+
if s.start_with?(':')
|
|
111
|
+
labels << s.delete_prefix(':')
|
|
112
|
+
CAPTURE_REGEX
|
|
113
|
+
else
|
|
114
|
+
s
|
|
115
|
+
end
|
|
116
|
+
end.join('\/')
|
|
117
|
+
# make sure beginning and end of the string matches
|
|
118
|
+
regexp_string = "^#{regexp_string}$"
|
|
119
|
+
regexp = Regexp.new(regexp_string)
|
|
120
|
+
|
|
121
|
+
values = regexp.match(actual_path).captures
|
|
122
|
+
labels.map do |next_label|
|
|
123
|
+
[next_label, values.delete_at(0)]
|
|
124
|
+
end.to_h
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def authorization_type
|
|
128
|
+
@options[:authorization_type]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
def ensure_jets_format(path)
|
|
133
|
+
path.split('/').map do |s|
|
|
134
|
+
if s =~ /^\{/ and s =~ /\+\}$/
|
|
135
|
+
s.sub(/^\{/, '*').sub(/\+\}$/,'') # {proxy+} => *proxy
|
|
136
|
+
elsif s =~ /^\{/ and s =~ /\}$/
|
|
137
|
+
s.sub('{',':').sub(/\}$/,'') # {id} => :id
|
|
138
|
+
else
|
|
139
|
+
s
|
|
140
|
+
end
|
|
141
|
+
end.join('/')
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def api_gateway_format(path)
|
|
145
|
+
path.split('/')
|
|
146
|
+
.map {|s| transform_capture(s) }
|
|
147
|
+
.map {|s| transform_proxy(s) }
|
|
148
|
+
.join('/')
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def transform_capture(text)
|
|
152
|
+
if text.starts_with?(':')
|
|
153
|
+
text = text.sub(':','')
|
|
154
|
+
text = "{#{text}}"
|
|
155
|
+
end
|
|
156
|
+
text
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def transform_proxy(text)
|
|
160
|
+
if text.starts_with?('*')
|
|
161
|
+
text = text.sub('*','')
|
|
162
|
+
text = "{#{text}+}"
|
|
163
|
+
end
|
|
164
|
+
text
|
|
165
|
+
end
|
|
166
|
+
end
|
data/lib/jets/router.rb
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
require 'text-table'
|
|
2
|
+
|
|
3
|
+
module Jets
|
|
4
|
+
class Router
|
|
5
|
+
autoload :Scope, 'jets/router/scope'
|
|
6
|
+
|
|
7
|
+
attr_reader :routes
|
|
8
|
+
def initialize
|
|
9
|
+
@routes = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def draw(&block)
|
|
13
|
+
instance_eval(&block)
|
|
14
|
+
check_collision!
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Validate routes that deployable
|
|
18
|
+
def check_collision!
|
|
19
|
+
paths = self.routes.map(&:path)
|
|
20
|
+
collision = Jets::Resource::ApiGateway::RestApi::Routes::Collision.new
|
|
21
|
+
collide = collision.collision?(paths)
|
|
22
|
+
raise collision.exception if collide
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Methods supported by API Gateway
|
|
26
|
+
%w[any delete get head options patch post put].each do |method_name|
|
|
27
|
+
define_method method_name do |path, options|
|
|
28
|
+
create_route(options.merge(path: path, method: __method__))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def create_route(options)
|
|
33
|
+
# Currently only using scope to add namespace
|
|
34
|
+
# TODO: Can use it to add additional things like authorization_type
|
|
35
|
+
# Would be good to add authorization_type at the controller level also
|
|
36
|
+
options[:path] = add_namespace(options[:path])
|
|
37
|
+
@routes << Route.new(options)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add_namespace(path)
|
|
41
|
+
return path unless @scope
|
|
42
|
+
ns = @scope.full_namespace
|
|
43
|
+
return path unless ns
|
|
44
|
+
"#{ns}/#{path}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def namespace(ns, &block)
|
|
48
|
+
scope(namespace: ns, &block)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def scope(options={})
|
|
52
|
+
root_level = @scope.nil?
|
|
53
|
+
@scope = root_level ? Scope.new(options) : @scope.new(options)
|
|
54
|
+
yield
|
|
55
|
+
ensure
|
|
56
|
+
@scope = @scope.parent if @scope
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# resources macro expands to all the routes
|
|
60
|
+
def resources(name)
|
|
61
|
+
get "#{name}", to: "#{name}#index"
|
|
62
|
+
get "#{name}/new", to: "#{name}#new" unless api_mode?
|
|
63
|
+
get "#{name}/:id", to: "#{name}#show"
|
|
64
|
+
post "#{name}", to: "#{name}#create"
|
|
65
|
+
get "#{name}/:id/edit", to: "#{name}#edit" unless api_mode?
|
|
66
|
+
put "#{name}/:id", to: "#{name}#update"
|
|
67
|
+
post "#{name}/:id", to: "#{name}#update" # for binary uploads
|
|
68
|
+
patch "#{name}/:id", to: "#{name}#update"
|
|
69
|
+
delete "#{name}/:id", to: "#{name}#delete"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def api_mode?
|
|
73
|
+
if Jets.config.key?(:api_mode) || Jets.config.key?(:api_generator)
|
|
74
|
+
puts <<~EOL.color(:yellow)
|
|
75
|
+
DEPRECATED: Jets.config.api_generator
|
|
76
|
+
Instead, please update your config/application.rb to use:
|
|
77
|
+
Jets.config.mode = 'api'
|
|
78
|
+
You can also run:
|
|
79
|
+
jets upgrade
|
|
80
|
+
EOL
|
|
81
|
+
end
|
|
82
|
+
api_mode = Jets.config.mode == 'api' || Jets.config.api_mode || Jets.config.api_generator
|
|
83
|
+
api_mode
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# root "posts#index"
|
|
87
|
+
def root(to, options={})
|
|
88
|
+
default = {path: '', to: to, method: :get, root: true}
|
|
89
|
+
options = default.merge(options)
|
|
90
|
+
@routes << Route.new(options)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Useful for creating API Gateway Resources
|
|
94
|
+
def all_paths
|
|
95
|
+
results = []
|
|
96
|
+
paths = routes.map(&:path)
|
|
97
|
+
paths.each do |p|
|
|
98
|
+
sub_paths = []
|
|
99
|
+
parts = p.split('/')
|
|
100
|
+
until parts.empty?
|
|
101
|
+
parts.pop
|
|
102
|
+
sub_path = parts.join('/')
|
|
103
|
+
sub_paths << sub_path unless sub_path == ''
|
|
104
|
+
end
|
|
105
|
+
results += sub_paths
|
|
106
|
+
end
|
|
107
|
+
@all_paths = (results + paths).sort.uniq
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Useful for RouterMatcher
|
|
111
|
+
#
|
|
112
|
+
# Precedence:
|
|
113
|
+
# 1. Routes with no captures get highest precedence: posts/new
|
|
114
|
+
# 2. Then consider the routes with captures: post/:id
|
|
115
|
+
# 3. Last consider the routes with wildcards: *catchall
|
|
116
|
+
#
|
|
117
|
+
# Within these 2 groups we consider the routes with the longest path first
|
|
118
|
+
# since posts/:id and posts/:id/edit can both match.
|
|
119
|
+
def ordered_routes
|
|
120
|
+
length = Proc.new { |r| r.path.length * -1 }
|
|
121
|
+
capture_routes = routes.select { |r| r.path.include?(':') }.sort_by(&length)
|
|
122
|
+
wildcard_routes = routes.select { |r| r.path.include?('*') }.sort_by(&length)
|
|
123
|
+
simple_routes = (routes - capture_routes - wildcard_routes).sort_by(&length)
|
|
124
|
+
simple_routes + capture_routes + wildcard_routes
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def self.has_controller?(name)
|
|
128
|
+
routes.detect { |r| r.controller_name == name }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Class methods
|
|
132
|
+
def self.draw
|
|
133
|
+
drawn_router
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
@@drawn_router = nil
|
|
137
|
+
def self.drawn_router
|
|
138
|
+
return @@drawn_router if @@drawn_router
|
|
139
|
+
|
|
140
|
+
router = Jets.application.routes
|
|
141
|
+
@@drawn_router = router
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def self.routes
|
|
145
|
+
drawn_router.routes
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Returns all paths including subpaths.
|
|
149
|
+
# Example:
|
|
150
|
+
# Input: ["posts/:id/edit"]
|
|
151
|
+
# Output: ["posts", "posts/:id", "posts/:id/edit"]
|
|
152
|
+
def self.all_paths
|
|
153
|
+
drawn_router.all_paths
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def self.routes_help
|
|
157
|
+
return "Your routes table is empty." if routes.empty?
|
|
158
|
+
|
|
159
|
+
table = Text::Table.new
|
|
160
|
+
table.head = %w[Verb Path Controller#action]
|
|
161
|
+
routes.each do |route|
|
|
162
|
+
table.rows << [route.method, route.path, route.to]
|
|
163
|
+
end
|
|
164
|
+
table
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def self.all_routes_valid
|
|
168
|
+
invalid_routes.empty?
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def self.invalid_routes
|
|
172
|
+
routes.select { |r| !r.valid? }
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|