rnx_rails 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8500771a30b64cbac0e54aebd62985c64f9a8f90c716f552cdabee1faeac35b6
4
+ data.tar.gz: 52f1816f7dff0db762ccd50883fe00d907955260ee37c1ff9d3d02bb533cd8c1
5
+ SHA512:
6
+ metadata.gz: 379c5ce5f42fc081964f129132e05984d88e0d7204b0844c2815e1663b8bd3b6c6f1c633c29645bfd21b7653cfa4d142c28c7f7aa197224908cf6fcdfa470e55
7
+ data.tar.gz: 6b20a381a7f082903c0920f214f09c17167f29b1abe61e49af8d72a27e660578692767dfe7717d26c26b9dc467ec1ce1ec08151468d9bc0d0c2312fe1820edb9
data/README.md ADDED
@@ -0,0 +1,484 @@
1
+ # rnx_rails
2
+
3
+ Rails gem providing view helpers and ERB directives for integrating [rnxJS](https://github.com/BaryoDev/rnxjs) reactive components into Rails applications.
4
+
5
+ [![License: MPL-2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0)
6
+ [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D2.7-red.svg)](https://www.ruby-lang.org/)
7
+
8
+ ## Overview
9
+
10
+ rnx_rails provides Rails view helpers that make it easy to:
11
+
12
+ - Include rnxJS library and stylesheets in your ERB templates
13
+ - Create reactive state from Rails data
14
+ - Render rnxJS components with Rails variables
15
+ - Initialize rnxJS plugins (router, toast, storage)
16
+ - Bind Rails data to reactive components
17
+
18
+ ## Installation
19
+
20
+ ### Add to Gemfile
21
+
22
+ ```ruby
23
+ gem 'rnx_rails', '~> 1.0'
24
+ ```
25
+
26
+ ### Bundle
27
+
28
+ ```bash
29
+ bundle install
30
+ ```
31
+
32
+ The gem is automatically loaded by Rails' engine system.
33
+
34
+ ## Quick Start
35
+
36
+ ### 1. Include rnxJS in Your Base Layout
37
+
38
+ ```erb
39
+ <%= rnx_scripts(cdn: true, theme: 'bootstrap') %>
40
+ ```
41
+
42
+ ### 2. Create Reactive State
43
+
44
+ Pass Rails data to rnxJS as reactive state:
45
+
46
+ ```erb
47
+ <% user_data = {
48
+ name: current_user.name,
49
+ email: current_user.email,
50
+ role: current_user.role
51
+ } %>
52
+
53
+ <%= rnx_state(user_data, 'user') %>
54
+
55
+ <p>Welcome, <span data-bind="user.name"></span>!</p>
56
+ ```
57
+
58
+ ### 3. Render Components
59
+
60
+ Use view helpers to render rnxJS components:
61
+
62
+ ```erb
63
+ <%= rnx_component('Button', variant: 'primary', label: 'Save') %>
64
+ <%= rnx_component('Input', type: 'email', placeholder: 'user@example.com') %>
65
+ <%= rnx_component('DataTable', data: 'users', columns: 'columns', sortable: true) %>
66
+ ```
67
+
68
+ ## View Helpers Reference
69
+
70
+ ### rnx_scripts
71
+
72
+ Include rnxJS library and stylesheets.
73
+
74
+ **Signature:**
75
+ ```ruby
76
+ rnx_scripts(cdn: true, theme: 'bootstrap')
77
+ ```
78
+
79
+ **Parameters:**
80
+ - `cdn` (Boolean, default: true) - Use CDN for resources
81
+ - `theme` (String, default: 'bootstrap') - Theme variant: 'bootstrap', 'm3', 'plugins', or nil
82
+
83
+ **Example:**
84
+ ```erb
85
+ <head>
86
+ <%= rnx_scripts(cdn: true, theme: 'm3') %>
87
+ </head>
88
+ ```
89
+
90
+ ### rnx_state
91
+
92
+ Create reactive state from Rails data.
93
+
94
+ **Signature:**
95
+ ```ruby
96
+ rnx_state(data, var_name = 'state')
97
+ ```
98
+
99
+ **Parameters:**
100
+ - `data` - Ruby hash or object to convert to reactive state
101
+ - `var_name` (String, optional, default: 'state') - Name of the global state variable
102
+
103
+ **Example:**
104
+ ```erb
105
+ <% app_data = {
106
+ user: current_user,
107
+ notifications: current_user.notifications,
108
+ settings: {
109
+ theme: 'light',
110
+ language: 'en'
111
+ }
112
+ } %>
113
+
114
+ <%= rnx_state(app_data, 'appState') %>
115
+
116
+ <!-- Access reactive state in HTML -->
117
+ <span data-bind="appState.user.name"></span>
118
+ <span data-bind="appState.user.email"></span>
119
+ ```
120
+
121
+ ### rnx_component
122
+
123
+ Render rnxJS components with props.
124
+
125
+ **Signature:**
126
+ ```ruby
127
+ rnx_component(name, props = {})
128
+ ```
129
+
130
+ **Parameters:**
131
+ - Component name (String)
132
+ - Hash of props (optional)
133
+
134
+ **Features:**
135
+ - Automatic string escaping for security
136
+ - Support for data binding expressions (state.*)
137
+ - Boolean attributes without values
138
+ - Numeric attribute values without quotes
139
+ - Snake_case to kebab-case conversion
140
+
141
+ **Examples:**
142
+
143
+ ```erb
144
+ <!-- Button component -->
145
+ <%= rnx_component('Button', variant: 'primary', label: 'Save') %>
146
+
147
+ <!-- Input with data binding -->
148
+ <%= rnx_component('Input',
149
+ type: 'email',
150
+ placeholder: 'user@example.com',
151
+ data_bind: 'state.email'
152
+ ) %>
153
+
154
+ <!-- DataTable with reactive data -->
155
+ <%= rnx_component('DataTable',
156
+ data: 'state.users',
157
+ columns: 'state.columns',
158
+ sortable: true,
159
+ pageable: true
160
+ ) %>
161
+
162
+ <!-- Loop example -->
163
+ <% @items.each do |item| %>
164
+ <%= rnx_component('Card',
165
+ title: item.title,
166
+ content: item.content,
167
+ id: item.id
168
+ ) %>
169
+ <% end %>
170
+ ```
171
+
172
+ ### rnx_plugin
173
+
174
+ Initialize rnxJS plugins.
175
+
176
+ **Signature:**
177
+ ```ruby
178
+ rnx_plugin(name, options = {})
179
+ ```
180
+
181
+ **Parameters:**
182
+ - Plugin name: 'router', 'toast', or 'storage'
183
+ - Plugin-specific configuration options
184
+
185
+ **Available Plugins:**
186
+
187
+ #### Router Plugin
188
+ Navigate between pages with hash-based routing.
189
+
190
+ ```erb
191
+ <%= rnx_plugin('router', mode: 'hash', default_route: '/') %>
192
+
193
+ <!-- Route-specific content visibility -->
194
+ <div data-route="/">Home Page</div>
195
+ <div data-route="/users">Users Page</div>
196
+ ```
197
+
198
+ #### Toast Plugin
199
+ Display notifications.
200
+
201
+ ```erb
202
+ <%= rnx_plugin('toast',
203
+ position: 'top-right',
204
+ duration: 3000,
205
+ max_toasts: 5
206
+ ) %>
207
+
208
+ <script>
209
+ window.rnx.toast.success('Operation completed!');
210
+ window.rnx.toast.error('An error occurred');
211
+ window.rnx.toast.warning('Warning message');
212
+ window.rnx.toast.info('Information');
213
+ </script>
214
+ ```
215
+
216
+ #### Storage Plugin
217
+ Persist state to localStorage/sessionStorage.
218
+
219
+ ```erb
220
+ <%= rnx_plugin('storage',
221
+ prefix: 'myapp_',
222
+ storage: 'localStorage'
223
+ ) %>
224
+
225
+ <script>
226
+ // Persist state
227
+ window.rnx.storage.persist(state, 'user_prefs', ['theme', 'language']);
228
+
229
+ // Retrieve
230
+ const theme = window.rnx.storage.get('user_prefs_theme');
231
+ </script>
232
+ ```
233
+
234
+ ### data_bind
235
+
236
+ Create a data binding attribute.
237
+
238
+ **Signature:**
239
+ ```ruby
240
+ data_bind(path)
241
+ ```
242
+
243
+ **Example:**
244
+ ```erb
245
+ <span <%= data_bind('user.name') %>></span>
246
+ <!-- Output: data-bind="user.name" -->
247
+ ```
248
+
249
+ ### data_rule
250
+
251
+ Create a validation rule attribute.
252
+
253
+ **Signature:**
254
+ ```ruby
255
+ data_rule(rules)
256
+ ```
257
+
258
+ **Example:**
259
+ ```erb
260
+ <input <%= data_rule('required|email|max:100') %> />
261
+ <!-- Output: data-rule="required|email|max:100" -->
262
+
263
+ <input <%= data_rule(['required', 'email']) %> />
264
+ <!-- Output: data-rule="required|email" -->
265
+ ```
266
+
267
+ ## Configuration
268
+
269
+ Create an initializer to configure rnx_rails:
270
+
271
+ ```ruby
272
+ # config/initializers/rnx.rb
273
+ RnxRails.configure do |config|
274
+ config.cdn = ENV.fetch('RNX_CDN', true)
275
+ config.theme = ENV.fetch('RNX_THEME', 'bootstrap')
276
+ config.storage_prefix = ENV.fetch('RNX_STORAGE_PREFIX', 'rnx_')
277
+ config.router_mode = ENV.fetch('RNX_ROUTER_MODE', 'hash')
278
+ config.toast_position = ENV.fetch('RNX_TOAST_POSITION', 'top-right')
279
+ config.toast_duration = ENV.fetch('RNX_TOAST_DURATION', 3000).to_i
280
+ config.toast_max = ENV.fetch('RNX_TOAST_MAX', 5).to_i
281
+ end
282
+ ```
283
+
284
+ ### Environment Variables
285
+
286
+ - `RNX_CDN` - Use CDN (default: true)
287
+ - `RNX_THEME` - Default theme (default: 'bootstrap')
288
+ - `RNX_STORAGE_PREFIX` - Storage key prefix (default: 'rnx_')
289
+ - `RNX_ROUTER_MODE` - Router mode (default: 'hash')
290
+ - `RNX_TOAST_POSITION` - Toast position (default: 'top-right')
291
+ - `RNX_TOAST_DURATION` - Toast duration in ms (default: 3000)
292
+ - `RNX_TOAST_MAX` - Max toasts on screen (default: 5)
293
+
294
+ ## Complete Example
295
+
296
+ ### app/controllers/profiles_controller.rb
297
+
298
+ ```ruby
299
+ class ProfilesController < ApplicationController
300
+ before_action :authenticate_user!
301
+
302
+ def show
303
+ @user = current_user
304
+ @notifications = current_user.notifications.recent.limit(10)
305
+ end
306
+ end
307
+ ```
308
+
309
+ ### app/views/profiles/show.html.erb
310
+
311
+ ```erb
312
+ <% app_state = {
313
+ user: {
314
+ name: @user.name,
315
+ email: @user.email,
316
+ role: @user.role,
317
+ avatar: @user.avatar_url
318
+ },
319
+ notifications: @notifications.map { |n| n.as_json },
320
+ routes: {
321
+ home: '/',
322
+ profile: '/profile',
323
+ settings: '/settings'
324
+ }
325
+ } %>
326
+
327
+ <%= rnx_state(app_state, 'appState') %>
328
+ <%= rnx_plugin('toast', position: 'top-right', duration: 3000) %>
329
+
330
+ <div class="profile-container">
331
+ <header>
332
+ <h1 data-bind="appState.user.name"></h1>
333
+ <p data-bind="appState.user.email"></p>
334
+ </header>
335
+
336
+ <section class="profile-actions">
337
+ <%= rnx_component('Button',
338
+ variant: 'primary',
339
+ label: 'Edit Profile',
340
+ onclick: 'editProfile()'
341
+ ) %>
342
+
343
+ <%= rnx_component('Button',
344
+ variant: 'danger',
345
+ label: 'Logout',
346
+ onclick: 'logout()'
347
+ ) %>
348
+ </section>
349
+
350
+ <section class="notifications">
351
+ <h2>Recent Notifications</h2>
352
+ <% @notifications.each do |notification| %>
353
+ <%= rnx_component('Card',
354
+ title: notification.title,
355
+ content: notification.message,
356
+ timestamp: notification.created_at,
357
+ dismissible: true
358
+ ) %>
359
+ <% end %>
360
+ </section>
361
+ </div>
362
+
363
+ <script>
364
+ function editProfile() {
365
+ window.rnx.toast.info('Opening edit dialog');
366
+ // Navigate to edit page
367
+ window.location.href = appState.routes.profile + '/edit';
368
+ }
369
+
370
+ function logout() {
371
+ window.rnx.toast.info('Logging out...');
372
+ window.location.href = '/logout';
373
+ }
374
+ </script>
375
+ ```
376
+
377
+ ### app/views/layouts/application.html.erb
378
+
379
+ ```erb
380
+ <!DOCTYPE html>
381
+ <html>
382
+ <head>
383
+ <title>My Rails App</title>
384
+ <meta name="viewport" content="width=device-width,initial-scale=1">
385
+ <%= csp_meta_tag %>
386
+ <%= csrf_meta_tags %>
387
+
388
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
389
+ <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
390
+
391
+ <!-- rnxJS -->
392
+ <%= rnx_scripts(cdn: true, theme: 'bootstrap') %>
393
+ </head>
394
+
395
+ <body>
396
+ <nav class="navbar navbar-expand-lg navbar-light bg-light">
397
+ <div class="container-fluid">
398
+ <%= link_to 'My App', root_path, class: 'navbar-brand' %>
399
+ <div class="collapse navbar-collapse">
400
+ <ul class="navbar-nav ms-auto">
401
+ <% if user_signed_in? %>
402
+ <li class="nav-item">
403
+ <%= link_to current_user.name, profile_path, class: 'nav-link' %>
404
+ </li>
405
+ <li class="nav-item">
406
+ <%= link_to 'Logout', destroy_user_session_path, method: :delete, class: 'nav-link' %>
407
+ </li>
408
+ <% else %>
409
+ <li class="nav-item">
410
+ <%= link_to 'Login', new_user_session_path, class: 'nav-link' %>
411
+ </li>
412
+ <% end %>
413
+ </ul>
414
+ </div>
415
+ </div>
416
+ </nav>
417
+
418
+ <main>
419
+ <%= yield %>
420
+ </main>
421
+
422
+ <%= rnx_plugin('toast', RnxRails.configuration.toast.to_hash) if RnxRails.configuration.toast %>
423
+ </body>
424
+ </html>
425
+ ```
426
+
427
+ ## Security Considerations
428
+
429
+ ### HTML Escaping
430
+
431
+ All component props are automatically HTML-escaped to prevent XSS attacks:
432
+
433
+ ```erb
434
+ <!-- Safe: Will escape < > & quotes -->
435
+ <%= rnx_component('Button', label: user_input) %>
436
+ ```
437
+
438
+ ### Data Binding Expressions
439
+
440
+ String values starting with `state.`, `{`, or `[` are preserved without escaping for data binding:
441
+
442
+ ```erb
443
+ <!-- Treated as data binding expression -->
444
+ <%= rnx_component('Div', data_content: 'state.userMessage') %>
445
+
446
+ <!-- Regular string, will be escaped -->
447
+ <%= rnx_component('Div', title: 'Hello World') %>
448
+ ```
449
+
450
+ ## Testing
451
+
452
+ Tests are included in the `spec` directory. Run them with RSpec:
453
+
454
+ ```bash
455
+ bundle exec rspec
456
+ ```
457
+
458
+ ## Contributing
459
+
460
+ Contributions are welcome! Please see [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.
461
+
462
+ ## License
463
+
464
+ MPL-2.0 - See [LICENSE](../../LICENSE) for details.
465
+
466
+ ## Support
467
+
468
+ - Documentation: [rnxJS Documentation](https://github.com/BaryoDev/rnxjs)
469
+ - Issues: [GitHub Issues](https://github.com/BaryoDev/rnxjs/issues)
470
+ - Discussions: [GitHub Discussions](https://github.com/BaryoDev/rnxjs/discussions)
471
+
472
+ ## Changelog
473
+
474
+ ### 1.0.0 (2024)
475
+
476
+ - Initial release
477
+ - Rails view helpers: rnx_scripts, rnx_state, rnx_component, rnx_plugin
478
+ - Helper methods: data_bind, data_rule
479
+ - Bootstrap 5.3+ support
480
+ - Plugin integration (router, toast, storage)
481
+ - Configuration via initializers
482
+ - Full test coverage
483
+ - Type-safe component rendering
484
+ - HTML escaping and XSS prevention
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RnxRails
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace RnxRails
6
+
7
+ config.generators do |g|
8
+ g.test_framework :rspec
9
+ end
10
+
11
+ initializer 'rnx_rails.view_helpers' do |app|
12
+ ActiveSupport.on_load(:action_view) do
13
+ include RnxRails::Helpers
14
+ end
15
+ end
16
+
17
+ initializer 'rnx_rails.asset_pipeline' do |app|
18
+ app.config.assets.paths << File.join(root, 'app', 'assets')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RnxRails
4
+ # Rails view helpers for rnxJS integration
5
+ module Helpers
6
+ # Generate rnxJS script includes
7
+ #
8
+ # @param cdn [Boolean] Use CDN (default: true)
9
+ # @param theme [String] Theme to include ('bootstrap', 'm3', 'plugins', or nil)
10
+ # @return [String] HTML script tags
11
+ def rnx_scripts(cdn: RnxRails.configuration.cdn, theme: RnxRails.configuration.theme)
12
+ if cdn
13
+ scripts = <<~HTML
14
+ <!-- rnxJS from CDN -->
15
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
16
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css" rel="stylesheet">
17
+ <script src="https://cdn.jsdelivr.net/npm/@arnelirobles/rnxjs/dist/rnx.global.js"></script>
18
+ HTML
19
+
20
+ case theme
21
+ when 'm3'
22
+ scripts += '<link href="https://cdn.jsdelivr.net/npm/@arnelirobles/rnxjs/css/bootstrap-m3-theme.css" rel="stylesheet">'
23
+ when 'plugins'
24
+ scripts += '<link href="https://cdn.jsdelivr.net/npm/@arnelirobles/rnxjs/css/plugins.css" rel="stylesheet">'
25
+ end
26
+
27
+ scripts.html_safe
28
+ else
29
+ # Local file serving
30
+ scripts = <<~HTML
31
+ <!-- rnxJS from local files -->
32
+ <link href="#{asset_path('bootstrap.min.css')}" rel="stylesheet">
33
+ <link href="#{asset_path('bootstrap-icons.min.css')}" rel="stylesheet">
34
+ <script src="#{asset_path('rnx.global.js')}"></script>
35
+ HTML
36
+
37
+ case theme
38
+ when 'm3'
39
+ scripts += "<link href=\"#{asset_path('bootstrap-m3-theme.css')}\" rel=\"stylesheet\">"
40
+ when 'plugins'
41
+ scripts += "<link href=\"#{asset_path('plugins.css')}\" rel=\"stylesheet\">"
42
+ end
43
+
44
+ scripts.html_safe
45
+ end
46
+ end
47
+
48
+ # Create reactive state from Rails data
49
+ #
50
+ # @param data [Object] Data to convert to state
51
+ # @param var_name [String] Name of the state variable (default: 'state')
52
+ # @return [String] JavaScript code to initialize state
53
+ def rnx_state(data, var_name = 'state')
54
+ begin
55
+ json_data = data.to_json
56
+ rescue StandardError => e
57
+ return tag.script("console.error('rnxJS: Failed to serialize state: #{e.message}')")
58
+ end
59
+
60
+ script = <<~JAVASCRIPT
61
+ <script>
62
+ // Initialize reactive state from Rails context
63
+ const #{var_name} = rnx.createReactiveState(#{json_data});
64
+ rnx.loadComponents(document.body, #{var_name});
65
+ </script>
66
+ JAVASCRIPT
67
+
68
+ script.html_safe
69
+ end
70
+
71
+ # Render an rnxJS component with props
72
+ #
73
+ # @param name [String] Component name
74
+ # @param props [Hash] Component properties
75
+ # @return [String] HTML component tag
76
+ def rnx_component(name, props = {})
77
+ attrs = []
78
+
79
+ props.each do |key, value|
80
+ # Convert snake_case to kebab-case
81
+ attr_name = key.to_s.gsub(/_/, '-')
82
+
83
+ if value.is_a?(TrueClass)
84
+ attrs << attr_name
85
+ elsif value.is_a?(FalseClass)
86
+ # Skip false boolean attributes
87
+ next
88
+ elsif value.is_a?(String) && (
89
+ value.start_with?('state.') ||
90
+ value.start_with?('{') ||
91
+ value.start_with?('[')
92
+ )
93
+ # Preserve data binding expressions
94
+ attrs << "#{attr_name}=\"#{value}\""
95
+ elsif value.is_a?(Numeric)
96
+ attrs << "#{attr_name}=#{value}"
97
+ else
98
+ # Escape and quote string values
99
+ escaped = ERB::Util.html_escape(value.to_s)
100
+ attrs << "#{attr_name}=\"#{escaped}\""
101
+ end
102
+ end
103
+
104
+ attrs_str = attrs.any? ? " #{attrs.join(' ')}" : ''
105
+ "<#{name}#{attrs_str}></#{name}>".html_safe
106
+ end
107
+
108
+ # Initialize an rnxJS plugin
109
+ #
110
+ # @param name [String] Plugin name ('router', 'toast', 'storage')
111
+ # @param options [Hash] Plugin configuration options
112
+ # @return [String] JavaScript code to initialize plugin
113
+ def rnx_plugin(name, options = {})
114
+ begin
115
+ options_json = options.to_json
116
+ rescue StandardError => e
117
+ return tag.script("console.error('rnxJS: Failed to serialize plugin options: #{e.message}')")
118
+ end
119
+
120
+ camel_name = name.to_s.camelize(:lower)
121
+
122
+ script = <<~JAVASCRIPT
123
+ <script>
124
+ // Initialize rnxJS plugin: #{name}
125
+ if (window.rnx && window.rnx.plugins) {
126
+ try {
127
+ const plugin = rnx.#{camel_name}Plugin ? rnx.#{camel_name}Plugin(#{options_json}) : null;
128
+ if (plugin) {
129
+ rnx.plugins.use(plugin);
130
+ }
131
+ } catch (e) {
132
+ console.error("[rnxJS] Failed to initialize #{name} plugin:", e);
133
+ }
134
+ }
135
+ </script>
136
+ JAVASCRIPT
137
+
138
+ script.html_safe
139
+ end
140
+
141
+ # Create a data binding attribute
142
+ #
143
+ # @param path [String] Data path (e.g., 'user.name')
144
+ # @return [String] data-bind attribute
145
+ def data_bind(path)
146
+ "data-bind=\"#{ERB::Util.html_escape(path)}\"".html_safe
147
+ end
148
+
149
+ # Create a validation rule attribute
150
+ #
151
+ # @param rules [String, Array] Validation rules
152
+ # @return [String] data-rule attribute
153
+ def data_rule(rules)
154
+ rules_str = rules.is_a?(Array) ? rules.join('|') : rules.to_s
155
+ "data-rule=\"#{ERB::Util.html_escape(rules_str)}\"".html_safe
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RnxRails
4
+ VERSION = '1.0.0'
5
+ end
data/lib/rnx_rails.rb ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rnx_rails/version'
4
+ require_relative 'rnx_rails/helpers'
5
+ require_relative 'rnx_rails/engine'
6
+
7
+ module RnxRails
8
+ class Error < StandardError; end
9
+
10
+ # Configuration for rnxRails
11
+ class << self
12
+ attr_accessor :configuration
13
+
14
+ def configure
15
+ self.configuration ||= Configuration.new
16
+ yield(configuration)
17
+ end
18
+
19
+ def configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+ end
23
+
24
+ # Configuration class
25
+ class Configuration
26
+ attr_accessor :cdn, :theme, :storage_prefix, :router_mode, :toast_position, :toast_duration, :toast_max
27
+
28
+ def initialize
29
+ @cdn = ENV.fetch('RNX_CDN', true)
30
+ @theme = ENV.fetch('RNX_THEME', 'bootstrap')
31
+ @storage_prefix = ENV.fetch('RNX_STORAGE_PREFIX', 'rnx_')
32
+ @router_mode = ENV.fetch('RNX_ROUTER_MODE', 'hash')
33
+ @toast_position = ENV.fetch('RNX_TOAST_POSITION', 'top-right')
34
+ @toast_duration = ENV.fetch('RNX_TOAST_DURATION', 3000).to_i
35
+ @toast_max = ENV.fetch('RNX_TOAST_MAX', 5).to_i
36
+ end
37
+ end
38
+ end
data/rnx_rails.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/rnx_rails/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'rnx_rails'
7
+ spec.version = RnxRails::VERSION
8
+ spec.authors = ['Arnel Irobles']
9
+ spec.email = ['arnel@arnelirobles.com']
10
+
11
+ spec.summary = 'rnxJS integration for Rails - View helpers and directives for reactive components'
12
+ spec.description = 'Rails gem providing view helpers, ERB directives, and configuration for integrating rnxJS reactive components into Rails applications'
13
+ spec.homepage = 'https://github.com/BaryoDev/rnxjs'
14
+ spec.license = 'MPL-2.0'
15
+ spec.required_ruby_version = '>= 2.7'
16
+
17
+ spec.metadata = {
18
+ 'homepage_uri' => spec.homepage,
19
+ 'source_code_uri' => spec.homepage,
20
+ 'changelog_uri' => "#{spec.homepage}/releases",
21
+ 'bug_tracker_uri' => "#{spec.homepage}/issues",
22
+ 'documentation_uri' => "#{spec.homepage}/tree/main/packages/rails-rnx",
23
+ }
24
+
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(spec|features)/}) }
27
+ end
28
+
29
+ spec.require_paths = ['lib']
30
+
31
+ spec.add_runtime_dependency 'rails', '>= 6.0'
32
+ spec.add_development_dependency 'bundler', '>= 2.0'
33
+ spec.add_development_dependency 'rake', '>= 10.0'
34
+ spec.add_development_dependency 'rspec-rails', '>= 5.0'
35
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rnx_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Arnel Irobles
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-12-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ description: Rails gem providing view helpers, ERB directives, and configuration for
70
+ integrating rnxJS reactive components into Rails applications
71
+ email:
72
+ - arnel@arnelirobles.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - README.md
78
+ - lib/rnx_rails.rb
79
+ - lib/rnx_rails/engine.rb
80
+ - lib/rnx_rails/helpers.rb
81
+ - lib/rnx_rails/version.rb
82
+ - rnx_rails.gemspec
83
+ homepage: https://github.com/BaryoDev/rnxjs
84
+ licenses:
85
+ - MPL-2.0
86
+ metadata:
87
+ homepage_uri: https://github.com/BaryoDev/rnxjs
88
+ source_code_uri: https://github.com/BaryoDev/rnxjs
89
+ changelog_uri: https://github.com/BaryoDev/rnxjs/releases
90
+ bug_tracker_uri: https://github.com/BaryoDev/rnxjs/issues
91
+ documentation_uri: https://github.com/BaryoDev/rnxjs/tree/main/packages/rails-rnx
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '2.7'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 3.0.3.1
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: rnxJS integration for Rails - View helpers and directives for reactive components
111
+ test_files: []