hanami 2.0.0.alpha8 → 2.0.0.beta1
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/CHANGELOG.md +442 -241
- data/FEATURES.md +30 -9
- data/README.md +1 -3
- data/hanami.gemspec +21 -11
- data/lib/hanami/app.rb +141 -0
- data/lib/hanami/assets/application_configuration.rb +10 -4
- data/lib/hanami/configuration/actions/content_security_policy.rb +5 -5
- data/lib/hanami/configuration/actions/cookies.rb +2 -2
- data/lib/hanami/configuration/actions.rb +10 -4
- data/lib/hanami/configuration/logger.rb +4 -4
- data/lib/hanami/configuration/router.rb +2 -6
- data/lib/hanami/configuration/sessions.rb +1 -1
- data/lib/hanami/configuration/views.rb +9 -4
- data/lib/hanami/configuration.rb +118 -46
- data/lib/hanami/constants.rb +24 -2
- data/lib/hanami/errors.rb +1 -1
- data/lib/hanami/{application → extensions}/action/slice_configured_action.rb +9 -9
- data/lib/hanami/extensions/action.rb +79 -0
- data/lib/hanami/extensions/view/context.rb +106 -0
- data/lib/hanami/{application → extensions}/view/slice_configured_context.rb +10 -10
- data/lib/hanami/{application → extensions}/view/slice_configured_view.rb +12 -6
- data/lib/hanami/extensions/view.rb +33 -0
- data/lib/hanami/extensions.rb +10 -0
- data/lib/hanami/providers/inflector.rb +13 -0
- data/lib/hanami/providers/logger.rb +13 -0
- data/lib/hanami/providers/rack.rb +27 -0
- data/lib/hanami/providers/routes.rb +33 -0
- data/lib/hanami/providers/settings.rb +23 -0
- data/lib/hanami/rake_tasks.rb +61 -0
- data/lib/hanami/routes.rb +51 -0
- data/lib/hanami/server.rb +1 -1
- data/lib/hanami/settings/dotenv_store.rb +58 -0
- data/lib/hanami/settings.rb +90 -0
- data/lib/hanami/setup.rb +4 -2
- data/lib/hanami/{application → slice}/router.rb +18 -13
- data/lib/hanami/slice/routes_helper.rb +37 -0
- data/lib/hanami/{application → slice}/routing/middleware/stack.rb +43 -5
- data/lib/hanami/slice/routing/resolver.rb +97 -0
- data/lib/hanami/{application → slice}/view_name_inferrer.rb +3 -3
- data/lib/hanami/slice.rb +246 -73
- data/lib/hanami/slice_configurable.rb +4 -17
- data/lib/hanami/slice_name.rb +6 -6
- data/lib/hanami/slice_registrar.rb +119 -0
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +1 -1
- data/lib/hanami.rb +34 -26
- data/spec/integration/application_middleware_stack_spec.rb +84 -0
- data/spec/integration/assets/cdn_spec.rb +48 -0
- data/spec/integration/assets/fingerprint_spec.rb +42 -0
- data/spec/integration/assets/helpers_spec.rb +50 -0
- data/spec/integration/assets/serve_spec.rb +70 -0
- data/spec/integration/assets/subresource_integrity_spec.rb +54 -0
- data/spec/integration/body_parsers_spec.rb +50 -0
- data/spec/integration/cli/assets/precompile_spec.rb +147 -0
- data/spec/integration/cli/assets_spec.rb +14 -0
- data/spec/integration/cli/console_spec.rb +105 -0
- data/spec/integration/cli/db/apply_spec.rb +74 -0
- data/spec/integration/cli/db/console_spec.rb +40 -0
- data/spec/integration/cli/db/create_spec.rb +50 -0
- data/spec/integration/cli/db/drop_spec.rb +54 -0
- data/spec/integration/cli/db/migrate_spec.rb +108 -0
- data/spec/integration/cli/db/prepare_spec.rb +36 -0
- data/spec/integration/cli/db/rollback_spec.rb +96 -0
- data/spec/integration/cli/db/version_spec.rb +38 -0
- data/spec/integration/cli/db_spec.rb +21 -0
- data/spec/integration/cli/destroy/action_spec.rb +143 -0
- data/spec/integration/cli/destroy/app_spec.rb +118 -0
- data/spec/integration/cli/destroy/mailer_spec.rb +74 -0
- data/spec/integration/cli/destroy/migration_spec.rb +70 -0
- data/spec/integration/cli/destroy/model_spec.rb +113 -0
- data/spec/integration/cli/destroy_spec.rb +18 -0
- data/spec/integration/cli/generate/action_spec.rb +469 -0
- data/spec/integration/cli/generate/app_spec.rb +215 -0
- data/spec/integration/cli/generate/mailer_spec.rb +189 -0
- data/spec/integration/cli/generate/migration_spec.rb +72 -0
- data/spec/integration/cli/generate/model_spec.rb +290 -0
- data/spec/integration/cli/generate/secret_spec.rb +56 -0
- data/spec/integration/cli/generate_spec.rb +19 -0
- data/spec/integration/cli/new/database_spec.rb +235 -0
- data/spec/integration/cli/new/hanami_head_spec.rb +27 -0
- data/spec/integration/cli/new/template_spec.rb +118 -0
- data/spec/integration/cli/new/test_spec.rb +274 -0
- data/spec/integration/cli/new_spec.rb +970 -0
- data/spec/integration/cli/plugins_spec.rb +39 -0
- data/spec/integration/cli/routes_spec.rb +49 -0
- data/spec/integration/cli/server_spec.rb +626 -0
- data/spec/integration/cli/version_spec.rb +85 -0
- data/spec/integration/early_hints_spec.rb +35 -0
- data/spec/integration/handle_exceptions_spec.rb +244 -0
- data/spec/integration/head_spec.rb +89 -0
- data/spec/integration/http_headers_spec.rb +29 -0
- data/spec/integration/mailer_spec.rb +32 -0
- data/spec/integration/middleware_spec.rb +81 -0
- data/spec/integration/mount_applications_spec.rb +88 -0
- data/spec/integration/project_initializers_spec.rb +40 -0
- data/spec/integration/rackup_spec.rb +35 -0
- data/spec/integration/rake/with_minitest_spec.rb +67 -0
- data/spec/integration/rake/with_rspec_spec.rb +69 -0
- data/spec/integration/routing_helpers_spec.rb +61 -0
- data/spec/integration/security/content_security_policy_spec.rb +46 -0
- data/spec/integration/security/csrf_protection_spec.rb +42 -0
- data/spec/integration/security/force_ssl_spec.rb +29 -0
- data/spec/integration/security/x_content_type_options_spec.rb +46 -0
- data/spec/integration/security/x_frame_options_spec.rb +46 -0
- data/spec/integration/security/x_xss_protection_spec.rb +46 -0
- data/spec/integration/send_file_spec.rb +51 -0
- data/spec/integration/sessions_spec.rb +247 -0
- data/spec/integration/static_middleware_spec.rb +21 -0
- data/spec/integration/streaming_spec.rb +41 -0
- data/spec/integration/unsafe_send_file_spec.rb +52 -0
- data/spec/isolation/hanami/application/already_configured_spec.rb +19 -0
- data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +10 -0
- data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +14 -0
- data/spec/isolation/hanami/application/not_configured_spec.rb +9 -0
- data/spec/isolation/hanami/application/routes/configured_spec.rb +44 -0
- data/spec/isolation/hanami/application/routes/not_configured_spec.rb +16 -0
- data/spec/isolation/hanami/boot/success_spec.rb +50 -0
- data/spec/new_integration/action/configuration_spec.rb +26 -0
- data/spec/new_integration/action/cookies_spec.rb +58 -0
- data/spec/new_integration/action/csrf_protection_spec.rb +54 -0
- data/spec/new_integration/action/routes_spec.rb +73 -0
- data/spec/new_integration/action/sessions_spec.rb +50 -0
- data/spec/new_integration/action/view_integration_spec.rb +165 -0
- data/spec/new_integration/action/view_rendering/automatic_rendering_spec.rb +247 -0
- data/spec/new_integration/action/view_rendering/paired_view_inference_spec.rb +115 -0
- data/spec/new_integration/action/view_rendering_spec.rb +107 -0
- data/spec/new_integration/code_loading/loading_from_app_spec.rb +152 -0
- data/spec/new_integration/code_loading/loading_from_slice_spec.rb +165 -0
- data/spec/new_integration/container/application_routes_helper_spec.rb +48 -0
- data/spec/new_integration/container/auto_injection_spec.rb +53 -0
- data/spec/new_integration/container/auto_registration_spec.rb +86 -0
- data/spec/new_integration/container/autoloader_spec.rb +80 -0
- data/spec/new_integration/container/imports_spec.rb +253 -0
- data/spec/new_integration/container/prepare_container_spec.rb +123 -0
- data/spec/new_integration/container/shutdown_spec.rb +91 -0
- data/spec/new_integration/container/standard_bootable_components_spec.rb +124 -0
- data/spec/new_integration/rack_app/middleware_spec.rb +215 -0
- data/spec/new_integration/rack_app/non_booted_rack_app_spec.rb +105 -0
- data/spec/new_integration/rack_app/rack_app_spec.rb +524 -0
- data/spec/new_integration/settings_spec.rb +115 -0
- data/spec/new_integration/slices/external_slice_spec.rb +92 -0
- data/spec/new_integration/slices/slice_configuration_spec.rb +40 -0
- data/spec/new_integration/slices/slice_routing_spec.rb +226 -0
- data/spec/new_integration/slices/slice_settings_spec.rb +141 -0
- data/spec/new_integration/slices_spec.rb +101 -0
- data/spec/new_integration/view/configuration_spec.rb +49 -0
- data/spec/new_integration/view/context/assets_spec.rb +67 -0
- data/spec/new_integration/view/context/inflector_spec.rb +48 -0
- data/spec/new_integration/view/context/request_spec.rb +61 -0
- data/spec/new_integration/view/context/routes_spec.rb +86 -0
- data/spec/new_integration/view/context/settings_spec.rb +50 -0
- data/spec/new_integration/view/inflector_spec.rb +57 -0
- data/spec/new_integration/view/part_namespace_spec.rb +96 -0
- data/spec/new_integration/view/path_spec.rb +56 -0
- data/spec/new_integration/view/template_spec.rb +68 -0
- data/spec/new_integration/view/views_spec.rb +103 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/app_integration.rb +91 -0
- data/spec/support/coverage.rb +1 -0
- data/spec/support/fixtures/hanami-plugin/Gemfile +8 -0
- data/spec/support/fixtures/hanami-plugin/README.md +35 -0
- data/spec/support/fixtures/hanami-plugin/Rakefile +4 -0
- data/spec/support/fixtures/hanami-plugin/bin/console +15 -0
- data/spec/support/fixtures/hanami-plugin/bin/setup +8 -0
- data/spec/support/fixtures/hanami-plugin/hanami-plugin.gemspec +28 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/cli.rb +19 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin/version.rb +7 -0
- data/spec/support/fixtures/hanami-plugin/lib/hanami/plugin.rb +8 -0
- data/spec/support/rspec.rb +27 -0
- data/spec/support/shared_examples/cli/generate/app.rb +494 -0
- data/spec/support/shared_examples/cli/generate/migration.rb +32 -0
- data/spec/support/shared_examples/cli/generate/model.rb +81 -0
- data/spec/support/shared_examples/cli/new.rb +97 -0
- data/spec/unit/hanami/configuration/actions/content_security_policy_spec.rb +102 -0
- data/spec/unit/hanami/configuration/actions/cookies_spec.rb +46 -0
- data/spec/unit/hanami/configuration/actions/csrf_protection_spec.rb +57 -0
- data/spec/unit/hanami/configuration/actions/default_values_spec.rb +52 -0
- data/spec/unit/hanami/configuration/actions/sessions_spec.rb +50 -0
- data/spec/unit/hanami/configuration/actions_spec.rb +78 -0
- data/spec/unit/hanami/configuration/base_url_spec.rb +25 -0
- data/spec/unit/hanami/configuration/inflector_spec.rb +35 -0
- data/spec/unit/hanami/configuration/logger_spec.rb +203 -0
- data/spec/unit/hanami/configuration/views_spec.rb +120 -0
- data/spec/unit/hanami/configuration_spec.rb +43 -0
- data/spec/unit/hanami/env_spec.rb +54 -0
- data/spec/unit/hanami/routes_spec.rb +25 -0
- data/spec/unit/hanami/settings/dotenv_store_spec.rb +119 -0
- data/spec/unit/hanami/settings_spec.rb +56 -0
- data/spec/unit/hanami/slice_configurable_spec.rb +104 -0
- data/spec/unit/hanami/slice_name_spec.rb +47 -0
- data/spec/unit/hanami/slice_spec.rb +17 -0
- data/spec/unit/hanami/version_spec.rb +7 -0
- data/spec/unit/hanami/web/rack_logger_spec.rb +78 -0
- metadata +353 -57
- data/lib/hanami/application/action.rb +0 -72
- data/lib/hanami/application/container/providers/inflector.rb +0 -7
- data/lib/hanami/application/container/providers/logger.rb +0 -7
- data/lib/hanami/application/container/providers/rack_logger.rb +0 -15
- data/lib/hanami/application/container/providers/rack_monitor.rb +0 -12
- data/lib/hanami/application/container/providers/routes_helper.rb +0 -9
- data/lib/hanami/application/container/providers/settings.rb +0 -7
- data/lib/hanami/application/routes.rb +0 -55
- data/lib/hanami/application/routes_helper.rb +0 -34
- data/lib/hanami/application/routing/resolver/node.rb +0 -50
- data/lib/hanami/application/routing/resolver/trie.rb +0 -59
- data/lib/hanami/application/routing/resolver.rb +0 -87
- data/lib/hanami/application/routing/router.rb +0 -36
- data/lib/hanami/application/settings/dotenv_store.rb +0 -60
- data/lib/hanami/application/settings.rb +0 -93
- data/lib/hanami/application/slice_registrar.rb +0 -106
- data/lib/hanami/application/view/context.rb +0 -95
- data/lib/hanami/application/view.rb +0 -24
- data/lib/hanami/application.rb +0 -273
- data/lib/hanami/cli/application/cli.rb +0 -40
- data/lib/hanami/cli/application/command.rb +0 -47
- data/lib/hanami/cli/application/commands/console.rb +0 -81
- data/lib/hanami/cli/application/commands.rb +0 -16
- data/lib/hanami/cli/base_command.rb +0 -48
- data/lib/hanami/cli/commands/command.rb +0 -171
- data/lib/hanami/cli/commands/server.rb +0 -88
- data/lib/hanami/cli/commands.rb +0 -65
- data/lib/hanami/configuration/middleware.rb +0 -20
- data/lib/hanami/configuration/source_dirs.rb +0 -42
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "pathname"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "CLI plugins", type: :integration do
|
|
6
|
+
xit "includes its commands in CLI output" do
|
|
7
|
+
with_project do
|
|
8
|
+
bundle_exec "hanami"
|
|
9
|
+
expect(out).to include("hanami plugin [SUBCOMMAND]")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
xit "executes command from plugin" do
|
|
14
|
+
with_project do
|
|
15
|
+
bundle_exec "hanami plugin version"
|
|
16
|
+
expect(out).to include("v0.1.0")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# See https://github.com/hanami/hanami/issues/838
|
|
21
|
+
it "guarantees 'hanami new' to generate a project" do
|
|
22
|
+
project = "bookshelf_without_gemfile"
|
|
23
|
+
|
|
24
|
+
with_system_tmp_directory do
|
|
25
|
+
run_cmd_with_clean_env "hanami new #{project}"
|
|
26
|
+
destination = Pathname.new(Dir.pwd).join(project)
|
|
27
|
+
|
|
28
|
+
expect(destination).to exist
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def with_project
|
|
35
|
+
super("bookshelf", gems: { "hanami-plugin" => { groups: [:plugins], path: Pathname.new(__dir__).join("..", "..", "..", "spec", "support", "fixtures", "hanami-plugin").realpath.to_s } }) do
|
|
36
|
+
yield
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe "hanami routes", type: :integration do
|
|
4
|
+
it "prints app routes" do
|
|
5
|
+
with_project do
|
|
6
|
+
generate "app admin"
|
|
7
|
+
|
|
8
|
+
write "lib/ping.rb", <<~EOF
|
|
9
|
+
class Ping
|
|
10
|
+
def call(env)
|
|
11
|
+
[200, {}, ["PONG"]]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
EOF
|
|
15
|
+
|
|
16
|
+
unshift "config/environment.rb", "require_relative '../lib/ping'"
|
|
17
|
+
replace "config/environment.rb", "Hanami.configure do", "Hanami.configure do\nmount Ping, at: '/ping'"
|
|
18
|
+
|
|
19
|
+
generate "action web home#index --url=/"
|
|
20
|
+
generate "action web books#create --url=/books --method=POST"
|
|
21
|
+
|
|
22
|
+
generate "action admin home#index --url=/"
|
|
23
|
+
|
|
24
|
+
hanami "routes"
|
|
25
|
+
|
|
26
|
+
expect(out).to eq "Name Method Path Action \n\n /ping Ping \n\n Name Method Path Action \n\n GET, HEAD /admin Admin::Controllers::Home::Index\n\n Name Method Path Action \n\n GET, HEAD / Web::Controllers::Home::Index \n POST /books Web::Controllers::Books::Create"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "prints help message" do
|
|
31
|
+
with_project do
|
|
32
|
+
output = <<~OUT
|
|
33
|
+
Command:
|
|
34
|
+
hanami routes
|
|
35
|
+
|
|
36
|
+
Usage:
|
|
37
|
+
hanami routes
|
|
38
|
+
|
|
39
|
+
Description:
|
|
40
|
+
Prints routes
|
|
41
|
+
|
|
42
|
+
Options:
|
|
43
|
+
--help, -h # Print this help
|
|
44
|
+
OUT
|
|
45
|
+
|
|
46
|
+
run_cmd 'hanami routes --help', output
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "hanami server", type: :integration do
|
|
6
|
+
context "without routes" do
|
|
7
|
+
it "shows welcome page" do
|
|
8
|
+
with_project do
|
|
9
|
+
server do
|
|
10
|
+
visit "/"
|
|
11
|
+
|
|
12
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
13
|
+
|
|
14
|
+
expect(page).to have_content("The web, with simplicity.")
|
|
15
|
+
expect(page).to have_content("Hanami is Open Source Software for MVC web development with Ruby.")
|
|
16
|
+
expect(page).to have_content("bundle exec hanami generate action web 'home#index' --url=/")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "shows welcome page for generated app" do
|
|
22
|
+
with_project do
|
|
23
|
+
generate "app admin"
|
|
24
|
+
|
|
25
|
+
server do
|
|
26
|
+
visit "/admin"
|
|
27
|
+
|
|
28
|
+
expect(page).to have_content("bundle exec hanami generate action admin 'home#index' --url=/")
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "with routes" do
|
|
35
|
+
it "serves action" do
|
|
36
|
+
with_project do
|
|
37
|
+
server do
|
|
38
|
+
generate "action web home#index --url=/"
|
|
39
|
+
|
|
40
|
+
visit "/"
|
|
41
|
+
expect(page).to have_title("Web")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "serves static asset" do
|
|
47
|
+
with_project do
|
|
48
|
+
server do
|
|
49
|
+
write "apps/web/assets/javascripts/app.js", <<~EOF
|
|
50
|
+
console.log('test');
|
|
51
|
+
EOF
|
|
52
|
+
visit "/assets/app.js"
|
|
53
|
+
expect(page).to have_content("console.log('test');")
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "serves contents from database" do
|
|
59
|
+
with_project do
|
|
60
|
+
setup_model
|
|
61
|
+
console do |input, _, _|
|
|
62
|
+
input.puts("BookRepository.new.create(title: 'Learn Hanami')")
|
|
63
|
+
input.puts("exit")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
generate "action web books#show --url=/books/:id"
|
|
67
|
+
rewrite "apps/web/controllers/books/show.rb", <<~EOF
|
|
68
|
+
module Web::Controllers::Books
|
|
69
|
+
class Show
|
|
70
|
+
include Web::Action
|
|
71
|
+
expose :book
|
|
72
|
+
|
|
73
|
+
def call(params)
|
|
74
|
+
@book = BookRepository.new.find(params[:id]) or halt(404)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
EOF
|
|
79
|
+
rewrite "apps/web/templates/books/show.html.erb", <<~EOF
|
|
80
|
+
<h1><%= book.title %></h1>
|
|
81
|
+
EOF
|
|
82
|
+
|
|
83
|
+
server do
|
|
84
|
+
visit "/books/1"
|
|
85
|
+
expect(page).to have_content("Learn Hanami")
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "logging" do
|
|
92
|
+
let(:log) { "log/development.log" }
|
|
93
|
+
let(:project) { "bookshelf" }
|
|
94
|
+
|
|
95
|
+
context "when enabled" do
|
|
96
|
+
it "logs GET requests" do
|
|
97
|
+
with_project(project) do
|
|
98
|
+
touch log
|
|
99
|
+
replace "config/environment.rb", "logger level: :debug", %(logger level: :debug, stream: "#{log}")
|
|
100
|
+
|
|
101
|
+
server do
|
|
102
|
+
visit "/"
|
|
103
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
content = contents(log)
|
|
107
|
+
expect(content).to include("[#{project}] [INFO]")
|
|
108
|
+
expect(content).to match(%r{HTTP/1.1 GET 200 (.*) /})
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "logs GET requests with query string" do
|
|
113
|
+
with_project(project) do
|
|
114
|
+
touch log
|
|
115
|
+
replace "config/environment.rb", "logger level: :debug", %(logger level: :debug, stream: "#{log}")
|
|
116
|
+
|
|
117
|
+
run_cmd "hanami generate action web home#index --url=/", []
|
|
118
|
+
|
|
119
|
+
server do
|
|
120
|
+
visit "/?ping=pong"
|
|
121
|
+
expect(page).to have_title("Web")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
content = contents(log)
|
|
125
|
+
expect(content).to include("[#{project}] [INFO]")
|
|
126
|
+
expect(content).to match(%({"ping"=>"pong"}))
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "logs non-GET requests with payload" do
|
|
131
|
+
with_project(project) do
|
|
132
|
+
touch log
|
|
133
|
+
replace "config/environment.rb", "logger level: :debug", %(logger level: :debug, stream: "#{log}")
|
|
134
|
+
|
|
135
|
+
run_cmd "hanami generate action web books#create --method=POST", []
|
|
136
|
+
|
|
137
|
+
server do
|
|
138
|
+
post "/books", book: { title: "Functions" }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
content = contents(log)
|
|
142
|
+
expect(content).to include("[#{project}] [INFO]")
|
|
143
|
+
expect(content).to match(%({"book"=>{"title"=>"Functions"}}))
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "logs non-GET requests from body parsers" do
|
|
148
|
+
with_project(project) do
|
|
149
|
+
touch log
|
|
150
|
+
replace "config/environment.rb", "logger level: :debug", %(logger level: :debug, stream: "#{log}")
|
|
151
|
+
inject_line_after "config/environment.rb", "Hanami.configure", "require 'hanami/middleware/body_parser'\nmiddleware.use Hanami::Middleware::BodyParser, :json"
|
|
152
|
+
|
|
153
|
+
run_cmd "hanami generate action web books#create --method=POST", []
|
|
154
|
+
inject_line_after "apps/web/controllers/books/create.rb", "call", 'Hanami.logger.debug(request.env["CONTENT_TYPE"]);self.body = %({"status":"OK"})'
|
|
155
|
+
|
|
156
|
+
server do
|
|
157
|
+
post "/books", book: { title: "Why we sleep" }
|
|
158
|
+
post "/books", JSON.generate(book: { title: "Parsers" }), "CONTENT_TYPE" => "app/json", "HTTP_ACCEPT" => "app/json"
|
|
159
|
+
post "/books", JSON.generate(%w[this is cool]), "CONTENT_TYPE" => "app/json", "HTTP_ACCEPT" => "app/json"
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
content = contents(log)
|
|
163
|
+
expect(content).to include("[#{project}] [INFO]")
|
|
164
|
+
expect(content).to include("POST 200")
|
|
165
|
+
|
|
166
|
+
expect(content).to include("app/x-www-form-urlencoded")
|
|
167
|
+
expect(content).to include(%({"book"=>{"title"=>"Why we sleep"}}))
|
|
168
|
+
|
|
169
|
+
expect(content).to include("app/json")
|
|
170
|
+
expect(content).to include(%({"book"=>{"title"=>"Parsers"}}))
|
|
171
|
+
expect(content).to include(%({"_"=>["this", "is", "cool"]}))
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
context "when not enabled" do
|
|
177
|
+
it "does not log request" do
|
|
178
|
+
with_project(project) do
|
|
179
|
+
replace "config/environment.rb", "logger level: :debug", ""
|
|
180
|
+
|
|
181
|
+
server do
|
|
182
|
+
visit "/"
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
expect(log).to_not be_an_existing_file
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
context "--host" do
|
|
192
|
+
it "starts on given host" do
|
|
193
|
+
with_project do
|
|
194
|
+
server(host: "127.0.0.1") do
|
|
195
|
+
visit "/"
|
|
196
|
+
|
|
197
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
xit "fails when missing" do
|
|
203
|
+
with_project do
|
|
204
|
+
server(host: nil)
|
|
205
|
+
|
|
206
|
+
expect(exitstatus).to eq(1)
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
context "--port" do
|
|
212
|
+
it "starts on given port" do
|
|
213
|
+
with_project do
|
|
214
|
+
server(port: 1982) do
|
|
215
|
+
visit "/"
|
|
216
|
+
|
|
217
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
xit "fails when missing" do
|
|
223
|
+
with_project do
|
|
224
|
+
server(port: nil)
|
|
225
|
+
|
|
226
|
+
expect(exitstatus).to eq(1)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
context "environment" do
|
|
232
|
+
it "starts with given environment" do
|
|
233
|
+
with_project do
|
|
234
|
+
generate "action web home#index --url=/"
|
|
235
|
+
|
|
236
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
237
|
+
module Web::Controllers::Home
|
|
238
|
+
class Index
|
|
239
|
+
include Web::Action
|
|
240
|
+
|
|
241
|
+
def call(params)
|
|
242
|
+
self.body = Hanami.env
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
EOF
|
|
247
|
+
|
|
248
|
+
RSpec::Support::Env["HANAMI_ENV"] = env = "production"
|
|
249
|
+
RSpec::Support::Env["DATABASE_URL"] = "sqlite://#{Pathname.new('db').join('bookshelf.sqlite')}"
|
|
250
|
+
RSpec::Support::Env["SMTP_HOST"] = "localhost"
|
|
251
|
+
RSpec::Support::Env["SMTP_PORT"] = "25"
|
|
252
|
+
|
|
253
|
+
server do
|
|
254
|
+
visit "/"
|
|
255
|
+
|
|
256
|
+
expect(page).to have_content(env)
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
xit "fails when missing" do
|
|
262
|
+
with_project do
|
|
263
|
+
server(environment: nil)
|
|
264
|
+
|
|
265
|
+
expect(exitstatus).to eq(1)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
context "puma" do
|
|
271
|
+
it "starts" do
|
|
272
|
+
with_project("bookshelf_server_puma", server: :puma) do
|
|
273
|
+
server do
|
|
274
|
+
visit "/"
|
|
275
|
+
|
|
276
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
context "unicorn" do
|
|
283
|
+
it "starts" do
|
|
284
|
+
with_project("bookshelf_server_unicorn", server: :unicorn) do
|
|
285
|
+
server do
|
|
286
|
+
visit "/"
|
|
287
|
+
|
|
288
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
context "code reloading" do
|
|
295
|
+
it "reloads templates code" do
|
|
296
|
+
with_project do
|
|
297
|
+
server do
|
|
298
|
+
visit "/"
|
|
299
|
+
|
|
300
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
301
|
+
generate "action web home#index --url=/"
|
|
302
|
+
|
|
303
|
+
rewrite "apps/web/templates/home/index.html.erb", <<~EOF
|
|
304
|
+
<h1>Hello, World!</h1>
|
|
305
|
+
EOF
|
|
306
|
+
|
|
307
|
+
visit "/"
|
|
308
|
+
expect(page).to have_title("Web")
|
|
309
|
+
expect(page).to have_content("Hello, World!")
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "reloads view" do
|
|
315
|
+
with_project do
|
|
316
|
+
server do
|
|
317
|
+
visit "/"
|
|
318
|
+
|
|
319
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
320
|
+
generate "action web home#index --url=/"
|
|
321
|
+
|
|
322
|
+
rewrite "apps/web/views/home/index.rb", <<~EOF
|
|
323
|
+
module Web::Views::Home
|
|
324
|
+
class Index
|
|
325
|
+
include Web::View
|
|
326
|
+
|
|
327
|
+
def greeting
|
|
328
|
+
"Ciao!"
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
EOF
|
|
333
|
+
|
|
334
|
+
rewrite "apps/web/templates/home/index.html.erb", <<~EOF
|
|
335
|
+
<%= greeting %>
|
|
336
|
+
EOF
|
|
337
|
+
|
|
338
|
+
visit "/"
|
|
339
|
+
expect(page).to have_title("Web")
|
|
340
|
+
expect(page).to have_content("Ciao!")
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
it "reloads action" do
|
|
346
|
+
with_project do
|
|
347
|
+
server do
|
|
348
|
+
visit "/"
|
|
349
|
+
|
|
350
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
351
|
+
generate "action web home#index --url=/"
|
|
352
|
+
|
|
353
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
354
|
+
module Web::Controllers::Home
|
|
355
|
+
class Index
|
|
356
|
+
include Web::Action
|
|
357
|
+
|
|
358
|
+
def call(params)
|
|
359
|
+
self.body = "Hi!"
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
EOF
|
|
364
|
+
|
|
365
|
+
visit "/"
|
|
366
|
+
expect(page).to have_content("Hi!")
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
it "reloads model" do
|
|
372
|
+
project_name = "bookshelf"
|
|
373
|
+
|
|
374
|
+
with_project(project_name) do
|
|
375
|
+
# STEP 1: prepare the database and the repository
|
|
376
|
+
generate_model "user"
|
|
377
|
+
generate_migration "create_users", <<~EOF
|
|
378
|
+
Hanami::Model.migration do
|
|
379
|
+
change do
|
|
380
|
+
create_table :users do
|
|
381
|
+
primary_key :id
|
|
382
|
+
column :name, String
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
execute "INSERT INTO users (name) VALUES('L')"
|
|
386
|
+
execute "INSERT INTO users (name) VALUES('MG')"
|
|
387
|
+
end
|
|
388
|
+
end
|
|
389
|
+
EOF
|
|
390
|
+
|
|
391
|
+
rewrite "lib/#{project_name}/repositories/user_repository.rb", <<~EOF
|
|
392
|
+
class UserRepository < Hanami::Repository
|
|
393
|
+
def listing
|
|
394
|
+
all
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
EOF
|
|
398
|
+
|
|
399
|
+
hanami "db prepare"
|
|
400
|
+
|
|
401
|
+
# STEP 2: generate the action
|
|
402
|
+
generate "action web users#index --url=/users"
|
|
403
|
+
|
|
404
|
+
rewrite "apps/web/controllers/users/index.rb", <<~EOF
|
|
405
|
+
module Web::Controllers::Users
|
|
406
|
+
class Index
|
|
407
|
+
include Web::Action
|
|
408
|
+
|
|
409
|
+
def call(params)
|
|
410
|
+
self.body = UserRepository.new.listing.map(&:name).join(", ")
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
EOF
|
|
415
|
+
|
|
416
|
+
server do
|
|
417
|
+
# STEP 3: visit the page
|
|
418
|
+
visit "/users"
|
|
419
|
+
|
|
420
|
+
expect(page).to have_content("L, MG")
|
|
421
|
+
|
|
422
|
+
# STEP 4: change the repository, then visit the page again
|
|
423
|
+
rewrite "lib/#{project_name}/repositories/user_repository.rb", <<~EOF
|
|
424
|
+
class UserRepository < Hanami::Repository
|
|
425
|
+
def listing
|
|
426
|
+
all.reverse
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
EOF
|
|
430
|
+
visit "/users"
|
|
431
|
+
|
|
432
|
+
expect(page).to have_content("MG, L")
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
xit "reloads asset" do
|
|
438
|
+
with_project do
|
|
439
|
+
server do
|
|
440
|
+
write "apps/web/assets/stylesheets/style.css", <<~EOF
|
|
441
|
+
body { background-color: #fff; }
|
|
442
|
+
EOF
|
|
443
|
+
|
|
444
|
+
visit "/assets/style.css"
|
|
445
|
+
expect(page).to have_content("#fff")
|
|
446
|
+
|
|
447
|
+
rewrite "apps/web/assets/stylesheets/style.css", <<~EOF
|
|
448
|
+
body { background-color: #333; }
|
|
449
|
+
EOF
|
|
450
|
+
|
|
451
|
+
visit "/assets/style.css"
|
|
452
|
+
expect(page).to have_content("#333")
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
context "without code reloading" do
|
|
459
|
+
it "doesn't reload code" do
|
|
460
|
+
with_project do
|
|
461
|
+
server("no-code-reloading" => nil) do
|
|
462
|
+
visit "/"
|
|
463
|
+
|
|
464
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
465
|
+
generate "action web home#index --url=/"
|
|
466
|
+
|
|
467
|
+
visit "/"
|
|
468
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
context "without hanami model" do
|
|
475
|
+
it "uses custom model domain" do
|
|
476
|
+
project_without_hanami_model("bookshelf", gems: ["dry-struct"]) do
|
|
477
|
+
write "lib/entities/access_token.rb", <<~EOF
|
|
478
|
+
require 'dry-struct'
|
|
479
|
+
require 'securerandom'
|
|
480
|
+
|
|
481
|
+
module Types
|
|
482
|
+
include Dry::Types.module
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
class AccessToken < Dry::Struct
|
|
486
|
+
attribute :id, Types::String.default { SecureRandom.uuid }
|
|
487
|
+
attribute :secret, Types::String
|
|
488
|
+
attribute :digest, Types::String
|
|
489
|
+
end
|
|
490
|
+
EOF
|
|
491
|
+
generate "action web access_tokens#show --url=/access_tokens/:id"
|
|
492
|
+
rewrite "apps/web/controllers/access_tokens/show.rb", <<~EOF
|
|
493
|
+
module Web::Controllers::AccessTokens
|
|
494
|
+
class Show
|
|
495
|
+
include Web::Action
|
|
496
|
+
expose :access_token
|
|
497
|
+
|
|
498
|
+
def call(params)
|
|
499
|
+
@access_token = AccessToken.new(id: '1', secret: 'shh', digest: 'abc')
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
EOF
|
|
504
|
+
rewrite "apps/web/templates/access_tokens/show.html.erb", <<~EOF
|
|
505
|
+
<h1><%= access_token.secret %></h1>
|
|
506
|
+
EOF
|
|
507
|
+
|
|
508
|
+
server do
|
|
509
|
+
visit "/access_tokens/1"
|
|
510
|
+
visit "/access_tokens/1" # forces code reloading
|
|
511
|
+
expect(page).to have_content("shh")
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
context "without mailer" do
|
|
518
|
+
it "returns page" do
|
|
519
|
+
with_project do
|
|
520
|
+
remove_block "config/environment.rb", "mailer do"
|
|
521
|
+
|
|
522
|
+
server do
|
|
523
|
+
visit "/"
|
|
524
|
+
expect(page).to have_title("Hanami | The web, with simplicity")
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
end
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
it "prints help message" do
|
|
531
|
+
with_project do
|
|
532
|
+
output = <<-OUT
|
|
533
|
+
Command:
|
|
534
|
+
hanami server
|
|
535
|
+
|
|
536
|
+
Usage:
|
|
537
|
+
hanami server
|
|
538
|
+
|
|
539
|
+
Description:
|
|
540
|
+
Start Hanami server (only for development)
|
|
541
|
+
|
|
542
|
+
Options:
|
|
543
|
+
--server=VALUE # Force a server engine (eg, webrick, puma, thin, etc..)
|
|
544
|
+
--host=VALUE # The host address to bind to
|
|
545
|
+
--port=VALUE, -p VALUE # The port to run the server on
|
|
546
|
+
--debug=VALUE # Turn on debug output
|
|
547
|
+
--warn=VALUE # Turn on warnings
|
|
548
|
+
--daemonize=VALUE # Daemonize the server
|
|
549
|
+
--pid=VALUE # Path to write a pid file after daemonize
|
|
550
|
+
--[no-]code-reloading # Code reloading, default: true
|
|
551
|
+
--help, -h # Print this help
|
|
552
|
+
|
|
553
|
+
Examples:
|
|
554
|
+
hanami server # Basic usage (it uses the bundled server engine)
|
|
555
|
+
hanami server --server=webrick # Force `webrick` server engine
|
|
556
|
+
hanami server --host=0.0.0.0 # Bind to a host
|
|
557
|
+
hanami server --port=2306 # Bind to a port
|
|
558
|
+
hanami server --no-code-reloading # Disable code reloading
|
|
559
|
+
OUT
|
|
560
|
+
|
|
561
|
+
run_cmd 'hanami server --help', output
|
|
562
|
+
end
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
context "with HANAMI_APPS ENV variable" do
|
|
566
|
+
it "loads only specific app" do
|
|
567
|
+
with_project do
|
|
568
|
+
generate "app admin"
|
|
569
|
+
|
|
570
|
+
remove_line "config/environment.rb", "require_relative '../apps/admin/app'"
|
|
571
|
+
remove_line "config/environment.rb", "mount Admin::App"
|
|
572
|
+
|
|
573
|
+
remove_line "config/environment.rb", "require_relative '../apps/web/app'"
|
|
574
|
+
remove_line "config/environment.rb", "mount Web::App"
|
|
575
|
+
|
|
576
|
+
inject_line_after "config/environment.rb", "Hanami.configure", <<-EOL
|
|
577
|
+
if Hanami.app?(:admin)
|
|
578
|
+
require_relative '../apps/admin/app'
|
|
579
|
+
mount Admin::App, at: '/admin'
|
|
580
|
+
end
|
|
581
|
+
|
|
582
|
+
if Hanami.app?(:web)
|
|
583
|
+
require_relative '../apps/web/app'
|
|
584
|
+
mount Web::App, at: '/'
|
|
585
|
+
end
|
|
586
|
+
EOL
|
|
587
|
+
generate "action web home#index --url=/"
|
|
588
|
+
|
|
589
|
+
rewrite "apps/web/controllers/home/index.rb", <<~EOF
|
|
590
|
+
module Web::Controllers::Home
|
|
591
|
+
class Index
|
|
592
|
+
include Web::Action
|
|
593
|
+
|
|
594
|
+
def call(params)
|
|
595
|
+
self.body = "app: web"
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
EOF
|
|
600
|
+
generate "action admin home#index --url=/"
|
|
601
|
+
|
|
602
|
+
rewrite "apps/admin/controllers/home/index.rb", <<~EOF
|
|
603
|
+
module Web::Controllers::Home
|
|
604
|
+
class Index
|
|
605
|
+
include Admin::Action
|
|
606
|
+
|
|
607
|
+
def call(params)
|
|
608
|
+
self.body = "app: admin"
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
end
|
|
612
|
+
EOF
|
|
613
|
+
|
|
614
|
+
RSpec::Support::Env["HANAMI_APPS"] = "web"
|
|
615
|
+
|
|
616
|
+
server do
|
|
617
|
+
visit "/"
|
|
618
|
+
expect(page).to have_content("app: web")
|
|
619
|
+
|
|
620
|
+
visit "/admin"
|
|
621
|
+
expect(page).to have_content("Not Found")
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
end
|