rbexy 2.0.0.beta8 → 2.0.0.beta9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.travis.yml +2 -0
- data/Dockerfile +1 -1
- data/Dockerfile-ruby2 +7 -0
- data/Gemfile.lock +81 -76
- data/README.md +120 -185
- data/bin/test +43 -0
- data/docker-compose.yml +9 -0
- data/lib/rbexy.rb +1 -0
- data/lib/rbexy/component.rb +10 -2
- data/lib/rbexy/nodes/abstract_node.rb +2 -0
- data/lib/rbexy/version.rb +1 -1
- data/rbexy.gemspec +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df2f31c9d3f08e035f5c3d2a7cb7673f29abdb69d17805073df4f615d2000c81
|
4
|
+
data.tar.gz: cd5c8a28d438f1ce73b0aeb50434cf308dedd17d8e9604e67354686d064f699a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4b9919d6e47c54a587bcc3be0c8f763b064f84544ac76c2e3b88b16870fe85100bbb597edeb11465aaa70b03ee92189fb7b8222865b0546455693d73b671bfb
|
7
|
+
data.tar.gz: 2f540c4199674536e55c9dce96cb03812c73251b349e1d222952c6eb12ce4d544a0c5e69e1f32fcedb770fa03aa50bce86f9848003d7da522d9f890e184a6dc2
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
data/Dockerfile
CHANGED
data/Dockerfile-ruby2
ADDED
data/Gemfile.lock
CHANGED
@@ -1,76 +1,80 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rbexy (2.0.0.
|
4
|
+
rbexy (2.0.0.beta9)
|
5
5
|
actionview (>= 6.0, < 7.0)
|
6
6
|
activesupport (>= 6.0, < 7.0)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
actioncable (6.
|
12
|
-
actionpack (= 6.
|
11
|
+
actioncable (6.1.3)
|
12
|
+
actionpack (= 6.1.3)
|
13
|
+
activesupport (= 6.1.3)
|
13
14
|
nio4r (~> 2.0)
|
14
15
|
websocket-driver (>= 0.6.1)
|
15
|
-
actionmailbox (6.
|
16
|
-
actionpack (= 6.
|
17
|
-
activejob (= 6.
|
18
|
-
activerecord (= 6.
|
19
|
-
activestorage (= 6.
|
20
|
-
activesupport (= 6.
|
16
|
+
actionmailbox (6.1.3)
|
17
|
+
actionpack (= 6.1.3)
|
18
|
+
activejob (= 6.1.3)
|
19
|
+
activerecord (= 6.1.3)
|
20
|
+
activestorage (= 6.1.3)
|
21
|
+
activesupport (= 6.1.3)
|
21
22
|
mail (>= 2.7.1)
|
22
|
-
actionmailer (6.
|
23
|
-
actionpack (= 6.
|
24
|
-
actionview (= 6.
|
25
|
-
activejob (= 6.
|
23
|
+
actionmailer (6.1.3)
|
24
|
+
actionpack (= 6.1.3)
|
25
|
+
actionview (= 6.1.3)
|
26
|
+
activejob (= 6.1.3)
|
27
|
+
activesupport (= 6.1.3)
|
26
28
|
mail (~> 2.5, >= 2.5.4)
|
27
29
|
rails-dom-testing (~> 2.0)
|
28
|
-
actionpack (6.
|
29
|
-
actionview (= 6.
|
30
|
-
activesupport (= 6.
|
31
|
-
rack (~> 2.0, >= 2.0.
|
30
|
+
actionpack (6.1.3)
|
31
|
+
actionview (= 6.1.3)
|
32
|
+
activesupport (= 6.1.3)
|
33
|
+
rack (~> 2.0, >= 2.0.9)
|
32
34
|
rack-test (>= 0.6.3)
|
33
35
|
rails-dom-testing (~> 2.0)
|
34
36
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
35
|
-
actiontext (6.
|
36
|
-
actionpack (= 6.
|
37
|
-
activerecord (= 6.
|
38
|
-
activestorage (= 6.
|
39
|
-
activesupport (= 6.
|
37
|
+
actiontext (6.1.3)
|
38
|
+
actionpack (= 6.1.3)
|
39
|
+
activerecord (= 6.1.3)
|
40
|
+
activestorage (= 6.1.3)
|
41
|
+
activesupport (= 6.1.3)
|
40
42
|
nokogiri (>= 1.8.5)
|
41
|
-
actionview (6.
|
42
|
-
activesupport (= 6.
|
43
|
+
actionview (6.1.3)
|
44
|
+
activesupport (= 6.1.3)
|
43
45
|
builder (~> 3.1)
|
44
46
|
erubi (~> 1.4)
|
45
47
|
rails-dom-testing (~> 2.0)
|
46
48
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
47
|
-
activejob (6.
|
48
|
-
activesupport (= 6.
|
49
|
+
activejob (6.1.3)
|
50
|
+
activesupport (= 6.1.3)
|
49
51
|
globalid (>= 0.3.6)
|
50
|
-
activemodel (6.
|
51
|
-
activesupport (= 6.
|
52
|
-
activerecord (6.
|
53
|
-
activemodel (= 6.
|
54
|
-
activesupport (= 6.
|
55
|
-
activestorage (6.
|
56
|
-
actionpack (= 6.
|
57
|
-
activejob (= 6.
|
58
|
-
activerecord (= 6.
|
52
|
+
activemodel (6.1.3)
|
53
|
+
activesupport (= 6.1.3)
|
54
|
+
activerecord (6.1.3)
|
55
|
+
activemodel (= 6.1.3)
|
56
|
+
activesupport (= 6.1.3)
|
57
|
+
activestorage (6.1.3)
|
58
|
+
actionpack (= 6.1.3)
|
59
|
+
activejob (= 6.1.3)
|
60
|
+
activerecord (= 6.1.3)
|
61
|
+
activesupport (= 6.1.3)
|
59
62
|
marcel (~> 0.3.1)
|
60
|
-
|
63
|
+
mimemagic (~> 0.3.2)
|
64
|
+
activesupport (6.1.3)
|
61
65
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
62
|
-
i18n (>=
|
63
|
-
minitest (
|
64
|
-
tzinfo (~>
|
65
|
-
zeitwerk (~> 2.
|
66
|
+
i18n (>= 1.6, < 2)
|
67
|
+
minitest (>= 5.1)
|
68
|
+
tzinfo (~> 2.0)
|
69
|
+
zeitwerk (~> 2.3)
|
66
70
|
builder (3.2.4)
|
67
71
|
byebug (11.1.3)
|
68
72
|
coderay (1.1.3)
|
69
|
-
concurrent-ruby (1.1.
|
73
|
+
concurrent-ruby (1.1.8)
|
70
74
|
crass (1.0.6)
|
71
75
|
diff-lcs (1.4.4)
|
72
|
-
erubi (1.
|
73
|
-
ffi (1.
|
76
|
+
erubi (1.10.0)
|
77
|
+
ffi (1.15.0)
|
74
78
|
formatador (0.2.5)
|
75
79
|
globalid (0.4.2)
|
76
80
|
activesupport (>= 4.2.0)
|
@@ -88,12 +92,12 @@ GEM
|
|
88
92
|
guard (~> 2.1)
|
89
93
|
guard-compat (~> 1.1)
|
90
94
|
rspec (>= 2.99.0, < 4.0)
|
91
|
-
i18n (1.8.
|
95
|
+
i18n (1.8.9)
|
92
96
|
concurrent-ruby (~> 1.0)
|
93
|
-
listen (3.
|
97
|
+
listen (3.4.1)
|
94
98
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
95
99
|
rb-inotify (~> 0.9, >= 0.9.10)
|
96
|
-
loofah (2.
|
100
|
+
loofah (2.9.0)
|
97
101
|
crass (~> 1.0.2)
|
98
102
|
nokogiri (>= 1.5.9)
|
99
103
|
lumberjack (1.2.8)
|
@@ -105,12 +109,13 @@ GEM
|
|
105
109
|
method_source (1.0.0)
|
106
110
|
mimemagic (0.3.5)
|
107
111
|
mini_mime (1.0.2)
|
108
|
-
mini_portile2 (2.
|
109
|
-
minitest (5.14.
|
112
|
+
mini_portile2 (2.5.0)
|
113
|
+
minitest (5.14.4)
|
110
114
|
nenv (0.3.0)
|
111
|
-
nio4r (2.5.
|
112
|
-
nokogiri (1.
|
113
|
-
mini_portile2 (~> 2.
|
115
|
+
nio4r (2.5.7)
|
116
|
+
nokogiri (1.11.1)
|
117
|
+
mini_portile2 (~> 2.5.0)
|
118
|
+
racc (~> 1.4)
|
114
119
|
notiffany (0.1.3)
|
115
120
|
nenv (~> 0.1)
|
116
121
|
shellany (~> 0.0)
|
@@ -120,36 +125,37 @@ GEM
|
|
120
125
|
pry-byebug (3.9.0)
|
121
126
|
byebug (~> 11.0)
|
122
127
|
pry (~> 0.13.0)
|
128
|
+
racc (1.5.2)
|
123
129
|
rack (2.2.3)
|
124
130
|
rack-test (1.1.0)
|
125
131
|
rack (>= 1.0, < 3)
|
126
|
-
rails (6.
|
127
|
-
actioncable (= 6.
|
128
|
-
actionmailbox (= 6.
|
129
|
-
actionmailer (= 6.
|
130
|
-
actionpack (= 6.
|
131
|
-
actiontext (= 6.
|
132
|
-
actionview (= 6.
|
133
|
-
activejob (= 6.
|
134
|
-
activemodel (= 6.
|
135
|
-
activerecord (= 6.
|
136
|
-
activestorage (= 6.
|
137
|
-
activesupport (= 6.
|
138
|
-
bundler (>= 1.
|
139
|
-
railties (= 6.
|
132
|
+
rails (6.1.3)
|
133
|
+
actioncable (= 6.1.3)
|
134
|
+
actionmailbox (= 6.1.3)
|
135
|
+
actionmailer (= 6.1.3)
|
136
|
+
actionpack (= 6.1.3)
|
137
|
+
actiontext (= 6.1.3)
|
138
|
+
actionview (= 6.1.3)
|
139
|
+
activejob (= 6.1.3)
|
140
|
+
activemodel (= 6.1.3)
|
141
|
+
activerecord (= 6.1.3)
|
142
|
+
activestorage (= 6.1.3)
|
143
|
+
activesupport (= 6.1.3)
|
144
|
+
bundler (>= 1.15.0)
|
145
|
+
railties (= 6.1.3)
|
140
146
|
sprockets-rails (>= 2.0.0)
|
141
147
|
rails-dom-testing (2.0.3)
|
142
148
|
activesupport (>= 4.2.0)
|
143
149
|
nokogiri (>= 1.6)
|
144
150
|
rails-html-sanitizer (1.3.0)
|
145
151
|
loofah (~> 2.3)
|
146
|
-
railties (6.
|
147
|
-
actionpack (= 6.
|
148
|
-
activesupport (= 6.
|
152
|
+
railties (6.1.3)
|
153
|
+
actionpack (= 6.1.3)
|
154
|
+
activesupport (= 6.1.3)
|
149
155
|
method_source
|
150
156
|
rake (>= 0.8.7)
|
151
|
-
thor (
|
152
|
-
rake (
|
157
|
+
thor (~> 1.0)
|
158
|
+
rake (13.0.3)
|
153
159
|
rb-fsevent (0.10.4)
|
154
160
|
rb-inotify (0.10.1)
|
155
161
|
ffi (~> 1.0)
|
@@ -186,14 +192,13 @@ GEM
|
|
186
192
|
activesupport (>= 4.0)
|
187
193
|
sprockets (>= 3.0.0)
|
188
194
|
sqlite3 (1.4.2)
|
189
|
-
thor (1.0
|
190
|
-
|
191
|
-
|
192
|
-
thread_safe (~> 0.1)
|
195
|
+
thor (1.1.0)
|
196
|
+
tzinfo (2.0.4)
|
197
|
+
concurrent-ruby (~> 1.0)
|
193
198
|
websocket-driver (0.7.3)
|
194
199
|
websocket-extensions (>= 0.1.0)
|
195
200
|
websocket-extensions (0.1.5)
|
196
|
-
zeitwerk (2.4.
|
201
|
+
zeitwerk (2.4.2)
|
197
202
|
|
198
203
|
PLATFORMS
|
199
204
|
ruby
|
@@ -211,4 +216,4 @@ DEPENDENCIES
|
|
211
216
|
sqlite3
|
212
217
|
|
213
218
|
BUNDLED WITH
|
214
|
-
2.
|
219
|
+
2.2.3
|
data/README.md
CHANGED
@@ -2,6 +2,19 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/patbenatar/rbexy.svg?branch=master)](https://travis-ci.org/patbenatar/rbexy)
|
4
4
|
|
5
|
+
* [Getting Started](#getting-started-with-rails)
|
6
|
+
* [Template Syntax](#template-syntax)
|
7
|
+
* [Components](#components)
|
8
|
+
* [`Rbexy::Component`](#rbexycomponent)
|
9
|
+
* [Usage with any component library](#usage-with-any-component-library)
|
10
|
+
* [Fragment caching in Rails](#fragment-caching-in-rails)
|
11
|
+
* [Advanced](#advanced)
|
12
|
+
* [Component resolution](#component-resolution)
|
13
|
+
* [AST Transforms](#ast-transforms)
|
14
|
+
* [Usage outside of Rails](#usage-outside-of-rails)
|
15
|
+
|
16
|
+
## Manifesto
|
17
|
+
|
5
18
|
Love JSX and component-based frontends, but sick of paying the costs of SPA development? Rbexy brings the elegance of JSX—operating on HTML elements and custom components with an interchangeable syntax—to the world of Rails server-rendered apps.
|
6
19
|
|
7
20
|
Combine this with CSS Modules in your Webpacker PostCSS pipeline and you'll have a first-class frontend development experience while maintaining the development efficiency of Rails.
|
@@ -85,78 +98,25 @@ Add a controller, action, route, and `rbx` view like `app/views/hello_worlds/ind
|
|
85
98
|
</HelloWorld>
|
86
99
|
```
|
87
100
|
|
88
|
-
_Or you can render Rbexy components from ERB with `<%= HelloWorldComponent.new(self, name: "Nick").render %>`_
|
89
|
-
|
90
101
|
Fire up `rails s`, navigate to your route, and you should see Rbexy in action!
|
91
102
|
|
92
103
|
## Template Syntax
|
93
104
|
|
94
|
-
|
95
|
-
|
96
|
-
You can put arbitrary strings anywhere.
|
97
|
-
|
98
|
-
At the root:
|
99
|
-
|
100
|
-
```jsx
|
101
|
-
Hello world
|
102
|
-
```
|
103
|
-
|
104
|
-
Inside tags:
|
105
|
-
|
106
|
-
```jsx
|
107
|
-
<p>Hello world</p>
|
108
|
-
```
|
109
|
-
|
110
|
-
As attributes:
|
111
|
-
|
112
|
-
```jsx
|
113
|
-
<div class="myClass"></div>
|
114
|
-
```
|
115
|
-
|
116
|
-
### Comments
|
117
|
-
|
118
|
-
Start a line with `#` to leave a comment:
|
119
|
-
|
120
|
-
```jsx
|
121
|
-
# Comments can be at the root
|
122
|
-
<div>
|
123
|
-
# Or within tags
|
124
|
-
# spanning multiple lines
|
125
|
-
<h1>Hello world</h1>
|
126
|
-
</div>
|
127
|
-
```
|
128
|
-
|
129
|
-
### Expressions
|
130
|
-
|
131
|
-
You can put ruby code anywhere that you would put text, just wrap it in `{ ... }`
|
132
|
-
|
133
|
-
At the root:
|
134
|
-
|
135
|
-
```jsx
|
136
|
-
{"hello world".upcase}
|
137
|
-
```
|
138
|
-
|
139
|
-
Inside a sentence:
|
140
|
-
|
141
|
-
```jsx
|
142
|
-
Hello {"world".upcase}
|
143
|
-
```
|
144
|
-
|
145
|
-
Inside tags:
|
105
|
+
You can use Ruby code within brackets:
|
146
106
|
|
147
107
|
```jsx
|
148
|
-
<p
|
108
|
+
<p class={@dynamic_class}>
|
109
|
+
Hello {"world".upcase}
|
110
|
+
</p>
|
149
111
|
```
|
150
112
|
|
151
|
-
|
113
|
+
You can splat a hash into attributes:
|
152
114
|
|
153
115
|
```jsx
|
154
|
-
<
|
116
|
+
<div {**{class: "myClass"}} {**@more_attrs}></div>
|
155
117
|
```
|
156
118
|
|
157
|
-
|
158
|
-
|
159
|
-
To conditionalize your template:
|
119
|
+
You can use HTML or component tags within expressions. e.g. to conditionalize a template:
|
160
120
|
|
161
121
|
```jsx
|
162
122
|
<div>
|
@@ -165,7 +125,7 @@ To conditionalize your template:
|
|
165
125
|
</div>
|
166
126
|
```
|
167
127
|
|
168
|
-
|
128
|
+
Or in loops:
|
169
129
|
|
170
130
|
```jsx
|
171
131
|
<ul>
|
@@ -181,7 +141,7 @@ Blocks:
|
|
181
141
|
end}
|
182
142
|
```
|
183
143
|
|
184
|
-
|
144
|
+
Pass a tag to a component as an attribute:
|
185
145
|
|
186
146
|
```jsx
|
187
147
|
<Hero title={<h1>Hello World</h1>}>
|
@@ -189,7 +149,7 @@ As an attribute:
|
|
189
149
|
</Hero>
|
190
150
|
```
|
191
151
|
|
192
|
-
|
152
|
+
Or pass a lambda as an attribute, that when called returns a tag:
|
193
153
|
|
194
154
|
```jsx
|
195
155
|
<Hero title={-> { <h1>Hello World</h1> }}>
|
@@ -207,70 +167,15 @@ _Note that when using tags inside blocks, the block must evaluate to a single ro
|
|
207
167
|
-> { <i>Hello</i> World }
|
208
168
|
```
|
209
169
|
|
210
|
-
|
211
|
-
|
212
|
-
You can put standard HTML tags anywhere.
|
213
|
-
|
214
|
-
At the root:
|
215
|
-
|
216
|
-
```jsx
|
217
|
-
<h1>Hello world</h1>
|
218
|
-
```
|
219
|
-
|
220
|
-
As children:
|
221
|
-
|
222
|
-
```jsx
|
223
|
-
<div>
|
224
|
-
<h1>Hello world</h1>
|
225
|
-
</div>
|
226
|
-
```
|
227
|
-
|
228
|
-
As siblings with other tags:
|
229
|
-
|
230
|
-
```jsx
|
231
|
-
<div>
|
232
|
-
<h1>Hello world</h1>
|
233
|
-
<p>Welcome to rbexy</p>
|
234
|
-
</div>
|
235
|
-
```
|
236
|
-
|
237
|
-
As siblings with text and expressions:
|
238
|
-
|
239
|
-
```jsx
|
240
|
-
<h1>Hello world</h1>
|
241
|
-
{an_expression}
|
242
|
-
Some arbitrary text
|
243
|
-
```
|
244
|
-
|
245
|
-
Self-closing tags:
|
246
|
-
|
247
|
-
```jsx
|
248
|
-
<input type="text" />
|
249
|
-
```
|
250
|
-
|
251
|
-
#### Attributes
|
252
|
-
|
253
|
-
Text and expressions can be provided as attributes:
|
254
|
-
|
255
|
-
```jsx
|
256
|
-
<div class="myClass" id={dynamic_id}></div>
|
257
|
-
```
|
258
|
-
|
259
|
-
Value-less attributes are allowed:
|
260
|
-
|
261
|
-
```jsx
|
262
|
-
<input type="submit" disabled>
|
263
|
-
```
|
264
|
-
|
265
|
-
You can splat a hash into attributes:
|
170
|
+
Start a line with `#` to leave a comment:
|
266
171
|
|
267
172
|
```jsx
|
268
|
-
|
173
|
+
# Private note to self that won't be rendered in the final HTML
|
269
174
|
```
|
270
175
|
|
271
|
-
##
|
176
|
+
## Components
|
272
177
|
|
273
|
-
You can use
|
178
|
+
You can use Ruby classes as components alongside standard HTML tags:
|
274
179
|
|
275
180
|
```jsx
|
276
181
|
<div>
|
@@ -281,6 +186,8 @@ You can use custom components alongside standard HTML tags:
|
|
281
186
|
</div>
|
282
187
|
```
|
283
188
|
|
189
|
+
By default, Rbexy will resolve `PageHeader` to a Ruby class called `PageHeaderComponent` and render it with the view context, attributes, and its children: `PageHeaderComponent.new(self, title: "Welcome").render_in(self, &block)`. This behavior is customizable, see "Component resolution" below.
|
190
|
+
|
284
191
|
### `Rbexy::Component`
|
285
192
|
|
286
193
|
We ship with a component superclass that integrates nicely with Rails' ActionView and the controller rendering context. You can use it to easily implement custom components in your Rails app:
|
@@ -301,13 +208,11 @@ By default, we'll look for a template file in the same directory as the class an
|
|
301
208
|
<h1>{@title}</h1>
|
302
209
|
```
|
303
210
|
|
304
|
-
|
305
|
-
|
306
|
-
Your components and their templates run in the same context as traditional Rails views, so you have access to all of the view helpers you're used to as well as any custom helpers you've defined in `app/helpers/`.
|
211
|
+
Your components and their templates run in the same context as traditional Rails views, so you have access to all of the view helpers you're used to as well as any custom helpers you've defined in `app/helpers/` or via `helper_method` in your controller.
|
307
212
|
|
308
213
|
#### Template-less components
|
309
214
|
|
310
|
-
If you'd prefer to render your components entirely from Ruby,
|
215
|
+
If you'd prefer to render your components entirely from Ruby, you can do so by implementing `#call`:
|
311
216
|
|
312
217
|
```ruby
|
313
218
|
class PageHeaderComponent < Rbexy::Component
|
@@ -361,106 +266,136 @@ class TextFieldComponent < Rbexy::Component
|
|
361
266
|
end
|
362
267
|
```
|
363
268
|
|
364
|
-
|
269
|
+
#### Usage with ERB
|
365
270
|
|
366
|
-
|
271
|
+
We recommend using `Rbexy::Component` with the rbx template language, but if you prefer ERB... a component's template can be `.html.erb` and you can render a component from ERB like so:
|
367
272
|
|
368
|
-
|
369
|
-
|
273
|
+
Rails 6.1:
|
274
|
+
|
275
|
+
```erb
|
276
|
+
<%= render PageHeaderComponent.new(self, title: "Welcome") do %>
|
277
|
+
<p>Children...</p>
|
278
|
+
<% end >
|
279
|
+
```
|
370
280
|
|
281
|
+
Rails 6.0 or earlier:
|
282
|
+
|
283
|
+
```erb
|
284
|
+
<%= PageHeaderComponent.new(self, title: "Welcome").render_in(self) %>
|
285
|
+
```
|
286
|
+
|
287
|
+
### Usage with any component library
|
288
|
+
|
289
|
+
You can use the rbx template language with other component libraries like Github's view_component. You just need to tell Rbexy how to render the component:
|
290
|
+
|
291
|
+
```ruby
|
292
|
+
# config/initializers/rbexy.rb
|
371
293
|
Rbexy.configure do |config|
|
372
|
-
config.
|
294
|
+
config.component_rendering_templates = {
|
295
|
+
children: "{capture{%{children}}}",
|
296
|
+
component: "::%{component_class}.new(%{view_context},%{kwargs}).render_in%{children_block}"
|
297
|
+
}
|
373
298
|
end
|
374
299
|
```
|
375
300
|
|
376
|
-
|
301
|
+
## Fragment caching in Rails
|
377
302
|
|
378
|
-
|
303
|
+
`.rbx` templates integrate with Rails fragment caching, automatically cachebusting when the template or its render dependencies change.
|
379
304
|
|
380
|
-
|
381
|
-
class MyComponentProvider
|
382
|
-
def match?(name)
|
383
|
-
# Return true if the given tag name matches one of your custom components
|
384
|
-
end
|
305
|
+
If you're using `Rbexy::Component`, you can further benefit from component cachebusting where the fragment cache will be busted if any dependent component's template _or_ class definition changes.
|
385
306
|
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
307
|
+
And you can use `<Rbexy.Cache>`, a convenient wrapper for the Rails fragment cache:
|
308
|
+
|
309
|
+
```rbx
|
310
|
+
<Rbexy.Cache key={...}>
|
311
|
+
<p>Fragment here...</p>
|
312
|
+
<MyButton />
|
313
|
+
</Rbexy.Cache>
|
314
|
+
```
|
315
|
+
|
316
|
+
## Advanced
|
317
|
+
|
318
|
+
### Component resolution
|
319
|
+
|
320
|
+
By default, Rbexy resolves component tags to Ruby classes named `#{tag}Component`, e.g.:
|
391
321
|
|
392
|
-
|
322
|
+
* `<PageHeader />` => `PageHeaderComponent`
|
323
|
+
* `<Admin.Button />` => `Admin::ButtonComponent`
|
324
|
+
|
325
|
+
You can customize this behavior by providing a custom resolver:
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
# config/initializers/rbexy.rb
|
393
329
|
Rbexy.configure do |config|
|
394
|
-
config.
|
330
|
+
config.element_resolver = MyResolver.new
|
395
331
|
end
|
396
332
|
```
|
397
333
|
|
398
|
-
|
334
|
+
Where `MyResolver` implements the following API:
|
335
|
+
|
336
|
+
* `component?(name: string, template: Rbexy::Template) => Boolean`
|
337
|
+
* `component_class(name: string, template: Rbexy::Template) => T`
|
338
|
+
|
339
|
+
See `lib/rbexy/component_resolver.rb` for an example.
|
340
|
+
|
341
|
+
#### Auto-namespacing
|
342
|
+
|
343
|
+
Want to namespace your components but sick of typing `Admin.` in front of every component call? Rbexy's default `ComponentResolver` implementation has an option for that:
|
399
344
|
|
400
345
|
```ruby
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
346
|
+
# config/initializers/rbexy.rb
|
347
|
+
Rbexy.configure do |config|
|
348
|
+
config.element_resolver.component_namespaces = {
|
349
|
+
Rails.root.join("app", "views", "admin") => %w[Admin],
|
350
|
+
Rails.root.join("app", "components", "admin") => %w[Admin]
|
351
|
+
}
|
405
352
|
end
|
406
353
|
```
|
407
354
|
|
408
|
-
|
355
|
+
Now any calls to `<Button>` made from `.rbx` views within `app/views/admin/` or from component templates within `app/components/admin/` will first check for `Admin::ButtonComponent` before `ButtonComponent`.
|
409
356
|
|
410
|
-
|
357
|
+
### AST Transforms
|
411
358
|
|
412
|
-
|
359
|
+
You can hook into Rbexy's compilation process to mutate the abstract syntax tree. This is both useful and dangerous, so use with caution.
|
413
360
|
|
414
|
-
|
361
|
+
An example use case is automatically scoping CSS class names if you're using something like CSS Modules. Here's an oversimplified example of this:
|
415
362
|
|
416
363
|
```ruby
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
"Method value"
|
364
|
+
# config/initializers/rbexy.rb
|
365
|
+
Rbexy.configure do |config|
|
366
|
+
config.transforms.register(Rbexy::Nodes::HTMLAttr) do |node, context|
|
367
|
+
if node.name == "class"
|
368
|
+
class_list = node.value.split(" ")
|
369
|
+
node.value.content = scope_names(class_list, scope: context.template.identifier)
|
370
|
+
end
|
425
371
|
end
|
426
372
|
end
|
427
|
-
|
428
|
-
Rbexy.evaluate("<p class={a_method}>{@an_ivar}</p>", MyRuntime.new)
|
429
373
|
```
|
430
374
|
|
431
|
-
|
375
|
+
### Usage outside of Rails
|
376
|
+
|
377
|
+
Rbexy compiles your template into ruby code, which you can then execute in any context you like. Subclass `Rbexy::Runtime` to add methods and instance variables that you'd like to make available to your template.
|
432
378
|
|
433
379
|
```ruby
|
434
380
|
class MyRuntime < Rbexy::Runtime
|
435
|
-
def initialize
|
436
|
-
super
|
437
|
-
@
|
381
|
+
def initialize
|
382
|
+
super
|
383
|
+
@an_ivar = "Ivar value"
|
438
384
|
end
|
439
385
|
|
440
|
-
def
|
441
|
-
|
442
|
-
key1: "val1",
|
443
|
-
key2: "val2"
|
444
|
-
}
|
386
|
+
def a_method
|
387
|
+
"Method value"
|
445
388
|
end
|
446
389
|
end
|
447
390
|
|
448
|
-
Rbexy.evaluate(
|
449
|
-
"<Forms.TextField /><Button prop1=\"val1\" prop2={true && \"val2\">Submit</Button>",
|
450
|
-
MyRuntime.new(MyComponentProvider.new)
|
451
|
-
)
|
391
|
+
Rbexy.evaluate("<p class={a_method}>{@an_ivar}</p>", MyRuntime.new)
|
452
392
|
```
|
453
393
|
|
454
|
-
Or implement your own runtime, so long as it conforms to the API:
|
455
|
-
|
456
|
-
* `#rbexy_tag` that returns a tag builder conforming to the API of `ActionView::Helpers::TagHelpers::TagBuilder`
|
457
|
-
* `#evaluate(code)` that evals the given string of ruby code
|
458
|
-
|
459
394
|
## Development
|
460
395
|
|
461
396
|
```
|
462
397
|
docker-compose build
|
463
|
-
docker-compose run rbexy
|
398
|
+
docker-compose run rbexy bin/test
|
464
399
|
```
|
465
400
|
|
466
401
|
Or auto-run tests with guard if you prefer:
|
@@ -471,7 +406,7 @@ docker-compose run rbexy guard
|
|
471
406
|
|
472
407
|
## Contributing
|
473
408
|
|
474
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
409
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/patbenatar/rbexy. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/patbenatar/rbexy/blob/master/CODE_OF_CONDUCT.md).
|
475
410
|
|
476
411
|
## License
|
477
412
|
|
@@ -479,4 +414,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
479
414
|
|
480
415
|
## Code of Conduct
|
481
416
|
|
482
|
-
Everyone interacting in the Rbexy project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/
|
417
|
+
Everyone interacting in the Rbexy project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/patbenatar/rbexy/blob/master/CODE_OF_CONDUCT.md).
|
data/bin/test
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
declare -i RESULT=0
|
4
|
+
|
5
|
+
echo "Running main suite..."
|
6
|
+
|
7
|
+
bundle exec rspec
|
8
|
+
RESULT+=$?
|
9
|
+
|
10
|
+
echo "Running initial caching specs to test cold cache behavior..."
|
11
|
+
|
12
|
+
bundle exec rspec spec/integration/caching/before_changes_spec.rb
|
13
|
+
RESULT+=$?
|
14
|
+
|
15
|
+
echo "Making template source changes to allow testing of cache-busting..."
|
16
|
+
|
17
|
+
templates=(
|
18
|
+
"spec/dummy/app/views/caching/inline.rbx"
|
19
|
+
"spec/dummy/app/components/cached_thing_component.rbx"
|
20
|
+
"spec/dummy/app/components/cached_class_thing_component.rb"
|
21
|
+
"spec/dummy/app/components/cached_thing_call_component.rb"
|
22
|
+
"spec/dummy/app/views/caching/_partial_render_partial.rbx"
|
23
|
+
)
|
24
|
+
for i in "${templates[@]}"
|
25
|
+
do
|
26
|
+
mv $i $i.original
|
27
|
+
mv $i.changed $i
|
28
|
+
done
|
29
|
+
|
30
|
+
echo "Running subsequent caching specs to test cache-busting of warm cache..."
|
31
|
+
|
32
|
+
bundle exec rspec spec/integration/caching/after_changes_spec.rb
|
33
|
+
RESULT+=$?
|
34
|
+
|
35
|
+
echo "Cleaning up..."
|
36
|
+
|
37
|
+
for i in "${templates[@]}"
|
38
|
+
do
|
39
|
+
mv $i $i.changed
|
40
|
+
mv $i.original $i
|
41
|
+
done
|
42
|
+
|
43
|
+
exit $RESULT
|
data/docker-compose.yml
CHANGED
@@ -2,6 +2,7 @@ version: '3'
|
|
2
2
|
|
3
3
|
volumes:
|
4
4
|
bundle:
|
5
|
+
bundle_ruby2:
|
5
6
|
|
6
7
|
services:
|
7
8
|
rbexy:
|
@@ -14,6 +15,14 @@ services:
|
|
14
15
|
- $HOME/.gitconfig:/root/.gitconfig:ro
|
15
16
|
- $HOME/.gem/credentials:/root/.gem/credentials
|
16
17
|
working_dir: /app
|
18
|
+
rbexy_ruby2:
|
19
|
+
build:
|
20
|
+
context: .
|
21
|
+
dockerfile: Dockerfile-ruby2
|
22
|
+
volumes:
|
23
|
+
- .:/app
|
24
|
+
- bundle_ruby2:/usr/local/bundle
|
25
|
+
working_dir: /app
|
17
26
|
dummy:
|
18
27
|
image: rbexy
|
19
28
|
volumes:
|
data/lib/rbexy.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "rbexy/version"
|
2
2
|
require "active_support/inflector"
|
3
3
|
require "active_support/concern"
|
4
|
+
require "active_support/core_ext/enumerable"
|
4
5
|
require "action_view/helpers/output_safety_helper"
|
5
6
|
require "action_view/helpers/capture_helper"
|
6
7
|
require "action_view/helpers/tag_helper"
|
data/lib/rbexy/component.rb
CHANGED
@@ -9,6 +9,14 @@ module Rbexy
|
|
9
9
|
def to_s
|
10
10
|
self
|
11
11
|
end
|
12
|
+
|
13
|
+
def split(*args)
|
14
|
+
super.map { |s| TemplatePath.new(s) }
|
15
|
+
end
|
16
|
+
|
17
|
+
def gsub(*args)
|
18
|
+
super.tap { |s| break TemplatePath.new(s) }
|
19
|
+
end
|
12
20
|
end
|
13
21
|
|
14
22
|
class_attribute :component_file_location
|
@@ -78,8 +86,8 @@ module Rbexy
|
|
78
86
|
raise error
|
79
87
|
end
|
80
88
|
|
81
|
-
def method_missing(meth, *args, &block)
|
82
|
-
view_context.send(meth, *args, &block)
|
89
|
+
def method_missing(meth, *args, **kwargs, &block)
|
90
|
+
view_context.send(meth, *args, **kwargs, &block)
|
83
91
|
end
|
84
92
|
|
85
93
|
def respond_to_missing?(method_name, include_all)
|
@@ -17,6 +17,7 @@ module Rbexy
|
|
17
17
|
@compile_context = context
|
18
18
|
children.each { |c| c.inject_compile_context(context) } if respond_to?(:children)
|
19
19
|
members.each { |c| c.inject_compile_context(context) } if respond_to?(:members)
|
20
|
+
value.inject_compile_context(context) if respond_to?(:value)
|
20
21
|
end
|
21
22
|
|
22
23
|
def transform!
|
@@ -24,6 +25,7 @@ module Rbexy
|
|
24
25
|
ast_transformer.transform(self, compile_context)
|
25
26
|
children.each(&:transform!) if respond_to?(:children)
|
26
27
|
members.each(&:transform!) if respond_to?(:members)
|
28
|
+
value.transform! if respond_to?(:value)
|
27
29
|
end
|
28
30
|
|
29
31
|
private
|
data/lib/rbexy/version.rb
CHANGED
data/rbexy.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.summary = "A Ruby template language inspired by JSX"
|
10
10
|
spec.homepage = "https://github.com/patbenatar/rbexy"
|
11
11
|
spec.license = "MIT"
|
12
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
12
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
13
13
|
|
14
14
|
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
15
15
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbexy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Giancola
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -206,6 +206,7 @@ files:
|
|
206
206
|
- ".travis.yml"
|
207
207
|
- CODE_OF_CONDUCT.md
|
208
208
|
- Dockerfile
|
209
|
+
- Dockerfile-ruby2
|
209
210
|
- Gemfile
|
210
211
|
- Gemfile.lock
|
211
212
|
- Guardfile
|
@@ -214,6 +215,7 @@ files:
|
|
214
215
|
- Rakefile
|
215
216
|
- bin/console
|
216
217
|
- bin/setup
|
218
|
+
- bin/test
|
217
219
|
- docker-compose.yml
|
218
220
|
- lib/rbexy.rb
|
219
221
|
- lib/rbexy/ast_transformer.rb
|
@@ -270,14 +272,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
270
272
|
requirements:
|
271
273
|
- - ">="
|
272
274
|
- !ruby/object:Gem::Version
|
273
|
-
version: 2.
|
275
|
+
version: 2.7.0
|
274
276
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
275
277
|
requirements:
|
276
278
|
- - ">"
|
277
279
|
- !ruby/object:Gem::Version
|
278
280
|
version: 1.3.1
|
279
281
|
requirements: []
|
280
|
-
rubygems_version: 3.
|
282
|
+
rubygems_version: 3.2.3
|
281
283
|
signing_key:
|
282
284
|
specification_version: 4
|
283
285
|
summary: A Ruby template language inspired by JSX
|