phlex 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of phlex might be problematic. Click here for more details.

Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +5 -0
  3. data/.rubocop.yml +6 -0
  4. data/CONTRIBUTING.md +23 -0
  5. data/README.md +2 -2
  6. data/Rakefile +2 -2
  7. data/SECURITY.md +5 -0
  8. data/bench.rb +1 -1
  9. data/docs/assets/application.css +2 -0
  10. data/docs/build.rb +4 -4
  11. data/docs/components/callout.rb +5 -5
  12. data/docs/components/code_block.rb +18 -18
  13. data/docs/components/example.rb +23 -23
  14. data/docs/components/heading.rb +5 -5
  15. data/docs/components/layout.rb +42 -41
  16. data/docs/components/markdown.rb +19 -19
  17. data/docs/components/tabs/tab.rb +18 -18
  18. data/docs/components/tabs.rb +21 -21
  19. data/docs/components/title.rb +5 -5
  20. data/docs/page_builder.rb +32 -32
  21. data/docs/pages/application_page.rb +3 -3
  22. data/docs/pages/index.rb +23 -25
  23. data/docs/pages/rails_integration.rb +58 -0
  24. data/docs/pages/templates.rb +238 -238
  25. data/docs/pages/views.rb +175 -0
  26. data/fixtures/compilation/vcall.rb +38 -0
  27. data/fixtures/dummy/app/views/articles/form.rb +9 -9
  28. data/fixtures/dummy/app/views/articles/index.html.erb +3 -0
  29. data/fixtures/dummy/app/views/card.rb +8 -8
  30. data/fixtures/dummy/app/views/heading.rb +9 -0
  31. data/fixtures/dummy/config/routes.rb +1 -1
  32. data/fixtures/dummy/db/schema.rb +2 -2
  33. data/fixtures/layout.rb +24 -24
  34. data/fixtures/page.rb +34 -34
  35. data/fixtures/test_helper.rb +2 -2
  36. data/fixtures/view_helper.rb +16 -0
  37. data/lib/generators/phlex/component/USAGE +1 -1
  38. data/lib/generators/phlex/component/component_generator.rb +8 -8
  39. data/lib/generators/phlex/component/templates/{component.rb.erb → view.rb.erb} +1 -1
  40. data/lib/install/phlex.rb +18 -0
  41. data/lib/overrides/symbol/name.rb +1 -1
  42. data/lib/phlex/block.rb +12 -12
  43. data/lib/phlex/buffered.rb +13 -13
  44. data/lib/phlex/compiler/formatter.rb +91 -0
  45. data/lib/phlex/compiler/generators/standard_element.rb +30 -0
  46. data/lib/phlex/compiler/generators/void_element.rb +29 -0
  47. data/lib/phlex/compiler/optimizers/base_optimizer.rb +34 -0
  48. data/lib/phlex/compiler/optimizers/vcall.rb +29 -0
  49. data/lib/phlex/compiler/visitors/base_visitor.rb +19 -0
  50. data/lib/phlex/compiler/visitors/component.rb +28 -0
  51. data/lib/phlex/compiler/visitors/component_method.rb +28 -0
  52. data/lib/phlex/compiler/visitors/file.rb +17 -0
  53. data/lib/phlex/compiler.rb +50 -0
  54. data/lib/phlex/configuration.rb +3 -3
  55. data/lib/phlex/engine.rb +11 -0
  56. data/lib/phlex/html.rb +136 -18
  57. data/lib/phlex/rails/tag_helpers.rb +23 -23
  58. data/lib/phlex/renderable.rb +33 -27
  59. data/lib/phlex/version.rb +1 -1
  60. data/lib/phlex/view.rb +223 -0
  61. data/lib/phlex.rb +27 -12
  62. data/lib/tasks/phlex_tasks.rake +10 -0
  63. metadata +41 -10
  64. data/CHANGELOG.md +0 -5
  65. data/docs/pages/components.rb +0 -175
  66. data/fixtures/component_helper.rb +0 -16
  67. data/lib/phlex/component.rb +0 -191
  68. data/lib/phlex/rails.rb +0 -8
data/docs/pages/index.rb CHANGED
@@ -1,40 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pages
4
- class Index < ApplicationPage
5
- def template
6
- render Layout.new(title: "Introduction to Phlex") do
7
- render Markdown.new(<<~MD)
8
- # Introduction
4
+ class Index < ApplicationPage
5
+ def template
6
+ render Layout.new(title: "Introduction to Phlex") do
7
+ render Markdown.new(<<~MD)
8
+ # Introduction
9
9
 
10
- Phlex is a framework for building fast, reusable, testable view components in pure Ruby.
10
+ Phlex is a framework for building fast, reusable, testable views in pure Ruby.
11
11
 
12
- Think of a component as anything on a web page that you could draw a circle around and name. Starting on the outside, you have the _“page”_ itself, inside the page is a _“header”_, in the header is a _“nav bar”_ and in the nav bar is a _“nav bar item.”_ These objects together make up an entire page and we call the objects components.
12
+ Each view object is an instance of a specific class of view. The nav-bar, for example, might contain three different nav-bar-items, but they’re all instances of the nav-bar-item class. This class, then, manifests everything there is to know about nav bar items in general. It models:
13
13
 
14
- Each component object is an instance of a specific class of component. The nav-bar, for example, might contain three different nav-bar-items, but they’re all instances of the nav-bar-item class. This class, then, manifests everything there is to know about nav bar items in general. It models:
14
+ 1. the **data** attributes being represented perhaps url and label;
15
+ 2. a **template**, which dictates how the data should be represented with HTML markup and CSS classes; and
16
+ 3. **logic**, conditions, or calculations on the data — perhaps a predicate method to determine whether the link is active or not.
15
17
 
16
- 1. the **data** attributes being represented — perhaps url and label;
17
- 2. a **template**, which dictates how the data should be represented with HTML markup and CSS classes; and
18
- 3. **logic**, conditions, or calculations on the data — perhaps a predicate method to determine whether the link is active or not.
18
+ # Why use Phlex?
19
19
 
20
- # Why use Phlex?
20
+ ## Better developer experience 🎉
21
21
 
22
- ## Better developer experience 🎉
22
+ You don’t need to introduce a new language like Slim, HAML, or ERB. Phlex views are plain old Ruby objects: view classes are just Ruby classes, templates are just methods, and HTML tags are just method calls. If you know how to define a method that calls another method, you pretty much already know how to use Phlex.
23
23
 
24
- You don’t need to introduce a new language like Slim, HAML, or ERB. Phlex components are plain old Ruby objects: component classes are just Ruby classes, templates are just methods, and HTML tags are just method calls. If you know how to define a method that calls another method, you pretty much already know how to use Phlex.
24
+ ## Better safety 🥽
25
+ Rails partials can implicitly depend on instance variables from a controller or view. This happens more often than you might think when copying code into a new partial extraction. If the partial is then rendered in a different context or the instance variable’s meaning changes, things can break quite severely without warning.
25
26
 
26
- ## Better safety 🥽
27
- Rails partials can implicitly depend on instance variables from a controller or view. This happens more often than you might think when copying code into a new partial extraction. If the partial is then rendered in a different context or the instance variable’s meaning changes, things can break quite severely without warning.
27
+ Conversely, Phlex view templates render in an isolated execution context where only the instance variables and methods for the specific view are exposed.
28
28
 
29
- Conversely, Phlex component templates render in an isolated execution context where only the instance variables and methods for the specific component are exposed.
29
+ ## Better performance 🚀
30
30
 
31
- ## Better performance 🚀
31
+ Phlex is ~4.35× faster than ActionView and ~2× faster than ViewComponent. Phlex views are also streamable.
32
32
 
33
- Phlex is ~4.35× faster than ActionView and ~2× faster than ViewComponent. Phlex components are also streamable.
34
-
35
- Rails apps typically spend 40-80% of the response time rendering views, so this could be a significant factor in overall app performance.
36
- MD
37
- end
38
- end
39
- end
33
+ Rails apps typically spend 40-80% of the response time rendering views, so this could be a significant factor in overall app performance.
34
+ MD
35
+ end
36
+ end
37
+ end
40
38
  end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pages
4
+ class RailsIntegration < ApplicationPage
5
+ def template
6
+ render Layout.new(title: "Ruby on Rails integration") do
7
+ render Markdown.new(<<~MD)
8
+ # Ruby on Rails integration
9
+
10
+ ## Installation
11
+
12
+ To install Phlex into your Rails application, you can run the `bin/rails phlex:install` command.
13
+
14
+ ## Component generator
15
+
16
+ You can generate new views with the `rails g phlex:view` command.
17
+
18
+ For example, running `rails g phlex:view Card` will create the following file:
19
+ MD
20
+
21
+ render CodeBlock.new(<<~RUBY, syntax: :ruby)
22
+ # app/views/card.rb
23
+
24
+ module Views
25
+ class Card < Phlex::View
26
+ def template
27
+ end
28
+ end
29
+ end
30
+ RUBY
31
+
32
+ render Markdown.new(<<~MD)
33
+ ## Helpers
34
+
35
+ You can use the `helpers` proxy to access helpers within a `Phlex::View`.
36
+
37
+ For example, you can use the `#t` helper for translations:
38
+ MD
39
+
40
+ render CodeBlock.new(<<~RUBY, syntax: :ruby)
41
+ # app/views/hello.rb
42
+
43
+ module Views
44
+ class Hello < Phlex::View
45
+ delegate :t, to: :helpers
46
+
47
+ def template
48
+ h1 do
49
+ t "hello"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ RUBY
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,242 +1,242 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pages
4
- class Templates < ApplicationPage
5
- def template
6
- render Layout.new(title: "Templates in Phlex") do
7
- render Markdown.new(<<~MD)
8
- # Templates
9
-
10
- Rather than use another langauge like ERB, HAML or Slim, Phlex provides a Ruby DSL for defining HTML templates.
11
-
12
- You can create a component class by subclassing `Phlex::Component` and defining a method called `template`. Within the `template` method, you can compose HTML markup by calling the name of any [HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element).
13
-
14
- The first argument to an HTML element method is the _text content_ for that element. For example, here’s a component with an `<h1>` element that says “Hello World!”
15
- MD
16
-
17
- render Example.new do |e|
18
- e.tab "heading.rb", <<~RUBY
19
- class Heading < Phlex::Component
20
- def template
21
- h1 "Hello World!"
22
- end
23
- end
24
- RUBY
25
-
26
- e.execute "Heading.new.call"
27
- end
28
-
29
- render Markdown.new(<<~MD)
30
- The text content is always HTML-escaped, so it’s safe to use with user input.
31
-
32
- ## Attributes
33
-
34
- You can add attributes to HTML elements by passing keyword arguments to the tag method. Underscores (`_`) in attribute names are automatically converted to dashes (`-`).
35
- MD
36
-
37
- render Example.new do |e|
38
- e.tab "heading.rb", <<~RUBY
39
- class Heading < Phlex::Component
40
- def template
41
- h1 "Hello World!",
42
- class: "text-xl font-bold",
43
- aria_details: "details"
44
- end
45
- end
46
- RUBY
47
-
48
- e.execute "Heading.new.call"
49
- end
50
-
51
- render Markdown.new(<<~MD)
52
- You can also use *boolean* attributes. When set to `true`, the attribute will be rendered without a value, when _falsy_, the attribute isn’t rendered at all.
53
- MD
54
-
55
- render Example.new do |e|
56
- e.tab "example.rb", <<~RUBY
57
- class Example < Phlex::Component
58
- def template
59
- input type: "radio", name: "channel", id: "1", checked: true
60
- input type: "radio", name: "channel", id: "2", checked: false
61
- end
62
- end
63
- RUBY
64
-
65
- e.execute "Example.new.call"
66
- end
67
-
68
- render Markdown.new(<<~MD)
69
- ## Nesting
70
-
71
- Pass a block to an element method to nest other elements inside it.
72
- MD
73
-
74
- render Example.new do |e|
75
- e.tab "nav.rb", <<~RUBY
76
- class Nav < Phlex::Component
77
- def template
78
- nav do
79
- ul do
80
- li { a "Home", href: "/" }
81
- li { a "About", href: "/about" }
82
- li { a "Contact", href: "/contact" }
83
- end
84
- end
85
- end
86
- end
87
- RUBY
88
-
89
- e.execute "Nav.new.call"
90
- end
91
-
92
- render Markdown.new(<<~MD)
93
- ## Stand-alone text
94
-
95
- You can also output text without wrapping it in an element by using the `text` method. All text content is HTML-escaped, so it’s safe to use with user input.
96
- MD
97
-
98
- render Example.new do |e|
99
- e.tab "heading.rb", <<~RUBY
100
- class Heading < Phlex::Component
101
- def template
102
- h1 { strong "Hello "; text "World!" }
103
- end
104
- end
105
- RUBY
106
-
107
- e.execute "Heading.new.call"
108
- end
109
-
110
- render Markdown.new(<<~MD)
111
- ## Whitespace
112
-
113
- While the examples on this page have been formatted for readability, there is usually no whitespace between HTML tags. If you need to add some whitespace, you can use the `whitespace` method. This is useful for adding space between _inline_ elements to allow them to wrap.
114
- MD
115
-
116
- render Example.new do |e|
117
- e.tab "links.rb", <<~RUBY
118
- class Links < Phlex::Component
119
- def template
120
- a "Home", href: "/"
121
- whitespace
122
- a "About", href: "/about"
123
- whitespace
124
- a "Contact", href: "/contact"
125
- end
126
- end
127
- RUBY
128
-
129
- e.execute "Links.new.call"
130
- end
131
-
132
- render Markdown.new(<<~MD)
133
- ## Tokens and classes
134
-
135
- The `tokens` method helps you define conditional HTML attribute tokens (such as CSS classes).
136
-
137
- The `tokens` method accepts a splat of tokens that should always be output, and accepts keyword arguments for conditional tokens.
138
-
139
- The keyword arguments allow you to specify under which conditions certain tokens are applicable. The keyword argument keys are the conditions and the values are the tokens. Conditions can be Procs or Symbols that map to a relevant method. The `:active?` Symbol, for example, maps to the `active?` instance method.
140
-
141
- Here we have a `Link` component that produces an `<a>` tag with the CSS class `nav-item`. And if the link is _active_, we also apply the CSS class `nav-item-active`.
142
- MD
143
-
144
- render Example.new do |e|
145
- e.tab "link.rb", <<~RUBY
146
- class Link < Phlex::Component
147
- def initialize(text, to:, active:)
148
- @text = text
149
- @to = to
150
- @active = active
151
- end
152
-
153
- def template
154
- a @text, href: @to, class: tokens("nav-item",
155
- active?: "nav-item-active")
156
- end
157
-
158
- private
159
-
160
- def active? = @active
161
- end
162
- RUBY
163
-
164
- e.tab "example.rb", <<~RUBY
165
- class Example < Phlex::Component
166
- def template
167
- nav do
168
- ul do
169
- li { render Link.new("Home", to: "/", active: true) }
170
- li { render Link.new("About", to: "/about", active: false) }
171
- end
172
- end
173
- end
174
- end
175
- RUBY
176
-
177
- e.execute "Example.new.call"
178
- end
179
-
180
- render Markdown.new(<<~MD)
181
- You can also use the `classes` helper method to create a token list of classes. Since this method returns a hash (e.g. `{ class: "your CSS classes here" }`), you can destructure it into a `class:` keyword argument using the `**` prefix operator.
182
- MD
183
-
184
- render Example.new do |e|
185
- e.tab "link.rb", <<~RUBY
186
- class Link < Phlex::Component
187
- def initialize(text, to:, active:)
188
- @text = text
189
- @to = to
190
- @active = active
191
- end
192
-
193
- def template
194
- a @text, href: @to, **classes("nav-item",
195
- active?: "nav-item-active")
196
- end
197
-
198
- private
199
-
200
- def active? = @active
201
- end
202
- RUBY
203
-
204
- e.tab "example.rb", <<~RUBY
205
- class Example < Phlex::Component
206
- def template
207
- nav do
208
- ul do
209
- li { render Link.new("Home", to: "/", active: true) }
210
- li { render Link.new("About", to: "/about", active: false) }
211
- end
212
- end
213
- end
214
- end
215
- RUBY
216
-
217
- e.execute "Example.new.call"
218
- end
219
-
220
- render Markdown.new(<<~MD)
221
- ## The template element
222
-
223
- Because the `template` method is used to define the component template itself, you need to use the method `template_tag` if you want to to render an HTML `<template>` tag.
224
- MD
225
-
226
- render Example.new do |e|
227
- e.tab "example.rb", <<~RUBY
228
- class Example < Phlex::Component
229
- def template
230
- template_tag do
231
- img src: "hidden.jpg", alt: "A hidden image."
232
- end
233
- end
234
- end
235
- RUBY
236
-
237
- e.execute "Example.new.call"
238
- end
239
- end
240
- end
241
- end
4
+ class Templates < ApplicationPage
5
+ def template
6
+ render Layout.new(title: "Templates in Phlex") do
7
+ render Markdown.new(<<~MD)
8
+ # Templates
9
+
10
+ Rather than use another language like ERB, HAML or Slim, Phlex provides a Ruby DSL for defining HTML templates.
11
+
12
+ You can create a view class by subclassing `Phlex::View` and defining a method called `template`. Within the `template` method, you can compose HTML markup by calling the name of any [HTML element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element).
13
+
14
+ The first argument to an HTML element method is the _text content_ for that element. For example, here’s a view with an `<h1>` element that says “Hello World!”
15
+ MD
16
+
17
+ render Example.new do |e|
18
+ e.tab "heading.rb", <<~RUBY
19
+ class Heading < Phlex::View
20
+ def template
21
+ h1 "Hello World!"
22
+ end
23
+ end
24
+ RUBY
25
+
26
+ e.execute "Heading.new.call"
27
+ end
28
+
29
+ render Markdown.new(<<~MD)
30
+ The text content is always HTML-escaped, so it’s safe to use with user input.
31
+
32
+ ## Attributes
33
+
34
+ You can add attributes to HTML elements by passing keyword arguments to the tag method. Underscores (`_`) in attribute names are automatically converted to dashes (`-`).
35
+ MD
36
+
37
+ render Example.new do |e|
38
+ e.tab "heading.rb", <<~RUBY
39
+ class Heading < Phlex::View
40
+ def template
41
+ h1 "Hello World!",
42
+ class: "text-xl font-bold",
43
+ aria_details: "details"
44
+ end
45
+ end
46
+ RUBY
47
+
48
+ e.execute "Heading.new.call"
49
+ end
50
+
51
+ render Markdown.new(<<~MD)
52
+ You can also use *boolean* attributes. When set to `true`, the attribute will be rendered without a value, when _falsy_, the attribute isn’t rendered at all.
53
+ MD
54
+
55
+ render Example.new do |e|
56
+ e.tab "example.rb", <<~RUBY
57
+ class Example < Phlex::View
58
+ def template
59
+ input type: "radio", name: "channel", id: "1", checked: true
60
+ input type: "radio", name: "channel", id: "2", checked: false
61
+ end
62
+ end
63
+ RUBY
64
+
65
+ e.execute "Example.new.call"
66
+ end
67
+
68
+ render Markdown.new(<<~MD)
69
+ ## Nesting
70
+
71
+ Pass a block to an element method to nest other elements inside it.
72
+ MD
73
+
74
+ render Example.new do |e|
75
+ e.tab "nav.rb", <<~RUBY
76
+ class Nav < Phlex::View
77
+ def template
78
+ nav do
79
+ ul do
80
+ li { a "Home", href: "/" }
81
+ li { a "About", href: "/about" }
82
+ li { a "Contact", href: "/contact" }
83
+ end
84
+ end
85
+ end
86
+ end
87
+ RUBY
88
+
89
+ e.execute "Nav.new.call"
90
+ end
91
+
92
+ render Markdown.new(<<~MD)
93
+ ## Stand-alone text
94
+
95
+ You can also output text without wrapping it in an element by using the `text` method. All text content is HTML-escaped, so it’s safe to use with user input.
96
+ MD
97
+
98
+ render Example.new do |e|
99
+ e.tab "heading.rb", <<~RUBY
100
+ class Heading < Phlex::View
101
+ def template
102
+ h1 { strong "Hello "; text "World!" }
103
+ end
104
+ end
105
+ RUBY
106
+
107
+ e.execute "Heading.new.call"
108
+ end
109
+
110
+ render Markdown.new(<<~MD)
111
+ ## Whitespace
112
+
113
+ While the examples on this page have been formatted for readability, there is usually no whitespace between HTML tags. If you need to add some whitespace, you can use the `whitespace` method. This is useful for adding space between _inline_ elements to allow them to wrap.
114
+ MD
115
+
116
+ render Example.new do |e|
117
+ e.tab "links.rb", <<~RUBY
118
+ class Links < Phlex::View
119
+ def template
120
+ a "Home", href: "/"
121
+ whitespace
122
+ a "About", href: "/about"
123
+ whitespace
124
+ a "Contact", href: "/contact"
125
+ end
126
+ end
127
+ RUBY
128
+
129
+ e.execute "Links.new.call"
130
+ end
131
+
132
+ render Markdown.new(<<~MD)
133
+ ## Tokens and classes
134
+
135
+ The `tokens` method helps you define conditional HTML attribute tokens (such as CSS classes).
136
+
137
+ The `tokens` method accepts a splat of tokens that should always be output, and accepts keyword arguments for conditional tokens.
138
+
139
+ The keyword arguments allow you to specify under which conditions certain tokens are applicable. The keyword argument keys are the conditions and the values are the tokens. Conditions can be Procs or Symbols that map to a relevant method. The `:active?` Symbol, for example, maps to the `active?` instance method.
140
+
141
+ Here we have a `Link` view that produces an `<a>` tag with the CSS class `nav-item`. And if the link is _active_, we also apply the CSS class `nav-item-active`.
142
+ MD
143
+
144
+ render Example.new do |e|
145
+ e.tab "link.rb", <<~RUBY
146
+ class Link < Phlex::View
147
+ def initialize(text, to:, active:)
148
+ @text = text
149
+ @to = to
150
+ @active = active
151
+ end
152
+
153
+ def template
154
+ a @text, href: @to, class: tokens("nav-item",
155
+ active?: "nav-item-active")
156
+ end
157
+
158
+ private
159
+
160
+ def active? = @active
161
+ end
162
+ RUBY
163
+
164
+ e.tab "example.rb", <<~RUBY
165
+ class Example < Phlex::View
166
+ def template
167
+ nav do
168
+ ul do
169
+ li { render Link.new("Home", to: "/", active: true) }
170
+ li { render Link.new("About", to: "/about", active: false) }
171
+ end
172
+ end
173
+ end
174
+ end
175
+ RUBY
176
+
177
+ e.execute "Example.new.call"
178
+ end
179
+
180
+ render Markdown.new(<<~MD)
181
+ You can also use the `classes` helper method to create a token list of classes. Since this method returns a hash (e.g. `{ class: "your CSS classes here" }`), you can destructure it into a `class:` keyword argument using the `**` prefix operator.
182
+ MD
183
+
184
+ render Example.new do |e|
185
+ e.tab "link.rb", <<~RUBY
186
+ class Link < Phlex::View
187
+ def initialize(text, to:, active:)
188
+ @text = text
189
+ @to = to
190
+ @active = active
191
+ end
192
+
193
+ def template
194
+ a @text, href: @to, **classes("nav-item",
195
+ active?: "nav-item-active")
196
+ end
197
+
198
+ private
199
+
200
+ def active? = @active
201
+ end
202
+ RUBY
203
+
204
+ e.tab "example.rb", <<~RUBY
205
+ class Example < Phlex::View
206
+ def template
207
+ nav do
208
+ ul do
209
+ li { render Link.new("Home", to: "/", active: true) }
210
+ li { render Link.new("About", to: "/about", active: false) }
211
+ end
212
+ end
213
+ end
214
+ end
215
+ RUBY
216
+
217
+ e.execute "Example.new.call"
218
+ end
219
+
220
+ render Markdown.new(<<~MD)
221
+ ## The template element
222
+
223
+ Because the `template` method is used to define the view template itself, you need to use the method `template_tag` if you want to to render an HTML `<template>` tag.
224
+ MD
225
+
226
+ render Example.new do |e|
227
+ e.tab "example.rb", <<~RUBY
228
+ class Example < Phlex::View
229
+ def template
230
+ template_tag do
231
+ img src: "hidden.jpg", alt: "A hidden image."
232
+ end
233
+ end
234
+ end
235
+ RUBY
236
+
237
+ e.execute "Example.new.call"
238
+ end
239
+ end
240
+ end
241
+ end
242
242
  end