hanami 2.0.3 → 2.1.0.beta2
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 +37 -2
- data/LICENSE.md +1 -1
- data/README.md +26 -10
- data/hanami.gemspec +2 -2
- data/lib/hanami/app.rb +5 -0
- data/lib/hanami/config/actions.rb +4 -11
- data/lib/hanami/config/assets.rb +84 -0
- data/lib/hanami/config/null_config.rb +3 -0
- data/lib/hanami/config/views.rb +0 -4
- data/lib/hanami/config.rb +71 -5
- data/lib/hanami/extensions/action/slice_configured_action.rb +15 -7
- data/lib/hanami/extensions/action.rb +8 -6
- data/lib/hanami/extensions/router/errors.rb +58 -0
- data/lib/hanami/extensions/view/context.rb +129 -60
- data/lib/hanami/extensions/view/part.rb +26 -0
- data/lib/hanami/extensions/view/scope.rb +26 -0
- data/lib/hanami/extensions/view/slice_configured_context.rb +0 -2
- data/lib/hanami/extensions/view/slice_configured_helpers.rb +44 -0
- data/lib/hanami/extensions/view/slice_configured_view.rb +106 -21
- data/lib/hanami/extensions/view/standard_helpers.rb +18 -0
- data/lib/hanami/extensions.rb +10 -3
- data/lib/hanami/helpers/assets_helper.rb +752 -0
- data/lib/hanami/helpers/form_helper/form_builder.rb +1391 -0
- data/lib/hanami/helpers/form_helper/values.rb +75 -0
- data/lib/hanami/helpers/form_helper.rb +213 -0
- data/lib/hanami/middleware/assets.rb +21 -0
- data/lib/hanami/middleware/public_errors_app.rb +75 -0
- data/lib/hanami/middleware/render_errors.rb +90 -0
- data/lib/hanami/providers/assets.rb +44 -0
- data/lib/hanami/rake_tasks.rb +19 -18
- data/lib/hanami/settings.rb +1 -1
- data/lib/hanami/slice.rb +48 -2
- data/lib/hanami/slice_configurable.rb +3 -2
- data/lib/hanami/version.rb +1 -1
- data/lib/hanami/web/rack_logger.rb +1 -1
- data/lib/hanami.rb +3 -3
- data/spec/integration/action/view_rendering/view_context_spec.rb +221 -0
- data/spec/integration/action/view_rendering_spec.rb +0 -18
- data/spec/integration/assets/assets_spec.rb +101 -0
- data/spec/integration/assets/serve_static_assets_spec.rb +152 -0
- data/spec/integration/logging/exception_logging_spec.rb +115 -0
- data/spec/integration/logging/notifications_spec.rb +68 -0
- data/spec/integration/logging/request_logging_spec.rb +128 -0
- data/spec/integration/rack_app/middleware_spec.rb +22 -22
- data/spec/integration/rack_app/rack_app_spec.rb +3 -220
- data/spec/integration/rake_tasks_spec.rb +107 -0
- data/spec/integration/view/config/default_context_spec.rb +149 -0
- data/spec/integration/view/{inflector_spec.rb → config/inflector_spec.rb} +1 -1
- data/spec/integration/view/config/part_class_spec.rb +147 -0
- data/spec/integration/view/config/part_namespace_spec.rb +103 -0
- data/spec/integration/view/config/paths_spec.rb +119 -0
- data/spec/integration/view/config/scope_class_spec.rb +147 -0
- data/spec/integration/view/config/scope_namespace_spec.rb +103 -0
- data/spec/integration/view/config/template_spec.rb +38 -0
- data/spec/integration/view/context/assets_spec.rb +3 -9
- data/spec/integration/view/context/request_spec.rb +3 -7
- data/spec/integration/view/helpers/form_helper_spec.rb +174 -0
- data/spec/integration/view/helpers/part_helpers_spec.rb +124 -0
- data/spec/integration/view/helpers/scope_helpers_spec.rb +84 -0
- data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +162 -0
- data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +119 -0
- data/spec/integration/view/slice_configuration_spec.rb +9 -9
- data/spec/integration/web/render_detailed_errors_spec.rb +107 -0
- data/spec/integration/web/render_errors_spec.rb +242 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/app_integration.rb +46 -2
- data/spec/support/matchers.rb +32 -0
- data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +24 -36
- data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +4 -3
- data/spec/unit/hanami/config/actions/default_values_spec.rb +3 -6
- data/spec/unit/hanami/config/render_detailed_errors_spec.rb +25 -0
- data/spec/unit/hanami/config/render_errors_spec.rb +25 -0
- data/spec/unit/hanami/config/views_spec.rb +0 -18
- data/spec/unit/hanami/env_spec.rb +11 -25
- data/spec/unit/hanami/extensions/view/context_spec.rb +59 -0
- data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +109 -0
- data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +132 -0
- data/spec/unit/hanami/helpers/assets_helper/favicon_link_tag_spec.rb +91 -0
- data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +92 -0
- data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +143 -0
- data/spec/unit/hanami/helpers/assets_helper/stylesheet_link_tag_spec.rb +126 -0
- data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +132 -0
- data/spec/unit/hanami/helpers/form_helper_spec.rb +2826 -0
- data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +27 -0
- data/spec/unit/hanami/router/errors/not_found_error_spec.rb +22 -0
- data/spec/unit/hanami/slice_configurable_spec.rb +18 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- data/spec/unit/hanami/web/rack_logger_spec.rb +1 -1
- metadata +95 -35
- data/lib/hanami/assets/app_config.rb +0 -61
- data/lib/hanami/assets/config.rb +0 -53
- data/spec/integration/action/view_integration_spec.rb +0 -165
- data/spec/integration/view/part_namespace_spec.rb +0 -96
- data/spec/integration/view/path_spec.rb +0 -56
- data/spec/integration/view/template_spec.rb +0 -68
- data/spec/isolation/hanami/application/already_configured_spec.rb +0 -19
- data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +0 -10
- data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +0 -14
- data/spec/isolation/hanami/application/not_configured_spec.rb +0 -9
- data/spec/isolation/hanami/application/routes/configured_spec.rb +0 -44
- data/spec/isolation/hanami/application/routes/not_configured_spec.rb +0 -16
- data/spec/isolation/hanami/boot/success_spec.rb +0 -50
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Hanami::Helpers::AssetsHelper, "#stylesheet_link_tag", :app_integration do
|
|
4
|
+
subject(:obj) {
|
|
5
|
+
helpers = described_class
|
|
6
|
+
Class.new {
|
|
7
|
+
include helpers
|
|
8
|
+
|
|
9
|
+
attr_reader :_context
|
|
10
|
+
|
|
11
|
+
def initialize(context)
|
|
12
|
+
@_context = context
|
|
13
|
+
end
|
|
14
|
+
}.new(context)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def stylesheet_link_tag(...)
|
|
18
|
+
subject.stylesheet_link_tag(...)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
let(:context) { TestApp::Views::Context.new }
|
|
22
|
+
let(:root) { make_tmp_directory }
|
|
23
|
+
|
|
24
|
+
before do
|
|
25
|
+
with_directory(root) do
|
|
26
|
+
write "config/app.rb", <<~RUBY
|
|
27
|
+
module TestApp
|
|
28
|
+
class App < Hanami::App
|
|
29
|
+
config.logger.stream = StringIO.new
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
RUBY
|
|
33
|
+
|
|
34
|
+
write "app/views/context.rb", <<~RUBY
|
|
35
|
+
# auto_register: false
|
|
36
|
+
|
|
37
|
+
require "hanami/view/context"
|
|
38
|
+
|
|
39
|
+
module TestApp
|
|
40
|
+
module Views
|
|
41
|
+
class Context < Hanami::View::Context
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
RUBY
|
|
46
|
+
|
|
47
|
+
write "app/assets/js/app.ts", <<~JS
|
|
48
|
+
import "../css/app.css";
|
|
49
|
+
|
|
50
|
+
console.log("Hello from index.ts");
|
|
51
|
+
JS
|
|
52
|
+
|
|
53
|
+
write "app/assets/css/app.css", <<~CSS
|
|
54
|
+
.btn {
|
|
55
|
+
background: #f00;
|
|
56
|
+
}
|
|
57
|
+
CSS
|
|
58
|
+
|
|
59
|
+
stub_assets("main.css")
|
|
60
|
+
|
|
61
|
+
require "hanami/setup"
|
|
62
|
+
before_prepare if respond_to?(:before_prepare)
|
|
63
|
+
require "hanami/prepare"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "returns an instance of SafeString" do
|
|
68
|
+
actual = stylesheet_link_tag("main")
|
|
69
|
+
expect(actual).to be_instance_of(::Hanami::View::HTML::SafeString)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "is aliased as `css`" do
|
|
73
|
+
expect(subject.css("main")).to eq stylesheet_link_tag("main")
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "renders <link> tag" do
|
|
77
|
+
actual = stylesheet_link_tag("main")
|
|
78
|
+
expect(actual).to eq(%(<link href="/assets/main.css" type="text/css" rel="stylesheet">))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
xit "renders <link> tag without appending ext after query string" do
|
|
82
|
+
actual = stylesheet_link_tag("fonts?font=Helvetica")
|
|
83
|
+
expect(actual).to eq(%(<link href="/assets/fonts?font=Helvetica" type="text/css" rel="stylesheet">))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "renders <link> tag with an integrity attribute" do
|
|
87
|
+
actual = stylesheet_link_tag("main", integrity: "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC")
|
|
88
|
+
expect(actual).to eq(%(<link href="/assets/main.css" type="text/css" rel="stylesheet" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="anonymous">))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "renders <link> tag with a crossorigin attribute" do
|
|
92
|
+
actual = stylesheet_link_tag("main", integrity: "sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC", crossorigin: "use-credentials")
|
|
93
|
+
expect(actual).to eq(%(<link href="/assets/main.css" type="text/css" rel="stylesheet" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="use-credentials">))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "ignores href passed as an option" do
|
|
97
|
+
actual = stylesheet_link_tag("main", href: "wrong")
|
|
98
|
+
expect(actual).to eq(%(<link href="/assets/main.css" type="text/css" rel="stylesheet">))
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe "subresource_integrity mode" do
|
|
102
|
+
def before_prepare
|
|
103
|
+
Hanami.app.config.assets.subresource_integrity = [:sha384]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
before { compile_assets! }
|
|
107
|
+
|
|
108
|
+
it "includes subresource_integrity and crossorigin attributes" do
|
|
109
|
+
actual = stylesheet_link_tag("app")
|
|
110
|
+
expect(actual).to match(%r{<link href="/assets/app-[A-Z0-9]{8}.css" type="text/css" rel="stylesheet" integrity="sha384-[A-Za-z0-9+/]{64}" crossorigin="anonymous">})
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe "cdn mode" do
|
|
115
|
+
let(:base_url) { "https://hanami.test" }
|
|
116
|
+
|
|
117
|
+
def before_prepare
|
|
118
|
+
Hanami.app.config.assets.base_url = base_url
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "returns absolute url for href attribute" do
|
|
122
|
+
actual = stylesheet_link_tag("main")
|
|
123
|
+
expect(actual).to eq(%(<link href="#{base_url}/assets/main.css" type="text/css" rel="stylesheet">))
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Hanami::Helpers::AssetsHelper, "#video_tag", :app_integration do
|
|
4
|
+
subject(:obj) {
|
|
5
|
+
helpers = described_class
|
|
6
|
+
Class.new {
|
|
7
|
+
include helpers
|
|
8
|
+
|
|
9
|
+
attr_reader :_context
|
|
10
|
+
|
|
11
|
+
def initialize(context)
|
|
12
|
+
@_context = context
|
|
13
|
+
end
|
|
14
|
+
}.new(context)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
def video_tag(...)
|
|
18
|
+
subject.video_tag(...)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
let(:context) { TestApp::Views::Context.new }
|
|
22
|
+
let(:root) { make_tmp_directory }
|
|
23
|
+
|
|
24
|
+
before do
|
|
25
|
+
with_directory(root) do
|
|
26
|
+
write "config/app.rb", <<~RUBY
|
|
27
|
+
module TestApp
|
|
28
|
+
class App < Hanami::App
|
|
29
|
+
config.logger.stream = StringIO.new
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
RUBY
|
|
33
|
+
|
|
34
|
+
write "app/views/context.rb", <<~RUBY
|
|
35
|
+
# auto_register: false
|
|
36
|
+
|
|
37
|
+
require "hanami/view/context"
|
|
38
|
+
|
|
39
|
+
module TestApp
|
|
40
|
+
module Views
|
|
41
|
+
class Context < Hanami::View::Context
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
RUBY
|
|
46
|
+
|
|
47
|
+
stub_assets("movie.mp4", "movie.en.vtt")
|
|
48
|
+
|
|
49
|
+
require "hanami/setup"
|
|
50
|
+
before_prepare if respond_to?(:before_prepare)
|
|
51
|
+
require "hanami/prepare"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "returns an instance of HtmlBuilder" do
|
|
56
|
+
actual = video_tag("movie.mp4")
|
|
57
|
+
expect(actual).to be_instance_of(::Hanami::View::HTML::SafeString)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "renders <video> tag" do
|
|
61
|
+
actual = video_tag("movie.mp4").to_s
|
|
62
|
+
expect(actual).to eq(%(<video src="/assets/movie.mp4"></video>))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "renders with html attributes" do
|
|
66
|
+
actual = video_tag("movie.mp4", autoplay: true, controls: true).to_s
|
|
67
|
+
expect(actual).to eq(%(<video autoplay="autoplay" controls="controls" src="/assets/movie.mp4"></video>))
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "renders with fallback content" do
|
|
71
|
+
actual = video_tag("movie.mp4") do
|
|
72
|
+
"Your browser does not support the video tag"
|
|
73
|
+
end.to_s
|
|
74
|
+
|
|
75
|
+
expect(actual).to eq(%(<video src="/assets/movie.mp4">Your browser does not support the video tag</video>))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "renders with tracks" do
|
|
79
|
+
actual = video_tag("movie.mp4") do
|
|
80
|
+
tag.track kind: "captions", src: subject.asset_url("movie.en.vtt"), srclang: "en", label: "English"
|
|
81
|
+
end.to_s
|
|
82
|
+
|
|
83
|
+
expect(actual).to eq(%(<video src="/assets/movie.mp4"><track kind="captions" src="/assets/movie.en.vtt" srclang="en" label="English"></video>))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
xit "renders with sources" do
|
|
87
|
+
actual = subject.video do
|
|
88
|
+
tag.text "Your browser does not support the video tag"
|
|
89
|
+
tag.source src: subject.asset_url("movie.mp4"), type: "video/mp4"
|
|
90
|
+
tag.source src: subject.asset_url("movie.ogg"), type: "video/ogg"
|
|
91
|
+
end.to_s
|
|
92
|
+
|
|
93
|
+
expect(actual).to eq(%(<video>Your browser does not support the video tag<source src="/assets/movie.mp4" type="video/mp4"><source src="/assets/movie.ogg" type="video/ogg"></video>))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "raises an exception when no arguments" do
|
|
97
|
+
expect do
|
|
98
|
+
video_tag
|
|
99
|
+
end.to raise_error(
|
|
100
|
+
ArgumentError,
|
|
101
|
+
"You should provide a source via `src` option or with a `source` HTML tag"
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "raises an exception when no src and no block" do
|
|
106
|
+
expect do
|
|
107
|
+
video_tag(content: true)
|
|
108
|
+
end.to raise_error(
|
|
109
|
+
ArgumentError,
|
|
110
|
+
"You should provide a source via `src` option or with a `source` HTML tag"
|
|
111
|
+
)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
describe "cdn mode" do
|
|
115
|
+
let(:base_url) { "https://hanami.test" }
|
|
116
|
+
|
|
117
|
+
def before_prepare
|
|
118
|
+
Hanami.app.config.assets.base_url = "https://hanami.test"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "returns absolute url for src attribute" do
|
|
122
|
+
actual = video_tag("movie.mp4").to_s
|
|
123
|
+
expect(actual).to eq(%(<video src="#{base_url}/assets/movie.mp4"></video>))
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
private
|
|
128
|
+
|
|
129
|
+
def tag(...)
|
|
130
|
+
subject.__send__(:tag, ...)
|
|
131
|
+
end
|
|
132
|
+
end
|