hanami 2.1.0.rc2 → 2.1.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -1
- data/hanami.gemspec +1 -1
- data/lib/hanami/app.rb +0 -5
- data/lib/hanami/config.rb +1 -5
- data/lib/hanami/extensions/view/context.rb +12 -3
- data/lib/hanami/helpers/assets_helper.rb +30 -29
- data/lib/hanami/helpers/form_helper/form_builder.rb +54 -54
- data/lib/hanami/helpers/form_helper/values.rb +8 -8
- data/lib/hanami/helpers/form_helper.rb +9 -9
- data/lib/hanami/providers/assets.rb +4 -1
- data/lib/hanami/rake_tasks.rb +1 -9
- data/lib/hanami/slice.rb +10 -0
- data/lib/hanami/version.rb +1 -1
- data/spec/integration/assets/assets_spec.rb +67 -24
- data/spec/integration/assets/cross_slice_assets_helpers_spec.rb +130 -0
- data/spec/integration/view/context/assets_spec.rb +57 -31
- data/spec/support/app_integration.rb +12 -6
- data/spec/unit/hanami/helpers/assets_helper/asset_url_spec.rb +11 -0
- data/spec/unit/hanami/version_spec.rb +1 -1
- metadata +11 -9
@@ -18,39 +18,17 @@ RSpec.describe "Assets", :app_integration do
|
|
18
18
|
end
|
19
19
|
RUBY
|
20
20
|
|
21
|
-
write "config/assets.
|
21
|
+
write "config/assets.js", <<~JS
|
22
22
|
import * as assets from "hanami-assets";
|
23
23
|
await assets.run();
|
24
24
|
JS
|
25
25
|
|
26
26
|
write "package.json", <<~JSON
|
27
27
|
{
|
28
|
-
"
|
29
|
-
"assets": "node config/assets.mjs"
|
30
|
-
}
|
28
|
+
"type": "module"
|
31
29
|
}
|
32
30
|
JSON
|
33
31
|
|
34
|
-
write "config/routes.rb", <<~RUBY
|
35
|
-
module TestApp
|
36
|
-
class Routes < Hanami::Routes
|
37
|
-
get "posts/:id/edit", to: "posts.edit"
|
38
|
-
put "posts/:id", to: "posts.update"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
RUBY
|
42
|
-
|
43
|
-
write "app/action.rb", <<~RUBY
|
44
|
-
# auto_register: false
|
45
|
-
|
46
|
-
require "hanami/action"
|
47
|
-
|
48
|
-
module TestApp
|
49
|
-
class Action < Hanami::Action
|
50
|
-
end
|
51
|
-
end
|
52
|
-
RUBY
|
53
|
-
|
54
32
|
write "app/view.rb", <<~RUBY
|
55
33
|
# auto_register: false
|
56
34
|
|
@@ -109,4 +87,69 @@ RSpec.describe "Assets", :app_integration do
|
|
109
87
|
expect(assets["app.css"].to_s).to match(%r{/assets/app-[A-Z0-9]{8}.css})
|
110
88
|
expect(assets["app.js"].to_s).to match(%r{/assets/app-[A-Z0-9]{8}.js})
|
111
89
|
end
|
90
|
+
|
91
|
+
describe "slice with assets" do
|
92
|
+
def before_prepare
|
93
|
+
write "slices/main/view.rb", <<~RUBY
|
94
|
+
# auto_register: false
|
95
|
+
|
96
|
+
module Main
|
97
|
+
class View < TestApp::View
|
98
|
+
end
|
99
|
+
end
|
100
|
+
RUBY
|
101
|
+
|
102
|
+
write "slices/main/views/posts/show.rb", <<~RUBY
|
103
|
+
module Main
|
104
|
+
module Views
|
105
|
+
module Posts
|
106
|
+
class Show < Main::View
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
RUBY
|
112
|
+
|
113
|
+
write "slices/main/templates/posts/show.html.erb", <<~ERB
|
114
|
+
<%= stylesheet_tag("app") %>
|
115
|
+
<%= javascript_tag("app") %>
|
116
|
+
ERB
|
117
|
+
|
118
|
+
write "slices/main/assets/js/app.ts", <<~TS
|
119
|
+
import "../css/app.css";
|
120
|
+
|
121
|
+
console.log("Hello from main slice index.ts");
|
122
|
+
TS
|
123
|
+
|
124
|
+
write "slices/main/assets/css/app.css", <<~CSS
|
125
|
+
.btn {
|
126
|
+
background: #f00;
|
127
|
+
}
|
128
|
+
CSS
|
129
|
+
end
|
130
|
+
|
131
|
+
specify "the slice's assets are available in its own and distinct `assets` component" do
|
132
|
+
compile_assets!
|
133
|
+
|
134
|
+
output = Main::Slice["views.posts.show"].call.to_s
|
135
|
+
|
136
|
+
expect(output).to match(%r{<link href="/assets/main/app-[A-Z0-9]{8}.css" type="text/css" rel="stylesheet">})
|
137
|
+
expect(output).to match(%r{<script src="/assets/main/app-[A-Z0-9]{8}.js" type="text/javascript"></script>})
|
138
|
+
|
139
|
+
assets = Main::Slice["assets"]
|
140
|
+
|
141
|
+
expect(assets["app.css"].to_s).to match(%r{/assets/main/app-[A-Z0-9]{8}.css})
|
142
|
+
expect(assets["app.js"].to_s).to match(%r{/assets/main/app-[A-Z0-9]{8}.js})
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "slice without assets" do
|
147
|
+
def before_prepare
|
148
|
+
write "slices/main/.keep", ""
|
149
|
+
end
|
150
|
+
|
151
|
+
it "does not have an assets component" do
|
152
|
+
expect(Main::Slice.key?("assets")).to be false
|
153
|
+
end
|
154
|
+
end
|
112
155
|
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rack/test"
|
4
|
+
require "stringio"
|
5
|
+
|
6
|
+
RSpec.describe "Cross-slice assets via helpers", :app_integration do
|
7
|
+
include Rack::Test::Methods
|
8
|
+
let(:app) { Hanami.app }
|
9
|
+
let(:root) { make_tmp_directory }
|
10
|
+
|
11
|
+
before do
|
12
|
+
with_directory(root) do
|
13
|
+
write "config/app.rb", <<~RUBY
|
14
|
+
module TestApp
|
15
|
+
class App < Hanami::App
|
16
|
+
config.logger.stream = StringIO.new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
RUBY
|
20
|
+
|
21
|
+
write "config/slices/admin.rb", <<~RUBY
|
22
|
+
module Admin
|
23
|
+
class Slice < Hanami::Slice
|
24
|
+
# TODO: we should update `import` to make importing from the app nicer
|
25
|
+
# TODO: this test failed when I tried doing `as: "app"` (string instead of symbol); fix this in dry-system
|
26
|
+
import keys: ["assets"], from: Hanami.app.container, as: :app
|
27
|
+
end
|
28
|
+
end
|
29
|
+
RUBY
|
30
|
+
|
31
|
+
write "config/assets.js", <<~JS
|
32
|
+
import * as assets from "hanami-assets";
|
33
|
+
await assets.run();
|
34
|
+
JS
|
35
|
+
|
36
|
+
write "package.json", <<~JSON
|
37
|
+
{
|
38
|
+
"type": "module"
|
39
|
+
}
|
40
|
+
JSON
|
41
|
+
|
42
|
+
write "app/view.rb", <<~RUBY
|
43
|
+
# auto_register: false
|
44
|
+
|
45
|
+
require "hanami/view"
|
46
|
+
|
47
|
+
module TestApp
|
48
|
+
class View < Hanami::View
|
49
|
+
config.layout = nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
RUBY
|
53
|
+
|
54
|
+
write "app/assets/js/app.ts", <<~TS
|
55
|
+
import "../css/app.css";
|
56
|
+
|
57
|
+
console.log("Hello from index.ts");
|
58
|
+
TS
|
59
|
+
|
60
|
+
write "app/assets/css/app.css", <<~CSS
|
61
|
+
.btn {
|
62
|
+
background: #f00;
|
63
|
+
}
|
64
|
+
CSS
|
65
|
+
|
66
|
+
write "slices/admin/assets/js/app.ts", <<~TS
|
67
|
+
import "../css/app.css";
|
68
|
+
|
69
|
+
console.log("Hello from admin's index.ts");
|
70
|
+
TS
|
71
|
+
|
72
|
+
write "slices/admin/assets/css/app.css", <<~CSS
|
73
|
+
.btn {
|
74
|
+
background: #f00;
|
75
|
+
}
|
76
|
+
CSS
|
77
|
+
|
78
|
+
write "slices/admin/view.rb", <<~RUBY
|
79
|
+
# auto_register: false
|
80
|
+
|
81
|
+
module Admin
|
82
|
+
class View < TestApp::View
|
83
|
+
end
|
84
|
+
end
|
85
|
+
RUBY
|
86
|
+
|
87
|
+
write "slices/admin/views/posts/show.rb", <<~RUBY
|
88
|
+
module Admin
|
89
|
+
module Views
|
90
|
+
module Posts
|
91
|
+
class Show < Admin::View
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
RUBY
|
97
|
+
|
98
|
+
write "slices/admin/views/context.rb", <<~RUBY
|
99
|
+
# auto_register: false
|
100
|
+
|
101
|
+
require "hanami/view"
|
102
|
+
|
103
|
+
module Admin
|
104
|
+
module Views
|
105
|
+
class Context < Hanami::View::Context
|
106
|
+
include Deps[app_assets: "app.assets"]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
RUBY
|
111
|
+
|
112
|
+
write "slices/admin/templates/posts/show.html.erb", <<~ERB
|
113
|
+
<%= stylesheet_tag(app_assets["app.css"]) %>
|
114
|
+
<%= javascript_tag(app_assets["app.js"]) %>
|
115
|
+
ERB
|
116
|
+
|
117
|
+
before_prepare if respond_to?(:before_prepare)
|
118
|
+
require "hanami/prepare"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
specify "assets are available in helpers and in `assets` component" do
|
123
|
+
compile_assets!
|
124
|
+
|
125
|
+
output = Admin::Slice["views.posts.show"].call.to_s
|
126
|
+
|
127
|
+
expect(output).to match(%r{<link href="/assets/app-[A-Z0-9]{8}.css" type="text/css" rel="stylesheet">})
|
128
|
+
expect(output).to match(%r{<script src="/assets/app-[A-Z0-9]{8}.js" type="text/javascript"></script>})
|
129
|
+
end
|
130
|
+
end
|
@@ -3,51 +3,77 @@
|
|
3
3
|
require "hanami"
|
4
4
|
|
5
5
|
RSpec.describe "App view / Context / Assets", :app_integration do
|
6
|
+
subject(:context) { context_class.new }
|
7
|
+
let(:context_class) { TestApp::Views::Context }
|
8
|
+
|
6
9
|
before do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
with_directory(make_tmp_directory) do
|
11
|
+
write "config/app.rb", <<~RUBY
|
12
|
+
module TestApp
|
13
|
+
class App < Hanami::App
|
14
|
+
config.logger.stream = File::NULL
|
15
|
+
end
|
16
|
+
end
|
17
|
+
RUBY
|
11
18
|
|
12
|
-
|
19
|
+
write "app/views/context.rb", <<~RUBY
|
20
|
+
# auto_register: false
|
13
21
|
|
14
|
-
|
15
|
-
|
16
|
-
|
22
|
+
require "hanami/view/context"
|
23
|
+
|
24
|
+
module TestApp
|
25
|
+
module Views
|
26
|
+
class Context < Hanami::View::Context
|
27
|
+
end
|
28
|
+
end
|
17
29
|
end
|
18
|
-
|
30
|
+
RUBY
|
31
|
+
|
32
|
+
before_prepare if respond_to?(:before_prepare)
|
33
|
+
require "hanami/prepare"
|
19
34
|
end
|
20
35
|
end
|
21
36
|
|
22
|
-
|
23
|
-
|
37
|
+
context "assets present and hanami-assets bundled" do
|
38
|
+
def before_prepare
|
39
|
+
write "app/assets/.keep", ""
|
40
|
+
end
|
24
41
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
42
|
+
it "is the app assets by default" do
|
43
|
+
expect(context.assets).to be TestApp::App[:assets]
|
44
|
+
end
|
45
|
+
end
|
29
46
|
|
30
|
-
|
31
|
-
|
32
|
-
|
47
|
+
context "assets not present" do
|
48
|
+
it "raises error" do
|
49
|
+
expect { context.assets }.to raise_error(Hanami::ComponentLoadError, /assets directory\?/)
|
33
50
|
end
|
51
|
+
end
|
34
52
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
53
|
+
context "hanami-assets not bundled" do
|
54
|
+
def before_prepare
|
55
|
+
# These must be here instead of an ordinary before hook because the Hanami.bundled? check for
|
56
|
+
# assets is done as part of requiring "hanami/prepare" above.
|
57
|
+
allow(Hanami).to receive(:bundled?).and_call_original
|
58
|
+
allow(Hanami).to receive(:bundled?).with("hanami-assets").and_return(false)
|
39
59
|
|
40
|
-
|
41
|
-
|
42
|
-
context_class.new(assets: assets)
|
43
|
-
}
|
60
|
+
write "app/assets/.keep", ""
|
61
|
+
end
|
44
62
|
|
45
|
-
|
63
|
+
it "raises error" do
|
64
|
+
expect { context.assets }.to raise_error(Hanami::ComponentLoadError, /hanami-assets gem/)
|
65
|
+
end
|
66
|
+
end
|
46
67
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
68
|
+
context "injected assets" do
|
69
|
+
subject(:context) {
|
70
|
+
context_class.new(assets: assets)
|
71
|
+
}
|
72
|
+
|
73
|
+
let(:assets) { double(:assets) }
|
74
|
+
|
75
|
+
it "is the injected assets" do
|
76
|
+
expect(context.assets).to be assets
|
51
77
|
end
|
52
78
|
end
|
53
79
|
end
|
@@ -29,12 +29,16 @@ module RSpec
|
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
+
# TODO: make slice-aware
|
32
33
|
def stub_assets(*assets)
|
33
34
|
manifest_hash = assets.each_with_object({}) { |source_path, hsh|
|
34
35
|
hsh[source_path] = {url: File.join("/assets", source_path)}
|
35
36
|
}
|
36
37
|
|
37
|
-
write "public/assets.json", JSON.generate(manifest_hash)
|
38
|
+
write "public/assets/assets.json", JSON.generate(manifest_hash)
|
39
|
+
|
40
|
+
# An assets dir isrequired to load the assets provider
|
41
|
+
write "app/assets/.keep", ""
|
38
42
|
end
|
39
43
|
|
40
44
|
def compile_assets!
|
@@ -44,7 +48,11 @@ module RSpec
|
|
44
48
|
require "hanami/cli/command"
|
45
49
|
require "hanami/cli/commands/app/command"
|
46
50
|
require "hanami/cli/commands/app/assets/compile"
|
47
|
-
assets_compile = Hanami::CLI::Commands::App::Assets::Compile.new(
|
51
|
+
assets_compile = Hanami::CLI::Commands::App::Assets::Compile.new(
|
52
|
+
config: Hanami.app.config.assets,
|
53
|
+
out: File.new(File::NULL, "w"),
|
54
|
+
err: File.new(File::NULL, "w"),
|
55
|
+
)
|
48
56
|
|
49
57
|
with_directory(Hanami.app.root) { assets_compile.call }
|
50
58
|
end
|
@@ -62,16 +70,14 @@ module RSpec
|
|
62
70
|
root = Hanami.app.root
|
63
71
|
|
64
72
|
with_directory(root) do
|
65
|
-
write("config/assets.
|
73
|
+
write("config/assets.js", <<~JS) unless root.join("config", "assets.js").exist?
|
66
74
|
import * as assets from "hanami-assets";
|
67
75
|
await assets.run();
|
68
76
|
JS
|
69
77
|
|
70
78
|
write("package.json", <<~JSON) unless root.join("package.json").exist?
|
71
79
|
{
|
72
|
-
"
|
73
|
-
"assets": "node config/assets.mjs"
|
74
|
-
}
|
80
|
+
"type": "module"
|
75
81
|
}
|
76
82
|
JSON
|
77
83
|
end
|
@@ -106,4 +106,15 @@ RSpec.describe Hanami::Helpers::AssetsHelper, "#asset_url", :app_integration do
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
109
|
+
|
110
|
+
context "given an asset object" do
|
111
|
+
it "returns the URL for the asset" do
|
112
|
+
asset = Hanami::Assets::Asset.new(
|
113
|
+
path: "/foo/bar.js",
|
114
|
+
base_url: Hanami.app.config.assets.base_url
|
115
|
+
)
|
116
|
+
|
117
|
+
expect(asset_url(asset)).to eq "/foo/bar.js"
|
118
|
+
end
|
119
|
+
end
|
109
120
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.0.
|
4
|
+
version: 2.1.0.rc3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -160,16 +160,16 @@ dependencies:
|
|
160
160
|
name: hanami-cli
|
161
161
|
requirement: !ruby/object:Gem::Requirement
|
162
162
|
requirements:
|
163
|
-
- -
|
163
|
+
- - '='
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: 2.1.
|
165
|
+
version: 2.1.0.rc3
|
166
166
|
type: :runtime
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
|
-
- -
|
170
|
+
- - '='
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version: 2.1.
|
172
|
+
version: 2.1.0.rc3
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
174
|
name: hanami-utils
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
@@ -325,6 +325,7 @@ files:
|
|
325
325
|
- spec/integration/action/view_rendering/view_context_spec.rb
|
326
326
|
- spec/integration/action/view_rendering_spec.rb
|
327
327
|
- spec/integration/assets/assets_spec.rb
|
328
|
+
- spec/integration/assets/cross_slice_assets_helpers_spec.rb
|
328
329
|
- spec/integration/assets/serve_static_assets_spec.rb
|
329
330
|
- spec/integration/code_loading/loading_from_app_spec.rb
|
330
331
|
- spec/integration/code_loading/loading_from_lib_spec.rb
|
@@ -446,11 +447,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
446
447
|
version: '3.0'
|
447
448
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
448
449
|
requirements:
|
449
|
-
- - "
|
450
|
+
- - ">="
|
450
451
|
- !ruby/object:Gem::Version
|
451
|
-
version:
|
452
|
+
version: '0'
|
452
453
|
requirements: []
|
453
|
-
rubygems_version: 3.
|
454
|
+
rubygems_version: 3.5.6
|
454
455
|
signing_key:
|
455
456
|
specification_version: 4
|
456
457
|
summary: The web, with simplicity
|
@@ -466,6 +467,7 @@ test_files:
|
|
466
467
|
- spec/integration/action/view_rendering/view_context_spec.rb
|
467
468
|
- spec/integration/action/view_rendering_spec.rb
|
468
469
|
- spec/integration/assets/assets_spec.rb
|
470
|
+
- spec/integration/assets/cross_slice_assets_helpers_spec.rb
|
469
471
|
- spec/integration/assets/serve_static_assets_spec.rb
|
470
472
|
- spec/integration/code_loading/loading_from_app_spec.rb
|
471
473
|
- spec/integration/code_loading/loading_from_lib_spec.rb
|