viu 0.0.2 → 0.0.3
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/CHANGELOG.md +6 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +5 -1
- data/README.md +368 -12
- data/lib/viu.rb +2 -0
- data/lib/viu/html.rb +6 -0
- data/lib/viu/json.rb +31 -0
- data/lib/viu/version.rb +1 -1
- data/lib/viu/xml.rb +31 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a20c56c9d9d9efc2b46ed24d46628f24e671e28f5601cdd475939df6b2162974
|
4
|
+
data.tar.gz: 2b940845dd9fc93fc8af36c7341581b2c37d2cf28649d17f156b7f56666191c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2864b1ecae62628434db59ea5256914b826c42305b66fa0bf6437319e16fa898e828fdea020b87c5d19e8537261f112732d7fbf90ef092e809e5369aa487f2e9
|
7
|
+
data.tar.gz: 1c0cb834d20c499808007b04a3c993a08a6858bb56bd03ac699ee27f047386f585b63075823f4d6cad84c714fefb71b714942865a2335500083f4954bedb53e6
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
viu (0.0.
|
4
|
+
viu (0.0.3)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -48,6 +48,7 @@ GEM
|
|
48
48
|
minitest (~> 5.1)
|
49
49
|
tzinfo (~> 1.1)
|
50
50
|
arel (9.0.0)
|
51
|
+
bigdecimal (2.0.0)
|
51
52
|
builder (3.2.4)
|
52
53
|
concurrent-ruby (1.1.7)
|
53
54
|
crass (1.0.6)
|
@@ -75,6 +76,8 @@ GEM
|
|
75
76
|
nio4r (2.5.2)
|
76
77
|
nokogiri (1.10.10)
|
77
78
|
mini_portile2 (~> 2.4.0)
|
79
|
+
oj (3.10.12)
|
80
|
+
bigdecimal (>= 1.0, < 3)
|
78
81
|
rack (2.2.3)
|
79
82
|
rack-test (1.1.0)
|
80
83
|
rack (>= 1.0, < 3)
|
@@ -134,6 +137,7 @@ DEPENDENCIES
|
|
134
137
|
bundler (~> 1.17)
|
135
138
|
haml (~> 5)
|
136
139
|
minitest (~> 5.0)
|
140
|
+
oj
|
137
141
|
rails (~> 5.2)
|
138
142
|
rake (~> 12.3)
|
139
143
|
simplecov (~> 0.18.0)
|
data/README.md
CHANGED
@@ -1,26 +1,382 @@
|
|
1
1
|
# Viu
|
2
2
|
|
3
|
-
|
4
|
-
`view_component`, `cells` and others, `viu` is just a small wrapper around `AV`. It aims to work with the least amount
|
5
|
-
of surprise with Rails, but with a few boundaries, like a View won't be able to automatically access `@ivars` defined
|
6
|
-
in the controller, those have to explicitly be passed to them.
|
3
|
+
Rails' missing View layer.
|
7
4
|
|
8
|
-
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem "viu"
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
$ bundle install
|
17
|
+
```
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ gem install viu
|
23
|
+
```
|
24
|
+
|
25
|
+
## Rails Setup
|
26
|
+
|
27
|
+
Add this to your `config/application.rb` file:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
config.eager_load_paths << Rails.root.join("app/views")
|
31
|
+
```
|
32
|
+
|
33
|
+
This will add the `app/views` folder to the eager load paths, as it is not loaded there by default.
|
34
|
+
|
35
|
+
## Viu::Html
|
36
|
+
|
37
|
+
Probably the most common view type of the wild web lands.
|
38
|
+
|
39
|
+
### Usage
|
40
|
+
|
41
|
+
`app/views/awesome_view.rb`:
|
42
|
+
```ruby
|
43
|
+
class AwesomeView < Viu::Html
|
44
|
+
|
45
|
+
layout! Layouts::ApplicationLayout
|
46
|
+
|
47
|
+
def initialize(posts:)
|
48
|
+
@posts = posts
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def power_level_class(power)
|
54
|
+
return "over-9000" if power > 9000
|
55
|
+
|
56
|
+
"not-awesome-enough"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
`app/views/awesome_view.html.erb`:
|
62
|
+
```erb
|
63
|
+
<h1>Awesomesauce</h1>
|
64
|
+
<%- @posts.each do |post| %>
|
65
|
+
<article class="<%= power_level_class(post.awesomeness) %>">
|
66
|
+
<h1><%= link_to post.title, post, class: "awesome-title" %></h1>
|
67
|
+
<p><%= post.summary %></p>
|
68
|
+
</article>
|
69
|
+
<%- end %>
|
70
|
+
```
|
71
|
+
|
72
|
+
`app/controllers/home_controller.rb`:
|
73
|
+
```ruby
|
74
|
+
# GET /awesome
|
75
|
+
def awesome
|
76
|
+
posts = Post.order(awesomeness: :desc)
|
77
|
+
render_view AwesomeView.new(posts: posts)
|
78
|
+
end
|
79
|
+
```
|
9
80
|
|
10
|
-
|
81
|
+
Unless a template is given directly (using the `template! "file"` option inside the view), a view will try to find a
|
82
|
+
template with it's name.
|
83
|
+
|
84
|
+
As seen in the example above a view's template has access to all instance variables, public and private methods defined
|
85
|
+
in the view, as well as all `ActionView` helpers.
|
86
|
+
|
87
|
+
Also, the view won't have access to any variables or instance variables defined in the controller, those have to be
|
88
|
+
passed in directly, as shown in `AwesomeView.new(posts: posts)`.
|
89
|
+
|
90
|
+
### ApplicationView
|
91
|
+
|
92
|
+
Usually it's a common practice in rails projects to define an `ApplicationController` or `ApplicationRecord` base class
|
93
|
+
that can be inherited from. The same can be done with views, an `ApplicationView` class is a good place to put some
|
94
|
+
basic functionalities that should be available to all views.
|
95
|
+
|
96
|
+
### Callable templates
|
97
|
+
|
98
|
+
A view's template can be overridden with a `proc`. __Attention:__ currently using a callable template doesn't work with
|
99
|
+
layouts, they will be ignored.
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
# defining the view
|
103
|
+
class HeaderView < ApplicationView
|
104
|
+
|
105
|
+
template! proc { tag.h1 @title }
|
106
|
+
|
107
|
+
def initialize(title:)
|
108
|
+
@title = title
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# rendering the view
|
113
|
+
render_view HeaderView.new(title: "Mas Gente!") # => "<h1>Mas Gente!</h1>"
|
114
|
+
```
|
115
|
+
|
116
|
+
### Layouts
|
117
|
+
|
118
|
+
By default a view won't be rendered inside a layout. To use a layout, one has to be declared, either directly on the
|
119
|
+
view or passed to the `render_view` method.
|
120
|
+
|
121
|
+
#### Defining a layout template
|
11
122
|
|
12
123
|
`app/views/my_view.rb`:
|
13
124
|
```ruby
|
14
|
-
class MyView <
|
15
|
-
|
16
|
-
|
125
|
+
class MyView < ApplicationView
|
126
|
+
# This will look for an application template inside app/views/layouts,
|
127
|
+
# it can be a html.erb or any other template language defined in your application.
|
128
|
+
layout! 'layouts/application'
|
129
|
+
end
|
130
|
+
```
|
131
|
+
|
132
|
+
`app/views/layouts/application.html.erb`:
|
133
|
+
```erb
|
134
|
+
<html>
|
135
|
+
<head>
|
136
|
+
<title>A view view a Layout</title>
|
137
|
+
<%= stylesheet_link_tag "application" %>
|
138
|
+
<%= javascript_include_tag "application" %>
|
139
|
+
</head>
|
140
|
+
<body>
|
141
|
+
<header>Header from the layout</header>
|
142
|
+
<%= yield %>
|
143
|
+
</body>
|
144
|
+
</html>
|
145
|
+
```
|
146
|
+
|
147
|
+
#### Defining a layout view
|
148
|
+
|
149
|
+
A layout can also be a `Viu::Layout` class, in this case it will work pretty much like a `Viu::Html`.
|
150
|
+
|
151
|
+
`app/views/my_view.rb`:
|
152
|
+
```ruby
|
153
|
+
class MyView < ApplicationView
|
154
|
+
layout! Layouts::ApplicationLayout
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
`app/views/layouts/application_layout.rb`:
|
159
|
+
```ruby
|
160
|
+
module Layouts
|
161
|
+
|
162
|
+
# a layout needs to inherit from Viu::Layout
|
163
|
+
class ApplicationLayout < Viu::Layout
|
164
|
+
|
165
|
+
def header_text
|
166
|
+
"This is a Viu::Layout"
|
167
|
+
end
|
17
168
|
end
|
18
169
|
end
|
19
170
|
```
|
20
171
|
|
21
|
-
`app/views/
|
172
|
+
`app/views/layouts/application_layout.html.erb`:
|
22
173
|
```erb
|
23
|
-
<
|
174
|
+
<html>
|
175
|
+
<head>
|
176
|
+
<title>A Viu::Layout</title>
|
177
|
+
<%= stylesheet_link_tag "application" %>
|
178
|
+
<%= javascript_include_tag "application" %>
|
179
|
+
</head>
|
180
|
+
<body>
|
181
|
+
<header><%= header_text %></header>
|
182
|
+
<%= yield %>
|
183
|
+
</body>
|
184
|
+
</html>
|
24
185
|
```
|
25
186
|
|
26
|
-
|
187
|
+
Similar as the `Viu::Html` a layout will search for a template with it's name, if none is given directly.
|
188
|
+
|
189
|
+
#### Defining a layout `proc`
|
190
|
+
|
191
|
+
A layout can also be declared as a `proc`, this is useful when the view wants to override the layout parameters.
|
192
|
+
The `proc` will be executed in the context of the view and the result must respond to `render_in`.
|
193
|
+
|
194
|
+
`app/views/my_view.rb`:
|
195
|
+
```ruby
|
196
|
+
class MyView < ApplicationView
|
197
|
+
|
198
|
+
layout! proc { Layouts::ApplicationLayout.new(header_text: text) }
|
199
|
+
|
200
|
+
private
|
201
|
+
|
202
|
+
def text
|
203
|
+
"Text from the view"
|
204
|
+
end
|
205
|
+
end
|
206
|
+
```
|
207
|
+
|
208
|
+
`app/views/layouts/application_layout.rb`:
|
209
|
+
```ruby
|
210
|
+
module Layouts
|
211
|
+
class ApplicationLayout < Viu::Layout
|
212
|
+
|
213
|
+
attr_reader :header_text
|
214
|
+
|
215
|
+
def initialize(header_text: 'The header text')
|
216
|
+
@header_text = header_text
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
`app/views/layouts/application_layout.html.erb`:
|
223
|
+
```erb
|
224
|
+
<html>
|
225
|
+
<head>
|
226
|
+
<title>A Viu::Layout</title>
|
227
|
+
<%= stylesheet_link_tag "application" %>
|
228
|
+
<%= javascript_include_tag "application" %>
|
229
|
+
</head>
|
230
|
+
<body>
|
231
|
+
<header>
|
232
|
+
<!-- it will render "Text from the view" here -->
|
233
|
+
<%= header_text %>
|
234
|
+
</header>
|
235
|
+
<%= yield %>
|
236
|
+
</body>
|
237
|
+
</html>
|
238
|
+
```
|
239
|
+
|
240
|
+
#### Overriding layout on `render_view`
|
241
|
+
|
242
|
+
Usually a `layout` is defined directly in the view, as most of the times a view will be used in a single "context",
|
243
|
+
but if needed it can be overridden on the `render_view` with the `layout:` option, like so:
|
244
|
+
|
245
|
+
```ruby
|
246
|
+
# it accepts a template
|
247
|
+
render_view MyView.new, layout: 'layouts/admin'
|
248
|
+
|
249
|
+
# a Viu::Layout
|
250
|
+
render_view MyView.new, layout: Layouts::OtherLayout
|
251
|
+
|
252
|
+
# or a proc
|
253
|
+
render_view MyView.new, layout: proc { Layouts::OtherLayout.new(title: 'Dashboard') }
|
254
|
+
```
|
255
|
+
|
256
|
+
## Viu::Json
|
257
|
+
|
258
|
+
This is a simple module that can be included in your views, it will add a `to_json` method, this is called by default
|
259
|
+
when rendering in a Rails env. The value returned from `json_output` will be the output of the view.
|
260
|
+
|
261
|
+
`app/views/api/posts/resource_view.rb`:
|
262
|
+
```ruby
|
263
|
+
module Api
|
264
|
+
module Posts
|
265
|
+
class ResourceView
|
266
|
+
include Viu::Json
|
267
|
+
|
268
|
+
def initialize(post:)
|
269
|
+
@post = post
|
270
|
+
end
|
271
|
+
|
272
|
+
private
|
273
|
+
|
274
|
+
def author
|
275
|
+
@author ||= @post.author
|
276
|
+
end
|
277
|
+
|
278
|
+
def json_output
|
279
|
+
{
|
280
|
+
title: @post.title,
|
281
|
+
published_on: @post.published_on.to_s(:iso8601),
|
282
|
+
author: {
|
283
|
+
name: author.name,
|
284
|
+
avatar: author.avatar.url
|
285
|
+
}
|
286
|
+
}
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
```
|
292
|
+
|
293
|
+
`app/controllers/api/posts_controller.rb`:
|
294
|
+
```ruby
|
295
|
+
def show
|
296
|
+
post = Post.find(params[:id])
|
297
|
+
render json: Api::Posts::ResourceView.new(post: post)
|
298
|
+
end
|
299
|
+
```
|
300
|
+
|
301
|
+
The default `JSON` encoder can be overridden like so:
|
302
|
+
|
303
|
+
```ruby
|
304
|
+
class MyJsonView
|
305
|
+
include Viu::Json
|
306
|
+
|
307
|
+
json_encoder ->(input) { Oj.dump(input) }
|
308
|
+
|
309
|
+
end
|
310
|
+
```
|
311
|
+
|
312
|
+
## Viu::Xml
|
313
|
+
|
314
|
+
Similar to `Viu::Json` this is a simple module that can be included in your views, it will add a `to_xml` method,
|
315
|
+
this is called by default when rendering in a Rails env. The value returned from `xml_output` will be the output
|
316
|
+
of the view.
|
317
|
+
|
318
|
+
`app/views/api/posts/resource_view.rb`:
|
319
|
+
```ruby
|
320
|
+
module Api
|
321
|
+
module Posts
|
322
|
+
class ResourceView
|
323
|
+
include Viu::Xml
|
324
|
+
|
325
|
+
def initialize(post:)
|
326
|
+
@post = post
|
327
|
+
end
|
328
|
+
|
329
|
+
private
|
330
|
+
|
331
|
+
def author
|
332
|
+
@author ||= @post.author
|
333
|
+
end
|
334
|
+
|
335
|
+
def xml_output
|
336
|
+
{
|
337
|
+
title: @post.title,
|
338
|
+
published_on: @post.published_on.to_s(:iso8601),
|
339
|
+
author: {
|
340
|
+
name: author.name,
|
341
|
+
avatar: author.avatar.url
|
342
|
+
}
|
343
|
+
}
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
```
|
349
|
+
|
350
|
+
`app/controllers/api/posts_controller.rb`:
|
351
|
+
```ruby
|
352
|
+
def show
|
353
|
+
post = Post.find(params[:id])
|
354
|
+
render xml Api::Posts::ResourceView.new(post: post)
|
355
|
+
end
|
356
|
+
```
|
357
|
+
|
358
|
+
The default `XML` encoder can be overridden like so:
|
359
|
+
|
360
|
+
```ruby
|
361
|
+
class MyXmlView
|
362
|
+
include Viu::Xml
|
363
|
+
|
364
|
+
xml_encoder ->(input) { Ox.dump(input) }
|
365
|
+
|
366
|
+
end
|
367
|
+
```
|
368
|
+
|
369
|
+
## Known Issues
|
370
|
+
|
371
|
+
* A `Viu::Layout` doesn't work with `content_for` blocks, it's only available on a regular layout template for now;
|
372
|
+
* Templates and partials require the "full" path, eg: `layouts/application` or `posts/index`;
|
373
|
+
* Currently layout inheritance isn't working correctly.
|
374
|
+
|
375
|
+
## About
|
376
|
+
|
377
|
+
Inspired by `view_component`, `cells` and others, currently this is a POC (proof of concept) to create a View layer
|
378
|
+
for Rails, it uses `ActionView` as the base for HTML views and it aims to work with the least amount of surprises on a
|
379
|
+
Rails application, but with a few boundaries, like a View won't be able to automatically access `@ivars` defined
|
380
|
+
in a controller, those have to explicitly be passed to them.
|
381
|
+
|
382
|
+
The project is already been tested on a small scale in our production environment.
|
data/lib/viu.rb
CHANGED
data/lib/viu/html.rb
CHANGED
@@ -10,6 +10,8 @@ module Viu
|
|
10
10
|
def render_in(view_context, options = EMPTY_HASH)
|
11
11
|
__setup!(view_context)
|
12
12
|
|
13
|
+
return __render_template_proc if __fetch_template!.is_a?(Proc)
|
14
|
+
|
13
15
|
layout = options.fetch(:layout, self.class.layout)
|
14
16
|
|
15
17
|
if layout.is_a?(Class)
|
@@ -48,6 +50,10 @@ module Viu
|
|
48
50
|
self.class.template!(self.class.name.underscore)
|
49
51
|
end
|
50
52
|
|
53
|
+
def __render_template_proc
|
54
|
+
self.instance_exec(&__fetch_template!)
|
55
|
+
end
|
56
|
+
|
51
57
|
def __render_layout_class(layout)
|
52
58
|
layout.new.render_in(@view_context) do
|
53
59
|
@view_renderer.render(self, template: __fetch_template!, layout: nil)
|
data/lib/viu/json.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'active_support/core_ext/class/attribute'
|
5
|
+
|
6
|
+
module Viu
|
7
|
+
module Json
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
DEFAULT_JSON_ENCODER = ->(input) { input.to_json }.freeze
|
11
|
+
|
12
|
+
included do
|
13
|
+
class_attribute :__json_encoder, instance_accessor: false, instance_predicate: false,
|
14
|
+
default: DEFAULT_JSON_ENCODER
|
15
|
+
|
16
|
+
attr_reader :rendering_options
|
17
|
+
|
18
|
+
def to_json(options = EMPTY_HASH)
|
19
|
+
@rendering_options = options
|
20
|
+
self.class.__json_encoder.call(json_output)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class_methods do
|
25
|
+
|
26
|
+
def json_encoder(value)
|
27
|
+
self.__json_encoder = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/viu/version.rb
CHANGED
data/lib/viu/xml.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
require 'active_support/core_ext/class/attribute'
|
5
|
+
|
6
|
+
module Viu
|
7
|
+
module Xml
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
DEFAULT_XML_ENCODER = ->(input) { input.to_xml }.freeze
|
11
|
+
|
12
|
+
included do
|
13
|
+
class_attribute :__xml_encoder, instance_accessor: false, instance_predicate: false,
|
14
|
+
default: DEFAULT_XML_ENCODER
|
15
|
+
|
16
|
+
attr_reader :rendering_options
|
17
|
+
|
18
|
+
def to_xml(options = EMPTY_HASH)
|
19
|
+
@rendering_options = options
|
20
|
+
self.class.__xml_encoder.call(xml_output)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class_methods do
|
25
|
+
|
26
|
+
def xml_encoder(value)
|
27
|
+
self.__xml_encoder = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: viu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ralf Schmitz Bongiolo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,12 +114,14 @@ files:
|
|
114
114
|
- bin/setup
|
115
115
|
- lib/viu.rb
|
116
116
|
- lib/viu/html.rb
|
117
|
+
- lib/viu/json.rb
|
117
118
|
- lib/viu/layout.rb
|
118
119
|
- lib/viu/railtie.rb
|
119
120
|
- lib/viu/rendering_helpers.rb
|
120
121
|
- lib/viu/test_case.rb
|
121
122
|
- lib/viu/test_helpers.rb
|
122
123
|
- lib/viu/version.rb
|
124
|
+
- lib/viu/xml.rb
|
123
125
|
- viu.gemspec
|
124
126
|
homepage: https://github.com/mrbongiolo/viu
|
125
127
|
licenses:
|