viu 0.0.2 → 0.0.3

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: 2f24b77a5e5a5ada196406705ac4ff02102f7915321f0b22cc946f8a9fc27040
4
- data.tar.gz: 2648be1eec444b862d8c7c40f4ccf557011be42784a9ab29b0944f8251d8fff7
3
+ metadata.gz: a20c56c9d9d9efc2b46ed24d46628f24e671e28f5601cdd475939df6b2162974
4
+ data.tar.gz: 2b940845dd9fc93fc8af36c7341581b2c37d2cf28649d17f156b7f56666191c2
5
5
  SHA512:
6
- metadata.gz: fb6709c1bf1b41bf7cd451fc20683fcb6e98e7aa4bfe107a21bea21e8a0d0ece7277f6de65e75c385eb545498306bd75a148e497ce5e3799d6d8f875238ed6ce
7
- data.tar.gz: 6b75da7d7c59928851d230ed0b1f4dcb527cf3f0d8b3bbef93c6c87d1ecd8f023155d1ab5026b75b64223c45301c6e7b8fbc70c415401ecfb4ab2984401a323f
6
+ metadata.gz: 2864b1ecae62628434db59ea5256914b826c42305b66fa0bf6437319e16fa898e828fdea020b87c5d19e8537261f112732d7fbf90ef092e809e5369aa487f2e9
7
+ data.tar.gz: 1c0cb834d20c499808007b04a3c993a08a6858bb56bd03ac699ee27f047386f585b63075823f4d6cad84c714fefb71b714942865a2335500083f4954bedb53e6
@@ -1,3 +1,9 @@
1
+ ## 0.0.3 2020-09-02
2
+
3
+ - Added Viu::Json
4
+ - Added Viu::Xml
5
+ - Allow Viu::Html template! to receive a proc
6
+
1
7
  ## 0.0.2 2020-08-16
2
8
 
3
9
  ### Added
data/Gemfile CHANGED
@@ -7,3 +7,4 @@ gemspec
7
7
  rails_version = "#{ENV['RAILS_VERSION'] || '~> 5.2'}"
8
8
 
9
9
  gem "rails", rails_version == "master" ? { github: "rails/rails" } : rails_version
10
+ gem "oj"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- viu (0.0.2)
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
- Currently this is a POC (proof of concept), on the usage of `ActionView` as a "real" view layer. Inspired on
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
- The project is already been tested on a small scale in our production environment.
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
- ## Your first View
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 < Viu::Html
15
- def initialize(name)
16
- @name = name
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/my_view.html.erb`:
172
+ `app/views/layouts/application_layout.html.erb`:
22
173
  ```erb
23
- <h1><%= @name %></h1>
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
- Unless a template is given directly, a view will try to find a template with it's name.
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
@@ -4,6 +4,8 @@ require "viu/version"
4
4
 
5
5
  require "viu/html"
6
6
  require "viu/layout"
7
+ require "viu/json"
8
+ require "viu/xml"
7
9
  require "viu/test_case"
8
10
 
9
11
  require 'viu/railtie' if defined?(Rails)
@@ -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)
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Viu
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.3"
5
5
  end
@@ -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.2
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-08-16 00:00:00.000000000 Z
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: