evc_rails 0.2.3 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -3
- data/README.md +85 -2
- data/lib/evc_rails/template_handler.rb +36 -8
- data/lib/evc_rails/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a155f85c540ca32801ef3033f92abdc7912a3ff5c533faa19f92b00c774968b
|
4
|
+
data.tar.gz: 79de2d1b2b3557009c0d9e98f5ade01418ad7e49b61567c2056898ddfe537ea9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1039a2e12cc8f11c8855dd0bafd2abd9de98e61a87f9e2c49fe27f7d40a497d30d6f1b05d4da7bfb8b7eede13b75c33ab67df4cb48fe8ab8de4d825284d52388
|
7
|
+
data.tar.gz: c73e72e59cd863f513bf07e60675081c3db3255b77090da206ae8652a8e6c15f1b6079641fd1e27b5dbe0b95e71ae45d80a7975b0af2479b5d4e802b9b102a0d
|
data/CHANGELOG.md
CHANGED
@@ -5,7 +5,33 @@ All notable changes to this project will be documented in this file.
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
7
|
|
8
|
-
## [
|
8
|
+
## [0.3.0] - 2024-12-19
|
9
|
+
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- **Enhanced slot nesting support**: Improved handling of deeply nested slots within components
|
13
|
+
- **Self-closing slot optimization**: Self-closing slots now render as method calls without blocks for better performance
|
14
|
+
- **Stack-based nesting logic**: More robust handling of complex nested component and slot structures
|
15
|
+
|
16
|
+
### Changed
|
17
|
+
|
18
|
+
- **Slot variable naming**: Improved slot variable naming by stripping `with_` prefix for cleaner block variables
|
19
|
+
- **Nested slot context**: Enhanced logic to ensure slots use the nearest component variable unless directly nested inside another slot
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
|
23
|
+
- **Block variable syntax**: Fixed Ruby block variable syntax to use `do |var|` instead of `|var| do`
|
24
|
+
- **Block variable yielding**: Corrected block variable yielding for complex nested structures
|
25
|
+
- **Slot method compatibility**: Ensured proper compatibility with ViewComponent's generated slot methods
|
26
|
+
- **Test suite improvements**: Updated all tests to reflect the new behavior and added comprehensive test coverage
|
27
|
+
|
28
|
+
## [0.2.3] - 2024-12-19
|
29
|
+
|
30
|
+
### Changed
|
31
|
+
|
32
|
+
- **Block variable yielding with `as`**: The block variable is now always yielded if the `as` attribute is present on a component tag, even if no `<With...>` slot tags are used inside the block. This makes advanced usage (such as calling plural slot methods directly) more ergonomic and predictable.
|
33
|
+
- **Documentation improvements**: Clarified the need for the `as` attribute when using plural slot methods with block variables, and improved wording for advanced usage in the README.
|
34
|
+
- **Test suite**: Added and updated tests to verify block variable yielding with `as` and to match the new behavior.
|
9
35
|
|
10
36
|
## [0.2.2] - 2024-12-19
|
11
37
|
|
@@ -77,11 +103,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
77
103
|
- **Drop-in replacement**: Works as a replacement for `.erb` files
|
78
104
|
- **Basic caching**: Template compilation caching for performance
|
79
105
|
|
80
|
-
---
|
81
|
-
|
82
106
|
## Version History Notes
|
83
107
|
|
84
108
|
- **0.1.0**: Initial release with core functionality
|
85
109
|
- **0.2.0**: Major feature addition with slots and namespaced components
|
86
110
|
- **0.2.1**: Improved variable naming and slot method compatibility
|
87
111
|
- **0.2.2**: Added boolean attribute shorthand for cleaner templates
|
112
|
+
- **0.2.3**: Added block variable yielding with `as` attribute for more ergonomic advanced usage
|
113
|
+
- **0.3.0**: Enhanced slot nesting support and improved block variable handling for complex component structures
|
data/README.md
CHANGED
@@ -42,10 +42,11 @@ No component modifications required - just install and enjoy easier syntax!
|
|
42
42
|
- **Block components**: `<Container>content</Container>`
|
43
43
|
- **Attributes**: String, Ruby expressions, and multiple attributes
|
44
44
|
- **Namespaced components**: `<UI::Button />`, `<Forms::Fields::TextField />`
|
45
|
-
- **
|
46
|
-
- **Deep nesting**: Complex component hierarchies
|
45
|
+
- **Advanced slot support**: `<WithHeader>...</WithHeader>` with `renders_one` and `renders_many`, including complex nesting
|
46
|
+
- **Deep nesting**: Complex component hierarchies with proper block variable handling
|
47
47
|
- **Production-ready caching** with Rails.cache integration
|
48
48
|
- **Better error messages** with line numbers and column positions
|
49
|
+
- **Boolean attribute shorthand** for cleaner templates
|
49
50
|
|
50
51
|
## Installation
|
51
52
|
|
@@ -230,6 +231,52 @@ Becomes:
|
|
230
231
|
<% end %>
|
231
232
|
```
|
232
233
|
|
234
|
+
#### Self-Closing Slots
|
235
|
+
|
236
|
+
You can also use self-closing slot tags when you don't need to pass content:
|
237
|
+
|
238
|
+
```erb
|
239
|
+
<Card>
|
240
|
+
<WithHeader />
|
241
|
+
<WithBody>
|
242
|
+
<p>This is the body content.</p>
|
243
|
+
</WithBody>
|
244
|
+
</Card>
|
245
|
+
```
|
246
|
+
|
247
|
+
Becomes:
|
248
|
+
|
249
|
+
```erb
|
250
|
+
<%= render CardComponent.new do |card| %>
|
251
|
+
<% card.with_header %>
|
252
|
+
<% card.with_body do %>
|
253
|
+
<p>This is the body content.</p>
|
254
|
+
<% end %>
|
255
|
+
<% end %>
|
256
|
+
```
|
257
|
+
|
258
|
+
#### Slot Attributes with Ruby Expressions
|
259
|
+
|
260
|
+
Slots can accept attributes and Ruby expressions:
|
261
|
+
|
262
|
+
```erb
|
263
|
+
<Card>
|
264
|
+
<WithHeader user={@current_user} class="welcome-header">
|
265
|
+
Welcome, <%= @current_user.name %>
|
266
|
+
</WithHeader>
|
267
|
+
</Card>
|
268
|
+
```
|
269
|
+
|
270
|
+
Becomes:
|
271
|
+
|
272
|
+
```erb
|
273
|
+
<%= render CardComponent.new do |card| %>
|
274
|
+
<% card.with_header(user: @current_user, class: "welcome-header") do %>
|
275
|
+
Welcome, <%= @current_user.name %>
|
276
|
+
<% end %>
|
277
|
+
<% end %>
|
278
|
+
```
|
279
|
+
|
233
280
|
#### Multiple Slots (`renders_many`)
|
234
281
|
|
235
282
|
```ruby
|
@@ -326,6 +373,42 @@ This is equivalent to the ERB version:
|
|
326
373
|
|
327
374
|
You can use this approach for any plural slot method generated by `renders_many`. The block variable (e.g., `navigation`) is always available inside the component block when you use the `as` attribute, even if there are no `<With...>` slot tags present.
|
328
375
|
|
376
|
+
#### Complex Nested Slot Structures
|
377
|
+
|
378
|
+
EVC handles complex nested slot structures with proper block variable scoping:
|
379
|
+
|
380
|
+
```erb
|
381
|
+
<Navigation>
|
382
|
+
<WithLink href={learning_path} text="Learning Path" />
|
383
|
+
<WithLink href={courses_path} text="All Courses" />
|
384
|
+
<WithLink text="Reports">
|
385
|
+
<WithSublink href={reports_users_path} text="Users" />
|
386
|
+
<WithSublink href={reports_activity_path} text="Activity" />
|
387
|
+
</WithLink>
|
388
|
+
<WithFooter>
|
389
|
+
<div>Footer content</div>
|
390
|
+
</WithFooter>
|
391
|
+
</Navigation>
|
392
|
+
```
|
393
|
+
|
394
|
+
Becomes:
|
395
|
+
|
396
|
+
```erb
|
397
|
+
<%= render NavigationComponent.new do |navigation| %>
|
398
|
+
<% navigation.with_link(href: learning_path, text: "Learning Path") %>
|
399
|
+
<% navigation.with_link(href: courses_path, text: "All Courses") %>
|
400
|
+
<% navigation.with_link(text: "Reports") do |link| %>
|
401
|
+
<% link.with_sublink(href: reports_users_path, text: "Users") %>
|
402
|
+
<% link.with_sublink(href: reports_activity_path, text: "Activity") %>
|
403
|
+
<% end %>
|
404
|
+
<% navigation.with_footer do %>
|
405
|
+
<div>Footer content</div>
|
406
|
+
<% end %>
|
407
|
+
<% end %>
|
408
|
+
```
|
409
|
+
|
410
|
+
This demonstrates how EVC properly handles nested slots with correct block variable scoping - the inner `WithSublink` slots use the `link` variable from their parent `WithLink` slot.
|
411
|
+
|
329
412
|
### Mixed Content
|
330
413
|
|
331
414
|
You can mix regular HTML, ERB, and component tags:
|
@@ -113,6 +113,7 @@ module EvcRails
|
|
113
113
|
|
114
114
|
# Determine if this is a slot (e.g., WithHeader, WithPost)
|
115
115
|
parent_component = stack.reverse.find { |item| item[4] == :component }
|
116
|
+
parent_slot_index = stack.rindex { |item| item[4] == :slot }
|
116
117
|
is_slot = false
|
117
118
|
slot_name = nil
|
118
119
|
|
@@ -121,15 +122,22 @@ module EvcRails
|
|
121
122
|
# Convert CamelCase slot name to snake_case
|
122
123
|
slot_name = tag_name[4..].gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
123
124
|
parent_component[6] = true # Mark parent as having a slot
|
125
|
+
# If this slot is nested inside another slot, mark the parent slot as having nested slots
|
126
|
+
stack[parent_slot_index][6] = true if parent_slot_index
|
124
127
|
end
|
125
128
|
|
126
129
|
if is_self_closing
|
127
130
|
if is_slot
|
128
|
-
|
131
|
+
# For self-closing slots, use the most recent slot variable if present, otherwise the component variable
|
132
|
+
parent_variable = if stack.last && stack.last[4] == :slot
|
133
|
+
stack.last[8]
|
134
|
+
else
|
135
|
+
parent_component[8]
|
136
|
+
end
|
129
137
|
result << if param_str.empty?
|
130
|
-
"<% #{parent_variable}.with_#{slot_name}
|
138
|
+
"<% #{parent_variable}.with_#{slot_name} %>"
|
131
139
|
else
|
132
|
-
"<% #{parent_variable}.with_#{slot_name}(#{param_str})
|
140
|
+
"<% #{parent_variable}.with_#{slot_name}(#{param_str}) %>"
|
133
141
|
end
|
134
142
|
else
|
135
143
|
component_class = "#{tag_name}Component"
|
@@ -140,8 +148,20 @@ module EvcRails
|
|
140
148
|
end
|
141
149
|
end
|
142
150
|
elsif is_slot
|
143
|
-
|
144
|
-
stack
|
151
|
+
# For block slots, determine the parent variable
|
152
|
+
if stack.last && stack.last[4] == :slot
|
153
|
+
# The most recent stack entry is a slot; use its variable
|
154
|
+
parent_variable = stack.last[8]
|
155
|
+
# Mark the parent slot as having nested slots
|
156
|
+
stack.last[6] = true
|
157
|
+
else
|
158
|
+
# Otherwise, use the nearest component variable
|
159
|
+
parent_variable = parent_component[8]
|
160
|
+
end
|
161
|
+
# Generate a variable name for this slot (strip 'with_' prefix)
|
162
|
+
slot_variable_name = component_variable_name(tag_name.sub(/^With/, ""))
|
163
|
+
stack << [tag_name, nil, param_str, result.length, :slot, slot_name, false, match.begin(0),
|
164
|
+
slot_variable_name]
|
145
165
|
result << if param_str.empty?
|
146
166
|
"<% #{parent_variable}.with_#{slot_name} do %>"
|
147
167
|
else
|
@@ -150,7 +170,6 @@ module EvcRails
|
|
150
170
|
else
|
151
171
|
component_class = "#{tag_name}Component"
|
152
172
|
variable_name = as_variable || component_variable_name(tag_name)
|
153
|
-
# If as_variable is present, force block variable to be yielded
|
154
173
|
force_block_variable = !as_variable.nil?
|
155
174
|
stack << [tag_name, component_class, param_str, result.length, :component, nil, false, match.begin(0),
|
156
175
|
variable_name, force_block_variable]
|
@@ -199,14 +218,23 @@ module EvcRails
|
|
199
218
|
relevant_part = result[start_pos..-1]
|
200
219
|
match_for_insertion = /( do)( %>)/.match(relevant_part)
|
201
220
|
if match_for_insertion
|
202
|
-
# Insert the variable name just
|
203
|
-
insertion_point = start_pos + match_for_insertion.begin(1)
|
221
|
+
# Insert the variable name just after the ` do`
|
222
|
+
insertion_point = start_pos + match_for_insertion.begin(1) + match_for_insertion[1].length
|
204
223
|
result.insert(insertion_point, " |#{variable_name}|")
|
205
224
|
end
|
206
225
|
end
|
207
226
|
|
208
227
|
result << "<% end %>"
|
209
228
|
else # It's a slot
|
229
|
+
_tag_name, _component_class, param_str, start_pos, _type, _slot_name, has_nested_slots, _open_pos, slot_variable_name = open_tag_data
|
230
|
+
if has_nested_slots
|
231
|
+
relevant_part = result[start_pos..-1]
|
232
|
+
match_for_insertion = /( do)( %>)/.match(relevant_part)
|
233
|
+
if match_for_insertion
|
234
|
+
insertion_point = start_pos + match_for_insertion.begin(1) + match_for_insertion[1].length
|
235
|
+
result.insert(insertion_point, " |#{slot_variable_name}|")
|
236
|
+
end
|
237
|
+
end
|
210
238
|
result << "<% end %>"
|
211
239
|
end
|
212
240
|
|
data/lib/evc_rails/version.rb
CHANGED