actionview 4.1.13 → 6.1.3.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionview might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/CHANGELOG.md +181 -359
- data/MIT-LICENSE +1 -1
- data/README.rdoc +12 -6
- data/lib/action_view/base.rb +115 -43
- data/lib/action_view/buffers.rb +22 -4
- data/lib/action_view/cache_expiry.rb +52 -0
- data/lib/action_view/context.rb +8 -12
- data/lib/action_view/dependency_tracker.rb +61 -21
- data/lib/action_view/digestor.rb +89 -84
- data/lib/action_view/flows.rb +12 -13
- data/lib/action_view/gem_version.rb +6 -4
- data/lib/action_view/helpers/active_model_helper.rb +16 -11
- data/lib/action_view/helpers/asset_tag_helper.rb +311 -105
- data/lib/action_view/helpers/asset_url_helper.rb +197 -80
- data/lib/action_view/helpers/atom_feed_helper.rb +20 -17
- data/lib/action_view/helpers/cache_helper.rb +109 -45
- data/lib/action_view/helpers/capture_helper.rb +20 -22
- data/lib/action_view/helpers/controller_helper.rb +15 -4
- data/lib/action_view/helpers/csp_helper.rb +26 -0
- data/lib/action_view/helpers/csrf_helper.rb +8 -6
- data/lib/action_view/helpers/date_helper.rb +245 -140
- data/lib/action_view/helpers/debug_helper.rb +14 -17
- data/lib/action_view/helpers/form_helper.rb +875 -148
- data/lib/action_view/helpers/form_options_helper.rb +128 -82
- data/lib/action_view/helpers/form_tag_helper.rb +253 -91
- data/lib/action_view/helpers/javascript_helper.rb +37 -15
- data/lib/action_view/helpers/number_helper.rb +100 -77
- data/lib/action_view/helpers/output_safety_helper.rb +42 -10
- data/lib/action_view/helpers/rendering_helper.rb +26 -15
- data/lib/action_view/helpers/sanitize_helper.rb +79 -164
- data/lib/action_view/helpers/tag_helper.rb +277 -64
- data/lib/action_view/helpers/tags/base.rb +143 -92
- data/lib/action_view/helpers/tags/check_box.rb +20 -19
- data/lib/action_view/helpers/tags/checkable.rb +4 -2
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +12 -30
- data/lib/action_view/helpers/tags/collection_helpers.rb +69 -36
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +6 -12
- data/lib/action_view/helpers/tags/collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/color_field.rb +4 -3
- data/lib/action_view/helpers/tags/date_field.rb +3 -2
- data/lib/action_view/helpers/tags/date_select.rb +38 -37
- data/lib/action_view/helpers/tags/datetime_field.rb +14 -5
- data/lib/action_view/helpers/tags/datetime_local_field.rb +3 -2
- data/lib/action_view/helpers/tags/datetime_select.rb +2 -0
- data/lib/action_view/helpers/tags/email_field.rb +2 -0
- data/lib/action_view/helpers/tags/file_field.rb +2 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +4 -2
- data/lib/action_view/helpers/tags/hidden_field.rb +2 -0
- data/lib/action_view/helpers/tags/label.rb +41 -22
- data/lib/action_view/helpers/tags/month_field.rb +3 -2
- data/lib/action_view/helpers/tags/number_field.rb +2 -0
- data/lib/action_view/helpers/tags/password_field.rb +3 -1
- data/lib/action_view/helpers/tags/placeholderable.rb +24 -0
- data/lib/action_view/helpers/tags/radio_button.rb +7 -6
- data/lib/action_view/helpers/tags/range_field.rb +2 -0
- data/lib/action_view/helpers/tags/search_field.rb +3 -0
- data/lib/action_view/helpers/tags/select.rb +11 -10
- data/lib/action_view/helpers/tags/tel_field.rb +2 -0
- data/lib/action_view/helpers/tags/text_area.rb +7 -1
- data/lib/action_view/helpers/tags/text_field.rb +11 -7
- data/lib/action_view/helpers/tags/time_field.rb +3 -2
- data/lib/action_view/helpers/tags/time_select.rb +2 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +3 -1
- data/lib/action_view/helpers/tags/translator.rb +39 -0
- data/lib/action_view/helpers/tags/url_field.rb +2 -0
- data/lib/action_view/helpers/tags/week_field.rb +3 -2
- data/lib/action_view/helpers/tags.rb +4 -1
- data/lib/action_view/helpers/text_helper.rb +80 -45
- data/lib/action_view/helpers/translation_helper.rb +148 -67
- data/lib/action_view/helpers/url_helper.rb +289 -147
- data/lib/action_view/helpers.rb +5 -3
- data/lib/action_view/layouts.rb +68 -63
- data/lib/action_view/log_subscriber.rb +80 -13
- data/lib/action_view/lookup_context.rb +137 -92
- data/lib/action_view/model_naming.rb +4 -2
- data/lib/action_view/path_set.rb +30 -16
- data/lib/action_view/railtie.rb +62 -13
- data/lib/action_view/record_identifier.rb +53 -26
- data/lib/action_view/renderer/abstract_renderer.rb +152 -13
- data/lib/action_view/renderer/collection_renderer.rb +196 -0
- data/lib/action_view/renderer/object_renderer.rb +34 -0
- data/lib/action_view/renderer/partial_renderer/collection_caching.rb +102 -0
- data/lib/action_view/renderer/partial_renderer.rb +61 -261
- data/lib/action_view/renderer/renderer.rb +67 -6
- data/lib/action_view/renderer/streaming_template_renderer.rb +58 -54
- data/lib/action_view/renderer/template_renderer.rb +83 -75
- data/lib/action_view/rendering.rb +73 -46
- data/lib/action_view/routing_url_for.rb +54 -17
- data/lib/action_view/tasks/cache_digests.rake +25 -0
- data/lib/action_view/template/error.rb +44 -29
- data/lib/action_view/template/handlers/builder.rb +12 -13
- data/lib/action_view/template/handlers/erb/erubi.rb +89 -0
- data/lib/action_view/template/handlers/erb.rb +23 -89
- data/lib/action_view/template/handlers/html.rb +11 -0
- data/lib/action_view/template/handlers/raw.rb +4 -4
- data/lib/action_view/template/handlers.rb +22 -9
- data/lib/action_view/template/html.rb +10 -11
- data/lib/action_view/template/inline.rb +22 -0
- data/lib/action_view/template/raw_file.rb +25 -0
- data/lib/action_view/template/renderable.rb +24 -0
- data/lib/action_view/template/resolver.rb +267 -181
- data/lib/action_view/template/sources/file.rb +17 -0
- data/lib/action_view/template/sources.rb +13 -0
- data/lib/action_view/template/text.rb +8 -10
- data/lib/action_view/template/types.rb +18 -18
- data/lib/action_view/template.rb +109 -99
- data/lib/action_view/test_case.rb +73 -53
- data/lib/action_view/testing/resolvers.rb +24 -33
- data/lib/action_view/unbound_template.rb +31 -0
- data/lib/action_view/version.rb +3 -1
- data/lib/action_view/view_paths.rb +74 -44
- data/lib/action_view.rb +14 -9
- data/lib/assets/compiled/rails-ujs.js +746 -0
- metadata +71 -26
- data/lib/action_view/helpers/record_tag_helper.rb +0 -108
- data/lib/action_view/tasks/dependencies.rake +0 -23
- data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
- data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
- data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
- data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
- data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
- data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
- data/lib/action_view/vendor/html-scanner.rb +0 -20
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:
|
4
|
+
version: 6.1.3.1
|
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:
|
11
|
+
date: 2021-03-26 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:
|
19
|
+
version: 6.1.3.1
|
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:
|
26
|
+
version: 6.1.3.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: builder
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,47 +39,81 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: erubi
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: '1.4'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: '1.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rails-html-sanitizer
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: 1.2.0
|
65
|
+
type: :runtime
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - "~>"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '1.1'
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 1.2.0
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rails-dom-testing
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '2.0'
|
82
|
+
type: :runtime
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '2.0'
|
55
89
|
- !ruby/object:Gem::Dependency
|
56
90
|
name: actionpack
|
57
91
|
requirement: !ruby/object:Gem::Requirement
|
58
92
|
requirements:
|
59
93
|
- - '='
|
60
94
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
95
|
+
version: 6.1.3.1
|
62
96
|
type: :development
|
63
97
|
prerelease: false
|
64
98
|
version_requirements: !ruby/object:Gem::Requirement
|
65
99
|
requirements:
|
66
100
|
- - '='
|
67
101
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
102
|
+
version: 6.1.3.1
|
69
103
|
- !ruby/object:Gem::Dependency
|
70
104
|
name: activemodel
|
71
105
|
requirement: !ruby/object:Gem::Requirement
|
72
106
|
requirements:
|
73
107
|
- - '='
|
74
108
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
109
|
+
version: 6.1.3.1
|
76
110
|
type: :development
|
77
111
|
prerelease: false
|
78
112
|
version_requirements: !ruby/object:Gem::Requirement
|
79
113
|
requirements:
|
80
114
|
- - '='
|
81
115
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
116
|
+
version: 6.1.3.1
|
83
117
|
description: Simple, battle-tested conventions and helpers for building web pages.
|
84
118
|
email: david@loudthinking.com
|
85
119
|
executables: []
|
@@ -92,6 +126,7 @@ files:
|
|
92
126
|
- lib/action_view.rb
|
93
127
|
- lib/action_view/base.rb
|
94
128
|
- lib/action_view/buffers.rb
|
129
|
+
- lib/action_view/cache_expiry.rb
|
95
130
|
- lib/action_view/context.rb
|
96
131
|
- lib/action_view/dependency_tracker.rb
|
97
132
|
- lib/action_view/digestor.rb
|
@@ -105,6 +140,7 @@ files:
|
|
105
140
|
- lib/action_view/helpers/cache_helper.rb
|
106
141
|
- lib/action_view/helpers/capture_helper.rb
|
107
142
|
- lib/action_view/helpers/controller_helper.rb
|
143
|
+
- lib/action_view/helpers/csp_helper.rb
|
108
144
|
- lib/action_view/helpers/csrf_helper.rb
|
109
145
|
- lib/action_view/helpers/date_helper.rb
|
110
146
|
- lib/action_view/helpers/debug_helper.rb
|
@@ -114,7 +150,6 @@ files:
|
|
114
150
|
- lib/action_view/helpers/javascript_helper.rb
|
115
151
|
- lib/action_view/helpers/number_helper.rb
|
116
152
|
- lib/action_view/helpers/output_safety_helper.rb
|
117
|
-
- lib/action_view/helpers/record_tag_helper.rb
|
118
153
|
- lib/action_view/helpers/rendering_helper.rb
|
119
154
|
- lib/action_view/helpers/sanitize_helper.rb
|
120
155
|
- lib/action_view/helpers/tag_helper.rb
|
@@ -140,6 +175,7 @@ files:
|
|
140
175
|
- lib/action_view/helpers/tags/month_field.rb
|
141
176
|
- lib/action_view/helpers/tags/number_field.rb
|
142
177
|
- lib/action_view/helpers/tags/password_field.rb
|
178
|
+
- lib/action_view/helpers/tags/placeholderable.rb
|
143
179
|
- lib/action_view/helpers/tags/radio_button.rb
|
144
180
|
- lib/action_view/helpers/tags/range_field.rb
|
145
181
|
- lib/action_view/helpers/tags/search_field.rb
|
@@ -150,6 +186,7 @@ files:
|
|
150
186
|
- lib/action_view/helpers/tags/time_field.rb
|
151
187
|
- lib/action_view/helpers/tags/time_select.rb
|
152
188
|
- lib/action_view/helpers/tags/time_zone_select.rb
|
189
|
+
- lib/action_view/helpers/tags/translator.rb
|
153
190
|
- lib/action_view/helpers/tags/url_field.rb
|
154
191
|
- lib/action_view/helpers/tags/week_field.rb
|
155
192
|
- lib/action_view/helpers/text_helper.rb
|
@@ -164,38 +201,48 @@ files:
|
|
164
201
|
- lib/action_view/railtie.rb
|
165
202
|
- lib/action_view/record_identifier.rb
|
166
203
|
- lib/action_view/renderer/abstract_renderer.rb
|
204
|
+
- lib/action_view/renderer/collection_renderer.rb
|
205
|
+
- lib/action_view/renderer/object_renderer.rb
|
167
206
|
- lib/action_view/renderer/partial_renderer.rb
|
207
|
+
- lib/action_view/renderer/partial_renderer/collection_caching.rb
|
168
208
|
- lib/action_view/renderer/renderer.rb
|
169
209
|
- lib/action_view/renderer/streaming_template_renderer.rb
|
170
210
|
- lib/action_view/renderer/template_renderer.rb
|
171
211
|
- lib/action_view/rendering.rb
|
172
212
|
- lib/action_view/routing_url_for.rb
|
173
|
-
- lib/action_view/tasks/
|
213
|
+
- lib/action_view/tasks/cache_digests.rake
|
174
214
|
- lib/action_view/template.rb
|
175
215
|
- lib/action_view/template/error.rb
|
176
216
|
- lib/action_view/template/handlers.rb
|
177
217
|
- lib/action_view/template/handlers/builder.rb
|
178
218
|
- lib/action_view/template/handlers/erb.rb
|
219
|
+
- lib/action_view/template/handlers/erb/erubi.rb
|
220
|
+
- lib/action_view/template/handlers/html.rb
|
179
221
|
- lib/action_view/template/handlers/raw.rb
|
180
222
|
- lib/action_view/template/html.rb
|
223
|
+
- lib/action_view/template/inline.rb
|
224
|
+
- lib/action_view/template/raw_file.rb
|
225
|
+
- lib/action_view/template/renderable.rb
|
181
226
|
- lib/action_view/template/resolver.rb
|
227
|
+
- lib/action_view/template/sources.rb
|
228
|
+
- lib/action_view/template/sources/file.rb
|
182
229
|
- lib/action_view/template/text.rb
|
183
230
|
- lib/action_view/template/types.rb
|
184
231
|
- lib/action_view/test_case.rb
|
185
232
|
- lib/action_view/testing/resolvers.rb
|
186
|
-
- lib/action_view/
|
187
|
-
- lib/action_view/vendor/html-scanner/html/document.rb
|
188
|
-
- lib/action_view/vendor/html-scanner/html/node.rb
|
189
|
-
- lib/action_view/vendor/html-scanner/html/sanitizer.rb
|
190
|
-
- lib/action_view/vendor/html-scanner/html/selector.rb
|
191
|
-
- lib/action_view/vendor/html-scanner/html/tokenizer.rb
|
192
|
-
- lib/action_view/vendor/html-scanner/html/version.rb
|
233
|
+
- lib/action_view/unbound_template.rb
|
193
234
|
- lib/action_view/version.rb
|
194
235
|
- lib/action_view/view_paths.rb
|
195
|
-
|
236
|
+
- lib/assets/compiled/rails-ujs.js
|
237
|
+
homepage: https://rubyonrails.org
|
196
238
|
licenses:
|
197
239
|
- MIT
|
198
|
-
metadata:
|
240
|
+
metadata:
|
241
|
+
bug_tracker_uri: https://github.com/rails/rails/issues
|
242
|
+
changelog_uri: https://github.com/rails/rails/blob/v6.1.3.1/actionview/CHANGELOG.md
|
243
|
+
documentation_uri: https://api.rubyonrails.org/v6.1.3.1/
|
244
|
+
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
245
|
+
source_code_uri: https://github.com/rails/rails/tree/v6.1.3.1/actionview
|
199
246
|
post_install_message:
|
200
247
|
rdoc_options: []
|
201
248
|
require_paths:
|
@@ -204,7 +251,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
204
251
|
requirements:
|
205
252
|
- - ">="
|
206
253
|
- !ruby/object:Gem::Version
|
207
|
-
version:
|
254
|
+
version: 2.5.0
|
208
255
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
209
256
|
requirements:
|
210
257
|
- - ">="
|
@@ -212,10 +259,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
259
|
version: '0'
|
213
260
|
requirements:
|
214
261
|
- none
|
215
|
-
|
216
|
-
rubygems_version: 2.4.7
|
262
|
+
rubygems_version: 3.1.2
|
217
263
|
signing_key:
|
218
264
|
specification_version: 4
|
219
265
|
summary: Rendering framework putting the V in MVC (part of Rails).
|
220
266
|
test_files: []
|
221
|
-
has_rdoc:
|
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'action_view/record_identifier'
|
2
|
-
|
3
|
-
module ActionView
|
4
|
-
# = Action View Record Tag Helpers
|
5
|
-
module Helpers
|
6
|
-
module RecordTagHelper
|
7
|
-
include ActionView::RecordIdentifier
|
8
|
-
|
9
|
-
# Produces a wrapper DIV element with id and class parameters that
|
10
|
-
# relate to the specified Active Record object. Usage example:
|
11
|
-
#
|
12
|
-
# <%= div_for(@person, class: "foo") do %>
|
13
|
-
# <%= @person.name %>
|
14
|
-
# <% end %>
|
15
|
-
#
|
16
|
-
# produces:
|
17
|
-
#
|
18
|
-
# <div id="person_123" class="person foo"> Joe Bloggs </div>
|
19
|
-
#
|
20
|
-
# You can also pass an array of Active Record objects, which will then
|
21
|
-
# get iterated over and yield each record as an argument for the block.
|
22
|
-
# For example:
|
23
|
-
#
|
24
|
-
# <%= div_for(@people, class: "foo") do |person| %>
|
25
|
-
# <%= person.name %>
|
26
|
-
# <% end %>
|
27
|
-
#
|
28
|
-
# produces:
|
29
|
-
#
|
30
|
-
# <div id="person_123" class="person foo"> Joe Bloggs </div>
|
31
|
-
# <div id="person_124" class="person foo"> Jane Bloggs </div>
|
32
|
-
#
|
33
|
-
def div_for(record, *args, &block)
|
34
|
-
content_tag_for(:div, record, *args, &block)
|
35
|
-
end
|
36
|
-
|
37
|
-
# content_tag_for creates an HTML element with id and class parameters
|
38
|
-
# that relate to the specified Active Record object. For example:
|
39
|
-
#
|
40
|
-
# <%= content_tag_for(:tr, @person) do %>
|
41
|
-
# <td><%= @person.first_name %></td>
|
42
|
-
# <td><%= @person.last_name %></td>
|
43
|
-
# <% end %>
|
44
|
-
#
|
45
|
-
# would produce the following HTML (assuming @person is an instance of
|
46
|
-
# a Person object, with an id value of 123):
|
47
|
-
#
|
48
|
-
# <tr id="person_123" class="person">....</tr>
|
49
|
-
#
|
50
|
-
# If you require the HTML id attribute to have a prefix, you can specify it:
|
51
|
-
#
|
52
|
-
# <%= content_tag_for(:tr, @person, :foo) do %> ...
|
53
|
-
#
|
54
|
-
# produces:
|
55
|
-
#
|
56
|
-
# <tr id="foo_person_123" class="person">...
|
57
|
-
#
|
58
|
-
# You can also pass an array of objects which this method will loop through
|
59
|
-
# and yield the current object to the supplied block, reducing the need for
|
60
|
-
# having to iterate through the object (using <tt>each</tt>) beforehand.
|
61
|
-
# For example (assuming @people is an array of Person objects):
|
62
|
-
#
|
63
|
-
# <%= content_tag_for(:tr, @people) do |person| %>
|
64
|
-
# <td><%= person.first_name %></td>
|
65
|
-
# <td><%= person.last_name %></td>
|
66
|
-
# <% end %>
|
67
|
-
#
|
68
|
-
# produces:
|
69
|
-
#
|
70
|
-
# <tr id="person_123" class="person">...</tr>
|
71
|
-
# <tr id="person_124" class="person">...</tr>
|
72
|
-
#
|
73
|
-
# content_tag_for also accepts a hash of options, which will be converted to
|
74
|
-
# additional HTML attributes. If you specify a <tt>:class</tt> value, it will be combined
|
75
|
-
# with the default class name for your object. For example:
|
76
|
-
#
|
77
|
-
# <%= content_tag_for(:li, @person, class: "bar") %>...
|
78
|
-
#
|
79
|
-
# produces:
|
80
|
-
#
|
81
|
-
# <li id="person_123" class="person bar">...
|
82
|
-
#
|
83
|
-
def content_tag_for(tag_name, single_or_multiple_records, prefix = nil, options = nil, &block)
|
84
|
-
options, prefix = prefix, nil if prefix.is_a?(Hash)
|
85
|
-
|
86
|
-
Array(single_or_multiple_records).map do |single_record|
|
87
|
-
content_tag_for_single_record(tag_name, single_record, prefix, options, &block)
|
88
|
-
end.join("\n").html_safe
|
89
|
-
end
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
# Called by <tt>content_tag_for</tt> internally to render a content tag
|
94
|
-
# for each record.
|
95
|
-
def content_tag_for_single_record(tag_name, record, prefix, options, &block)
|
96
|
-
options = options ? options.dup : {}
|
97
|
-
options[:class] = [ dom_class(record, prefix), options[:class] ].compact
|
98
|
-
options[:id] = dom_id(record, prefix)
|
99
|
-
|
100
|
-
if block_given?
|
101
|
-
content_tag(tag_name, capture(record, &block), options)
|
102
|
-
else
|
103
|
-
content_tag(tag_name, "", options)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
namespace :cache_digests do
|
2
|
-
desc 'Lookup nested dependencies for TEMPLATE (like messages/show or comments/_comment.html)'
|
3
|
-
task :nested_dependencies => :environment do
|
4
|
-
abort 'You must provide TEMPLATE for the task to run' unless ENV['TEMPLATE'].present?
|
5
|
-
puts JSON.pretty_generate ActionView::Digestor.new(name: CacheDigests.template_name, finder: CacheDigests.finder).nested_dependencies
|
6
|
-
end
|
7
|
-
|
8
|
-
desc 'Lookup first-level dependencies for TEMPLATE (like messages/show or comments/_comment.html)'
|
9
|
-
task :dependencies => :environment do
|
10
|
-
abort 'You must provide TEMPLATE for the task to run' unless ENV['TEMPLATE'].present?
|
11
|
-
puts JSON.pretty_generate ActionView::Digestor.new(name: CacheDigests.template_name, finder: CacheDigests.finder).dependencies
|
12
|
-
end
|
13
|
-
|
14
|
-
class CacheDigests
|
15
|
-
def self.template_name
|
16
|
-
ENV['TEMPLATE'].split('.', 2).first
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.finder
|
20
|
-
ApplicationController.new.lookup_context
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
require 'html/tokenizer'
|
2
|
-
require 'html/node'
|
3
|
-
require 'html/selector'
|
4
|
-
require 'html/sanitizer'
|
5
|
-
|
6
|
-
module HTML #:nodoc:
|
7
|
-
# A top-level HTML document. You give it a body of text, and it will parse that
|
8
|
-
# text into a tree of nodes.
|
9
|
-
class Document #:nodoc:
|
10
|
-
|
11
|
-
# The root of the parsed document.
|
12
|
-
attr_reader :root
|
13
|
-
|
14
|
-
# Create a new Document from the given text.
|
15
|
-
def initialize(text, strict=false, xml=false)
|
16
|
-
tokenizer = Tokenizer.new(text)
|
17
|
-
@root = Node.new(nil)
|
18
|
-
node_stack = [ @root ]
|
19
|
-
while token = tokenizer.next
|
20
|
-
node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token, strict)
|
21
|
-
|
22
|
-
node_stack.last.children << node unless node.tag? && node.closing == :close
|
23
|
-
if node.tag?
|
24
|
-
if node_stack.length > 1 && node.closing == :close
|
25
|
-
if node_stack.last.name == node.name
|
26
|
-
if node_stack.last.children.empty?
|
27
|
-
node_stack.last.children << Text.new(node_stack.last, node.line, node.position, "")
|
28
|
-
end
|
29
|
-
node_stack.pop
|
30
|
-
else
|
31
|
-
open_start = node_stack.last.position - 20
|
32
|
-
open_start = 0 if open_start < 0
|
33
|
-
close_start = node.position - 20
|
34
|
-
close_start = 0 if close_start < 0
|
35
|
-
msg = <<EOF.strip
|
36
|
-
ignoring attempt to close #{node_stack.last.name} with #{node.name}
|
37
|
-
opened at byte #{node_stack.last.position}, line #{node_stack.last.line}
|
38
|
-
closed at byte #{node.position}, line #{node.line}
|
39
|
-
attributes at open: #{node_stack.last.attributes.inspect}
|
40
|
-
text around open: #{text[open_start,40].inspect}
|
41
|
-
text around close: #{text[close_start,40].inspect}
|
42
|
-
EOF
|
43
|
-
strict ? raise(msg) : warn(msg)
|
44
|
-
end
|
45
|
-
elsif !node.childless?(xml) && node.closing != :close
|
46
|
-
node_stack.push node
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Search the tree for (and return) the first node that matches the given
|
53
|
-
# conditions. The conditions are interpreted differently for different node
|
54
|
-
# types, see HTML::Text#find and HTML::Tag#find.
|
55
|
-
def find(conditions)
|
56
|
-
@root.find(conditions)
|
57
|
-
end
|
58
|
-
|
59
|
-
# Search the tree for (and return) all nodes that match the given
|
60
|
-
# conditions. The conditions are interpreted differently for different node
|
61
|
-
# types, see HTML::Text#find and HTML::Tag#find.
|
62
|
-
def find_all(conditions)
|
63
|
-
@root.find_all(conditions)
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
@@ -1,532 +0,0 @@
|
|
1
|
-
require 'strscan'
|
2
|
-
|
3
|
-
module HTML #:nodoc:
|
4
|
-
|
5
|
-
class Conditions < Hash #:nodoc:
|
6
|
-
def initialize(hash)
|
7
|
-
super()
|
8
|
-
hash = { :content => hash } unless Hash === hash
|
9
|
-
hash = keys_to_symbols(hash)
|
10
|
-
hash.each do |k,v|
|
11
|
-
case k
|
12
|
-
when :tag, :content then
|
13
|
-
# keys are valid, and require no further processing
|
14
|
-
when :attributes then
|
15
|
-
hash[k] = keys_to_strings(v)
|
16
|
-
when :parent, :child, :ancestor, :descendant, :sibling, :before,
|
17
|
-
:after
|
18
|
-
hash[k] = Conditions.new(v)
|
19
|
-
when :children
|
20
|
-
hash[k] = v = keys_to_symbols(v)
|
21
|
-
v.each do |key,value|
|
22
|
-
case key
|
23
|
-
when :count, :greater_than, :less_than
|
24
|
-
# keys are valid, and require no further processing
|
25
|
-
when :only
|
26
|
-
v[key] = Conditions.new(value)
|
27
|
-
else
|
28
|
-
raise "illegal key #{key.inspect} => #{value.inspect}"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
else
|
32
|
-
raise "illegal key #{k.inspect} => #{v.inspect}"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
update hash
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def keys_to_strings(hash)
|
41
|
-
Hash[hash.keys.map {|k| [k.to_s, hash[k]]}]
|
42
|
-
end
|
43
|
-
|
44
|
-
def keys_to_symbols(hash)
|
45
|
-
Hash[hash.keys.map do |k|
|
46
|
-
raise "illegal key #{k.inspect}" unless k.respond_to?(:to_sym)
|
47
|
-
[k.to_sym, hash[k]]
|
48
|
-
end]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# The base class of all nodes, textual and otherwise, in an HTML document.
|
53
|
-
class Node #:nodoc:
|
54
|
-
# The array of children of this node. Not all nodes have children.
|
55
|
-
attr_reader :children
|
56
|
-
|
57
|
-
# The parent node of this node. All nodes have a parent, except for the
|
58
|
-
# root node.
|
59
|
-
attr_reader :parent
|
60
|
-
|
61
|
-
# The line number of the input where this node was begun
|
62
|
-
attr_reader :line
|
63
|
-
|
64
|
-
# The byte position in the input where this node was begun
|
65
|
-
attr_reader :position
|
66
|
-
|
67
|
-
# Create a new node as a child of the given parent.
|
68
|
-
def initialize(parent, line=0, pos=0)
|
69
|
-
@parent = parent
|
70
|
-
@children = []
|
71
|
-
@line, @position = line, pos
|
72
|
-
end
|
73
|
-
|
74
|
-
# Returns a textual representation of the node.
|
75
|
-
def to_s
|
76
|
-
@children.join()
|
77
|
-
end
|
78
|
-
|
79
|
-
# Returns false (subclasses must override this to provide specific matching
|
80
|
-
# behavior.) +conditions+ may be of any type.
|
81
|
-
def match(conditions)
|
82
|
-
false
|
83
|
-
end
|
84
|
-
|
85
|
-
# Search the children of this node for the first node for which #find
|
86
|
-
# returns non +nil+. Returns the result of the #find call that succeeded.
|
87
|
-
def find(conditions)
|
88
|
-
conditions = validate_conditions(conditions)
|
89
|
-
@children.each do |child|
|
90
|
-
node = child.find(conditions)
|
91
|
-
return node if node
|
92
|
-
end
|
93
|
-
nil
|
94
|
-
end
|
95
|
-
|
96
|
-
# Search for all nodes that match the given conditions, and return them
|
97
|
-
# as an array.
|
98
|
-
def find_all(conditions)
|
99
|
-
conditions = validate_conditions(conditions)
|
100
|
-
|
101
|
-
matches = []
|
102
|
-
matches << self if match(conditions)
|
103
|
-
@children.each do |child|
|
104
|
-
matches.concat child.find_all(conditions)
|
105
|
-
end
|
106
|
-
matches
|
107
|
-
end
|
108
|
-
|
109
|
-
# Returns +false+. Subclasses may override this if they define a kind of
|
110
|
-
# tag.
|
111
|
-
def tag?
|
112
|
-
false
|
113
|
-
end
|
114
|
-
|
115
|
-
def validate_conditions(conditions)
|
116
|
-
Conditions === conditions ? conditions : Conditions.new(conditions)
|
117
|
-
end
|
118
|
-
|
119
|
-
def ==(node)
|
120
|
-
return false unless self.class == node.class && children.size == node.children.size
|
121
|
-
|
122
|
-
equivalent = true
|
123
|
-
|
124
|
-
children.size.times do |i|
|
125
|
-
equivalent &&= children[i] == node.children[i]
|
126
|
-
end
|
127
|
-
|
128
|
-
equivalent
|
129
|
-
end
|
130
|
-
|
131
|
-
class <<self
|
132
|
-
def parse(parent, line, pos, content, strict=true)
|
133
|
-
if content !~ /^<\S/
|
134
|
-
Text.new(parent, line, pos, content)
|
135
|
-
else
|
136
|
-
scanner = StringScanner.new(content)
|
137
|
-
|
138
|
-
unless scanner.skip(/</)
|
139
|
-
if strict
|
140
|
-
raise "expected <"
|
141
|
-
else
|
142
|
-
return Text.new(parent, line, pos, content)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
if scanner.skip(/!\[CDATA\[/)
|
147
|
-
unless scanner.skip_until(/\]\]>/)
|
148
|
-
if strict
|
149
|
-
raise "expected ]]> (got #{scanner.rest.inspect} for #{content})"
|
150
|
-
else
|
151
|
-
scanner.skip_until(/\Z/)
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
return CDATA.new(parent, line, pos, scanner.pre_match.gsub(/<!\[CDATA\[/, ''))
|
156
|
-
end
|
157
|
-
|
158
|
-
closing = ( scanner.scan(/\//) ? :close : nil )
|
159
|
-
return Text.new(parent, line, pos, content) unless name = scanner.scan(/[^\s!>\/]+/)
|
160
|
-
name.downcase!
|
161
|
-
|
162
|
-
unless closing
|
163
|
-
scanner.skip(/\s*/)
|
164
|
-
attributes = {}
|
165
|
-
while attr = scanner.scan(/[-\w:]+/)
|
166
|
-
value = true
|
167
|
-
if scanner.scan(/\s*=\s*/)
|
168
|
-
if delim = scanner.scan(/['"]/)
|
169
|
-
value = ""
|
170
|
-
while text = scanner.scan(/[^#{delim}\\]+|./)
|
171
|
-
case text
|
172
|
-
when "\\" then
|
173
|
-
value << text
|
174
|
-
break if scanner.eos?
|
175
|
-
value << scanner.getch
|
176
|
-
when delim
|
177
|
-
break
|
178
|
-
else value << text
|
179
|
-
end
|
180
|
-
end
|
181
|
-
else
|
182
|
-
value = scanner.scan(/[^\s>\/]+/)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
attributes[attr.downcase] = value
|
186
|
-
scanner.skip(/\s*/)
|
187
|
-
end
|
188
|
-
|
189
|
-
closing = ( scanner.scan(/\//) ? :self : nil )
|
190
|
-
end
|
191
|
-
|
192
|
-
unless scanner.scan(/\s*>/)
|
193
|
-
if strict
|
194
|
-
raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
|
195
|
-
else
|
196
|
-
# throw away all text until we find what we're looking for
|
197
|
-
scanner.skip_until(/>/) or scanner.terminate
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
Tag.new(parent, line, pos, name, attributes, closing)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
# A node that represents text, rather than markup.
|
208
|
-
class Text < Node #:nodoc:
|
209
|
-
|
210
|
-
attr_reader :content
|
211
|
-
|
212
|
-
# Creates a new text node as a child of the given parent, with the given
|
213
|
-
# content.
|
214
|
-
def initialize(parent, line, pos, content)
|
215
|
-
super(parent, line, pos)
|
216
|
-
@content = content
|
217
|
-
end
|
218
|
-
|
219
|
-
# Returns the content of this node.
|
220
|
-
def to_s
|
221
|
-
@content
|
222
|
-
end
|
223
|
-
|
224
|
-
# Returns +self+ if this node meets the given conditions. Text nodes support
|
225
|
-
# conditions of the following kinds:
|
226
|
-
#
|
227
|
-
# * if +conditions+ is a string, it must be a substring of the node's
|
228
|
-
# content
|
229
|
-
# * if +conditions+ is a regular expression, it must match the node's
|
230
|
-
# content
|
231
|
-
# * if +conditions+ is a hash, it must contain a <tt>:content</tt> key that
|
232
|
-
# is either a string or a regexp, and which is interpreted as described
|
233
|
-
# above.
|
234
|
-
def find(conditions)
|
235
|
-
match(conditions) && self
|
236
|
-
end
|
237
|
-
|
238
|
-
# Returns non-+nil+ if this node meets the given conditions, or +nil+
|
239
|
-
# otherwise. See the discussion of #find for the valid conditions.
|
240
|
-
def match(conditions)
|
241
|
-
case conditions
|
242
|
-
when String
|
243
|
-
@content == conditions
|
244
|
-
when Regexp
|
245
|
-
@content =~ conditions
|
246
|
-
when Hash
|
247
|
-
conditions = validate_conditions(conditions)
|
248
|
-
|
249
|
-
# Text nodes only have :content, :parent, :ancestor
|
250
|
-
unless (conditions.keys - [:content, :parent, :ancestor]).empty?
|
251
|
-
return false
|
252
|
-
end
|
253
|
-
|
254
|
-
match(conditions[:content])
|
255
|
-
else
|
256
|
-
nil
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
def ==(node)
|
261
|
-
return false unless super
|
262
|
-
content == node.content
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
# A CDATA node is simply a text node with a specialized way of displaying
|
267
|
-
# itself.
|
268
|
-
class CDATA < Text #:nodoc:
|
269
|
-
def to_s
|
270
|
-
"<![CDATA[#{super}]]>"
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
# A Tag is any node that represents markup. It may be an opening tag, a
|
275
|
-
# closing tag, or a self-closing tag. It has a name, and may have a hash of
|
276
|
-
# attributes.
|
277
|
-
class Tag < Node #:nodoc:
|
278
|
-
|
279
|
-
# Either +nil+, <tt>:close</tt>, or <tt>:self</tt>
|
280
|
-
attr_reader :closing
|
281
|
-
|
282
|
-
# Either +nil+, or a hash of attributes for this node.
|
283
|
-
attr_reader :attributes
|
284
|
-
|
285
|
-
# The name of this tag.
|
286
|
-
attr_reader :name
|
287
|
-
|
288
|
-
# Create a new node as a child of the given parent, using the given content
|
289
|
-
# to describe the node. It will be parsed and the node name, attributes and
|
290
|
-
# closing status extracted.
|
291
|
-
def initialize(parent, line, pos, name, attributes, closing)
|
292
|
-
super(parent, line, pos)
|
293
|
-
@name = name
|
294
|
-
@attributes = attributes
|
295
|
-
@closing = closing
|
296
|
-
end
|
297
|
-
|
298
|
-
# A convenience for obtaining an attribute of the node. Returns +nil+ if
|
299
|
-
# the node has no attributes.
|
300
|
-
def [](attr)
|
301
|
-
@attributes ? @attributes[attr] : nil
|
302
|
-
end
|
303
|
-
|
304
|
-
# Returns non-+nil+ if this tag can contain child nodes.
|
305
|
-
def childless?(xml = false)
|
306
|
-
return false if xml && @closing.nil?
|
307
|
-
!@closing.nil? ||
|
308
|
-
@name =~ /^(img|br|hr|link|meta|area|base|basefont|
|
309
|
-
col|frame|input|isindex|param)$/ox
|
310
|
-
end
|
311
|
-
|
312
|
-
# Returns a textual representation of the node
|
313
|
-
def to_s
|
314
|
-
if @closing == :close
|
315
|
-
"</#{@name}>"
|
316
|
-
else
|
317
|
-
s = "<#{@name}"
|
318
|
-
@attributes.each do |k,v|
|
319
|
-
s << " #{k}"
|
320
|
-
s << "=\"#{v}\"" if String === v
|
321
|
-
end
|
322
|
-
s << " /" if @closing == :self
|
323
|
-
s << ">"
|
324
|
-
@children.each { |child| s << child.to_s }
|
325
|
-
s << "</#{@name}>" if @closing != :self && !@children.empty?
|
326
|
-
s
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
# If either the node or any of its children meet the given conditions, the
|
331
|
-
# matching node is returned. Otherwise, +nil+ is returned. (See the
|
332
|
-
# description of the valid conditions in the +match+ method.)
|
333
|
-
def find(conditions)
|
334
|
-
match(conditions) && self || super
|
335
|
-
end
|
336
|
-
|
337
|
-
# Returns +true+, indicating that this node represents an HTML tag.
|
338
|
-
def tag?
|
339
|
-
true
|
340
|
-
end
|
341
|
-
|
342
|
-
# Returns +true+ if the node meets any of the given conditions. The
|
343
|
-
# +conditions+ parameter must be a hash of any of the following keys
|
344
|
-
# (all are optional):
|
345
|
-
#
|
346
|
-
# * <tt>:tag</tt>: the node name must match the corresponding value
|
347
|
-
# * <tt>:attributes</tt>: a hash. The node's values must match the
|
348
|
-
# corresponding values in the hash.
|
349
|
-
# * <tt>:parent</tt>: a hash. The node's parent must match the
|
350
|
-
# corresponding hash.
|
351
|
-
# * <tt>:child</tt>: a hash. At least one of the node's immediate children
|
352
|
-
# must meet the criteria described by the hash.
|
353
|
-
# * <tt>:ancestor</tt>: a hash. At least one of the node's ancestors must
|
354
|
-
# meet the criteria described by the hash.
|
355
|
-
# * <tt>:descendant</tt>: a hash. At least one of the node's descendants
|
356
|
-
# must meet the criteria described by the hash.
|
357
|
-
# * <tt>:sibling</tt>: a hash. At least one of the node's siblings must
|
358
|
-
# meet the criteria described by the hash.
|
359
|
-
# * <tt>:after</tt>: a hash. The node must be after any sibling meeting
|
360
|
-
# the criteria described by the hash, and at least one sibling must match.
|
361
|
-
# * <tt>:before</tt>: a hash. The node must be before any sibling meeting
|
362
|
-
# the criteria described by the hash, and at least one sibling must match.
|
363
|
-
# * <tt>:children</tt>: a hash, for counting children of a node. Accepts the
|
364
|
-
# keys:
|
365
|
-
# ** <tt>:count</tt>: either a number or a range which must equal (or
|
366
|
-
# include) the number of children that match.
|
367
|
-
# ** <tt>:less_than</tt>: the number of matching children must be less than
|
368
|
-
# this number.
|
369
|
-
# ** <tt>:greater_than</tt>: the number of matching children must be
|
370
|
-
# greater than this number.
|
371
|
-
# ** <tt>:only</tt>: another hash consisting of the keys to use
|
372
|
-
# to match on the children, and only matching children will be
|
373
|
-
# counted.
|
374
|
-
#
|
375
|
-
# Conditions are matched using the following algorithm:
|
376
|
-
#
|
377
|
-
# * if the condition is a string, it must be a substring of the value.
|
378
|
-
# * if the condition is a regexp, it must match the value.
|
379
|
-
# * if the condition is a number, the value must match number.to_s.
|
380
|
-
# * if the condition is +true+, the value must not be +nil+.
|
381
|
-
# * if the condition is +false+ or +nil+, the value must be +nil+.
|
382
|
-
#
|
383
|
-
# Usage:
|
384
|
-
#
|
385
|
-
# # test if the node is a "span" tag
|
386
|
-
# node.match tag: "span"
|
387
|
-
#
|
388
|
-
# # test if the node's parent is a "div"
|
389
|
-
# node.match parent: { tag: "div" }
|
390
|
-
#
|
391
|
-
# # test if any of the node's ancestors are "table" tags
|
392
|
-
# node.match ancestor: { tag: "table" }
|
393
|
-
#
|
394
|
-
# # test if any of the node's immediate children are "em" tags
|
395
|
-
# node.match child: { tag: "em" }
|
396
|
-
#
|
397
|
-
# # test if any of the node's descendants are "strong" tags
|
398
|
-
# node.match descendant: { tag: "strong" }
|
399
|
-
#
|
400
|
-
# # test if the node has between 2 and 4 span tags as immediate children
|
401
|
-
# node.match children: { count: 2..4, only: { tag: "span" } }
|
402
|
-
#
|
403
|
-
# # get funky: test to see if the node is a "div", has a "ul" ancestor
|
404
|
-
# # and an "li" parent (with "class" = "enum"), and whether or not it has
|
405
|
-
# # a "span" descendant that contains # text matching /hello world/:
|
406
|
-
# node.match tag: "div",
|
407
|
-
# ancestor: { tag: "ul" },
|
408
|
-
# parent: { tag: "li",
|
409
|
-
# attributes: { class: "enum" } },
|
410
|
-
# descendant: { tag: "span",
|
411
|
-
# child: /hello world/ }
|
412
|
-
def match(conditions)
|
413
|
-
conditions = validate_conditions(conditions)
|
414
|
-
# check content of child nodes
|
415
|
-
if conditions[:content]
|
416
|
-
if children.empty?
|
417
|
-
return false unless match_condition("", conditions[:content])
|
418
|
-
else
|
419
|
-
return false unless children.find { |child| child.match(conditions[:content]) }
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
# test the name
|
424
|
-
return false unless match_condition(@name, conditions[:tag]) if conditions[:tag]
|
425
|
-
|
426
|
-
# test attributes
|
427
|
-
(conditions[:attributes] || {}).each do |key, value|
|
428
|
-
return false unless match_condition(self[key], value)
|
429
|
-
end
|
430
|
-
|
431
|
-
# test parent
|
432
|
-
return false unless parent.match(conditions[:parent]) if conditions[:parent]
|
433
|
-
|
434
|
-
# test children
|
435
|
-
return false unless children.find { |child| child.match(conditions[:child]) } if conditions[:child]
|
436
|
-
|
437
|
-
# test ancestors
|
438
|
-
if conditions[:ancestor]
|
439
|
-
return false unless catch :found do
|
440
|
-
p = self
|
441
|
-
throw :found, true if p.match(conditions[:ancestor]) while p = p.parent
|
442
|
-
end
|
443
|
-
end
|
444
|
-
|
445
|
-
# test descendants
|
446
|
-
if conditions[:descendant]
|
447
|
-
return false unless children.find do |child|
|
448
|
-
# test the child
|
449
|
-
child.match(conditions[:descendant]) ||
|
450
|
-
# test the child's descendants
|
451
|
-
child.match(:descendant => conditions[:descendant])
|
452
|
-
end
|
453
|
-
end
|
454
|
-
|
455
|
-
# count children
|
456
|
-
if opts = conditions[:children]
|
457
|
-
matches = children.select do |c|
|
458
|
-
(c.kind_of?(HTML::Tag) and (c.closing == :self or ! c.childless?))
|
459
|
-
end
|
460
|
-
|
461
|
-
matches = matches.select { |c| c.match(opts[:only]) } if opts[:only]
|
462
|
-
opts.each do |key, value|
|
463
|
-
next if key == :only
|
464
|
-
case key
|
465
|
-
when :count
|
466
|
-
if Integer === value
|
467
|
-
return false if matches.length != value
|
468
|
-
else
|
469
|
-
return false unless value.include?(matches.length)
|
470
|
-
end
|
471
|
-
when :less_than
|
472
|
-
return false unless matches.length < value
|
473
|
-
when :greater_than
|
474
|
-
return false unless matches.length > value
|
475
|
-
else raise "unknown count condition #{key}"
|
476
|
-
end
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
# test siblings
|
481
|
-
if conditions[:sibling] || conditions[:before] || conditions[:after]
|
482
|
-
siblings = parent ? parent.children : []
|
483
|
-
self_index = siblings.index(self)
|
484
|
-
|
485
|
-
if conditions[:sibling]
|
486
|
-
return false unless siblings.detect do |s|
|
487
|
-
s != self && s.match(conditions[:sibling])
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
if conditions[:before]
|
492
|
-
return false unless siblings[self_index+1..-1].detect do |s|
|
493
|
-
s != self && s.match(conditions[:before])
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
if conditions[:after]
|
498
|
-
return false unless siblings[0,self_index].detect do |s|
|
499
|
-
s != self && s.match(conditions[:after])
|
500
|
-
end
|
501
|
-
end
|
502
|
-
end
|
503
|
-
|
504
|
-
true
|
505
|
-
end
|
506
|
-
|
507
|
-
def ==(node)
|
508
|
-
return false unless super
|
509
|
-
return false unless closing == node.closing && self.name == node.name
|
510
|
-
attributes == node.attributes
|
511
|
-
end
|
512
|
-
|
513
|
-
private
|
514
|
-
# Match the given value to the given condition.
|
515
|
-
def match_condition(value, condition)
|
516
|
-
case condition
|
517
|
-
when String
|
518
|
-
value && value == condition
|
519
|
-
when Regexp
|
520
|
-
value && value.match(condition)
|
521
|
-
when Numeric
|
522
|
-
value == condition.to_s
|
523
|
-
when true
|
524
|
-
!value.nil?
|
525
|
-
when false, nil
|
526
|
-
value.nil?
|
527
|
-
else
|
528
|
-
false
|
529
|
-
end
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|