nice_partials 0.1.0 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 80f4ce71d7a0d70adfd7f7c6775178df6705bd74fc520d7d81e1f28ab2b4b831
4
- data.tar.gz: 37bfd17903477aad2e7cdfc2a0eb8a42a36749851e445be88c1172a013b58fba
3
+ metadata.gz: 3275a33c9f1de9e8267042ab36b485297451804bb1c704082576890d800a20cd
4
+ data.tar.gz: 7b55dd85d2d291eb411b564819c602e039dc412ec8cbb82df7b58f8472d062e4
5
5
  SHA512:
6
- metadata.gz: 44aeee28bb6aaa22fcb7f3021c49142d6c463ab7f72e083a73c0f0465a7dd96296e5a13271ea74e711ae4905d2f7deadfe89e1b12886c5af6332a3d75b8ce595
7
- data.tar.gz: 90262c8cb7eafae7d7f0b88b4a36ac2e4e41acd1d3e78957e4a6016136b4f788de9d0cd274480774f0f63e9a81cc43e8b040ac980ce91bc0b343dfcd417387e2
6
+ metadata.gz: ef49218a25d20bb8b0446b5b0dd975fb173191ea1e236e9dfa6a700fec717ef9b24f8f06fcc114b4e1e731ddf62aed143cd225193cd6ebc64acb4fd06edb0e3b
7
+ data.tar.gz: 52e0f030102269996e35132ad2ff16bcb94100faca76787b13059a31450c0d65456961b71bf69d2610f46bb8f48a9b410f4a01090c96f946d2d5b1ec6ece9b8c
data/.travis.yml CHANGED
@@ -2,6 +2,7 @@ sudo: false
2
2
  language: ruby
3
3
 
4
4
  rvm:
5
+ - 3.0
5
6
  - 2.7
6
7
  - 2.6
7
8
  - 2.5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,8 @@
1
1
  ## CHANGELOG
2
2
 
3
+ * Rely on `ActiveSupport.on_load :action_view`
4
+ * Add support for Ruby 3.0
5
+
3
6
  ### 0.1.0
4
7
 
5
8
  * Initial release
data/README.md CHANGED
@@ -1,6 +1,89 @@
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
- TODO
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
+
5
+ `app/views/components/_card.html.erb`:
6
+ ```html+erb
7
+ <div class="card">
8
+ <%= p.yield :image %>
9
+ <div class="card-body">
10
+ <h5 class="card-title"><%= title %></h5>
11
+ <% if p.content_for? :body %>
12
+ <p class="card-text">
13
+ <%= p.yield :body %>
14
+ </p>
15
+ <% end %>
16
+ </div>
17
+ </div>
18
+ ```
19
+
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
+
22
+ ```html+erb
23
+ <%= render 'components/card', title: 'Some Title' do |p| %>
24
+ <% p.content_for :body do %>
25
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
26
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
27
+ <strong>quis nostrud exercitation ullamco laboris</strong> nisi ut aliquip
28
+ ex ea commodo consequat.
29
+ <% end %>
30
+
31
+ <% p.content_for :image do %>
32
+ <%= image_tag image_path('example.jpg'), alt: 'An example image' %>
33
+ <% end %>
34
+ <% end %>
35
+ ```
36
+
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
+
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
+
51
+ ## Benefits of Nice Partials
52
+
53
+ Compared to something more heavy-handed, Nice Partials:
54
+
55
+ - is just regular Rails view partials like you're used to.
56
+ - reduces the friction when extracting components.
57
+ - only ends up in the specific partials you need its functionality in.
58
+ - reduces context switching.
59
+ - allows isolated helper logic alongside your partial view code.
60
+ - doesn't require any upgrades to existing partials for interoperability.
61
+ - are still testable!
62
+
63
+
64
+ ## Can't I do the same thing without Nice Partials?
65
+
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:
67
+
68
+ ```html+erb
69
+ <div class="card">
70
+ <%= yield :image %>
71
+ <% content_for :image, flush: true do '' end %>
72
+ <div class="card-body">
73
+ <h5 class="card-title"><%= title %></h5>
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 %>
80
+ </div>
81
+ </div>
82
+ ```
83
+
84
+ Earlier iterations of Nice Partials aimed to simply clean up this syntax with helper methods like `flush_content_for`, but because the named content buffers were in a global namespace, it was also possible to accidentally create situations where two partials with a `:body` content area would end up interfering with each other, depending on the order they're nested and rendered.
85
+
86
+ Nice Partials resolves the last-mile issues with standard view partials and content buffers by introducing a small, generic object that helps transparently namespace your named content buffers. This same object can also be used to define helper methods specific to your partial that are isolated from the global helper namespace.
4
87
 
5
88
 
6
89
  ## Setup
@@ -11,12 +94,61 @@ Add to your `Gemfile`:
11
94
  gem "nice_partials"
12
95
  ```
13
96
 
14
-
15
97
  ## Usage
16
98
 
17
- ```ruby
99
+ ### When to use Nice Partials
100
+
101
+ You only need to use Nice Partials when:
102
+
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.
104
+
105
+ - you want to specifically isolate your helper methods for a specific partial.
106
+
107
+ ### Use Nice Partials in a partial
108
+
109
+ To invoke nice partials, start your partial file with the following:
110
+
111
+ ```html+erb
112
+ <% yield p = np %>
18
113
  ```
19
114
 
115
+ Here's what is happening here:
116
+
117
+ - `yield` executes the block we receive when someone uses our partial.
118
+ - `np` fetches an instance of the generic class that helps isolate our content buffers and helper methods.
119
+ - `p = np` ensures we have a reference to that object in this partial.
120
+ - `yield p = np` ensures the developer using this partial also has a reference to that object, so they can define what goes in the various content buffers.
121
+
122
+ (This is, [as far as we know](https://github.com/bullet-train-co/nice_partials/issues/1), the minimum viable invocation.)
123
+
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.
125
+
126
+
127
+ ### Defining and using well isolated helper methods
128
+
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:
130
+
131
+ ```html+erb
132
+ <% p.helpers do
133
+
134
+ # references should be a link if the user can drill down, otherwise just a text label.
135
+ def reference_to(user)
136
+ # look! this method has access to the scope of the entire view context and all the other helpers that come with it!
137
+ if can? :show, user
138
+ link_to user.name, user
139
+ else
140
+ object.name
141
+ end
142
+ end
143
+
144
+ end %>
145
+ ```
146
+
147
+ Then later in the partial you can use the helper method like so:
148
+
149
+ ```html+erb
150
+ <td><%= p.reference_to(user) %></td>
151
+ ```
20
152
 
21
153
  ## MIT License
22
154
 
@@ -1,23 +1,25 @@
1
+ require_relative "partial"
2
+
1
3
  module NicePartials::Helper
2
4
  def np
3
- # self in this context is the context of the view partial we're being called from.
4
- DecoratedViewContext.new(self)
5
+ NicePartials::Partial.new(self)
5
6
  end
6
7
 
7
- private
8
- class DecoratedViewContext
9
- def initialize(view_context)
10
- @view_context = view_context
11
- @key = SecureRandom.uuid
12
- end
8
+ def nice_partials_push_t_prefix(prefix)
9
+ @_nice_partials_t_prefixes ||= []
10
+ @_nice_partials_t_prefixes << prefix
11
+ end
13
12
 
14
- def yield(name = nil)
15
- raise "You can only use Nice Partial's yield method to retrieve the content of named content area blocks. If you're not trying to fetch the content of a named content area block, you don't need Nice Partials! You can just call the vanilla Rails `yield`." unless name
16
- content_for(name)
17
- end
13
+ def nice_partials_pop_t_prefix
14
+ @_nice_partials_t_prefixes ||= []
15
+ @_nice_partials_t_prefixes.pop
16
+ end
18
17
 
19
- def content_for(name, content = nil, options = {}, &block)
20
- @view_context.content_for("#{name}_#{@key}".to_sym, content, options, &block)
18
+ def t(key, options = {})
19
+ if @_nice_partials_t_prefixes&.any? && key.first == '.'
20
+ key = "#{@_nice_partials_t_prefixes.last}#{key}"
21
21
  end
22
+
23
+ super(key, options)
22
24
  end
23
25
  end
@@ -0,0 +1,23 @@
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
+ result = original_render(partial, context, block)
17
+
18
+ # Whether there was a block or not, pop off whatever we put on the stack.
19
+ context.nice_partials_pop_t_prefix
20
+
21
+ return result
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ module NicePartials
2
+ class Partial
3
+ delegate_missing_to :@view_context
4
+
5
+ def initialize(view_context)
6
+ @view_context = view_context
7
+ @key = SecureRandom.uuid
8
+ end
9
+
10
+ def yield(name = nil)
11
+ raise "You can only use Nice Partial's yield method to retrieve the content of named content area blocks. If you're not trying to fetch the content of a named content area block, you don't need Nice Partials! You can just call the vanilla Rails `yield`." unless name
12
+ content_for(name)
13
+ end
14
+
15
+ def helpers(&block)
16
+ class_eval &block
17
+ end
18
+
19
+ # See the `ActionView::PartialRenderer` monkey patch in `lib/nice_partials/monkey_patch.rb` for something similar.
20
+ def content_for(name, content = nil, options = {}, &block)
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
33
+ end
34
+
35
+ def content_for?(name)
36
+ @view_context.content_for?("#{name}_#{@key}".to_sym)
37
+ end
38
+ end
39
+ end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NicePartials
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.4"
5
5
  end
6
-
data/lib/nice_partials.rb CHANGED
@@ -2,8 +2,20 @@
2
2
 
3
3
  require_relative "nice_partials/version"
4
4
  require_relative "nice_partials/helper"
5
+ require_relative "nice_partials/monkey_patch"
6
+ require_relative "partials"
5
7
 
6
8
  module NicePartials
7
9
  end
8
10
 
9
- ActionView::Base.send :include, NicePartials::Helper
11
+ # TODO Is there somewhere better we can put this?
12
+ def nice_partials_locale_prefix_from_view_context_and_block(context, block)
13
+ root_paths = context.view_renderer.lookup_context.view_paths.map(&:path)
14
+ partial_location = block.source_location.first.dup
15
+ root_paths.each { |path| partial_location.gsub!(/^#{path}\//, '') }
16
+ partial_location.split('.').first.gsub('/_', '/').gsub('/', '.')
17
+ end
18
+
19
+ ActiveSupport.on_load :action_view do
20
+ include NicePartials::Helper
21
+ end
data/lib/partials.rb ADDED
@@ -0,0 +1,2 @@
1
+ module Partials
2
+ end
@@ -17,5 +17,7 @@ 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 = "~> 2.0"
20
+ gem.required_ruby_version = ">= 2.0"
21
+
22
+ gem.add_dependency "actionview", '>= 4.2.6'
21
23
  end
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.0
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-12-01 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2021-10-05 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
14
28
  description: A little bit of magic to make partials perfect for components.
15
29
  email:
16
30
  - andrew.culver@gmail.com
@@ -29,7 +43,10 @@ files:
29
43
  - Rakefile
30
44
  - lib/nice_partials.rb
31
45
  - lib/nice_partials/helper.rb
46
+ - lib/nice_partials/monkey_patch.rb
47
+ - lib/nice_partials/partial.rb
32
48
  - lib/nice_partials/version.rb
49
+ - lib/partials.rb
33
50
  - nice_partials.gemspec
34
51
  - spec/nice_partials_spec.rb
35
52
  homepage: https://github.com/bullet-train-co/nice_partials
@@ -42,7 +59,7 @@ require_paths:
42
59
  - lib
43
60
  required_ruby_version: !ruby/object:Gem::Requirement
44
61
  requirements:
45
- - - "~>"
62
+ - - ">="
46
63
  - !ruby/object:Gem::Version
47
64
  version: '2.0'
48
65
  required_rubygems_version: !ruby/object:Gem::Requirement
@@ -51,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
51
68
  - !ruby/object:Gem::Version
52
69
  version: '0'
53
70
  requirements: []
54
- rubygems_version: 3.0.8
71
+ rubygems_version: 3.1.4
55
72
  signing_key:
56
73
  specification_version: 4
57
74
  summary: A little bit of magic to make partials perfect for components.