actionview-component 1.3.6 → 1.4.0
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/.github/workflows/ruby_on_rails.yml +2 -6
- data/CHANGELOG.md +22 -0
- data/Gemfile.lock +2 -2
- data/README.md +17 -2
- data/actionview-component.gemspec +1 -1
- data/lib/action_view/component/base.rb +94 -46
- data/lib/action_view/component/test_helpers.rb +9 -1
- data/lib/action_view/component/version.rb +2 -2
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 30f9a7b6c2e7f0549743bf979ce3db726539f9c1f9391cb4f2f34e6d955b8689
|
|
4
|
+
data.tar.gz: 6db7efd3c77edbdacfa376d78729c8092848fc48176378a0677b50e6cd110433
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd86da9ed9d6be7b8397711cde1da635d657630b1864da03e297e87596395476d84bbafb4c84447b4518207ead5cbe2f905b6b7fc95f10b96cfe0b2bd5e9fcc5
|
|
7
|
+
data.tar.gz: d42213b009dfbd75489be053daab29fa0c74614f8657d308a08254c72ba31327933d0683d5c4ad6df43d1cdf63b86236ef3cda9e6b23b9b883ba987c1692b719
|
|
@@ -8,22 +8,18 @@ jobs:
|
|
|
8
8
|
strategy:
|
|
9
9
|
matrix:
|
|
10
10
|
rails_version: [5.0.0, 5.2.3, 6.0.0, master]
|
|
11
|
-
ruby_version: [2.
|
|
11
|
+
ruby_version: [2.4.x, 2.5.x, 2.6.x]
|
|
12
12
|
exclude:
|
|
13
13
|
- rails_version: master
|
|
14
14
|
ruby_version: 2.4.x
|
|
15
|
-
- rails_version: master
|
|
16
|
-
ruby_version: 2.3.x
|
|
17
15
|
- rails_version: 6.0.0
|
|
18
16
|
ruby_version: 2.4.x
|
|
19
|
-
- rails_version: 6.0.0
|
|
20
|
-
ruby_version: 2.3.x
|
|
21
17
|
steps:
|
|
22
18
|
- uses: actions/checkout@master
|
|
23
19
|
- name: Setup Ruby
|
|
24
20
|
uses: actions/setup-ruby@v1
|
|
25
21
|
with:
|
|
26
|
-
version: ${{ matrix.ruby_version }}
|
|
22
|
+
ruby-version: ${{ matrix.ruby_version }}
|
|
27
23
|
- name: Build and test with Rake
|
|
28
24
|
run: |
|
|
29
25
|
gem install bundler:1.14.0
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
# v1.4.0
|
|
2
|
+
|
|
3
|
+
* Fix bug where components broke in application paths with periods.
|
|
4
|
+
|
|
5
|
+
*Anton, Joel Hawksley*
|
|
6
|
+
|
|
7
|
+
* Add support for `cache_if` in component templates.
|
|
8
|
+
|
|
9
|
+
*Aaron Patterson, Joel Hawksley*
|
|
10
|
+
|
|
11
|
+
* Add support for variants.
|
|
12
|
+
|
|
13
|
+
*Juan Manuel Ramallo*
|
|
14
|
+
|
|
15
|
+
* Fix bug in virtual path lookup.
|
|
16
|
+
|
|
17
|
+
*Juan Manuel Ramallo*
|
|
18
|
+
|
|
19
|
+
* Preselect the rendered component in render_inline.
|
|
20
|
+
|
|
21
|
+
*Elia Schito*
|
|
22
|
+
|
|
1
23
|
# v1.3.6
|
|
2
24
|
|
|
3
25
|
* Allow template file names without format.
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
actionview-component (1.
|
|
4
|
+
actionview-component (1.4.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -168,7 +168,7 @@ DEPENDENCIES
|
|
|
168
168
|
minitest (= 5.1.0)
|
|
169
169
|
rails (= 6.0.0)
|
|
170
170
|
rake (~> 10.0)
|
|
171
|
-
rubocop (
|
|
171
|
+
rubocop (= 0.74)
|
|
172
172
|
rubocop-github (~> 0.13.0)
|
|
173
173
|
slim (~> 4.0)
|
|
174
174
|
|
data/README.md
CHANGED
|
@@ -15,7 +15,7 @@ As the goal of this gem is to be upstreamed into Rails, it is designed to integr
|
|
|
15
15
|
|
|
16
16
|
## Compatibility
|
|
17
17
|
|
|
18
|
-
`actionview-component` is tested for compatibility with combinations of Ruby `2.
|
|
18
|
+
`actionview-component` is tested for compatibility with combinations of Ruby `2.4`/`2.5`/`2.6` and Rails `5.0.0`/`5.2.3`/`6.0.0`/`6.1.0.alpha`.
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
21
21
|
Add this line to your application's Gemfile:
|
|
@@ -178,7 +178,7 @@ class MyComponentTest < Minitest::Test
|
|
|
178
178
|
def test_render_component
|
|
179
179
|
assert_equal(
|
|
180
180
|
%(<span title="my title">Hello, World!</span>),
|
|
181
|
-
render_inline(TestComponent, title: "my title") { "Hello, World!" }.
|
|
181
|
+
render_inline(TestComponent, title: "my title") { "Hello, World!" }.to_html
|
|
182
182
|
)
|
|
183
183
|
end
|
|
184
184
|
end
|
|
@@ -186,6 +186,21 @@ end
|
|
|
186
186
|
|
|
187
187
|
In general, we’ve found it makes the most sense to test components based on their rendered HTML.
|
|
188
188
|
|
|
189
|
+
#### Action Pack Variants
|
|
190
|
+
|
|
191
|
+
To test a specific variant you can wrap your test with the `with_variant` helper method as:
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
def test_render_component_for_tablet
|
|
195
|
+
with_variant :tablet do
|
|
196
|
+
assert_equal(
|
|
197
|
+
%(<span title="my title">Hello, tablets!</span>),
|
|
198
|
+
render_inline(TestComponent, title: "my title") { "Hello, tablets!" }.css("span").to_html
|
|
199
|
+
)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
```
|
|
203
|
+
|
|
189
204
|
## Frequently Asked Questions
|
|
190
205
|
|
|
191
206
|
### Can I use other templating languages besides ERB?
|
|
@@ -39,6 +39,6 @@ Gem::Specification.new do |spec|
|
|
|
39
39
|
spec.add_development_dependency "minitest", "= 5.1.0"
|
|
40
40
|
spec.add_development_dependency "haml", "~> 5"
|
|
41
41
|
spec.add_development_dependency "slim", "~> 4.0"
|
|
42
|
-
spec.add_development_dependency "rubocop", "
|
|
42
|
+
spec.add_development_dependency "rubocop", "= 0.74"
|
|
43
43
|
spec.add_development_dependency "rubocop-github", "~> 0.13.0"
|
|
44
44
|
end
|
|
@@ -9,7 +9,7 @@ class ActionView::Base
|
|
|
9
9
|
def render(options = {}, args = {}, &block)
|
|
10
10
|
if options.respond_to?(:render_in)
|
|
11
11
|
ActiveSupport::Deprecation.warn(
|
|
12
|
-
"passing component instances
|
|
12
|
+
"passing component instances (`render MyComponent.new(foo: :bar)`) has been deprecated and will be removed in v2.0.0. Use `render MyComponent, foo: :bar` instead."
|
|
13
13
|
)
|
|
14
14
|
|
|
15
15
|
options.render_in(self, &block)
|
|
@@ -33,6 +33,8 @@ module ActionView
|
|
|
33
33
|
include ActiveSupport::Configurable
|
|
34
34
|
include ActionController::RequestForgeryProtection
|
|
35
35
|
|
|
36
|
+
validate :variant_exists
|
|
37
|
+
|
|
36
38
|
# Entrypoint for rendering components. Called by ActionView::Base#render.
|
|
37
39
|
#
|
|
38
40
|
# view_context: ActionView context from calling view
|
|
@@ -65,10 +67,16 @@ module ActionView
|
|
|
65
67
|
@lookup_context ||= view_context.lookup_context
|
|
66
68
|
@view_flow ||= view_context.view_flow
|
|
67
69
|
@virtual_path ||= virtual_path
|
|
70
|
+
@variant = @lookup_context.variants.first
|
|
71
|
+
old_current_template = @current_template
|
|
72
|
+
@current_template = self
|
|
68
73
|
|
|
69
74
|
@content = view_context.capture(&block) if block_given?
|
|
70
75
|
validate!
|
|
71
|
-
|
|
76
|
+
|
|
77
|
+
send(self.class.call_method_name(@variant))
|
|
78
|
+
ensure
|
|
79
|
+
@current_template = old_current_template
|
|
72
80
|
end
|
|
73
81
|
|
|
74
82
|
def initialize(*); end
|
|
@@ -88,9 +96,31 @@ module ActionView
|
|
|
88
96
|
# Looks for the source file path of the initialize method of the instance's class.
|
|
89
97
|
# Removes the first part of the path and the extension.
|
|
90
98
|
def virtual_path
|
|
91
|
-
self.class.source_location.gsub(%r{(.*app/)|(
|
|
99
|
+
self.class.source_location.gsub(%r{(.*app/)|(\.rb)}, "")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def view_cache_dependencies
|
|
103
|
+
[]
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def format # :nodoc:
|
|
107
|
+
@variant
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
def variant_exists
|
|
113
|
+
return if self.class.variants.include?(@variant) || @variant.nil?
|
|
114
|
+
|
|
115
|
+
errors.add(:variant, "'#{@variant}' has no template defined")
|
|
92
116
|
end
|
|
93
117
|
|
|
118
|
+
def request
|
|
119
|
+
@request ||= controller.request
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
attr_reader :content, :view_context
|
|
123
|
+
|
|
94
124
|
class << self
|
|
95
125
|
def inherited(child)
|
|
96
126
|
child.include Rails.application.routes.url_helpers unless child < Rails.application.routes.url_helpers
|
|
@@ -98,64 +128,90 @@ module ActionView
|
|
|
98
128
|
super
|
|
99
129
|
end
|
|
100
130
|
|
|
131
|
+
def call_method_name(variant)
|
|
132
|
+
if variant.present?
|
|
133
|
+
"call_#{variant}"
|
|
134
|
+
else
|
|
135
|
+
"call"
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
101
139
|
def source_location
|
|
140
|
+
# Require #initialize to be defined so that we can use
|
|
141
|
+
# method#source_location to look up the file name
|
|
142
|
+
# of the component.
|
|
143
|
+
#
|
|
144
|
+
# If we were able to only support Ruby 2.7+,
|
|
145
|
+
# We could just use Module#const_source_location,
|
|
146
|
+
# rendering this unnecessary.
|
|
147
|
+
raise NotImplementedError.new("#{self} must implement #initialize.") unless self.instance_method(:initialize).owner == self
|
|
148
|
+
|
|
102
149
|
instance_method(:initialize).source_location[0]
|
|
103
150
|
end
|
|
104
151
|
|
|
105
|
-
# Compile
|
|
152
|
+
# Compile templates to instance methods, assuming they haven't been compiled already.
|
|
106
153
|
# We could in theory do this on app boot, at least in production environments.
|
|
107
|
-
# Right now this just compiles the
|
|
154
|
+
# Right now this just compiles the first time the component is rendered.
|
|
108
155
|
def compile
|
|
109
156
|
return if @compiled && ActionView::Base.cache_template_loading
|
|
110
|
-
ensure_initializer_defined
|
|
111
157
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
158
|
+
validate_templates
|
|
159
|
+
|
|
160
|
+
templates.each do |template|
|
|
161
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
162
|
+
def #{call_method_name(template[:variant])}
|
|
163
|
+
@output_buffer = ActionView::OutputBuffer.new
|
|
164
|
+
#{compiled_template(template[:path])}
|
|
165
|
+
end
|
|
166
|
+
RUBY
|
|
167
|
+
end
|
|
118
168
|
|
|
119
169
|
@compiled = true
|
|
120
170
|
end
|
|
121
171
|
|
|
172
|
+
def variants
|
|
173
|
+
templates.map { |template| template[:variant] }
|
|
174
|
+
end
|
|
175
|
+
|
|
122
176
|
private
|
|
123
177
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
178
|
+
def templates
|
|
179
|
+
@templates ||=
|
|
180
|
+
(Dir["#{source_location.sub(/#{File.extname(source_location)}$/, '')}.*{#{ActionView::Template.template_handler_extensions.join(',')}}"] - [source_location]).each_with_object([]) do |path, memo|
|
|
181
|
+
memo << {
|
|
182
|
+
path: path,
|
|
183
|
+
variant: path.split(".").second.split("+")[1]&.to_sym,
|
|
184
|
+
handler: path.split(".").last
|
|
185
|
+
}
|
|
186
|
+
end
|
|
133
187
|
end
|
|
134
188
|
|
|
135
|
-
def
|
|
136
|
-
|
|
137
|
-
|
|
189
|
+
def validate_templates
|
|
190
|
+
if templates.empty?
|
|
191
|
+
raise NotImplementedError.new("Could not find a template file for #{self}.")
|
|
192
|
+
end
|
|
138
193
|
|
|
139
|
-
if
|
|
140
|
-
|
|
141
|
-
else
|
|
142
|
-
handler.call(DummyTemplate.new(template))
|
|
194
|
+
if templates.select { |template| template[:variant].nil? }.length > 1
|
|
195
|
+
raise StandardError.new("More than one template found for #{self}. There can only be one default template file per component.")
|
|
143
196
|
end
|
|
144
|
-
end
|
|
145
197
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
Dir["#{source_location.split(".")[0]}.*{#{ActionView::Template.template_handler_extensions.join(',')}}"] - [source_location]
|
|
198
|
+
variants.each_with_object(Hash.new(0)) { |variant, counts| counts[variant] += 1 }.each do |variant, count|
|
|
199
|
+
next unless count > 1
|
|
149
200
|
|
|
150
|
-
|
|
151
|
-
raise StandardError.new("More than one template found for #{self}. There can only be one sidecar template file per component.")
|
|
201
|
+
raise StandardError.new("More than one template found for variant '#{variant}' in #{self}. There can only be one template file per variant.")
|
|
152
202
|
end
|
|
203
|
+
end
|
|
153
204
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
205
|
+
def compiled_template(file_path)
|
|
206
|
+
handler = ActionView::Template.handler_for_extension(File.extname(file_path).gsub(".", ""))
|
|
207
|
+
template = File.read(file_path)
|
|
157
208
|
|
|
158
|
-
|
|
209
|
+
# This can be removed once this code is merged into Rails
|
|
210
|
+
if handler.method(:call).parameters.length > 1
|
|
211
|
+
handler.call(DummyTemplate.new, template)
|
|
212
|
+
else
|
|
213
|
+
handler.call(DummyTemplate.new(template))
|
|
214
|
+
end
|
|
159
215
|
end
|
|
160
216
|
end
|
|
161
217
|
|
|
@@ -175,14 +231,6 @@ module ActionView
|
|
|
175
231
|
"text/html"
|
|
176
232
|
end
|
|
177
233
|
end
|
|
178
|
-
|
|
179
|
-
private
|
|
180
|
-
|
|
181
|
-
def request
|
|
182
|
-
@request ||= controller.request
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
attr_reader :content, :view_context
|
|
186
234
|
end
|
|
187
235
|
end
|
|
188
236
|
end
|
|
@@ -4,7 +4,7 @@ module ActionView
|
|
|
4
4
|
module Component
|
|
5
5
|
module TestHelpers
|
|
6
6
|
def render_inline(component, **args, &block)
|
|
7
|
-
Nokogiri::HTML(controller.view_context.render(component, args, &block))
|
|
7
|
+
Nokogiri::HTML(controller.view_context.render(component, args, &block)).css("body > *")
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
def controller
|
|
@@ -22,6 +22,14 @@ module ActionView
|
|
|
22
22
|
|
|
23
23
|
render_inline(component, args, &block)
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
def with_variant(variant)
|
|
27
|
+
old_variants = controller.view_context.lookup_context.variants
|
|
28
|
+
|
|
29
|
+
controller.view_context.lookup_context.variants = variant
|
|
30
|
+
yield
|
|
31
|
+
controller.view_context.lookup_context.variants = old_variants
|
|
32
|
+
end
|
|
25
33
|
end
|
|
26
34
|
end
|
|
27
35
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: actionview-component
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitHub Open Source
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-
|
|
11
|
+
date: 2019-11-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -84,16 +84,16 @@ dependencies:
|
|
|
84
84
|
name: rubocop
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- -
|
|
87
|
+
- - '='
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0.
|
|
89
|
+
version: '0.74'
|
|
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: '0.
|
|
96
|
+
version: '0.74'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
98
|
name: rubocop-github
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|