evc_rails 0.1.0 → 0.1.1
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/README.md +59 -11
- data/lib/evc_rails/template_handler.rb +16 -11
- 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: a7fda15b180ea02549511ff7aa2f1a51071ef8cce0fbf9721c92cc8fe4b6f605
|
4
|
+
data.tar.gz: 03ab565adcff81843d342152c4631c22124ee01d820e8a007a590afea3792347
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1b7c0694278f7bffbf73b23423f14ca96f993cdfd0f19fe230ce52014405d8f1221f0ff3922c9ae7fab2e889832d1de480b0465b875cfcb4cd6ad26c012fd34
|
7
|
+
data.tar.gz: 24c79d6ba0ac68acea62831ee0043bfb175ac05a3aab97cbe641b503258dfb4becabc21cc72b7f2b03bffdd8d68a0d88902dd9e82d79101e0c876cd28654f285
|
data/README.md
CHANGED
@@ -6,11 +6,13 @@ EvcRails is a Rails gem that introduces a custom .evc template handler, allowing
|
|
6
6
|
|
7
7
|
PascalCase Component Tags: Define and use your View Components with <MyComponent> or self-closing <MyComponent /> syntax directly in your .evc templates.
|
8
8
|
|
9
|
+
Namespaced Components: Support for namespaced components like <Ui::Button /> or <Forms::Input /> for better organization.
|
10
|
+
|
9
11
|
Attribute Handling: Pass attributes to your components using standard HTML-like key="value", key='value', or Ruby expressions key={@variable}.
|
10
12
|
|
11
13
|
Content Blocks: Components can accept content blocks (<MyComponent>content</MyComponent>) which are passed to the View Component via a block.
|
12
14
|
|
13
|
-
Automatic Component Resolution: Automatically appends "Component" to your tag name if it's not already present (e.g., <Button> resolves to ButtonComponent).
|
15
|
+
Automatic Component Resolution: Automatically appends "Component" to your tag name if it's not already present (e.g., <Button> resolves to ButtonComponent, <Ui::Button> resolves to Ui::ButtonComponent).
|
14
16
|
|
15
17
|
Performance Optimized: Includes in-memory caching of compiled templates and memoization of component class lookups for efficient rendering in production.
|
16
18
|
|
@@ -57,7 +59,7 @@ end
|
|
57
59
|
|
58
60
|
And its associated template app/components/my_component_component.html.erb (if you're using separate templates):
|
59
61
|
|
60
|
-
```
|
62
|
+
```erb
|
61
63
|
<!-- app/components/my_component_component.html.erb -->
|
62
64
|
<div class="my-component">
|
63
65
|
<h2><%= @title %></h2>
|
@@ -68,7 +70,7 @@ And its associated template app/components/my_component_component.html.erb (if y
|
|
68
70
|
2. Create an .evc Template
|
69
71
|
Now, create a template file with the .evc extension. For instance, app/views/pages/home.html.evc:
|
70
72
|
|
71
|
-
```
|
73
|
+
```erb
|
72
74
|
<!-- app/views/pages/home.html.evc -->
|
73
75
|
<h1>Welcome to My App</h1>
|
74
76
|
|
@@ -77,8 +79,15 @@ And its associated template app/components/my_component_component.html.erb (if y
|
|
77
79
|
<button text="Click Me" />
|
78
80
|
</MyComponent>
|
79
81
|
|
82
|
+
<%# Namespaced components for better organization %>
|
83
|
+
<Ui::Button text="Click Me" />
|
84
|
+
<Forms::Input name="email" placeholder="Enter your email" />
|
85
|
+
<Layout::Container>
|
86
|
+
<p>Content inside a layout container</p>
|
87
|
+
</Layout::Container>
|
88
|
+
|
80
89
|
<%# A more concise way to render your DoughnutChartComponent %>
|
81
|
-
<DoughnutChart rings=
|
90
|
+
<DoughnutChart rings={@progress_data} />
|
82
91
|
|
83
92
|
<%# You can still use standard ERB within .evc files %>
|
84
93
|
<p><%= link_to "Go somewhere", some_path %></p>
|
@@ -92,24 +101,57 @@ And its associated template app/components/my_component_component.html.erb (if y
|
|
92
101
|
config.eager_load_paths << Rails.root.join("app/components")
|
93
102
|
```
|
94
103
|
|
104
|
+
## Component Organization
|
105
|
+
|
106
|
+
You can organize your components into namespaces for better structure:
|
107
|
+
|
108
|
+
```
|
109
|
+
app/components/
|
110
|
+
├── ui/
|
111
|
+
│ ├── button_component.rb
|
112
|
+
│ ├── card_component.rb
|
113
|
+
│ └── input_component.rb
|
114
|
+
├── forms/
|
115
|
+
│ ├── input_component.rb
|
116
|
+
│ ├── select_component.rb
|
117
|
+
│ └── checkbox_component.rb
|
118
|
+
├── layout/
|
119
|
+
│ ├── container_component.rb
|
120
|
+
│ ├── header_component.rb
|
121
|
+
│ └── footer_component.rb
|
122
|
+
└── my_component_component.rb
|
123
|
+
```
|
124
|
+
|
125
|
+
Then use them in your .evc templates:
|
126
|
+
|
127
|
+
```erb
|
128
|
+
<Ui::Button text="Submit" />
|
129
|
+
<Forms::Input name="username" />
|
130
|
+
<Layout::Container>
|
131
|
+
<Layout::Header title="My App" />
|
132
|
+
<p>Main content</p>
|
133
|
+
<Layout::Footer />
|
134
|
+
</Layout::Container>
|
135
|
+
```
|
136
|
+
|
95
137
|
## How it Works
|
96
138
|
|
97
139
|
When Rails processes an .evc template, EvcRails intercepts it and performs the following transformations:
|
98
140
|
|
99
141
|
```erb
|
100
|
-
<
|
142
|
+
<Card title="Hello World">... </Card>
|
101
143
|
```
|
102
144
|
|
103
145
|
becomes:
|
104
146
|
|
105
147
|
```ruby
|
106
|
-
<%= render
|
148
|
+
<%= render CardComponent.new(title: "Hello World") do %>
|
107
149
|
... (processed content) ...
|
108
150
|
<% end %>
|
109
151
|
```
|
110
152
|
|
111
153
|
```erb
|
112
|
-
|
154
|
+
<Button text="Click Me" />
|
113
155
|
```
|
114
156
|
|
115
157
|
becomes:
|
@@ -118,6 +160,16 @@ becomes:
|
|
118
160
|
<%= render ButtonComponent.new(text: "Click Me") %>
|
119
161
|
```
|
120
162
|
|
163
|
+
```erb
|
164
|
+
<Ui::Button text="Click Me" />
|
165
|
+
```
|
166
|
+
|
167
|
+
becomes:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
<%= render Ui::ButtonComponent.new(text: "Click Me") %>
|
171
|
+
```
|
172
|
+
|
121
173
|
```erb
|
122
174
|
<DoughnutChart rings={@progress_data} />
|
123
175
|
```
|
@@ -147,7 +199,3 @@ Bug reports and pull requests are welcome on GitHub at [your-gem-repo-link]. Thi
|
|
147
199
|
## License
|
148
200
|
|
149
201
|
The gem is available as open source under the terms of the MIT License
|
150
|
-
|
151
|
-
```
|
152
|
-
|
153
|
-
```
|
@@ -12,16 +12,18 @@ module EvcRails
|
|
12
12
|
module TemplateHandlers
|
13
13
|
class Evc
|
14
14
|
# Regex to match opening or self-closing PascalCase component tags with attributes
|
15
|
-
|
15
|
+
# Updated to support namespaced components like UI::Button
|
16
|
+
TAG_REGEX = %r{<([A-Z][a-zA-Z_]*(::[A-Z][a-zA-Z_]*)*)([^>]*)/?>}
|
16
17
|
|
17
18
|
# Regex to match closing PascalCase component tags
|
18
|
-
|
19
|
+
# Updated to support namespaced components like UI::Button
|
20
|
+
CLOSE_TAG_REGEX = %r{</([A-Z][a-zA-Z_]*(::[A-Z][a-zA-Z_]*)*)>}
|
19
21
|
|
20
22
|
# Regex for attributes: Supports string literals (key="value", key='value')
|
21
23
|
# and Ruby expressions (key={@variable}).
|
22
24
|
# Group 1: Attribute key, Group 2: Double-quoted value, Group 3: Single-quoted value,
|
23
25
|
# Group 4: Ruby expression.
|
24
|
-
ATTRIBUTE_REGEX = /(\w+)=(
|
26
|
+
ATTRIBUTE_REGEX = /(\w+)=(?:"([^"]*)"|'([^']*)'|\{([^}]*)\})/
|
25
27
|
|
26
28
|
# Cache for compiled templates to improve performance.
|
27
29
|
# @cache will store { identifier: { source: original_source, result: compiled_result } }
|
@@ -56,8 +58,8 @@ module EvcRails
|
|
56
58
|
# In development, templates change frequently, so caching would hinder development flow.
|
57
59
|
unless Rails.env.development?
|
58
60
|
self.class.instance_variable_set(:@cache, self.class.instance_variable_get(:@cache).merge({
|
59
|
-
|
60
|
-
|
61
|
+
identifier => { source: source, result: result }
|
62
|
+
}))
|
61
63
|
end
|
62
64
|
result
|
63
65
|
end
|
@@ -93,10 +95,14 @@ module EvcRails
|
|
93
95
|
|
94
96
|
is_self_closing = match[0].end_with?("/>")
|
95
97
|
tag_name = match[1]
|
96
|
-
attributes_str = match[
|
98
|
+
attributes_str = match[3].strip
|
97
99
|
|
98
100
|
# Determine the full component class name
|
99
|
-
|
101
|
+
# Handle both namespaced (UI::Button) and non-namespaced (Button) components
|
102
|
+
component_class_name = if tag_name.include?("::")
|
103
|
+
# For namespaced components, just append Component
|
104
|
+
"#{tag_name}Component"
|
105
|
+
elsif tag_name.end_with?("Component")
|
100
106
|
tag_name
|
101
107
|
else
|
102
108
|
"#{tag_name}Component"
|
@@ -161,7 +167,8 @@ module EvcRails
|
|
161
167
|
|
162
168
|
# Check for mismatched tags (e.g., <div></p>)
|
163
169
|
if component_class_name != closing_tag_name
|
164
|
-
raise ArgumentError,
|
170
|
+
raise ArgumentError,
|
171
|
+
"Mismatched tags: expected </#{component_class_name}>, got </#{closing_tag_name}> in template #{template.identifier}"
|
165
172
|
end
|
166
173
|
|
167
174
|
# Recursively process the content between the opening and closing tags.
|
@@ -179,9 +186,7 @@ module EvcRails
|
|
179
186
|
end
|
180
187
|
|
181
188
|
# After parsing, if the stack is not empty, it means there are unclosed tags.
|
182
|
-
unless stack.empty?
|
183
|
-
raise ArgumentError, "Unclosed tag <#{stack.last[0]}> in template #{template.identifier}"
|
184
|
-
end
|
189
|
+
raise ArgumentError, "Unclosed tag <#{stack.last[0]}> in template #{template.identifier}" unless stack.empty?
|
185
190
|
|
186
191
|
# Join all the collected parts to form the final ERB string.
|
187
192
|
parts.join("")
|
data/lib/evc_rails/version.rb
CHANGED