evc_rails 0.2.1 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5fa808d0d2dcb0efe2ff7a1807cbfabfb62995594731b066eb718e3aac9e1ee3
4
- data.tar.gz: fc944ac269042805ec1bb1c9175a4646ac56ed4a3ac2461c6061c211c831b608
3
+ metadata.gz: '0083734e9b8f16100d769aa08c7393c7e60105a5c9bcbc3774c5955cc3c71def'
4
+ data.tar.gz: 9099d7be89c3b5c6805fbd0b7b9316409c53a89ff62b1460391265c4a18fa97b
5
5
  SHA512:
6
- metadata.gz: 197a8e203c89e35b9a2365b38d40a9c24c042045a9ea654538f9fa5eb860778d7a1312231c921d6a7b9119cc41869ece6240ce5af201a4c94420406a5f02f228
7
- data.tar.gz: 0ae04a20540c3ad665ac2b7309e1053bdb200ca6f0a9c439752904ff9400fb6ce45defbe15cc620256a6959dd7b2c2b46489bea45921c1d44b09ea813a86f000
6
+ metadata.gz: 742227dddbef882cf3a085bfd2c8642e4decc61a76bb83f858b55bb900d1064d09b9507beb3cbfbb62d5472a644793f4457057d23962cce134a6d75aa018bfca
7
+ data.tar.gz: 13948d925ffc1419337d7d6a104be86bdae102577a133393978cb8c00eab2f7ee63bc627c6e15667c34671534f020588cf5e97297cbc82f6e0d79e800c9b416e
data/CHANGELOG.md ADDED
@@ -0,0 +1,87 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.2] - 2024-12-19
11
+
12
+ ### Added
13
+
14
+ - **Boolean attribute shorthand**: Support for HTML-style boolean attributes without values
15
+ - `<Button disabled required />` now converts to `disabled: true, required: true`
16
+ - Makes templates more concise and readable for boolean parameters
17
+ - Works with any boolean parameter your component defines
18
+
19
+ ### Changed
20
+
21
+ - Updated test suite to use new snake_case variable naming convention
22
+ - Improved block variable syntax consistency across all examples
23
+
24
+ ## [0.2.1] - 2024-12-19
25
+
26
+ ### Added
27
+
28
+ - **Custom block variable naming**: Support for `as` attribute to customize yielded variable names
29
+ - `<Card as="my_card">` yields `|my_card|` instead of `|card|`
30
+ - Helps avoid variable name collisions in nested components
31
+ - Useful for accessing parent component context from nested components
32
+
33
+ ### Changed
34
+
35
+ - **Block variable naming**: Components now yield snake_case variable names by default
36
+ - `<Card>` now yields `|card|` instead of `|c|`
37
+ - More descriptive and consistent with Ruby naming conventions
38
+ - Only yields variables when slots are present in the component
39
+
40
+ ### Fixed
41
+
42
+ - Improved slot method naming to match ViewComponent conventions
43
+ - `<WithHeader>` maps to `with_header` method (not `header`)
44
+ - `<WithItem>` maps to `with_item` method for both `renders_one` and `renders_many`
45
+ - Ensures compatibility with ViewComponent's generated method names
46
+
47
+ ## [0.2.0] - 2024-12-19
48
+
49
+ ### Added
50
+
51
+ - **Slot support**: Full support for ViewComponent slots with `<With...>` syntax
52
+ - `<WithHeader>` for `renders_one :header`
53
+ - `<WithItem>` for `renders_many :items` (uses singular method name)
54
+ - Support for slot attributes and Ruby expressions
55
+ - Automatic block variable yielding when slots are present
56
+ - **Namespaced component support**: Components in subdirectories
57
+ - `<UI::Button />` maps to `app/components/ui/button_component.rb`
58
+ - `<Forms::Fields::TextField />` for deeply nested components
59
+ - **Enhanced error messages**: Line numbers and column positions for better debugging
60
+ - **Production caching**: Automatic template caching using Rails.cache
61
+ - **Cache management**: Methods to clear and inspect template cache
62
+
63
+ ### Changed
64
+
65
+ - **Template handler architecture**: Improved performance and reliability
66
+ - **Error handling**: More descriptive error messages with context
67
+
68
+ ## [0.1.0] - 2024-12-19
69
+
70
+ ### Added
71
+
72
+ - **Initial release**: Basic JSX-like syntax for ViewComponent
73
+ - **Self-closing components**: `<Button />` syntax
74
+ - **Block components**: `<Card>content</Card>` syntax
75
+ - **Attribute support**: String, Ruby expressions, and multiple attributes
76
+ - **ERB integration**: Full support for ERB tags and Ruby expressions
77
+ - **Drop-in replacement**: Works as a replacement for `.erb` files
78
+ - **Basic caching**: Template compilation caching for performance
79
+
80
+ ---
81
+
82
+ ## Version History Notes
83
+
84
+ - **0.1.0**: Initial release with core functionality
85
+ - **0.2.0**: Major feature addition with slots and namespaced components
86
+ - **0.2.1**: Improved variable naming and slot method compatibility
87
+ - **0.2.2**: Added boolean attribute shorthand for cleaner templates
data/README.md CHANGED
@@ -176,6 +176,22 @@ There are two ways to pass information to a component:
176
176
  - **As attributes:** Data passed as attributes on the main component tag (e.g. `<Card title="...">`) is sent to its `initialize` method.
177
177
  - **As slot content:** Rich content passed via `<With...>` tags is used to populate the component's named slots.
178
178
 
179
+ #### Boolean Attribute Shorthand
180
+
181
+ You can use HTML-style boolean attributes in EVC. If you specify an attribute with no value, it will be passed as `true` to your component initializer. This makes templates more concise and readable:
182
+
183
+ ```erb
184
+ <Button disabled required />
185
+ ```
186
+
187
+ is equivalent to:
188
+
189
+ ```erb
190
+ <%= render ButtonComponent.new(disabled: true, required: true) %>
191
+ ```
192
+
193
+ This works for any boolean parameter your component defines.
194
+
179
195
  #### When a Block Variable is Yielded
180
196
 
181
197
  The contextual variable (e.g., `|card|`) is only yielded if one or more `<With...>` slot tags are present inside the component block. If you render a component like `<Card></Card>` with no slots inside, `evc_rails` is smart enough to render it without the `do |card|` part.
@@ -282,6 +298,34 @@ end
282
298
 
283
299
  This generates distinct variables, `outer_card` and `inner_card`, allowing you to access the context of each component without collision.
284
300
 
301
+ #### Passing a Collection to a Plural Slot (Array Notation)
302
+
303
+ You can also pass an array directly to a plural slot method using embedded Ruby inside your EVC template. For this advanced use case, block variables are not inferred automatically and it is necessary to define block variables with the `as` attribute.
304
+
305
+ ```erb
306
+ <Navigation as="navigation">
307
+ <% navigation.with_links([
308
+ { name: "Home", href: "/" },
309
+ { name: "Pricing", href: "/pricing" },
310
+ { name: "Sign Up", href: "/sign-up" }
311
+ ]) %>
312
+ </Navigation>
313
+ ```
314
+
315
+ This is equivalent to the ERB version:
316
+
317
+ ```erb
318
+ <%= render NavigationComponent.new do |navigation| %>
319
+ <% navigation.with_links([
320
+ { name: "Home", href: "/" },
321
+ { name: "Pricing", href: "/pricing" },
322
+ { name: "Sign Up", href: "/sign-up" }
323
+ ]) %>
324
+ <% end %>
325
+ ```
326
+
327
+ 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
+
285
329
  ### Mixed Content
286
330
 
287
331
  You can mix regular HTML, ERB, and component tags:
@@ -13,7 +13,7 @@ module EvcRails
13
13
  CLOSE_TAG_REGEX = %r{</([A-Z][a-zA-Z0-9_]*(?:::[A-Z][a-zA-Z0-9_]*)*)>}
14
14
 
15
15
  # Regex for attributes
16
- ATTRIBUTE_REGEX = /(\w+)=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\})/
16
+ ATTRIBUTE_REGEX = /(\w+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/
17
17
 
18
18
  # Cache for compiled templates
19
19
  @template_cache = {}
@@ -150,8 +150,10 @@ module EvcRails
150
150
  else
151
151
  component_class = "#{tag_name}Component"
152
152
  variable_name = as_variable || component_variable_name(tag_name)
153
+ # If as_variable is present, force block variable to be yielded
154
+ force_block_variable = !as_variable.nil?
153
155
  stack << [tag_name, component_class, param_str, result.length, :component, nil, false, match.begin(0),
154
- variable_name]
156
+ variable_name, force_block_variable]
155
157
  result << if param_str.empty?
156
158
  "<%= render #{component_class}.new do %>"
157
159
  else
@@ -188,10 +190,10 @@ module EvcRails
188
190
  tag_type = open_tag_data[4]
189
191
 
190
192
  if tag_type == :component
191
- _tag_name, component_class, param_str, start_pos, _type, _slot_name, slot_used, _open_pos, variable_name = open_tag_data
193
+ _tag_name, component_class, param_str, start_pos, _type, _slot_name, slot_used, _open_pos, variable_name, force_block_variable = open_tag_data
192
194
 
193
- # Patch in |variable_name| for component if a slot was used
194
- if slot_used
195
+ # Patch in |variable_name| for component if a slot was used or as_variable was present
196
+ if slot_used || force_block_variable
195
197
  # More robustly find the end of the `do` block to insert the variable.
196
198
  # This avoids faulty regex matching on complex parameters.
197
199
  relevant_part = result[start_pos..-1]
@@ -254,13 +256,16 @@ module EvcRails
254
256
 
255
257
  params = []
256
258
  attributes_str.scan(attribute_regex) do |key, quoted_value, single_quoted_value, ruby_expression|
257
- if ruby_expression
258
- params << "#{key}: #{ruby_expression}"
259
- elsif quoted_value
260
- params << "#{key}: \"#{quoted_value.gsub('"', '\\"')}\""
261
- elsif single_quoted_value
262
- params << "#{key}: \"#{single_quoted_value.gsub("'", "\\'")}\""
263
- end
259
+ params << if ruby_expression
260
+ "#{key}: #{ruby_expression}"
261
+ elsif quoted_value
262
+ "#{key}: \"#{quoted_value.gsub('"', '\\"')}\""
263
+ elsif single_quoted_value
264
+ "#{key}: \"#{single_quoted_value.gsub("'", "\\'")}\""
265
+ else
266
+ # Standalone attribute (no value) - treat as boolean true
267
+ "#{key}: true"
268
+ end
264
269
  end
265
270
  [params, as_variable]
266
271
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EvcRails
4
- VERSION = "0.2.1"
4
+ VERSION = "0.2.3"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evc_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - scttymn
@@ -77,6 +77,7 @@ extensions: []
77
77
  extra_rdoc_files: []
78
78
  files:
79
79
  - ".rubocop.yml"
80
+ - CHANGELOG.md
80
81
  - LICENSE.txt
81
82
  - README.md
82
83
  - Rakefile