dry-view 0.5.1 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +143 -18
- data/LICENSE +20 -0
- data/README.md +22 -14
- data/dry-view.gemspec +29 -21
- data/lib/dry-view.rb +3 -1
- data/lib/dry/view.rb +514 -2
- data/lib/dry/view/context.rb +80 -0
- data/lib/dry/view/decorated_attributes.rb +82 -0
- data/lib/dry/view/errors.rb +29 -0
- data/lib/dry/view/exposure.rb +35 -14
- data/lib/dry/view/exposures.rb +18 -6
- data/lib/dry/view/part.rb +166 -53
- data/lib/dry/view/part_builder.rb +140 -0
- data/lib/dry/view/path.rb +35 -7
- data/lib/dry/view/render_environment.rb +62 -0
- data/lib/dry/view/render_environment_missing.rb +44 -0
- data/lib/dry/view/rendered.rb +55 -0
- data/lib/dry/view/renderer.rb +36 -29
- data/lib/dry/view/scope.rb +160 -14
- data/lib/dry/view/scope_builder.rb +98 -0
- data/lib/dry/view/tilt.rb +78 -0
- data/lib/dry/view/tilt/erb.rb +26 -0
- data/lib/dry/view/tilt/erbse.rb +21 -0
- data/lib/dry/view/tilt/haml.rb +26 -0
- data/lib/dry/view/version.rb +5 -2
- metadata +78 -115
- data/.gitignore +0 -26
- data/.rspec +0 -2
- data/.travis.yml +0 -23
- data/CONTRIBUTING.md +0 -29
- data/Gemfile +0 -22
- data/LICENSE.md +0 -10
- data/Rakefile +0 -6
- data/benchmarks/templates/button.html.erb +0 -1
- data/benchmarks/view.rb +0 -24
- data/bin/console +0 -7
- data/lib/dry/view/controller.rb +0 -155
- data/lib/dry/view/decorator.rb +0 -45
- data/lib/dry/view/missing_renderer.rb +0 -15
- data/spec/fixtures/templates/_hello.html.slim +0 -1
- data/spec/fixtures/templates/decorated_parts.html.slim +0 -4
- data/spec/fixtures/templates/edit.html.slim +0 -11
- data/spec/fixtures/templates/empty.html.slim +0 -1
- data/spec/fixtures/templates/greeting.html.slim +0 -2
- data/spec/fixtures/templates/hello.html.slim +0 -1
- data/spec/fixtures/templates/layouts/app.html.slim +0 -6
- data/spec/fixtures/templates/layouts/app.txt.erb +0 -3
- data/spec/fixtures/templates/parts_with_args.html.slim +0 -3
- data/spec/fixtures/templates/parts_with_args/_box.html.slim +0 -3
- data/spec/fixtures/templates/shared/_index_table.html.slim +0 -2
- data/spec/fixtures/templates/shared/_shared_hello.html.slim +0 -1
- data/spec/fixtures/templates/tasks.html.slim +0 -3
- data/spec/fixtures/templates/user.html.slim +0 -2
- data/spec/fixtures/templates/users.html.slim +0 -5
- data/spec/fixtures/templates/users.txt.erb +0 -3
- data/spec/fixtures/templates/users/_row.html.slim +0 -2
- data/spec/fixtures/templates/users/_tbody.html.slim +0 -5
- data/spec/fixtures/templates/users_with_count.html.slim +0 -5
- data/spec/fixtures/templates/users_with_count_inherit.html.slim +0 -6
- data/spec/fixtures/templates_override/_hello.html.slim +0 -1
- data/spec/fixtures/templates_override/users.html.slim +0 -5
- data/spec/integration/decorator_spec.rb +0 -80
- data/spec/integration/exposures_spec.rb +0 -392
- data/spec/integration/part/decorated_attributes_spec.rb +0 -157
- data/spec/integration/view_spec.rb +0 -133
- data/spec/spec_helper.rb +0 -46
- data/spec/unit/controller_spec.rb +0 -37
- data/spec/unit/decorator_spec.rb +0 -61
- data/spec/unit/exposure_spec.rb +0 -227
- data/spec/unit/exposures_spec.rb +0 -103
- data/spec/unit/part_spec.rb +0 -90
- data/spec/unit/renderer_spec.rb +0 -57
- data/spec/unit/scope_spec.rb +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e819c2e7fc0b6fe2aed059b2d63993b2e107e7d9b682652dc9a0dedefdf7458
|
4
|
+
data.tar.gz: e45c5c695005d30eb755ccffd22efc5bbdf7c91b018f4c2fe859cb6b015f70bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4797bca5d6dba8ba676794d9ff21c531c1ee303a0af87f924ee09e89c9faadc898f5b1dc9d24731c32e62d5b5c031efa4b6f8a7062ab30bd3f7ea4397eac7b2
|
7
|
+
data.tar.gz: 60fe4d2131720fd19cebe465283f06f05abb0247b094fc946ff96ac9b0b77c5962561ee68da1dd067876ace1d5def0caccdf18e7598a25800cf199aad5f36772
|
data/CHANGELOG.md
CHANGED
@@ -1,21 +1,129 @@
|
|
1
|
-
|
1
|
+
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
|
+
|
3
|
+
## 0.7.1 2021-02-08
|
4
|
+
|
5
|
+
|
6
|
+
### Fixed
|
7
|
+
|
8
|
+
- Template not found errors properly show configured paths (@adam12 in #144)
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- Compatible with Ruby 2.7/3.0 keyword argument handling (@flash-gordon in 4e7cefb)
|
13
|
+
- dry-equalizer dependency dropped in favor of dry-core (@solnic)
|
14
|
+
|
15
|
+
[Compare v0.7.0...v0.7.1](https://github.com/dry-rb/dry-view/compare/v0.7.0...v0.7.1)
|
16
|
+
|
17
|
+
## 0.7.0 2019-03-06
|
18
|
+
|
19
|
+
|
20
|
+
### Added
|
21
|
+
|
22
|
+
- Raise a `Dry::View::UndefinedConfigError` when a view is called but no paths have been configured (timriley in [#130][pr130])
|
23
|
+
|
24
|
+
### Fixed
|
25
|
+
|
26
|
+
- Avoid a `SystemStackError` when a view is configured with a template that cannot be found on the filesystem (timriley in [#129][pr129])
|
27
|
+
|
28
|
+
### Changed
|
29
|
+
|
30
|
+
- [BREAKING] Move `Dry::View::Renderer::TemplateNotFoundError` to `Dry::View::TemplateNotFoundError` (timriley in [#130][pr130])
|
31
|
+
- [BREAKING] `Dry::View::UndefinedConfigError` is raised instead of `Dry::View::UndefinedTemplateError` when a view is called but no template has been configured (timriley in [#130][pr130])
|
32
|
+
- Stop searching upwards through parent directories when rendering a view's template (as opposed to partials) (timriley in [#130][pr130])
|
33
|
+
- Stop searching in `shared/` subdirectories when rendering a view's template (as opposed to partials) (timriley in [#130][pr130])
|
34
|
+
- Adjust template lookup cache keys to ensure no false hits (timriley in [#130][pr130])
|
35
|
+
|
36
|
+
[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-view/compare/v0.6.0...v0.7.0)
|
37
|
+
|
38
|
+
## 0.6.0 2019-01-30
|
39
|
+
|
40
|
+
|
41
|
+
### Added
|
42
|
+
|
43
|
+
- [BREAKING] `Dry::View#call` now returns a `Dry::View::Rendered` instance, which carries both the rendered output (accessible via `#to_s` or `#to_str`) as well as all of the view's locals, wrapped in their view parts (accessible via `#locals` or individually via `#[]`) (timriley in [#72][pr72])
|
44
|
+
- [BREAKING] Added `Dry::View::PartBuilder` (renamed from `Dry::View::Decorator`), which resolves part classes from a namespace configured via View's `part_namespace` setting. A custom part builder can be specified via a View's `part_builder` setting. (timriley in [#80][pr80])
|
45
|
+
- [BREAKING] Context classes can now declare decorated attributes just like part classes, via `.decorate` class-level API. Context classes are now required to inherit from `Dry::View::Context`. `Dry::View::Context` provides a `#with` method for creating copies of itself while preserving the rendering details needed for decorated attributes to work (timriley in [#89][pr89] and [#91][pr91])
|
46
|
+
- Customizable _scope_ objects, which work like view parts, but instead of encapsulating a single value, they encapsulate a whole template or partial and all of its locals. Scopes can be created via `#scope` method in templates, parts, as well as scope classes themselves. Scope classes are resolved via a View's `scope_builder` setting, which defaults to an instance of `Dry::View::ScopeBuilder`.
|
47
|
+
- Added `inflector` setting to View, which is used by the part and scope builders to resolve classes for a given part or scope name. Defaults to `Dry::Inflector.new` (timriley in [#80][pr80] and [#90][pr90])
|
48
|
+
- Exposures can be sent to the layout template when defined with `layout: true` option (GustavoCaso in [#87][pr87])
|
49
|
+
- Exposures can be left undecorated by a part when defined with `decorate: false` option (timriley in [#88][pr88])
|
50
|
+
- Part classes have access to the current template format via a private `#_format` method (timriley in [#118][pr118])
|
51
|
+
- Added "Tilt adapter" layer, to ensure a rendering engine compatible with dry-view's features is being used. Added adapters for "haml" and "erb" templates to ensure that "hamlit-block" and "erbse" are required and used as engines (unlike their more common counterparts, both of these engines support the implicit block capturing that is a central part of dry-view rendering behaviour) (timriley in [#106][pr106])
|
52
|
+
- Added `renderer_engine_mapping` setting to View, which allows an explicit engine class to be provided for the rendering of a given type of template (e.g. `config.renderer_engine_mapping = {erb: Tilt::ErubiTemplate}`) (timriley in [#106][pr106])
|
53
|
+
|
54
|
+
### Fixed
|
55
|
+
|
56
|
+
- Preserve renderer options when chdir-ing (timriley in [889ac7b](https://github.com/dry-rb/dry-view/commit/889ac7b))
|
57
|
+
|
58
|
+
### Changed
|
59
|
+
|
60
|
+
- [BREAKING] `Dry::View::Controller` renamed to `Dry::View` (timriley in [#115][pr115])
|
61
|
+
- [BREAKING] `Dry::View` `context` setting renamed to `default_context` (GustavoCaso in [#86][pr86])
|
62
|
+
- Exposure values are wrapped in their view parts before being made available as exposure dependencies (timriley in [#80][pr80])
|
63
|
+
- Exposures can access current context object through `context:` block or method parameter (timriley in [#119][pr119])
|
64
|
+
- Improved performance due to caching various lookups (timriley and GustavoCaso in [#97][pr97])
|
65
|
+
- `Part#inspect` output simplified to include only name and value (timriley in [#98][pr98])
|
66
|
+
- Attribute decoration in `Part` now achieved via a prepended module, which means it is possible to decorate an attribute provided by an instance method directly on the part class, which wasn't possible with the previous `method_missing`-based approach (timriley in [#110][pr110])
|
67
|
+
- `Part` classes can be initialized with missing `name:` and `rendering:` values, which can be useful for unit testing Part methods that don't use any rendering facilities (timriley in [#116][pr116])
|
68
|
+
|
69
|
+
[Compare v0.5.4...v0.6.0](https://github.com/dry-rb/dry-view/compare/v0.5.4...v0.6.0)
|
70
|
+
|
71
|
+
## 0.5.4 2019-01-06
|
72
|
+
|
73
|
+
This version was yanked due to the release accidentally containing a batch of breaking changes from master.
|
74
|
+
|
75
|
+
### Fixed
|
76
|
+
|
77
|
+
- Preserve renderer options when chdir-ing (timriley in [889ac7b](https://github.com/dry-rb/dry-view/commit/889ac7b))
|
78
|
+
|
79
|
+
|
80
|
+
[Compare v0.5.3...v0.5.4](https://github.com/dry-rb/dry-view/compare/v0.5.3...v0.5.4)
|
81
|
+
|
82
|
+
## 0.5.3 2018-10-22
|
83
|
+
|
84
|
+
|
85
|
+
### Added
|
86
|
+
|
87
|
+
- `renderer_options` setting for configuring tilt-based renderer (liseki in [#62][pr62])
|
88
|
+
|
89
|
+
### Changed
|
90
|
+
|
91
|
+
- Part objects wrap values more transparently, via added `#respond_to_missing?` (liseki in [#63][pr63])
|
92
|
+
|
93
|
+
[Compare v0.5.2...v0.5.3](https://github.com/dry-rb/dry-view/compare/v0.5.2...v0.5.3)
|
94
|
+
|
95
|
+
## 0.5.2 2018-06-13
|
96
|
+
|
97
|
+
|
98
|
+
### Changed
|
99
|
+
|
100
|
+
- Only truthy view part attributes are decorated (timriley)
|
101
|
+
|
102
|
+
[Compare v0.5.1...v0.5.2](https://github.com/dry-rb/dry-view/compare/v0.5.1...v0.5.2)
|
103
|
+
|
104
|
+
## 0.5.1 2018-02-20
|
105
|
+
|
2
106
|
|
3
107
|
### Added
|
4
108
|
|
5
109
|
- Exposures are inherited from parent view controller classes (GustavoCaso)
|
6
110
|
|
111
|
+
|
7
112
|
[Compare v0.5.0...v0.5.1](https://github.com/dry-rb/dry-view/compare/v0.5.0...v0.5.1)
|
8
113
|
|
9
|
-
|
114
|
+
## 0.5.0 2018-01-23
|
115
|
+
|
10
116
|
|
11
117
|
### Added
|
12
118
|
|
13
119
|
- Support for parts with decorated attributes (timriley + GustavoCaso)
|
14
120
|
- Ability to easily create another part instance via `Part#new` (GustavoCaso)
|
15
121
|
|
122
|
+
|
16
123
|
[Compare v0.4.0...v0.5.0](https://github.com/dry-rb/dry-view/compare/v0.4.0...v0.5.0)
|
17
124
|
|
18
|
-
|
125
|
+
## 0.4.0 2017-11-01
|
126
|
+
|
19
127
|
|
20
128
|
### Added
|
21
129
|
|
@@ -29,35 +137,52 @@
|
|
29
137
|
- Allow `Dry::View::Part` instances to be created without explicitly passing a `renderer`. This is helpful for unit testing view parts that don't need to render anything (dNitza)
|
30
138
|
- Partials can be nested within additional sub-directories by rendering them their relative path as their name, e.g. `render(:"foo/bar")` will look for a `foo/_bar.html.slim` template within the normal template lookup paths (timriley)
|
31
139
|
|
32
|
-
|
140
|
+
[Compare v0.3.0...v0.4.0](https://github.com/dry-rb/dry-view/compare/v0.3.0...v0.4.0)
|
141
|
+
|
142
|
+
## 0.3.0 2017-05-14
|
33
143
|
|
34
144
|
This release reintroduces view parts in a more helpful form. You can provide your own custom view part classes to encapsulate your view logic, as well as a decorator for custom, shared behavior arouund view part wrapping.
|
35
145
|
|
146
|
+
### Added
|
147
|
+
|
148
|
+
- Wrap all values passed to the template in `Dry::View::Part` objects
|
149
|
+
- Added a `decorator` config to `Dry::View::Controller`, with a default `Dry::View::Decorator` that wraps the exposure values in `Dry::View::Part` objects (as above). Provide your own part classes by passing an `:as` option to your exposures, e.g. `expose :user, as: MyApp::UserPart`
|
150
|
+
|
36
151
|
### Changed
|
37
152
|
|
38
153
|
- [BREAKING] Partial rendering in templates requires an explicit `render` method call instead of method_missing behaviour usinig the partial's name (e.g. `<%= render :my_partial %>` instead of `<%= my_partial %>`)
|
39
154
|
|
40
|
-
|
155
|
+
[Compare v0.2.2...v0.3.0](https://github.com/dry-rb/dry-view/compare/v0.2.2...v0.3.0)
|
41
156
|
|
42
|
-
|
43
|
-
- Added a `decorator` config to `Dry::View::Controller`, with a default `Dry::View::Decorator` that wraps the exposure values in `Dry::View::Part` objects (as above). Provide your own part classes by passing an `:as` option to your exposures, e.g. `expose :user, as: MyApp::UserPart`
|
157
|
+
## 0.2.2 2017-01-31
|
44
158
|
|
45
|
-
# 0.2.2 / 2017-01-31
|
46
159
|
|
47
160
|
### Changed
|
48
161
|
|
49
162
|
- Make input passthrough exposures (when there is no block or matching instance metod) return nil instead of raise in the case of a missing input key (timriley)
|
50
163
|
|
51
|
-
|
164
|
+
[Compare v0.2.1...v0.2.2](https://github.com/dry-rb/dry-view/compare/v0.2.1...v0.2.2)
|
165
|
+
|
166
|
+
## 0.2.1 2017-01-30
|
167
|
+
|
52
168
|
|
53
169
|
### Fixed
|
54
170
|
|
55
171
|
- Exposure blocks now have access to the view controller instance when they're called (timriley)
|
56
172
|
|
57
|
-
|
173
|
+
|
174
|
+
[Compare v0.2.0...v0.2.1](https://github.com/dry-rb/dry-view/compare/v0.2.0...v0.2.1)
|
175
|
+
|
176
|
+
## 0.2.0 2017-01-30
|
58
177
|
|
59
178
|
This release is a major reorientation for dry-view, and it should allow for more natural, straightforward template authoring.
|
60
179
|
|
180
|
+
### Added
|
181
|
+
|
182
|
+
- Will render templates using any Tilt-supported engine, based on the template's final file extension (e.g. `hello.html.slim` will use Slim). For thread-safety, be sure to explicitly require any engine gems you intend to use. (timriley)
|
183
|
+
- `expose` (and `expose_private`) `Dry::View::Controller` class methods allow you to more easily declare and prepare the data for your template (timriley)
|
184
|
+
- Added `Dry::View::Scope`, which is the scope used for rendering templates. This includes the data from the exposures along with the context object (timriley)
|
185
|
+
|
61
186
|
### Changed
|
62
187
|
|
63
188
|
- [BREAKING] `Dry::View::Layout` renamed to `Dry::View::Controller`. The "view controller" name better represents this object's job: to (timriley)
|
@@ -69,13 +194,10 @@ This release is a major reorientation for dry-view, and it should allow for more
|
|
69
194
|
- [BREAKING] With view parts removed, partials can only be rendered by top-level method calls within templates (timriley)
|
70
195
|
- Ruby version 2.1.0 is now the earliest supported version (timriley)
|
71
196
|
|
72
|
-
|
197
|
+
[Compare v0.1.1...v0.2.0](https://github.com/dry-rb/dry-view/compare/v0.1.1...v0.2.0)
|
73
198
|
|
74
|
-
|
75
|
-
- `expose` (and `expose_private`) `Dry::View::Controller` class methods allow you to more easily declare and prepare the data for your template (timriley)
|
76
|
-
- Added `Dry::View::Scope`, which is the scope used for rendering templates. This includes the data from the exposures along with the context object (timriley)
|
199
|
+
## 0.1.1 2016-07-07
|
77
200
|
|
78
|
-
# 0.1.1 / 2016-07-07
|
79
201
|
|
80
202
|
### Changed
|
81
203
|
|
@@ -83,12 +205,15 @@ This release is a major reorientation for dry-view, and it should allow for more
|
|
83
205
|
- Render template content first, before passing that content to the layout. This makes "content_for"-style behaviours possible, where the template stores some data that the layout can then use later (timriley)
|
84
206
|
- Configure default template encoding to be UTF-8, fixing some issues with template rendering on deployed sites (gotar)
|
85
207
|
|
86
|
-
|
208
|
+
[Compare v0.1.0...v0.1.1](https://github.com/dry-rb/dry-view/compare/v0.1.0...v0.1.1)
|
209
|
+
|
210
|
+
## 0.1.0 2016-03-28
|
211
|
+
|
87
212
|
|
88
213
|
### Added
|
89
214
|
|
90
|
-
– `Dry::View::Layout` supports multiple view template formats. Configure format/engine pairs (e.g. `{html: :slim, text: :erb}`) on the `formats` setting. The first format becomes the default. Request specific formats when calling the view, e.g. `my_view.call(format: :text)`.
|
215
|
+
- – `Dry::View::Layout` supports multiple view template formats. Configure format/engine pairs (e.g. `{html: :slim, text: :erb}`) on the `formats` setting. The first format becomes the default. Request specific formats when calling the view, e.g. `my_view.call(format: :text)`.
|
91
216
|
|
92
217
|
### Changed
|
93
218
|
|
94
|
-
– Extracted from rodakase and renamed to dry-view. `Rodakase::View` is now `Dry::View`.
|
219
|
+
- – Extracted from rodakase and renamed to dry-view. `Rodakase::View` is now `Dry::View`.
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015-2021 dry-rb team
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,21 +1,29 @@
|
|
1
|
-
[gitter]: https://gitter.im/dry-rb/chat
|
2
1
|
[gem]: https://rubygems.org/gems/dry-view
|
3
|
-
[
|
4
|
-
[
|
2
|
+
[actions]: https://github.com/dry-rb/dry-view/actions
|
3
|
+
[codacy]: https://www.codacy.com/gh/dry-rb/dry-view
|
4
|
+
[chat]: https://dry-rb.zulipchat.com
|
5
|
+
[inchpages]: http://inch-ci.org/github/dry-rb/dry-view
|
5
6
|
|
6
|
-
# dry-view [![Join the
|
7
|
+
# dry-view [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
|
7
8
|
|
8
|
-
[![Gem Version](https://
|
9
|
-
[![
|
10
|
-
[![
|
11
|
-
[![
|
12
|
-
[![
|
9
|
+
[![Gem Version](https://badge.fury.io/rb/dry-view.svg)][gem]
|
10
|
+
[![CI Status](https://github.com/dry-rb/dry-view/workflows/ci/badge.svg)][actions]
|
11
|
+
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/fe8a45d76d8b45f6a680a29c48b43a99)][codacy]
|
12
|
+
[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/fe8a45d76d8b45f6a680a29c48b43a99)][codacy]
|
13
|
+
[![Inline docs](http://inch-ci.org/github/dry-rb/dry-view.svg?branch=master)][inchpages]
|
13
14
|
|
15
|
+
## Links
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
transformations, accepting user input and returning your rendered view.
|
17
|
+
* [User documentation](http://dry-rb.org/gems/dry-view)
|
18
|
+
* [API documentation](http://rubydoc.info/gems/dry-view)
|
18
19
|
|
19
|
-
##
|
20
|
+
## Supported Ruby versions
|
21
|
+
|
22
|
+
This library officially supports the following Ruby versions:
|
23
|
+
|
24
|
+
* MRI >= `2.5`
|
25
|
+
* jruby >= `9.2`
|
26
|
+
|
27
|
+
## License
|
20
28
|
|
21
|
-
|
29
|
+
See `LICENSE` file.
|
data/dry-view.gemspec
CHANGED
@@ -1,32 +1,40 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# this file is managed by dry-rb/devtools project
|
3
|
+
|
4
|
+
lib = File.expand_path('lib', __dir__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
require 'dry/view/version'
|
5
7
|
|
6
8
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
8
|
-
spec.
|
9
|
-
spec.
|
10
|
-
spec.
|
11
|
-
spec.
|
9
|
+
spec.name = 'dry-view'
|
10
|
+
spec.authors = ["Tim Riley", "Piotr Solnica"]
|
11
|
+
spec.email = ["tim@icelab.com.au", "piotr.solnica@gmail.com"]
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.version = Dry::View::VERSION.dup
|
14
|
+
|
15
|
+
spec.summary = "A complete, standalone view rendering system that gives you everything you need to write well-factored view code"
|
12
16
|
spec.description = spec.summary
|
13
|
-
spec.homepage =
|
14
|
-
spec.
|
17
|
+
spec.homepage = 'https://dry-rb.org/gems/dry-view'
|
18
|
+
spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-view.gemspec", "lib/**/*"]
|
19
|
+
spec.bindir = 'bin'
|
20
|
+
spec.executables = []
|
21
|
+
spec.require_paths = ['lib']
|
15
22
|
|
16
|
-
spec.
|
17
|
-
spec.
|
18
|
-
spec.
|
19
|
-
spec.
|
20
|
-
spec.require_paths = ["lib"]
|
23
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
24
|
+
spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-view/blob/master/CHANGELOG.md'
|
25
|
+
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-view'
|
26
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-view/issues'
|
21
27
|
|
22
|
-
spec.required_ruby_version =
|
28
|
+
spec.required_ruby_version = ">= 2.5.0"
|
23
29
|
|
24
|
-
|
25
|
-
spec.add_runtime_dependency "
|
30
|
+
# to update dependencies edit project.yml
|
31
|
+
spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
|
26
32
|
spec.add_runtime_dependency "dry-configurable", "~> 0.1"
|
27
|
-
spec.add_runtime_dependency "dry-
|
33
|
+
spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
|
34
|
+
spec.add_runtime_dependency "dry-inflector", "~> 0.1"
|
35
|
+
spec.add_runtime_dependency "tilt", "~> 2.0", ">= 2.0.6"
|
28
36
|
|
29
|
-
spec.add_development_dependency "bundler"
|
30
|
-
spec.add_development_dependency "rake"
|
31
|
-
spec.add_development_dependency "rspec"
|
37
|
+
spec.add_development_dependency "bundler"
|
38
|
+
spec.add_development_dependency "rake"
|
39
|
+
spec.add_development_dependency "rspec"
|
32
40
|
end
|
data/lib/dry-view.rb
CHANGED
data/lib/dry/view.rb
CHANGED
@@ -1,2 +1,514 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/configurable"
|
4
|
+
require "dry/core/cache"
|
5
|
+
require "dry/core/equalizer"
|
6
|
+
require "dry/inflector"
|
7
|
+
|
8
|
+
require_relative "view/context"
|
9
|
+
require_relative "view/exposures"
|
10
|
+
require_relative "view/errors"
|
11
|
+
require_relative "view/part_builder"
|
12
|
+
require_relative "view/path"
|
13
|
+
require_relative "view/render_environment"
|
14
|
+
require_relative "view/rendered"
|
15
|
+
require_relative "view/renderer"
|
16
|
+
require_relative "view/scope_builder"
|
17
|
+
|
18
|
+
# A collection of next-generation Ruby libraries, helping you to write clear,
|
19
|
+
# flexible, and more maintainable Ruby code. Each dry-rb gem fulfils a common
|
20
|
+
# task, and together they make a powerful platform for any kind of Ruby
|
21
|
+
# application.
|
22
|
+
module Dry
|
23
|
+
# A standalone, template-based view rendering system that offers everything
|
24
|
+
# you need to write well-factored view code.
|
25
|
+
#
|
26
|
+
# This represents a single view, holding the configuration and exposures
|
27
|
+
# necessary for rendering its template.
|
28
|
+
#
|
29
|
+
# @abstract Subclass this and provide your own configuration and exposures to
|
30
|
+
# define your own view (along with a custom `#initialize` if you wish to
|
31
|
+
# inject dependencies into your subclass)
|
32
|
+
#
|
33
|
+
# @see https://dry-rb.org/gems/dry-view/
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
class View
|
37
|
+
# @api private
|
38
|
+
DEFAULT_RENDERER_OPTIONS = {default_encoding: "utf-8"}.freeze
|
39
|
+
|
40
|
+
include Dry::Equalizer(:config, :exposures)
|
41
|
+
|
42
|
+
extend Dry::Core::Cache
|
43
|
+
|
44
|
+
extend Dry::Configurable
|
45
|
+
|
46
|
+
# @!group Configuration
|
47
|
+
|
48
|
+
# @overload config.paths=(paths)
|
49
|
+
# Set an array of directories that will be searched for all templates
|
50
|
+
# (templates, partials, and layouts).
|
51
|
+
#
|
52
|
+
# These will be converted into Path objects and used for template lookup
|
53
|
+
# when rendering.
|
54
|
+
#
|
55
|
+
# This is a **required setting**.
|
56
|
+
#
|
57
|
+
# @param paths [String, Path, Array<String, Path>] the paths
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
# @!scope class
|
61
|
+
setting :paths do |paths|
|
62
|
+
Array(paths).map { |path| Path[path] }
|
63
|
+
end
|
64
|
+
|
65
|
+
# @overload config.template=(name)
|
66
|
+
# Set the name of the template for rendering this view. Template name
|
67
|
+
# should be relative to the configured `paths`.
|
68
|
+
#
|
69
|
+
# This is a **required setting**.
|
70
|
+
#
|
71
|
+
# @param name [String] template name
|
72
|
+
# @api public
|
73
|
+
# @!scope class
|
74
|
+
setting :template
|
75
|
+
|
76
|
+
# @overload config.layout=(name)
|
77
|
+
# Set the name of the layout to render templates within. Layouts will be
|
78
|
+
# looked up within the configured `layouts_dir`, within the configured
|
79
|
+
# `paths`.
|
80
|
+
#
|
81
|
+
# A false or nil value will use no layout. Defaults to `nil`.
|
82
|
+
#
|
83
|
+
# @param name [String, FalseClass, nil] layout name, or false to indicate no layout
|
84
|
+
# @api public
|
85
|
+
# @!scope class
|
86
|
+
setting :layout, false
|
87
|
+
|
88
|
+
# @overload config.layouts_dir=(dir)
|
89
|
+
# Set the name of the directory (within the configured `paths`) holding
|
90
|
+
# the layouts. Defaults to `"layouts"`
|
91
|
+
#
|
92
|
+
# @param dir [String] directory name
|
93
|
+
# @api public
|
94
|
+
# @!scope class
|
95
|
+
setting :layouts_dir, "layouts"
|
96
|
+
|
97
|
+
# @overload config.scope=(scope_class)
|
98
|
+
# Set the scope class to use when rendering the view's template.
|
99
|
+
#
|
100
|
+
# Configuring a custom scope class allows you to provide extra behaviour
|
101
|
+
# (alongside exposures) to the template.
|
102
|
+
#
|
103
|
+
# @see https://dry-rb.org/gems/dry-view/scopes/
|
104
|
+
#
|
105
|
+
# @param scope_class [Class] scope class (inheriting from `Dry::View::Scope`)
|
106
|
+
# @api public
|
107
|
+
# @!scope class
|
108
|
+
setting :scope
|
109
|
+
|
110
|
+
# @overload config.default_context=(context)
|
111
|
+
# Set the default context object to use when rendering. This will be used
|
112
|
+
# unless another context object is applied at render-time to `View#call`
|
113
|
+
#
|
114
|
+
# Defaults to a frozen instance of `Dry::View::Context`.
|
115
|
+
#
|
116
|
+
# @see View#call
|
117
|
+
#
|
118
|
+
# @param context [Dry::View::Context] context object
|
119
|
+
# @api public
|
120
|
+
# @!scope class
|
121
|
+
setting :default_context, Context.new.freeze
|
122
|
+
|
123
|
+
# @overload config.default_format=(format)
|
124
|
+
# Set the default format to use when rendering.
|
125
|
+
#
|
126
|
+
# Defaults to `:html`.
|
127
|
+
#
|
128
|
+
# @param format [Symbol]
|
129
|
+
# @api public
|
130
|
+
# @!scope class
|
131
|
+
setting :default_format, :html
|
132
|
+
|
133
|
+
# @overload config.scope_namespace=(namespace)
|
134
|
+
# Set a namespace that will be searched when building scope classes.
|
135
|
+
#
|
136
|
+
# @param namespace [Module, Class]
|
137
|
+
#
|
138
|
+
# @see Scope
|
139
|
+
#
|
140
|
+
# @api public
|
141
|
+
# @!scope class
|
142
|
+
setting :part_namespace
|
143
|
+
|
144
|
+
# @overload config.part_builder=(part_builder)
|
145
|
+
# Set a custom part builder class
|
146
|
+
#
|
147
|
+
# @see https://dry-rb.org/gems/dry-view/parts/
|
148
|
+
#
|
149
|
+
# @param part_builder [Class]
|
150
|
+
# @api public
|
151
|
+
# @!scope class
|
152
|
+
setting :part_builder, PartBuilder
|
153
|
+
|
154
|
+
# @overload config.scope_namespace=(namespace)
|
155
|
+
# Set a namespace that will be searched when building scope classes.
|
156
|
+
#
|
157
|
+
# @param namespace [Module, Class]
|
158
|
+
#
|
159
|
+
# @see Scope
|
160
|
+
#
|
161
|
+
# @api public
|
162
|
+
# @!scope class
|
163
|
+
setting :scope_namespace
|
164
|
+
|
165
|
+
# @overload config.scope_builder=(scope_builder)
|
166
|
+
# Set a custom scope builder class
|
167
|
+
#
|
168
|
+
# @see https://dry-rb.org/gems/dry-view/scopes/
|
169
|
+
#
|
170
|
+
# @param scope_builder [Class]
|
171
|
+
# @api public
|
172
|
+
# @!scope class
|
173
|
+
setting :scope_builder, ScopeBuilder
|
174
|
+
|
175
|
+
# @overload config.inflector=(inflector)
|
176
|
+
# Set an inflector to provide to the part_builder and scope_builder.
|
177
|
+
#
|
178
|
+
# Defaults to `Dry::Inflector.new`.
|
179
|
+
#
|
180
|
+
# @param inflector
|
181
|
+
# @api public
|
182
|
+
# @!scope class
|
183
|
+
setting :inflector, Dry::Inflector.new
|
184
|
+
|
185
|
+
# @overload config.renderer_options=(options)
|
186
|
+
# A hash of options to pass to the template engine. Template engines are
|
187
|
+
# provided by Tilt; see Tilt's documentation for what options your
|
188
|
+
# template engine may support.
|
189
|
+
#
|
190
|
+
# Defaults to `{default_encoding: "utf-8"}`. Any options passed will be
|
191
|
+
# merged onto the defaults.
|
192
|
+
#
|
193
|
+
# @see https://github.com/rtomayko/tilt
|
194
|
+
#
|
195
|
+
# @param options [Hash] renderer options
|
196
|
+
# @api public
|
197
|
+
# @!scope class
|
198
|
+
setting :renderer_options, DEFAULT_RENDERER_OPTIONS do |options|
|
199
|
+
DEFAULT_RENDERER_OPTIONS.merge(options.to_h).freeze
|
200
|
+
end
|
201
|
+
|
202
|
+
# @overload config.renderer_engine_mapping=(mapping)
|
203
|
+
# A hash specifying the (Tilt-compatible) template engine class to use
|
204
|
+
# for a given format. Template engine detection is automatic based on
|
205
|
+
# format; use this setting only if you want to force a non-preferred
|
206
|
+
# engine.
|
207
|
+
#
|
208
|
+
# @example
|
209
|
+
# config.renderer_engine_mapping = {erb: Tilt::ErubiTemplate}
|
210
|
+
#
|
211
|
+
# @see https://github.com/rtomayko/tilt
|
212
|
+
#
|
213
|
+
# @param mapping [Hash<Symbol, Class>] engine mapping
|
214
|
+
# @api public
|
215
|
+
# @!scope class
|
216
|
+
setting :renderer_engine_mapping
|
217
|
+
|
218
|
+
# @!endgroup
|
219
|
+
|
220
|
+
# @api private
|
221
|
+
def self.inherited(klass)
|
222
|
+
super
|
223
|
+
exposures.each do |name, exposure|
|
224
|
+
klass.exposures.import(name, exposure)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# @!group Exposures
|
229
|
+
|
230
|
+
# @!macro [new] exposure_options
|
231
|
+
# @param options [Hash] the exposure's options
|
232
|
+
# @option options [Boolean] :layout expose this value to the layout (defaults to false)
|
233
|
+
# @option options [Boolean] :decorate decorate this value in a matching Part (defaults to
|
234
|
+
# true)
|
235
|
+
# @option options [Symbol, Class] :as an alternative name or class to use when finding a
|
236
|
+
# matching Part
|
237
|
+
|
238
|
+
# @overload expose(name, **options, &block)
|
239
|
+
# Define a value to be passed to the template. The return value of the
|
240
|
+
# block will be decorated by a matching Part and passed to the template.
|
241
|
+
#
|
242
|
+
# The block will be evaluated with the view instance as its `self`. The
|
243
|
+
# block's parameters will determine what it is given:
|
244
|
+
#
|
245
|
+
# - To receive other exposure values, provide positional parameters
|
246
|
+
# matching the exposure names. These exposures will already by decorated
|
247
|
+
# by their Parts.
|
248
|
+
# - To receive the view's input arguments (whatever is passed to
|
249
|
+
# `View#call`), provide matching keyword parameters. You can provide
|
250
|
+
# default values for these parameters to make the corresponding input
|
251
|
+
# keys optional
|
252
|
+
# - To receive the Context object, provide a `context:` keyword parameter
|
253
|
+
# - To receive the view's input arguments in their entirety, provide a
|
254
|
+
# keywords splat parameter (i.e. `**input`)
|
255
|
+
#
|
256
|
+
# @example Accessing input arguments
|
257
|
+
# expose :article do |slug:|
|
258
|
+
# article_repo.find_by_slug(slug)
|
259
|
+
# end
|
260
|
+
#
|
261
|
+
# @example Accessing other exposures
|
262
|
+
# expose :articles do
|
263
|
+
# article_repo.listing
|
264
|
+
# end
|
265
|
+
#
|
266
|
+
# expose :featured_articles do |articles|
|
267
|
+
# articles.select(&:featured?)
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# @param name [Symbol] name for the exposure
|
271
|
+
# @macro exposure_options
|
272
|
+
#
|
273
|
+
# @overload expose(name, **options)
|
274
|
+
# Define a value to be passed to the template, provided by an instance
|
275
|
+
# method matching the name. The method's return value will be decorated by
|
276
|
+
# a matching Part and passed to the template.
|
277
|
+
#
|
278
|
+
# The method's parameters will determine what it is given:
|
279
|
+
#
|
280
|
+
# - To receive other exposure values, provide positional parameters
|
281
|
+
# matching the exposure names. These exposures will already by decorated
|
282
|
+
# by their Parts.
|
283
|
+
# - To receive the view's input arguments (whatever is passed to
|
284
|
+
# `View#call`), provide matching keyword parameters. You can provide
|
285
|
+
# default values for these parameters to make the corresponding input
|
286
|
+
# keys optional
|
287
|
+
# - To receive the Context object, provide a `context:` keyword parameter
|
288
|
+
# - To receive the view's input arguments in their entirey, provide a
|
289
|
+
# keywords splat parameter (i.e. `**input`)
|
290
|
+
#
|
291
|
+
# @example Accessing input arguments
|
292
|
+
# expose :article
|
293
|
+
#
|
294
|
+
# def article(slug:)
|
295
|
+
# article_repo.find_by_slug(slug)
|
296
|
+
# end
|
297
|
+
#
|
298
|
+
# @example Accessing other exposures
|
299
|
+
# expose :articles
|
300
|
+
# expose :featured_articles
|
301
|
+
#
|
302
|
+
# def articles
|
303
|
+
# article_repo.listing
|
304
|
+
# end
|
305
|
+
#
|
306
|
+
# def featured_articles
|
307
|
+
# articles.select(&:featured?)
|
308
|
+
# end
|
309
|
+
#
|
310
|
+
# @param name [Symbol] name for the exposure
|
311
|
+
# @macro exposure_options
|
312
|
+
#
|
313
|
+
# @overload expose(name, **options)
|
314
|
+
# Define a single value to pass through from the input data (when there is
|
315
|
+
# no instance method matching the `name`). This value will be decorated by
|
316
|
+
# a matching Part and passed to the template.
|
317
|
+
#
|
318
|
+
# @param name [Symbol] name for the exposure
|
319
|
+
# @macro exposure_options
|
320
|
+
# @option options [Boolean] :default a default value to provide if there is no matching
|
321
|
+
# input data
|
322
|
+
#
|
323
|
+
# @overload expose(*names, **options)
|
324
|
+
# Define multiple values to pass through from the input data (when there
|
325
|
+
# is no instance methods matching their names). These values will be
|
326
|
+
# decorated by matching Parts and passed through to the template.
|
327
|
+
#
|
328
|
+
# The provided options will be applied to all the exposures.
|
329
|
+
#
|
330
|
+
# @param names [Symbol] names for the exposures
|
331
|
+
# @macro exposure_options
|
332
|
+
# @option options [Boolean] :default a default value to provide if there is no matching
|
333
|
+
# input data
|
334
|
+
#
|
335
|
+
# @see https://dry-rb.org/gems/dry-view/exposures/
|
336
|
+
#
|
337
|
+
# @api public
|
338
|
+
def self.expose(*names, **options, &block)
|
339
|
+
if names.length == 1
|
340
|
+
exposures.add(names.first, block, **options)
|
341
|
+
else
|
342
|
+
names.each do |name|
|
343
|
+
exposures.add(name, **options)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# @api public
|
349
|
+
def self.private_expose(*names, **options, &block)
|
350
|
+
expose(*names, **options, private: true, &block)
|
351
|
+
end
|
352
|
+
|
353
|
+
# Returns the defined exposures. These are unbound, since bound exposures
|
354
|
+
# are only created when initializing a View instance.
|
355
|
+
#
|
356
|
+
# @return [Exposures]
|
357
|
+
# @api private
|
358
|
+
def self.exposures
|
359
|
+
@exposures ||= Exposures.new
|
360
|
+
end
|
361
|
+
|
362
|
+
# @!endgroup
|
363
|
+
|
364
|
+
# @!group Render environment
|
365
|
+
|
366
|
+
# Returns a render environment for the view and the given options. This
|
367
|
+
# environment isn't chdir'ed into any particular directory.
|
368
|
+
#
|
369
|
+
# @param format [Symbol] template format to use (defaults to the `default_format` setting)
|
370
|
+
# @param context [Context] context object to use (defaults to the `default_context` setting)
|
371
|
+
#
|
372
|
+
# @see View.template_env render environment for the view's template
|
373
|
+
# @see View.layout_env render environment for the view's layout
|
374
|
+
#
|
375
|
+
# @return [RenderEnvironment]
|
376
|
+
# @api public
|
377
|
+
def self.render_env(format: config.default_format, context: config.default_context)
|
378
|
+
RenderEnvironment.prepare(renderer(format), config, context)
|
379
|
+
end
|
380
|
+
|
381
|
+
# @overload template_env(format: config.default_format, context: config.default_context)
|
382
|
+
# Returns a render environment for the view and the given options,
|
383
|
+
# chdir'ed into the view's template directory. This is the environment
|
384
|
+
# used when rendering the template, and is useful to to fetch
|
385
|
+
# independently when unit testing Parts and Scopes.
|
386
|
+
#
|
387
|
+
# @param format [Symbol] template format to use (defaults to the `default_format` setting)
|
388
|
+
# @param context [Context] context object to use (defaults to the `default_context` setting)
|
389
|
+
#
|
390
|
+
# @return [RenderEnvironment]
|
391
|
+
# @api public
|
392
|
+
def self.template_env(**args)
|
393
|
+
render_env(**args).chdir(config.template)
|
394
|
+
end
|
395
|
+
|
396
|
+
# @overload layout_env(format: config.default_format, context: config.default_context)
|
397
|
+
# Returns a render environment for the view and the given options,
|
398
|
+
# chdir'ed into the view's layout directory. This is the environment used
|
399
|
+
# when rendering the view's layout.
|
400
|
+
#
|
401
|
+
# @param format [Symbol] template format to use (defaults to the `default_format` setting)
|
402
|
+
# @param context [Context] context object to use (defaults to the `default_context` setting)
|
403
|
+
#
|
404
|
+
# @return [RenderEnvironment] @api public
|
405
|
+
def self.layout_env(**args)
|
406
|
+
render_env(**args).chdir(layout_path)
|
407
|
+
end
|
408
|
+
|
409
|
+
# Returns renderer for the view and provided format
|
410
|
+
#
|
411
|
+
# @api private
|
412
|
+
def self.renderer(format)
|
413
|
+
fetch_or_store(:renderer, config, format) {
|
414
|
+
Renderer.new(
|
415
|
+
config.paths,
|
416
|
+
format: format,
|
417
|
+
engine_mapping: config.renderer_engine_mapping,
|
418
|
+
**config.renderer_options
|
419
|
+
)
|
420
|
+
}
|
421
|
+
end
|
422
|
+
|
423
|
+
# @api private
|
424
|
+
def self.layout_path
|
425
|
+
File.join(config.layouts_dir, config.layout)
|
426
|
+
end
|
427
|
+
|
428
|
+
# @!endgroup
|
429
|
+
|
430
|
+
# The view's bound exposures
|
431
|
+
#
|
432
|
+
# @return [Exposures]
|
433
|
+
# @api private
|
434
|
+
attr_reader :exposures
|
435
|
+
|
436
|
+
# Returns an instance of the view. This binds the defined exposures to the
|
437
|
+
# view instance.
|
438
|
+
#
|
439
|
+
# Subclasses can define their own `#initialize` to accept injected
|
440
|
+
# dependencies, but must call `super()` to ensure the standard view
|
441
|
+
# initialization can proceed.
|
442
|
+
#
|
443
|
+
# @api public
|
444
|
+
def initialize
|
445
|
+
@exposures = self.class.exposures.bind(self)
|
446
|
+
end
|
447
|
+
|
448
|
+
# The view's configuration
|
449
|
+
#
|
450
|
+
# @api private
|
451
|
+
def config
|
452
|
+
self.class.config
|
453
|
+
end
|
454
|
+
|
455
|
+
# Render the view
|
456
|
+
#
|
457
|
+
# @param format [Symbol] template format to use
|
458
|
+
# @param context [Context] context object to use
|
459
|
+
# @param input input data for preparing exposure values
|
460
|
+
#
|
461
|
+
# @return [Rendered] rendered view object
|
462
|
+
# @api public
|
463
|
+
def call(format: config.default_format, context: config.default_context, **input)
|
464
|
+
ensure_config
|
465
|
+
|
466
|
+
env = self.class.render_env(format: format, context: context)
|
467
|
+
template_env = self.class.template_env(format: format, context: context)
|
468
|
+
|
469
|
+
locals = locals(template_env, input)
|
470
|
+
output = env.template(config.template, template_env.scope(config.scope, locals))
|
471
|
+
|
472
|
+
if layout?
|
473
|
+
layout_env = self.class.layout_env(format: format, context: context)
|
474
|
+
output = env.template(
|
475
|
+
self.class.layout_path,
|
476
|
+
layout_env.scope(config.scope, layout_locals(locals))
|
477
|
+
) { output }
|
478
|
+
end
|
479
|
+
|
480
|
+
Rendered.new(output: output, locals: locals)
|
481
|
+
end
|
482
|
+
|
483
|
+
private
|
484
|
+
|
485
|
+
# @api private
|
486
|
+
def ensure_config
|
487
|
+
raise UndefinedConfigError, :paths unless Array(config.paths).any?
|
488
|
+
raise UndefinedConfigError, :template unless config.template
|
489
|
+
end
|
490
|
+
|
491
|
+
# @api private
|
492
|
+
def locals(render_env, input)
|
493
|
+
exposures.(context: render_env.context, **input) do |value, exposure|
|
494
|
+
if exposure.decorate? && value
|
495
|
+
render_env.part(exposure.name, value, **exposure.options)
|
496
|
+
else
|
497
|
+
value
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
|
502
|
+
# @api private
|
503
|
+
def layout_locals(locals)
|
504
|
+
locals.each_with_object({}) do |(key, value), layout_locals|
|
505
|
+
layout_locals[key] = value if exposures[key].for_layout?
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
# @api private
|
510
|
+
def layout?
|
511
|
+
!!config.layout # rubocop:disable Style/DoubleNegation
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|