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.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -2
  3. data/LICENSE.md +1 -1
  4. data/README.md +26 -10
  5. data/hanami.gemspec +2 -2
  6. data/lib/hanami/app.rb +5 -0
  7. data/lib/hanami/config/actions.rb +4 -11
  8. data/lib/hanami/config/assets.rb +84 -0
  9. data/lib/hanami/config/null_config.rb +3 -0
  10. data/lib/hanami/config/views.rb +0 -4
  11. data/lib/hanami/config.rb +71 -5
  12. data/lib/hanami/extensions/action/slice_configured_action.rb +15 -7
  13. data/lib/hanami/extensions/action.rb +8 -6
  14. data/lib/hanami/extensions/router/errors.rb +58 -0
  15. data/lib/hanami/extensions/view/context.rb +129 -60
  16. data/lib/hanami/extensions/view/part.rb +26 -0
  17. data/lib/hanami/extensions/view/scope.rb +26 -0
  18. data/lib/hanami/extensions/view/slice_configured_context.rb +0 -2
  19. data/lib/hanami/extensions/view/slice_configured_helpers.rb +44 -0
  20. data/lib/hanami/extensions/view/slice_configured_view.rb +106 -21
  21. data/lib/hanami/extensions/view/standard_helpers.rb +18 -0
  22. data/lib/hanami/extensions.rb +10 -3
  23. data/lib/hanami/helpers/assets_helper.rb +752 -0
  24. data/lib/hanami/helpers/form_helper/form_builder.rb +1391 -0
  25. data/lib/hanami/helpers/form_helper/values.rb +75 -0
  26. data/lib/hanami/helpers/form_helper.rb +213 -0
  27. data/lib/hanami/middleware/assets.rb +21 -0
  28. data/lib/hanami/middleware/public_errors_app.rb +75 -0
  29. data/lib/hanami/middleware/render_errors.rb +90 -0
  30. data/lib/hanami/providers/assets.rb +44 -0
  31. data/lib/hanami/rake_tasks.rb +19 -18
  32. data/lib/hanami/settings.rb +1 -1
  33. data/lib/hanami/slice.rb +48 -2
  34. data/lib/hanami/slice_configurable.rb +3 -2
  35. data/lib/hanami/version.rb +1 -1
  36. data/lib/hanami/web/rack_logger.rb +1 -1
  37. data/lib/hanami.rb +3 -3
  38. data/spec/integration/action/view_rendering/view_context_spec.rb +221 -0
  39. data/spec/integration/action/view_rendering_spec.rb +0 -18
  40. data/spec/integration/assets/assets_spec.rb +101 -0
  41. data/spec/integration/assets/serve_static_assets_spec.rb +152 -0
  42. data/spec/integration/logging/exception_logging_spec.rb +115 -0
  43. data/spec/integration/logging/notifications_spec.rb +68 -0
  44. data/spec/integration/logging/request_logging_spec.rb +128 -0
  45. data/spec/integration/rack_app/middleware_spec.rb +22 -22
  46. data/spec/integration/rack_app/rack_app_spec.rb +3 -220
  47. data/spec/integration/rake_tasks_spec.rb +107 -0
  48. data/spec/integration/view/config/default_context_spec.rb +149 -0
  49. data/spec/integration/view/{inflector_spec.rb → config/inflector_spec.rb} +1 -1
  50. data/spec/integration/view/config/part_class_spec.rb +147 -0
  51. data/spec/integration/view/config/part_namespace_spec.rb +103 -0
  52. data/spec/integration/view/config/paths_spec.rb +119 -0
  53. data/spec/integration/view/config/scope_class_spec.rb +147 -0
  54. data/spec/integration/view/config/scope_namespace_spec.rb +103 -0
  55. data/spec/integration/view/config/template_spec.rb +38 -0
  56. data/spec/integration/view/context/assets_spec.rb +3 -9
  57. data/spec/integration/view/context/request_spec.rb +3 -7
  58. data/spec/integration/view/helpers/form_helper_spec.rb +174 -0
  59. data/spec/integration/view/helpers/part_helpers_spec.rb +124 -0
  60. data/spec/integration/view/helpers/scope_helpers_spec.rb +84 -0
  61. data/spec/integration/view/helpers/user_defined_helpers/part_helpers_spec.rb +162 -0
  62. data/spec/integration/view/helpers/user_defined_helpers/scope_helpers_spec.rb +119 -0
  63. data/spec/integration/view/slice_configuration_spec.rb +9 -9
  64. data/spec/integration/web/render_detailed_errors_spec.rb +107 -0
  65. data/spec/integration/web/render_errors_spec.rb +242 -0
  66. data/spec/spec_helper.rb +1 -1
  67. data/spec/support/app_integration.rb +46 -2
  68. data/spec/support/matchers.rb +32 -0
  69. data/spec/unit/hanami/config/actions/content_security_policy_spec.rb +24 -36
  70. data/spec/unit/hanami/config/actions/csrf_protection_spec.rb +4 -3
  71. data/spec/unit/hanami/config/actions/default_values_spec.rb +3 -6
  72. data/spec/unit/hanami/config/render_detailed_errors_spec.rb +25 -0
  73. data/spec/unit/hanami/config/render_errors_spec.rb +25 -0
  74. data/spec/unit/hanami/config/views_spec.rb +0 -18
  75. data/spec/unit/hanami/env_spec.rb +11 -25
  76. data/spec/unit/hanami/extensions/view/context_spec.rb +59 -0
  77. data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +109 -0
  78. data/spec/unit/hanami/helpers/assets_helper/audio_tag_spec.rb +132 -0
  79. data/spec/unit/hanami/helpers/assets_helper/favicon_link_tag_spec.rb +91 -0
  80. data/spec/unit/hanami/helpers/assets_helper/image_tag_spec.rb +92 -0
  81. data/spec/unit/hanami/helpers/assets_helper/javascript_tag_spec.rb +143 -0
  82. data/spec/unit/hanami/helpers/assets_helper/stylesheet_link_tag_spec.rb +126 -0
  83. data/spec/unit/hanami/helpers/assets_helper/video_tag_spec.rb +132 -0
  84. data/spec/unit/hanami/helpers/form_helper_spec.rb +2826 -0
  85. data/spec/unit/hanami/router/errors/not_allowed_error_spec.rb +27 -0
  86. data/spec/unit/hanami/router/errors/not_found_error_spec.rb +22 -0
  87. data/spec/unit/hanami/slice_configurable_spec.rb +18 -0
  88. data/spec/unit/hanami/version_spec.rb +1 -1
  89. data/spec/unit/hanami/web/rack_logger_spec.rb +1 -1
  90. metadata +95 -35
  91. data/lib/hanami/assets/app_config.rb +0 -61
  92. data/lib/hanami/assets/config.rb +0 -53
  93. data/spec/integration/action/view_integration_spec.rb +0 -165
  94. data/spec/integration/view/part_namespace_spec.rb +0 -96
  95. data/spec/integration/view/path_spec.rb +0 -56
  96. data/spec/integration/view/template_spec.rb +0 -68
  97. data/spec/isolation/hanami/application/already_configured_spec.rb +0 -19
  98. data/spec/isolation/hanami/application/inherit_anonymous_class_spec.rb +0 -10
  99. data/spec/isolation/hanami/application/inherit_concrete_class_spec.rb +0 -14
  100. data/spec/isolation/hanami/application/not_configured_spec.rb +0 -9
  101. data/spec/isolation/hanami/application/routes/configured_spec.rb +0 -44
  102. data/spec/isolation/hanami/application/routes/not_configured_spec.rb +0 -16
  103. 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