viu 0.0.1 → 0.0.6

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: 7fcf443dc32a50462eb147063436581b225a066e1368a51132eb485379bd4891
4
- data.tar.gz: 18ba17c3be19f4562447374e2b65c2dba7bba3acf3acb6d91c1f6412a3a4b5bc
3
+ metadata.gz: 34b16c8835912c41e5464fa58b2e7f70b947d502c02fd50954464a7db5656820
4
+ data.tar.gz: a5dea697f921f16c336d6d038d6416e4353e5ee103a8d2dc081b9ed8b7ad6cba
5
5
  SHA512:
6
- metadata.gz: 7e4f28c552311fa43527a3cc0c59e18f22f172848f0c28b7eb05fe0dea8fa3bd8c3ab943f14018bfae347877632071b71c12a916645ec222ae22b74ac096ee78
7
- data.tar.gz: 0b00071e7a91eb93f75c933f6ed0c5e56178afae13ad66027911a20bf582b715c59d061b98b639ce83c730242ebd5ea37ac2dd4c4fc2d37b44726ab1a62e8a67
6
+ metadata.gz: e65307f39be95a5e33328e22368a8072ece3357bf71bf53598f797470a71a6dd81241817b22bb623c1953e7e24db36dc54112a92ea27ad3f44ab8974c55b085d
7
+ data.tar.gz: 4ff6b0286b900b2cec67f034342238b498ecda7d455f1210ea610f44323d0d19423fcee6bd55f766934d8be58f14ee5ce9624706be15f32eb23366aedac9a924
data/.gitignore CHANGED
@@ -9,3 +9,5 @@
9
9
  /test/support/dummy/tmp
10
10
  /test/support/dummy/log
11
11
  *.gem
12
+
13
+ /gemfiles/*.gemfile.lock
@@ -0,0 +1,19 @@
1
+ # appraise "rails-5-0" do
2
+ # gem "rails", "~> 5.0.0"
3
+ # end
4
+
5
+ # appraise "rails-5-1" do
6
+ # gem "rails", "~> 5.1.0"
7
+ # end
8
+
9
+ appraise "rails-5-2" do
10
+ gem "rails", "~> 5.2.0"
11
+ end
12
+
13
+ appraise "rails-6-0" do
14
+ gem "rails", "~> 6.0.0"
15
+ end
16
+
17
+ appraise "rails-6-1" do
18
+ gem "rails", "~> 6.1.0"
19
+ end
@@ -0,0 +1,32 @@
1
+ ## 0.0.6 2020-12-23
2
+
3
+ - Set content type as "text/html" when using #render_view
4
+
5
+ ## 0.0.5 2020-12-01
6
+
7
+ - Added support for Rails 6.1.0.rc1
8
+ - Fixed bug with views not having access to compiled template methods (using #compiled_method_container)
9
+
10
+ ## 0.0.4 2020-11-29
11
+
12
+ - Added support for Rails ~> 6.0.0
13
+
14
+ ## 0.0.3 2020-09-02
15
+
16
+ - Added Viu::Json
17
+ - Added Viu::Xml
18
+ - Allow Viu::Html template! to receive a proc
19
+
20
+ ## 0.0.2 2020-08-16
21
+
22
+ ### Added
23
+
24
+ - Improve test helpers
25
+
26
+ ### Fixed
27
+
28
+ - Viu::Html#controller should be public
29
+
30
+ ## 0.0.1 2020-08-10
31
+
32
+ First public release
data/Gemfile CHANGED
@@ -4,6 +4,5 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  gemspec
6
6
 
7
- rails_version = "#{ENV['RAILS_VERSION'] || '~> 5.2'}"
8
-
9
- gem "rails", rails_version == "master" ? { github: "rails/rails" } : rails_version
7
+ gem "rails", github: "rails/rails"
8
+ gem "oj"
@@ -1,66 +1,113 @@
1
- PATH
2
- remote: .
3
- specs:
4
- viu (0.0.1)
5
-
6
- GEM
7
- remote: https://rubygems.org/
1
+ GIT
2
+ remote: https://github.com/rails/rails
3
+ revision: 007a86506f02db265b6c8156575f29733931338e
8
4
  specs:
9
- actioncable (5.2.4.3)
10
- actionpack (= 5.2.4.3)
5
+ actioncable (6.2.0.alpha)
6
+ actionpack (= 6.2.0.alpha)
7
+ activesupport (= 6.2.0.alpha)
11
8
  nio4r (~> 2.0)
12
9
  websocket-driver (>= 0.6.1)
13
- actionmailer (5.2.4.3)
14
- actionpack (= 5.2.4.3)
15
- actionview (= 5.2.4.3)
16
- activejob (= 5.2.4.3)
10
+ actionmailbox (6.2.0.alpha)
11
+ actionpack (= 6.2.0.alpha)
12
+ activejob (= 6.2.0.alpha)
13
+ activerecord (= 6.2.0.alpha)
14
+ activestorage (= 6.2.0.alpha)
15
+ activesupport (= 6.2.0.alpha)
16
+ mail (>= 2.7.1)
17
+ actionmailer (6.2.0.alpha)
18
+ actionpack (= 6.2.0.alpha)
19
+ actionview (= 6.2.0.alpha)
20
+ activejob (= 6.2.0.alpha)
21
+ activesupport (= 6.2.0.alpha)
17
22
  mail (~> 2.5, >= 2.5.4)
18
23
  rails-dom-testing (~> 2.0)
19
- actionpack (5.2.4.3)
20
- actionview (= 5.2.4.3)
21
- activesupport (= 5.2.4.3)
22
- rack (~> 2.0, >= 2.0.8)
24
+ actionpack (6.2.0.alpha)
25
+ actionview (= 6.2.0.alpha)
26
+ activesupport (= 6.2.0.alpha)
27
+ rack (~> 2.0, >= 2.0.9)
23
28
  rack-test (>= 0.6.3)
24
29
  rails-dom-testing (~> 2.0)
25
- rails-html-sanitizer (~> 1.0, >= 1.0.2)
26
- actionview (5.2.4.3)
27
- activesupport (= 5.2.4.3)
30
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
31
+ actiontext (6.2.0.alpha)
32
+ actionpack (= 6.2.0.alpha)
33
+ activerecord (= 6.2.0.alpha)
34
+ activestorage (= 6.2.0.alpha)
35
+ activesupport (= 6.2.0.alpha)
36
+ nokogiri (>= 1.8.5)
37
+ actionview (6.2.0.alpha)
38
+ activesupport (= 6.2.0.alpha)
28
39
  builder (~> 3.1)
29
40
  erubi (~> 1.4)
30
41
  rails-dom-testing (~> 2.0)
31
- rails-html-sanitizer (~> 1.0, >= 1.0.3)
32
- activejob (5.2.4.3)
33
- activesupport (= 5.2.4.3)
42
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
43
+ activejob (6.2.0.alpha)
44
+ activesupport (= 6.2.0.alpha)
34
45
  globalid (>= 0.3.6)
35
- activemodel (5.2.4.3)
36
- activesupport (= 5.2.4.3)
37
- activerecord (5.2.4.3)
38
- activemodel (= 5.2.4.3)
39
- activesupport (= 5.2.4.3)
40
- arel (>= 9.0)
41
- activestorage (5.2.4.3)
42
- actionpack (= 5.2.4.3)
43
- activerecord (= 5.2.4.3)
46
+ activemodel (6.2.0.alpha)
47
+ activesupport (= 6.2.0.alpha)
48
+ activerecord (6.2.0.alpha)
49
+ activemodel (= 6.2.0.alpha)
50
+ activesupport (= 6.2.0.alpha)
51
+ activestorage (6.2.0.alpha)
52
+ actionpack (= 6.2.0.alpha)
53
+ activejob (= 6.2.0.alpha)
54
+ activerecord (= 6.2.0.alpha)
55
+ activesupport (= 6.2.0.alpha)
44
56
  marcel (~> 0.3.1)
45
- activesupport (5.2.4.3)
57
+ mimemagic (~> 0.3.2)
58
+ activesupport (6.2.0.alpha)
46
59
  concurrent-ruby (~> 1.0, >= 1.0.2)
47
- i18n (>= 0.7, < 2)
48
- minitest (~> 5.1)
49
- tzinfo (~> 1.1)
50
- arel (9.0.0)
60
+ i18n (>= 1.6, < 2)
61
+ minitest (>= 5.1)
62
+ tzinfo (~> 2.0)
63
+ zeitwerk (~> 2.3)
64
+ rails (6.2.0.alpha)
65
+ actioncable (= 6.2.0.alpha)
66
+ actionmailbox (= 6.2.0.alpha)
67
+ actionmailer (= 6.2.0.alpha)
68
+ actionpack (= 6.2.0.alpha)
69
+ actiontext (= 6.2.0.alpha)
70
+ actionview (= 6.2.0.alpha)
71
+ activejob (= 6.2.0.alpha)
72
+ activemodel (= 6.2.0.alpha)
73
+ activerecord (= 6.2.0.alpha)
74
+ activestorage (= 6.2.0.alpha)
75
+ activesupport (= 6.2.0.alpha)
76
+ bundler (>= 1.15.0)
77
+ railties (= 6.2.0.alpha)
78
+ sprockets-rails (>= 2.0.0)
79
+ railties (6.2.0.alpha)
80
+ actionpack (= 6.2.0.alpha)
81
+ activesupport (= 6.2.0.alpha)
82
+ method_source
83
+ rake (>= 0.8.7)
84
+ thor (~> 1.0)
85
+
86
+ PATH
87
+ remote: .
88
+ specs:
89
+ viu (0.0.6)
90
+
91
+ GEM
92
+ remote: https://rubygems.org/
93
+ specs:
94
+ appraisal (2.3.0)
95
+ bundler
96
+ rake
97
+ thor (>= 0.14.0)
51
98
  builder (3.2.4)
52
99
  concurrent-ruby (1.1.7)
53
100
  crass (1.0.6)
54
- docile (1.3.2)
55
- erubi (1.9.0)
101
+ docile (1.3.4)
102
+ erubi (1.10.0)
56
103
  globalid (0.4.2)
57
104
  activesupport (>= 4.2.0)
58
- haml (5.1.2)
105
+ haml (5.2.1)
59
106
  temple (>= 0.8.0)
60
107
  tilt
61
108
  i18n (1.8.5)
62
109
  concurrent-ruby (~> 1.0)
63
- loofah (2.6.0)
110
+ loofah (2.8.0)
64
111
  crass (~> 1.0.2)
65
112
  nokogiri (>= 1.5.9)
66
113
  mail (2.7.1)
@@ -71,70 +118,54 @@ GEM
71
118
  mimemagic (0.3.5)
72
119
  mini_mime (1.0.2)
73
120
  mini_portile2 (2.4.0)
74
- minitest (5.14.1)
75
- nio4r (2.5.2)
121
+ minitest (5.14.2)
122
+ nio4r (2.5.4)
76
123
  nokogiri (1.10.10)
77
124
  mini_portile2 (~> 2.4.0)
125
+ oj (3.10.17)
78
126
  rack (2.2.3)
79
127
  rack-test (1.1.0)
80
128
  rack (>= 1.0, < 3)
81
- rails (5.2.4.3)
82
- actioncable (= 5.2.4.3)
83
- actionmailer (= 5.2.4.3)
84
- actionpack (= 5.2.4.3)
85
- actionview (= 5.2.4.3)
86
- activejob (= 5.2.4.3)
87
- activemodel (= 5.2.4.3)
88
- activerecord (= 5.2.4.3)
89
- activestorage (= 5.2.4.3)
90
- activesupport (= 5.2.4.3)
91
- bundler (>= 1.3.0)
92
- railties (= 5.2.4.3)
93
- sprockets-rails (>= 2.0.0)
94
129
  rails-dom-testing (2.0.3)
95
130
  activesupport (>= 4.2.0)
96
131
  nokogiri (>= 1.6)
97
132
  rails-html-sanitizer (1.3.0)
98
133
  loofah (~> 2.3)
99
- railties (5.2.4.3)
100
- actionpack (= 5.2.4.3)
101
- activesupport (= 5.2.4.3)
102
- method_source
103
- rake (>= 0.8.7)
104
- thor (>= 0.19.0, < 2.0)
105
134
  rake (12.3.3)
106
135
  simplecov (0.18.5)
107
136
  docile (~> 1.1)
108
137
  simplecov-html (~> 0.11)
109
- simplecov-html (0.12.2)
138
+ simplecov-html (0.12.3)
110
139
  slim (4.1.0)
111
140
  temple (>= 0.7.6, < 0.9)
112
141
  tilt (>= 2.0.6, < 2.1)
113
142
  sprockets (4.0.2)
114
143
  concurrent-ruby (~> 1.0)
115
144
  rack (> 1, < 3)
116
- sprockets-rails (3.2.1)
145
+ sprockets-rails (3.2.2)
117
146
  actionpack (>= 4.0)
118
147
  activesupport (>= 4.0)
119
148
  sprockets (>= 3.0.0)
120
149
  temple (0.8.2)
121
150
  thor (1.0.1)
122
- thread_safe (0.3.6)
123
151
  tilt (2.0.10)
124
- tzinfo (1.2.7)
125
- thread_safe (~> 0.1)
152
+ tzinfo (2.0.4)
153
+ concurrent-ruby (~> 1.0)
126
154
  websocket-driver (0.7.3)
127
155
  websocket-extensions (>= 0.1.0)
128
156
  websocket-extensions (0.1.5)
157
+ zeitwerk (2.4.2)
129
158
 
130
159
  PLATFORMS
131
160
  ruby
132
161
 
133
162
  DEPENDENCIES
163
+ appraisal (~> 2.3)
134
164
  bundler (~> 1.17)
135
165
  haml (~> 5)
136
166
  minitest (~> 5.0)
137
- rails (~> 5.2)
167
+ oj
168
+ rails!
138
169
  rake (~> 12.3)
139
170
  simplecov (~> 0.18.0)
140
171
  slim (~> 4)
data/README.md CHANGED
@@ -1,26 +1,402 @@
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
+ ```
80
+
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
122
+
123
+ `app/views/my_view.rb`:
124
+ ```ruby
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
168
+ end
169
+ end
170
+ ```
9
171
 
10
- ## Your first View
172
+ `app/views/layouts/application_layout.html.erb`:
173
+ ```erb
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>
185
+ ```
186
+
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`.
11
193
 
12
194
  `app/views/my_view.rb`:
13
195
  ```ruby
14
- class MyView < Viu::Html
15
- def initialize(name)
16
- @name = name
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
17
218
  end
18
219
  end
19
220
  ```
20
221
 
21
- `app/views/my_view.html.erb`:
222
+ `app/views/layouts/application_layout.html.erb`:
22
223
  ```erb
23
- <h1><%= @name %></h1>
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
24
356
  ```
25
357
 
26
- Unless a template is given directly, a view will try to find a template with it's name.
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.
383
+
384
+ ## Development
385
+
386
+ ```ruby
387
+ # install dependencies
388
+ bin/setup install
389
+
390
+ # running tests
391
+ bundle exec rake test
392
+
393
+ # running tests for all rails versions
394
+ bundle exec appraisal rake test
395
+
396
+ # releasing a new version:
397
+ # update changelog
398
+ # update VERSION on lib/viu/version.rb
399
+ # run bundle exec rake release
400
+ # create a Bump to version x.x.x commit
401
+ # run bundle exec rake release
402
+ ```
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_RETRY: "1"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 5.2.0"
6
+ gem "oj"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 6.0.0"
6
+ gem "oj"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "~> 6.1.0"
6
+ gem "oj"
7
+
8
+ gemspec path: "../"
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)
@@ -7,9 +7,17 @@ module Viu
7
7
 
8
8
  def initialize(*); end
9
9
 
10
+ module CompiledMethodContainer; end
11
+
12
+ def compiled_method_container
13
+ Viu::Html::CompiledMethodContainer
14
+ end
15
+
10
16
  def render_in(view_context, options = EMPTY_HASH)
11
17
  __setup!(view_context)
12
18
 
19
+ return __render_template_proc if __fetch_template!.is_a?(Proc)
20
+
13
21
  layout = options.fetch(:layout, self.class.layout)
14
22
 
15
23
  if layout.is_a?(Class)
@@ -21,9 +29,11 @@ module Viu
21
29
  end
22
30
  end
23
31
 
32
+ attr_reader :controller
33
+
24
34
  private
25
35
 
26
- attr_reader :controller, :request
36
+ attr_reader :request
27
37
 
28
38
  delegate :protect_against_forgery?, :form_authenticity_token, :content_security_policy?, to: :helpers
29
39
 
@@ -46,6 +56,10 @@ module Viu
46
56
  self.class.template!(self.class.name.underscore)
47
57
  end
48
58
 
59
+ def __render_template_proc
60
+ self.instance_exec(&__fetch_template!)
61
+ end
62
+
49
63
  def __render_layout_class(layout)
50
64
  layout.new.render_in(@view_context) do
51
65
  @view_renderer.render(self, template: __fetch_template!, layout: nil)
@@ -61,8 +75,10 @@ module Viu
61
75
  class << self
62
76
 
63
77
  def inherited(child)
78
+ child.include(Viu::Html::CompiledMethodContainer)
79
+
64
80
  if defined?(Rails) && child != Viu::Layout
65
- child.include Rails.application.routes.url_helpers unless child < Rails.application.routes.url_helpers
81
+ child.include(Rails.application.routes.url_helpers) unless child < Rails.application.routes.url_helpers
66
82
  end
67
83
  end
68
84
 
@@ -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
@@ -15,10 +15,22 @@ module Viu
15
15
  end
16
16
  end
17
17
 
18
+ RAILS_6_0 = Gem::Version.new('6.0.0')
19
+ RAILS_6_1_WITH_PRERELEASES = Gem::Version.new('6.1.0.a')
20
+ private_constant :RAILS_6_0, :RAILS_6_1_WITH_PRERELEASES
21
+
18
22
  def render_in(view_context, &block)
19
23
  __setup!(view_context)
20
24
 
21
- Renderer.new(@lookup_context).render(self, { partial: __fetch_template!, layout: nil }, block)
25
+ rails_version = ::Rails.gem_version
26
+
27
+ if rails_version >= RAILS_6_1_WITH_PRERELEASES
28
+ Renderer.new(@lookup_context, layout: nil).render(__fetch_template!, self, block).body
29
+ elsif rails_version >= RAILS_6_0
30
+ Renderer.new(@lookup_context).render(self, { partial: __fetch_template!, layout: nil }, block).body
31
+ else
32
+ Renderer.new(@lookup_context).render(self, { partial: __fetch_template!, layout: nil }, block)
33
+ end
22
34
  end
23
35
  end
24
36
  end
@@ -10,7 +10,7 @@ module Viu
10
10
 
11
11
  module ActionControllerHelpers
12
12
  def render_view(view, options = EMPTY_HASH)
13
- self.response_body = view.render_in(view_context, options)
13
+ render(html: view.render_in(view_context, options))
14
14
  end
15
15
  end
16
16
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/test_case"
3
+ require "action_view/test_case"
4
4
  require "rails/dom/testing/assertions"
5
5
  require "viu/test_helpers"
6
6
 
7
7
  module Viu
8
- class TestCase < ActiveSupport::TestCase
8
+ class TestCase < ActionView::TestCase
9
9
  include Rails::Dom::Testing::Assertions
10
10
  include Viu::TestHelpers
11
11
  end
@@ -1,19 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'active_support/concern'
4
+ require 'active_support/inflector'
5
+ require 'active_support/core_ext/class/attribute'
6
+
3
7
  module Viu
4
8
  module TestHelpers
9
+ extend ActiveSupport::Concern
10
+
11
+ private
5
12
 
6
- attr_reader :rendered_view
13
+ attr_reader :view_instance, :raw_rendered_view, :rendered_view
7
14
 
8
15
  def render_view(view, **args)
9
- @rendered_view = Nokogiri::HTML::Document.parse(
10
- view.render_in(controller.view_context, args)
11
- )
16
+ @rendered ||= []
17
+ @view_instance = view
18
+ @raw_rendered_view = @view_instance.render_in(__controller.view_context, **args)
19
+ @rendered << @raw_rendered_view
20
+ @rendered_view = Nokogiri::HTML::Document.parse(@raw_rendered_view)
12
21
  end
13
22
 
14
- def controller
15
- # TODO: make ApplicationController usage here configurable
16
- @controller ||= ApplicationController.new.tap { |c| c.request = request }
23
+ def __controller
24
+ @__controller ||= __constantize(self.class.__controller_class).new.tap do |c|
25
+ c.request = request
26
+ c.action_name = 'show'
27
+ end
17
28
  .extend(Rails.application.routes.url_helpers)
18
29
  end
19
30
 
@@ -21,10 +32,22 @@ module Viu
21
32
  @request ||= ActionDispatch::TestRequest.create
22
33
  end
23
34
 
24
- private
35
+ def __constantize(value)
36
+ return value if value.is_a?(Class)
37
+
38
+ ActiveSupport::Inflector.constantize(value)
39
+ end
40
+
41
+ included do
42
+ class_attribute :__controller_class, instance_accessor: false, instance_predicate: false,
43
+ default: 'ApplicationController'
44
+ end
45
+
46
+ class_methods do
25
47
 
26
- def document_root_element
27
- @rendered_view.root
48
+ def controller_class(klass)
49
+ self.__controller_class = klass
50
+ end
28
51
  end
29
52
  end
30
53
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Viu
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.6"
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
@@ -40,4 +40,5 @@ Gem::Specification.new do |spec|
40
40
  spec.add_development_dependency "simplecov", "~> 0.18.0"
41
41
  spec.add_development_dependency "haml", "~> 5"
42
42
  spec.add_development_dependency "slim", "~> 4"
43
+ spec.add_development_dependency "appraisal", "~> 2.3"
43
44
  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.1
4
+ version: 0.0.6
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-10 00:00:00.000000000 Z
11
+ date: 2020-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: appraisal
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.3'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.3'
97
111
  description: Rails' missing View layer.
98
112
  email:
99
113
  - mrbongiolo@hey.com
@@ -103,6 +117,8 @@ extra_rdoc_files: []
103
117
  files:
104
118
  - ".gitignore"
105
119
  - ".travis.yml"
120
+ - Appraisals
121
+ - CHANGELOG.md
106
122
  - CODE_OF_CONDUCT.md
107
123
  - Gemfile
108
124
  - Gemfile.lock
@@ -111,14 +127,20 @@ files:
111
127
  - Rakefile
112
128
  - bin/console
113
129
  - bin/setup
130
+ - gemfiles/.bundle/config
131
+ - gemfiles/rails_5_2.gemfile
132
+ - gemfiles/rails_6_0.gemfile
133
+ - gemfiles/rails_6_1.gemfile
114
134
  - lib/viu.rb
115
135
  - lib/viu/html.rb
136
+ - lib/viu/json.rb
116
137
  - lib/viu/layout.rb
117
138
  - lib/viu/railtie.rb
118
139
  - lib/viu/rendering_helpers.rb
119
140
  - lib/viu/test_case.rb
120
141
  - lib/viu/test_helpers.rb
121
142
  - lib/viu/version.rb
143
+ - lib/viu/xml.rb
122
144
  - viu.gemspec
123
145
  homepage: https://github.com/mrbongiolo/viu
124
146
  licenses: