nice_partials 0.1.2 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +3 -0
- data/README.md +37 -20
- data/Rakefile +4 -4
- data/lib/nice_partials/helper.rb +18 -0
- data/lib/nice_partials/monkey_patch.rb +59 -0
- data/lib/nice_partials/partial.rb +15 -1
- data/lib/nice_partials/version.rb +1 -1
- data/lib/nice_partials.rb +12 -2
- data/nice_partials.gemspec +5 -1
- data/test/fixtures/_basic.html.erb +2 -0
- data/test/fixtures/_card.html.erb +13 -0
- data/test/fixtures/card_test.html.erb +9 -0
- data/test/renderer_test.rb +57 -0
- data/test/test_helper.rb +7 -0
- metadata +44 -8
- data/lib/partials.rb +0 -2
- data/spec/nice_partials_spec.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a2bc1c656f72b37d7766bd5353a4320fc516dd2bfa808352f8b96217991c78b
|
4
|
+
data.tar.gz: fefb7742857fec22b402f714ce10e5d4e6b33279b3fe7abdb84b1408b31cb38c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40b811eb0e0231da0ed04d023af718200400880dffac5e64cb8f8c80de2f30ae187fb0e4c43235d305f1a60e74c321b370c4ff6d07a18fc975becea8c5faa975
|
7
|
+
data.tar.gz: 9ae278eb935fc27bb1f7ae46bb71efcdbf84d3ef0157e0897f4412208a1c8864251a8f8cec5ea9961d01c1884f451b6695c2a8862d2456c4f7ee2698a124362a
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
# nice_partials [![[version]](https://badge.fury.io/rb/nice_partials.svg)](https://badge.fury.io/rb/nice_partials) [![[travis]](https://travis-ci.org/andrewculver/nice_partials.svg)](https://travis-ci.org/andrewculver/nice_partials)
|
2
2
|
|
3
|
-
Nice Partials
|
3
|
+
Nice Partials extends the concept of [`content_for` blocks and `yield`](https://guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method) for those times when a partial needs to provide one or more named "content areas" or "slots". This thin, optional layer of magic helps make traditional Rails view partials an even better fit for extracting components from your views, like so:
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
`app/views/partials/_card.html.erb`:
|
5
|
+
`app/views/components/_card.html.erb`:
|
8
6
|
```html+erb
|
9
7
|
<div class="card">
|
10
8
|
<%= p.yield :image %>
|
11
9
|
<div class="card-body">
|
12
10
|
<h5 class="card-title"><%= title %></h5>
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
<% if p.content_for? :body %>
|
12
|
+
<p class="card-text">
|
13
|
+
<%= p.yield :body %>
|
14
|
+
</p>
|
15
|
+
<% end %>
|
16
16
|
</div>
|
17
17
|
</div>
|
18
18
|
```
|
@@ -20,7 +20,7 @@ It allows your partials to define named content areas like this:
|
|
20
20
|
These partials can still be utilized with a standard `render` call, but you can specify how to populate the content areas like so:
|
21
21
|
|
22
22
|
```html+erb
|
23
|
-
<%= render '
|
23
|
+
<%= render 'components/card', title: 'Some Title' do |p| %>
|
24
24
|
<% p.content_for :body do %>
|
25
25
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
|
26
26
|
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
@@ -37,9 +37,20 @@ These partials can still be utilized with a standard `render` call, but you can
|
|
37
37
|
Nice Partials is a lightweight and hopefully more Rails-native alternative to [ViewComponent](http://viewcomponent.org). It aims to provide many of the same benefits as ViewComponent while requiring less ceremony. This specific approach originated with [Bullet Train](https://bullettrain.co)'s "Field Partials" and was later reimagined and completely reimplemented by Dom Christie.
|
38
38
|
|
39
39
|
|
40
|
+
## Sponsored By
|
41
|
+
|
42
|
+
<a href="https://bullettrain.co" target="_blank">
|
43
|
+
<img src="https://github.com/CanCanCommunity/cancancan/raw/develop/logo/bullet_train.png" alt="Bullet Train" width="400"/>
|
44
|
+
</a>
|
45
|
+
<br/>
|
46
|
+
<br/>
|
47
|
+
|
48
|
+
> Would you like to support Nice Partials development and have your logo featured here? [Reach out!](http://twitter.com/andrewculver)
|
49
|
+
|
50
|
+
|
40
51
|
## Benefits of Nice Partials
|
41
52
|
|
42
|
-
|
53
|
+
Nice Partials:
|
43
54
|
|
44
55
|
- is just regular Rails view partials like you're used to.
|
45
56
|
- reduces the friction when extracting components.
|
@@ -50,11 +61,7 @@ Compared to something more heavy-handed, Nice Partials:
|
|
50
61
|
- are still testable!
|
51
62
|
|
52
63
|
|
53
|
-
##
|
54
|
-
|
55
|
-
Nice Partials slightly extends the concept of [`content_for` blocks and `yield`](https://guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method) so they can be properly used to define and utilize "content areas" or "slots" in simple ERB partials.
|
56
|
-
|
57
|
-
### Can't I do the same thing without Nice Partials?
|
64
|
+
## Can't I do the same thing without Nice Partials?
|
58
65
|
|
59
66
|
You can almost accomplish the same thing without Nice Partials, but in practice you end up having to flush the content buffers after using them, leading to something like this:
|
60
67
|
|
@@ -64,10 +71,12 @@ You can almost accomplish the same thing without Nice Partials, but in practice
|
|
64
71
|
<% content_for :image, flush: true do '' end %>
|
65
72
|
<div class="card-body">
|
66
73
|
<h5 class="card-title"><%= title %></h5>
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
74
|
+
<% if content_for? :body %>
|
75
|
+
<p class="card-text">
|
76
|
+
<%= yield :body %>
|
77
|
+
<% content_for :body, flush: true do '' end %>
|
78
|
+
</p>
|
79
|
+
<% end %>
|
71
80
|
</div>
|
72
81
|
</div>
|
73
82
|
```
|
@@ -91,7 +100,7 @@ gem "nice_partials"
|
|
91
100
|
|
92
101
|
You only need to use Nice Partials when:
|
93
102
|
|
94
|
-
- you want to define
|
103
|
+
- you want to define one or more named content areas in your partial. If you don't have multiple named content areas in your partial, you could just pass your content into the partial using the standard block and `yield` approach.
|
95
104
|
|
96
105
|
- you want to specifically isolate your helper methods for a specific partial.
|
97
106
|
|
@@ -115,7 +124,7 @@ Here's what is happening here:
|
|
115
124
|
Once you've done this at the top of your partial file, you can then use `<%= p.yield :some_section %>` to render whatever content areas you want to be passed into your partial.
|
116
125
|
|
117
126
|
|
118
|
-
###
|
127
|
+
### Defining and using well isolated helper methods
|
119
128
|
|
120
129
|
To minimize the amount of pollution in the global helper namespace, you can use the shared context object to define helper methods specifically for your partials _within your partial_ like so:
|
121
130
|
|
@@ -141,6 +150,14 @@ Then later in the partial you can use the helper method like so:
|
|
141
150
|
<td><%= p.reference_to(user) %></td>
|
142
151
|
```
|
143
152
|
|
153
|
+
## Development
|
154
|
+
|
155
|
+
### Testing
|
156
|
+
|
157
|
+
```sh
|
158
|
+
bundle exec rake test
|
159
|
+
```
|
160
|
+
|
144
161
|
## MIT License
|
145
162
|
|
146
163
|
Copyright (C) 2020 Andrew Culver <https://bullettrain.co> and Dom Christie <https://domchristie.co.uk>. Released under the MIT license.
|
data/Rakefile
CHANGED
@@ -30,8 +30,8 @@ end
|
|
30
30
|
# # #
|
31
31
|
# Run specs
|
32
32
|
|
33
|
-
desc "#{gemspec.name} |
|
34
|
-
task :
|
35
|
-
sh "for file in
|
33
|
+
desc "#{gemspec.name} | Test"
|
34
|
+
task :test do
|
35
|
+
sh "for file in test/*_test.rb; do ruby $file; done"
|
36
36
|
end
|
37
|
-
task default: :
|
37
|
+
task default: :test
|
data/lib/nice_partials/helper.rb
CHANGED
@@ -4,4 +4,22 @@ module NicePartials::Helper
|
|
4
4
|
def np
|
5
5
|
NicePartials::Partial.new(self)
|
6
6
|
end
|
7
|
+
|
8
|
+
def nice_partials_push_t_prefix(prefix)
|
9
|
+
@_nice_partials_t_prefixes ||= []
|
10
|
+
@_nice_partials_t_prefixes << prefix
|
11
|
+
end
|
12
|
+
|
13
|
+
def nice_partials_pop_t_prefix
|
14
|
+
@_nice_partials_t_prefixes ||= []
|
15
|
+
@_nice_partials_t_prefixes.pop
|
16
|
+
end
|
17
|
+
|
18
|
+
def t(key, options = {})
|
19
|
+
if @_nice_partials_t_prefixes&.any? && key.first == '.'
|
20
|
+
key = "#{@_nice_partials_t_prefixes.last}#{key}"
|
21
|
+
end
|
22
|
+
|
23
|
+
super(key, **options)
|
24
|
+
end
|
7
25
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# Monkey patch required to make `t` work as expected. Is this evil?
|
2
|
+
# TODO Do we need to monkey patch other types of renderers as well?
|
3
|
+
class ActionView::PartialRenderer
|
4
|
+
alias_method :original_render, :render
|
5
|
+
|
6
|
+
# See `content_for` in `lib/nice_partials/partial.rb` for something similar.
|
7
|
+
def render(partial, context, block)
|
8
|
+
if block
|
9
|
+
partial_prefix = nice_partials_locale_prefix_from_view_context_and_block(context, block)
|
10
|
+
context.nice_partials_push_t_prefix partial_prefix
|
11
|
+
else
|
12
|
+
# Render partial calls with no block should disable any prefix magic.
|
13
|
+
context.nice_partials_push_t_prefix ''
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
result = original_render(partial, context, block)
|
18
|
+
rescue Exception => exception
|
19
|
+
# If there was some sort of exception thrown, we also need to pop the `t` prefix.
|
20
|
+
# This provides compatibility with other libraries that depend on catching exceptions from the view renderer.
|
21
|
+
context.nice_partials_pop_t_prefix
|
22
|
+
raise exception
|
23
|
+
end
|
24
|
+
|
25
|
+
# Whether there was a block or not, pop off whatever we put on the stack.
|
26
|
+
context.nice_partials_pop_t_prefix
|
27
|
+
|
28
|
+
return result
|
29
|
+
end
|
30
|
+
|
31
|
+
# This and ActionView::Template#render below are for compatibility
|
32
|
+
# with Ruby 3, as opposed to altering the original functionality.
|
33
|
+
def render_partial_template(view, locals, template, layout, block)
|
34
|
+
ActiveSupport::Notifications.instrument(
|
35
|
+
"render_partial.action_view",
|
36
|
+
identifier: template.identifier,
|
37
|
+
layout: layout && layout.virtual_path
|
38
|
+
) do |payload|
|
39
|
+
content = template.render(view, locals, ActionView::OutputBuffer.new, {add_to_stack: !block}) do |*name|
|
40
|
+
view._layout_for(*name, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
content = layout.render(view, locals) { content } if layout
|
44
|
+
payload[:cache_hit] = view.view_renderer.cache_hits[template.virtual_path]
|
45
|
+
build_rendered_template(content, template)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class ActionView::Template
|
51
|
+
def render(view, locals, buffer = ActionView::OutputBuffer.new, flag = {add_to_stack: true}, &block)
|
52
|
+
instrument_render_template do
|
53
|
+
compile!(view)
|
54
|
+
view._run(method_name, self, locals, buffer, **flag, &block)
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
handle_render_error(view, e)
|
58
|
+
end
|
59
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module NicePartials
|
2
2
|
class Partial
|
3
|
+
delegate_missing_to :@view_context
|
4
|
+
|
3
5
|
def initialize(view_context)
|
4
6
|
@view_context = view_context
|
5
7
|
@key = SecureRandom.uuid
|
@@ -14,8 +16,20 @@ module NicePartials
|
|
14
16
|
class_eval &block
|
15
17
|
end
|
16
18
|
|
19
|
+
# See the `ActionView::PartialRenderer` monkey patch in `lib/nice_partials/monkey_patch.rb` for something similar.
|
17
20
|
def content_for(name, content = nil, options = {}, &block)
|
18
|
-
|
21
|
+
if block_given?
|
22
|
+
partial_prefix = nice_partials_locale_prefix_from_view_context_and_block(@view_context, block)
|
23
|
+
@view_context.nice_partials_push_t_prefix(partial_prefix)
|
24
|
+
end
|
25
|
+
|
26
|
+
result = @view_context.content_for("#{name}_#{@key}".to_sym, content, options, &block)
|
27
|
+
|
28
|
+
if block_given?
|
29
|
+
@view_context.nice_partials_pop_t_prefix
|
30
|
+
end
|
31
|
+
|
32
|
+
return result
|
19
33
|
end
|
20
34
|
|
21
35
|
def content_for?(name)
|
data/lib/nice_partials.rb
CHANGED
@@ -2,9 +2,19 @@
|
|
2
2
|
|
3
3
|
require_relative "nice_partials/version"
|
4
4
|
require_relative "nice_partials/helper"
|
5
|
-
require_relative "
|
5
|
+
require_relative "nice_partials/monkey_patch"
|
6
6
|
|
7
7
|
module NicePartials
|
8
8
|
end
|
9
9
|
|
10
|
-
|
10
|
+
# TODO Is there somewhere better we can put this?
|
11
|
+
def nice_partials_locale_prefix_from_view_context_and_block(context, block)
|
12
|
+
root_paths = context.view_renderer.lookup_context.view_paths.map(&:path)
|
13
|
+
partial_location = block.source_location.first.dup
|
14
|
+
root_paths.each { |path| partial_location.gsub!(/^#{path}\//, '') }
|
15
|
+
partial_location.split('.').first.gsub('/_', '/').gsub('/', '.')
|
16
|
+
end
|
17
|
+
|
18
|
+
ActiveSupport.on_load :action_view do
|
19
|
+
include NicePartials::Helper
|
20
|
+
end
|
data/nice_partials.gemspec
CHANGED
@@ -17,5 +17,9 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
gem.require_paths = ["lib"]
|
19
19
|
|
20
|
-
gem.required_ruby_version = "
|
20
|
+
gem.required_ruby_version = ">= 2.0"
|
21
|
+
|
22
|
+
gem.add_dependency "actionview", '>= 4.2.6'
|
23
|
+
|
24
|
+
gem.add_development_dependency "rails"
|
21
25
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% yield p = np %>
|
2
|
+
|
3
|
+
<div class="card">
|
4
|
+
<%= p.yield :image %>
|
5
|
+
<div class="card-body">
|
6
|
+
<h5 class="card-title"><%= title %></h5>
|
7
|
+
<% if p.content_for? :body %>
|
8
|
+
<p class="card-text">
|
9
|
+
<%= p.content_for :body %>
|
10
|
+
</p>
|
11
|
+
<% end %>
|
12
|
+
</div>
|
13
|
+
</div>
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative "./test_helper"
|
2
|
+
|
3
|
+
class RendererTest < ActiveSupport::TestCase
|
4
|
+
# from actionview/render_test
|
5
|
+
class TestController < ActionController::Base
|
6
|
+
end
|
7
|
+
|
8
|
+
def setup_view(paths)
|
9
|
+
ActionView::Base.include(NicePartials::Helper)
|
10
|
+
|
11
|
+
@assigns = { secret: "in the sauce" }
|
12
|
+
|
13
|
+
@view = Class.new(ActionView::Base.with_empty_template_cache) do
|
14
|
+
def view_cache_dependencies; []; end
|
15
|
+
|
16
|
+
def combined_fragment_cache_key(key)
|
17
|
+
[:views, key]
|
18
|
+
end
|
19
|
+
end.with_view_paths(paths, @assigns)
|
20
|
+
|
21
|
+
controller = TestController.new
|
22
|
+
controller.perform_caching = true
|
23
|
+
controller.cache_store = :memory_store
|
24
|
+
@view.controller = controller
|
25
|
+
|
26
|
+
@controller_view = controller.view_context_class.with_empty_template_cache.new(
|
27
|
+
controller.lookup_context,
|
28
|
+
controller.view_assigns,
|
29
|
+
controller)
|
30
|
+
end
|
31
|
+
|
32
|
+
def setup
|
33
|
+
ActionView::LookupContext::DetailsKey.clear
|
34
|
+
path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
|
35
|
+
view_paths = ActionView::PathSet.new([path])
|
36
|
+
assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first
|
37
|
+
setup_view(view_paths)
|
38
|
+
end
|
39
|
+
|
40
|
+
def teardown
|
41
|
+
ActionController::Base.view_paths.map(&:clear_cache)
|
42
|
+
end
|
43
|
+
|
44
|
+
test "render basic nice partial" do
|
45
|
+
rendered = @view.render("basic") { |p| p.content_for :message, "hello from nice partials" }.squish
|
46
|
+
|
47
|
+
assert_equal "hello from nice partials", rendered
|
48
|
+
end
|
49
|
+
|
50
|
+
test "render nice partial in card template" do
|
51
|
+
rendered = @view.render(template: "card_test").squish
|
52
|
+
|
53
|
+
assert_match "Some Title", rendered
|
54
|
+
assert_match "Lorem Ipsum", rendered
|
55
|
+
assert_match "https://example.com/image.jpg", rendered
|
56
|
+
end
|
57
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nice_partials
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
@@ -9,8 +9,36 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
12
|
+
date: 2022-02-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: actionview
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 4.2.6
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 4.2.6
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rails
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
14
42
|
description: A little bit of magic to make partials perfect for components.
|
15
43
|
email:
|
16
44
|
- andrew.culver@gmail.com
|
@@ -29,11 +57,15 @@ files:
|
|
29
57
|
- Rakefile
|
30
58
|
- lib/nice_partials.rb
|
31
59
|
- lib/nice_partials/helper.rb
|
60
|
+
- lib/nice_partials/monkey_patch.rb
|
32
61
|
- lib/nice_partials/partial.rb
|
33
62
|
- lib/nice_partials/version.rb
|
34
|
-
- lib/partials.rb
|
35
63
|
- nice_partials.gemspec
|
36
|
-
-
|
64
|
+
- test/fixtures/_basic.html.erb
|
65
|
+
- test/fixtures/_card.html.erb
|
66
|
+
- test/fixtures/card_test.html.erb
|
67
|
+
- test/renderer_test.rb
|
68
|
+
- test/test_helper.rb
|
37
69
|
homepage: https://github.com/bullet-train-co/nice_partials
|
38
70
|
licenses:
|
39
71
|
- MIT
|
@@ -44,7 +76,7 @@ require_paths:
|
|
44
76
|
- lib
|
45
77
|
required_ruby_version: !ruby/object:Gem::Requirement
|
46
78
|
requirements:
|
47
|
-
- - "
|
79
|
+
- - ">="
|
48
80
|
- !ruby/object:Gem::Version
|
49
81
|
version: '2.0'
|
50
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
@@ -53,9 +85,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
85
|
- !ruby/object:Gem::Version
|
54
86
|
version: '0'
|
55
87
|
requirements: []
|
56
|
-
rubygems_version: 3.
|
88
|
+
rubygems_version: 3.2.22
|
57
89
|
signing_key:
|
58
90
|
specification_version: 4
|
59
91
|
summary: A little bit of magic to make partials perfect for components.
|
60
92
|
test_files:
|
61
|
-
-
|
93
|
+
- test/fixtures/_basic.html.erb
|
94
|
+
- test/fixtures/_card.html.erb
|
95
|
+
- test/fixtures/card_test.html.erb
|
96
|
+
- test/renderer_test.rb
|
97
|
+
- test/test_helper.rb
|
data/lib/partials.rb
DELETED