actionview 7.1.0.beta1 → 7.1.0.rc1
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 +21 -0
- data/lib/action_view/base.rb +5 -5
- data/lib/action_view/gem_version.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +1 -1
- data/lib/action_view/layouts.rb +2 -2
- data/lib/action_view/template.rb +48 -1
- data/lib/action_view/test_case.rb +166 -16
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 801a14daea55551db924b943eba4b8fda7efcb2f95cfa5fc5e661f103400d455
|
4
|
+
data.tar.gz: 51b377932ac6ee1515e20af8d20da0c0f6ab296dbce50745b744a83bc626fdd7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebbde2c0523e9d77e7510ce00f6e5961329130b6f6d2daf3326e62f99d73b8f8f0b830a9fb975c265c6a6c5bed7f7bdeed5c3a827e3d88b2896688c9ea917c47
|
7
|
+
data.tar.gz: aa071eccb5d24f5be5604ffac911420001b3b7c7b8c70134b4094bdf4c347f23f53efeaadc739d35ea6d6f6fc49d3521c29f9233b1c80113f4f66619f8bfc0aa
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
## Rails 7.1.0.rc1 (September 27, 2023) ##
|
2
|
+
|
3
|
+
* Introduce `ActionView::TestCase.register_parser`
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
register_parser :rss, -> rendered { RSS::Parser.parse(rendered) }
|
7
|
+
|
8
|
+
test "renders RSS" do
|
9
|
+
article = Article.create!(title: "Hello, world")
|
10
|
+
|
11
|
+
render formats: :rss, partial: article
|
12
|
+
|
13
|
+
assert_equal "Hello, world", rendered.rss.items.last.title
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
By default, register parsers for `:html` and `:json`.
|
18
|
+
|
19
|
+
*Sean Doyle*
|
20
|
+
|
21
|
+
|
1
22
|
## Rails 7.1.0.beta1 (September 13, 2023) ##
|
2
23
|
|
3
24
|
* Fix `simple_format` with blank `wrapper_tag` option returns plain html tag
|
data/lib/action_view/base.rb
CHANGED
@@ -44,9 +44,9 @@ module ActionView # :nodoc:
|
|
44
44
|
# Using sub templates allows you to sidestep tedious replication and extract common display structures in shared templates. The
|
45
45
|
# classic example is the use of a header and footer (even though the Action Pack-way would be to use Layouts):
|
46
46
|
#
|
47
|
-
# <%= render "
|
47
|
+
# <%= render "application/header" %>
|
48
48
|
# Something really specific and terrific
|
49
|
-
# <%= render "
|
49
|
+
# <%= render "application/footer" %>
|
50
50
|
#
|
51
51
|
# As you see, we use the output embeddings for the render methods. The render call itself will just return a string holding the
|
52
52
|
# result of the rendering. The output embedding writes it to the current template.
|
@@ -55,7 +55,7 @@ module ActionView # :nodoc:
|
|
55
55
|
# variables defined using the regular embedding tags. Like this:
|
56
56
|
#
|
57
57
|
# <% @page_title = "A Wonderful Hello" %>
|
58
|
-
# <%= render "
|
58
|
+
# <%= render "application/header" %>
|
59
59
|
#
|
60
60
|
# Now the header can pick up on the <tt>@page_title</tt> variable and use it for outputting a title tag:
|
61
61
|
#
|
@@ -65,9 +65,9 @@ module ActionView # :nodoc:
|
|
65
65
|
#
|
66
66
|
# You can pass local variables to sub templates by using a hash with the variable names as keys and the objects as values:
|
67
67
|
#
|
68
|
-
# <%= render "
|
68
|
+
# <%= render "application/header", { headline: "Welcome", person: person } %>
|
69
69
|
#
|
70
|
-
# These can now be accessed in <tt>
|
70
|
+
# These can now be accessed in <tt>application/header</tt> with:
|
71
71
|
#
|
72
72
|
# Headline: <%= headline %>
|
73
73
|
# First name: <%= person.first_name %>
|
@@ -2521,7 +2521,7 @@ module ActionView
|
|
2521
2521
|
# * Creates standard HTML attributes for the tag.
|
2522
2522
|
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
|
2523
2523
|
# * <tt>:multiple</tt> - If set to true, *in most updated browsers* the user will be allowed to select multiple files.
|
2524
|
-
# * <tt>:include_hidden</tt> - When <tt>multiple: true</tt> and <tt>include_hidden: true</tt>, the field will be prefixed with an <tt><input type="hidden"></tt> field with an empty value to support submitting an empty collection of files.
|
2524
|
+
# * <tt>:include_hidden</tt> - When <tt>multiple: true</tt> and <tt>include_hidden: true</tt>, the field will be prefixed with an <tt><input type="hidden"></tt> field with an empty value to support submitting an empty collection of files. Since <tt>include_hidden</tt> will default to <tt>config.active_storage.multiple_file_field_include_hidden</tt> if you don't specify <tt>include_hidden</tt>, you will need to pass <tt>include_hidden: false</tt> to prevent submitting an empty collection of files when passing <tt>multiple: true</tt>.
|
2525
2525
|
# * <tt>:accept</tt> - If set to one or multiple mime-types, the user will be suggested a filter when choosing a file. You still need to set up model validations.
|
2526
2526
|
#
|
2527
2527
|
# ==== Examples
|
data/lib/action_view/layouts.rb
CHANGED
@@ -9,9 +9,9 @@ module ActionView
|
|
9
9
|
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
|
10
10
|
# repeated setups. The inclusion pattern has pages that look like this:
|
11
11
|
#
|
12
|
-
# <%= render "
|
12
|
+
# <%= render "application/header" %>
|
13
13
|
# Hello World
|
14
|
-
# <%= render "
|
14
|
+
# <%= render "application/footer" %>
|
15
15
|
#
|
16
16
|
# This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose
|
17
17
|
# and if you ever want to change the structure of these two includes, you'll have to change all the templates.
|
data/lib/action_view/template.rb
CHANGED
@@ -96,11 +96,58 @@ module ActionView
|
|
96
96
|
#
|
97
97
|
# Given this sub template rendering:
|
98
98
|
#
|
99
|
-
# <%= render "
|
99
|
+
# <%= render "application/header", { headline: "Welcome", person: person } %>
|
100
100
|
#
|
101
101
|
# You can use +local_assigns+ in the sub templates to access the local variables:
|
102
102
|
#
|
103
103
|
# local_assigns[:headline] # => "Welcome"
|
104
|
+
#
|
105
|
+
# Each key in +local_assigns+ is available as a partial-local variable:
|
106
|
+
#
|
107
|
+
# local_assigns[:headline] # => "Welcome"
|
108
|
+
# headline # => "Welcome"
|
109
|
+
#
|
110
|
+
# Since +local_assigns+ is a +Hash+, it's compatible with Ruby 3.1's pattern
|
111
|
+
# matching assignment operator:
|
112
|
+
#
|
113
|
+
# local_assigns => { headline:, **options }
|
114
|
+
# headline # => "Welcome"
|
115
|
+
# options # => {}
|
116
|
+
#
|
117
|
+
# Pattern matching assignment also supports variable renaming:
|
118
|
+
#
|
119
|
+
# local_assigns => { headline: title }
|
120
|
+
# title # => "Welcome"
|
121
|
+
#
|
122
|
+
# If a template refers to a variable that isn't passed into the view as part
|
123
|
+
# of the <tt>locals: { ... }</tt> Hash, the template will raise an
|
124
|
+
# +ActionView::Template::Error+:
|
125
|
+
#
|
126
|
+
# <%# => raises ActionView::Template::Error %>
|
127
|
+
# <% alerts.each do |alert| %>
|
128
|
+
# <p><%= alert %></p>
|
129
|
+
# <% end %>
|
130
|
+
#
|
131
|
+
# Since +local_assigns+ returns a +Hash+ instance, you can conditionally
|
132
|
+
# read a variable, then fall back to a default value when
|
133
|
+
# the key isn't part of the <tt>locals: { ... }</tt> options:
|
134
|
+
#
|
135
|
+
# <% local_assigns.fetch(:alerts, []).each do |alert| %>
|
136
|
+
# <p><%= alert %></p>
|
137
|
+
# <% end %>
|
138
|
+
#
|
139
|
+
# Combining Ruby 3.1's pattern matching assignment with calls to
|
140
|
+
# +Hash#with_defaults+ enables compact partial-local variable
|
141
|
+
# assignments:
|
142
|
+
#
|
143
|
+
# <% local_assigns.with_defaults(alerts: []) => { headline:, alerts: } %>
|
144
|
+
#
|
145
|
+
# <h1><%= headline %></h1>
|
146
|
+
#
|
147
|
+
# <% alerts.each do |alert| %>
|
148
|
+
# <p><%= alert %></p>
|
149
|
+
# <% end %>
|
150
|
+
#
|
104
151
|
|
105
152
|
eager_autoload do
|
106
153
|
autoload :Error
|
@@ -9,6 +9,9 @@ require "rails-dom-testing"
|
|
9
9
|
|
10
10
|
module ActionView
|
11
11
|
# = Action View Test Case
|
12
|
+
#
|
13
|
+
# Read more about <tt>ActionView::TestCase</tt> in {Testing Rails Applications}[https://guides.rubyonrails.org/testing.html#testing-view-partials]
|
14
|
+
# in the guides.
|
12
15
|
class TestCase < ActiveSupport::TestCase
|
13
16
|
class TestController < ActionController::Base
|
14
17
|
include ActionDispatch::TestProcess
|
@@ -57,9 +60,96 @@ module ActionView
|
|
57
60
|
include ActiveSupport::Testing::ConstantLookup
|
58
61
|
|
59
62
|
delegate :lookup_context, to: :controller
|
60
|
-
attr_accessor :controller, :request, :output_buffer
|
63
|
+
attr_accessor :controller, :request, :output_buffer
|
61
64
|
|
62
65
|
module ClassMethods
|
66
|
+
def inherited(descendant) # :nodoc:
|
67
|
+
super
|
68
|
+
|
69
|
+
descendant_content_class = content_class.dup
|
70
|
+
|
71
|
+
if descendant_content_class.respond_to?(:set_temporary_name)
|
72
|
+
descendant_content_class.set_temporary_name("rendered_content")
|
73
|
+
end
|
74
|
+
|
75
|
+
descendant.content_class = descendant_content_class
|
76
|
+
end
|
77
|
+
|
78
|
+
# Register a callable to parse rendered content for a given template
|
79
|
+
# format.
|
80
|
+
#
|
81
|
+
# Each registered parser will also define a +#rendered.[FORMAT]+ helper
|
82
|
+
# method, where +[FORMAT]+ corresponds to the value of the
|
83
|
+
# +format+ argument.
|
84
|
+
#
|
85
|
+
# === Arguments
|
86
|
+
#
|
87
|
+
# <tt>format</tt> - Symbol the name of the format used to render view's content
|
88
|
+
# <tt>callable</tt> - Callable to parse the String. Accepts the String.
|
89
|
+
# value as its only argument.
|
90
|
+
# <tt>block</tt> - Block serves as the parser when the
|
91
|
+
# <tt>callable</tt> is omitted.
|
92
|
+
#
|
93
|
+
# By default, ActionView::TestCase defines a parser for:
|
94
|
+
#
|
95
|
+
# * :html - returns an instance of Nokogiri::XML::Node
|
96
|
+
# * :json - returns an instance of ActiveSupport::HashWithIndifferentAccess
|
97
|
+
#
|
98
|
+
# Each pre-registered parser also defines a corresponding helper:
|
99
|
+
#
|
100
|
+
# * :html - defines `rendered.html`
|
101
|
+
# * :json - defines `rendered.json`
|
102
|
+
#
|
103
|
+
# === Examples
|
104
|
+
#
|
105
|
+
# test "renders HTML" do
|
106
|
+
# article = Article.create!(title: "Hello, world")
|
107
|
+
#
|
108
|
+
# render partial: "articles/article", locals: { article: article }
|
109
|
+
#
|
110
|
+
# assert_pattern { rendered.html.at("main h1") => { content: "Hello, world" } }
|
111
|
+
# end
|
112
|
+
#
|
113
|
+
# test "renders JSON" do
|
114
|
+
# article = Article.create!(title: "Hello, world")
|
115
|
+
#
|
116
|
+
# render formats: :json, partial: "articles/article", locals: { article: article }
|
117
|
+
#
|
118
|
+
# assert_pattern { rendered.json => { title: "Hello, world" } }
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# To parse the rendered content into RSS, register a call to <tt>RSS::Parser.parse</tt>:
|
122
|
+
#
|
123
|
+
# register_parser :rss, -> rendered { RSS::Parser.parse(rendered) }
|
124
|
+
#
|
125
|
+
# test "renders RSS" do
|
126
|
+
# article = Article.create!(title: "Hello, world")
|
127
|
+
#
|
128
|
+
# render formats: :rss, partial: article
|
129
|
+
#
|
130
|
+
# assert_equal "Hello, world", rendered.rss.items.last.title
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# To parse the rendered content into a Capybara::Simple::Node,
|
134
|
+
# re-register an <tt>:html</tt> parser with a call to
|
135
|
+
# <tt>Capybara.string</tt>:
|
136
|
+
#
|
137
|
+
# register_parser :html, -> rendered { Capybara.string(rendered) }
|
138
|
+
#
|
139
|
+
# test "renders HTML" do
|
140
|
+
# article = Article.create!(title: "Hello, world")
|
141
|
+
#
|
142
|
+
# render partial: article
|
143
|
+
#
|
144
|
+
# rendered.html.assert_css "h1", text: "Hello, world"
|
145
|
+
# end
|
146
|
+
def register_parser(format, callable = nil, &block)
|
147
|
+
parser = callable || block || :itself.to_proc
|
148
|
+
content_class.redefine_method(format) do
|
149
|
+
parser.call(to_s)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
63
153
|
def tests(helper_class)
|
64
154
|
case helper_class
|
65
155
|
when String, Symbol
|
@@ -105,6 +195,27 @@ module ActionView
|
|
105
195
|
end
|
106
196
|
end
|
107
197
|
|
198
|
+
included do
|
199
|
+
class_attribute :content_class, instance_accessor: false, default: Content
|
200
|
+
|
201
|
+
setup :setup_with_controller
|
202
|
+
|
203
|
+
register_parser :html, -> rendered { Rails::Dom::Testing.html_document.parse(rendered).root }
|
204
|
+
register_parser :json, -> rendered { JSON.parse(rendered, object_class: ActiveSupport::HashWithIndifferentAccess) }
|
205
|
+
|
206
|
+
ActiveSupport.run_load_hooks(:action_view_test_case, self)
|
207
|
+
|
208
|
+
helper do
|
209
|
+
def protect_against_forgery?
|
210
|
+
false
|
211
|
+
end
|
212
|
+
|
213
|
+
def _test_case
|
214
|
+
controller._test_case
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
108
219
|
def setup_with_controller
|
109
220
|
controller_class = Class.new(ActionView::TestCase::TestController)
|
110
221
|
@controller = controller_class.new
|
@@ -131,10 +242,64 @@ module ActionView
|
|
131
242
|
@_rendered_views ||= RenderedViewsCollection.new
|
132
243
|
end
|
133
244
|
|
245
|
+
# Returns the content rendered by the last +render+ call.
|
246
|
+
#
|
247
|
+
# The returned object behaves like a string but also exposes a number of methods
|
248
|
+
# that allows you to parse the content string in formats registered using
|
249
|
+
# <tt>.register_parser</tt>.
|
250
|
+
#
|
251
|
+
# By default includes the following parsers:
|
252
|
+
#
|
253
|
+
# +.html+
|
254
|
+
#
|
255
|
+
# Parse the <tt>rendered</tt> content String into HTML. By default, this means
|
256
|
+
# a <tt>Nokogiri::XML::Node</tt>.
|
257
|
+
#
|
258
|
+
# test "renders HTML" do
|
259
|
+
# article = Article.create!(title: "Hello, world")
|
260
|
+
#
|
261
|
+
# render partial: "articles/article", locals: { article: article }
|
262
|
+
#
|
263
|
+
# assert_pattern { rendered.html.at("main h1") => { content: "Hello, world" } }
|
264
|
+
# end
|
265
|
+
#
|
266
|
+
# To parse the rendered content into a <tt>Capybara::Simple::Node</tt>,
|
267
|
+
# re-register an <tt>:html</tt> parser with a call to
|
268
|
+
# <tt>Capybara.string</tt>:
|
269
|
+
#
|
270
|
+
# register_parser :html, -> rendered { Capybara.string(rendered) }
|
271
|
+
#
|
272
|
+
# test "renders HTML" do
|
273
|
+
# article = Article.create!(title: "Hello, world")
|
274
|
+
#
|
275
|
+
# render partial: article
|
276
|
+
#
|
277
|
+
# rendered.html.assert_css "h1", text: "Hello, world"
|
278
|
+
# end
|
279
|
+
#
|
280
|
+
# +.json+
|
281
|
+
#
|
282
|
+
# Parse the <tt>rendered</tt> content String into JSON. By default, this means
|
283
|
+
# a <tt>ActiveSupport::HashWithIndifferentAccess</tt>.
|
284
|
+
#
|
285
|
+
# test "renders JSON" do
|
286
|
+
# article = Article.create!(title: "Hello, world")
|
287
|
+
#
|
288
|
+
# render formats: :json, partial: "articles/article", locals: { article: article }
|
289
|
+
#
|
290
|
+
# assert_pattern { rendered.json => { title: "Hello, world" } }
|
291
|
+
# end
|
292
|
+
def rendered
|
293
|
+
@_rendered ||= self.class.content_class.new(@rendered)
|
294
|
+
end
|
295
|
+
|
134
296
|
def _routes
|
135
297
|
@controller._routes if @controller.respond_to?(:_routes)
|
136
298
|
end
|
137
299
|
|
300
|
+
class Content < SimpleDelegator
|
301
|
+
end
|
302
|
+
|
138
303
|
# Need to experiment if this priority is the best one: rendered => output_buffer
|
139
304
|
class RenderedViewsCollection
|
140
305
|
def initialize
|
@@ -161,21 +326,6 @@ module ActionView
|
|
161
326
|
end
|
162
327
|
end
|
163
328
|
|
164
|
-
included do
|
165
|
-
setup :setup_with_controller
|
166
|
-
ActiveSupport.run_load_hooks(:action_view_test_case, self)
|
167
|
-
|
168
|
-
helper do
|
169
|
-
def protect_against_forgery?
|
170
|
-
false
|
171
|
-
end
|
172
|
-
|
173
|
-
def _test_case
|
174
|
-
controller._test_case
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
329
|
private
|
180
330
|
# Need to experiment if this priority is the best one: rendered => output_buffer
|
181
331
|
def document_root_element
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionview
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.1.0.
|
4
|
+
version: 7.1.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-09-
|
11
|
+
date: 2023-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 7.1.0.
|
19
|
+
version: 7.1.0.rc1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 7.1.0.
|
26
|
+
version: 7.1.0.rc1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: builder
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,28 +86,28 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - '='
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 7.1.0.
|
89
|
+
version: 7.1.0.rc1
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - '='
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 7.1.0.
|
96
|
+
version: 7.1.0.rc1
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: activemodel
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - '='
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 7.1.0.
|
103
|
+
version: 7.1.0.rc1
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - '='
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 7.1.0.
|
110
|
+
version: 7.1.0.rc1
|
111
111
|
description: Simple, battle-tested conventions and helpers for building web pages.
|
112
112
|
email: david@loudthinking.com
|
113
113
|
executables: []
|
@@ -246,10 +246,10 @@ licenses:
|
|
246
246
|
- MIT
|
247
247
|
metadata:
|
248
248
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
249
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.1.0.
|
250
|
-
documentation_uri: https://api.rubyonrails.org/v7.1.0.
|
249
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.1.0.rc1/actionview/CHANGELOG.md
|
250
|
+
documentation_uri: https://api.rubyonrails.org/v7.1.0.rc1/
|
251
251
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
252
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.1.0.
|
252
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.1.0.rc1/actionview
|
253
253
|
rubygems_mfa_required: 'true'
|
254
254
|
post_install_message:
|
255
255
|
rdoc_options: []
|