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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 703fa9100249c54f63c8e567d5d8cde7b3908b6777dfb555f2d2e72a949d4daa
4
- data.tar.gz: f175e943945bc31a3d4da2be22290e7f843546c0bb6dc0426ad22d1433472fe6
3
+ metadata.gz: a7fda15b180ea02549511ff7aa2f1a51071ef8cce0fbf9721c92cc8fe4b6f605
4
+ data.tar.gz: 03ab565adcff81843d342152c4631c22124ee01d820e8a007a590afea3792347
5
5
  SHA512:
6
- metadata.gz: dcd338b43347af1e971b99d50298d425da85193856f0362a4b7358ad19fbe3b059b5808b6c7ba0bf0f53944244d2bf2a5a7fd8e2283d6d13912f138c683d6b36
7
- data.tar.gz: c902814035da4a002d4006df67b07e8e71256084a9bc3585a256d1b14281eb5bee41c4941b0d7956f4c6d87330bf72cfdfb5edef2b03321a94e99c676af2e331
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
- ```html
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
- ```html
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="{@progress_data}" />
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
- <MyComponent title="Hello World">... </MyComponent>
142
+ <Card title="Hello World">... </Card>
101
143
  ```
102
144
 
103
145
  becomes:
104
146
 
105
147
  ```ruby
106
- <%= render MyComponentComponent.new(title: "Hello World") do %>
148
+ <%= render CardComponent.new(title: "Hello World") do %>
107
149
  ... (processed content) ...
108
150
  <% end %>
109
151
  ```
110
152
 
111
153
  ```erb
112
- <%=<button text="Click Me" />
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
- TAG_REGEX = %r{<([A-Z][a-zA-Z_]*)([^>]*)/?>}
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
- CLOSE_TAG_REGEX = %r{</([A-Z][a-zA-Z_]*)>}
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
- identifier => { source: source, result: result }
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[2].strip
98
+ attributes_str = match[3].strip
97
99
 
98
100
  # Determine the full component class name
99
- component_class_name = if tag_name.end_with?("Component")
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, "Mismatched tags: expected </#{component_class_name}>, got </#{closing_tag_name}> in template #{template.identifier}"
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("")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EvcRails
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
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.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - scttymn