reactive-actions 0.1.0.pre.alpha.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.
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ReactiveActions module provides functionality for creating and executing reactive actions in Rails applications
4
+ module ReactiveActions
5
+ # Configuration class for ReactiveActions
6
+ # Manages settings for controller method delegation and instance variable delegation
7
+ class Configuration
8
+ attr_accessor :delegated_controller_methods, :delegated_instance_variables
9
+
10
+ def initialize
11
+ # Default methods to delegate
12
+ @delegated_controller_methods = %i[
13
+ render redirect_to head params
14
+ session cookies flash request response
15
+ ]
16
+
17
+ # Default instance variables to delegate
18
+ @delegated_instance_variables = []
19
+ end
20
+ end
21
+
22
+ class << self
23
+ attr_writer :configuration
24
+
25
+ def configuration
26
+ @configuration ||= Configuration.new
27
+ end
28
+
29
+ def configure
30
+ yield(configuration)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'reactive_actions'
4
+
5
+ module ReactiveActions
6
+ # Rails engine for the ReactiveActions gem
7
+ # Handles asset inclusion, autoloading, and namespace management
8
+ class Engine < ::Rails::Engine
9
+ isolate_namespace ReactiveActions
10
+
11
+ config.generators do |g|
12
+ g.test_framework :rspec
13
+ g.fixture_replacement :factory_bot
14
+ g.factory_bot dir: 'spec/factories'
15
+ end
16
+
17
+ # Tell Zeitwerk to ignore the bridge file specifically
18
+ initializer 'reactive_actions.zeitwerk_ignore' do
19
+ Rails.autoloaders.main.ignore("#{root}/lib/reactive-actions.rb")
20
+ end
21
+
22
+ # Configure assets for both Sprockets and Propshaft compatibility
23
+ initializer 'reactive_actions.assets' do |app|
24
+ # Add the JavaScript file to asset paths for Propshaft
25
+ app.config.assets.paths << root.join('app/assets/javascripts') if defined?(Propshaft)
26
+
27
+ # For Sprockets compatibility (if still being used)
28
+ app.config.assets.precompile += %w[reactive_actions.js] if defined?(Sprockets)
29
+ end
30
+
31
+ # Load and namespace action classes properly
32
+ initializer 'reactive_actions.load_actions', after: :load_config_initializers do |app|
33
+ actions_path = "#{app.root}/app/reactive_actions"
34
+ next unless Dir.exist?(actions_path)
35
+
36
+ # Find all action files
37
+ Dir.glob("#{actions_path}/**/*_action.rb").each do |file_path|
38
+ # Get relative path and class name
39
+ file_path.sub("#{actions_path}/", '')
40
+ class_name = File.basename(file_path, '.rb').camelize
41
+
42
+ # Skip if already defined in ReactiveActions namespace
43
+ next if ReactiveActions.const_defined?(class_name, false)
44
+
45
+ begin
46
+ # Load the file to ensure the class is defined
47
+ require_dependency file_path
48
+
49
+ # Try to find the class in global namespace
50
+ if Object.const_defined?(class_name, false)
51
+ original_class = Object.const_get(class_name)
52
+
53
+ # Create an alias in the ReactiveActions namespace
54
+ ReactiveActions.const_set(class_name, original_class)
55
+
56
+ Rails.logger.debug { "ReactiveActions: Aliased #{class_name} to ReactiveActions::#{class_name}" }
57
+ end
58
+ rescue StandardError => e
59
+ Rails.logger.warn "ReactiveActions: Failed to load action #{file_path}: #{e.message}"
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactiveActions
4
+ # Base error class for all ReactiveActions errors
5
+ class Error < StandardError; end
6
+
7
+ # Raised when an action is not found
8
+ class ActionNotFoundError < Error; end
9
+
10
+ # Raised when an action fails to execute properly
11
+ class ActionExecutionError < Error; end
12
+
13
+ # Raised when parameters are invalid
14
+ class InvalidParametersError < Error; end
15
+
16
+ # Raised when a required parameter is missing
17
+ class MissingParameterError < InvalidParametersError; end
18
+
19
+ # Raised when a parameter has an invalid type or format
20
+ class ParameterTypeError < InvalidParametersError; end
21
+
22
+ # Raised when the user is not authorized to perform the action
23
+ class UnauthorizedError < Error; end
24
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactiveActions
4
+ # Base class for reactive actions
5
+ # Provides common functionality for executing actions and handling responses
6
+ class ReactiveAction
7
+ attr_reader :action_params, :result, :controller
8
+
9
+ # Initialize a new reactive action
10
+ #
11
+ # @param [ActionController::Base] controller The controller instance
12
+ # @param [Hash] action_params Parameters to be used in the action
13
+ def initialize(controller = nil, **action_params)
14
+ @controller = controller
15
+ @action_params = action_params
16
+
17
+ # Delegate instance variables from controller to actions class
18
+ ReactiveActions.configuration.delegated_instance_variables.each do |instance_variable|
19
+ instance_variable_set("@#{instance_variable}", controller.instance_variable_get("@#{instance_variable}"))
20
+ end
21
+ end
22
+
23
+ # Execute the action and handle the response through the controller
24
+ def run
25
+ ReactiveActions.logger.info "Running action #{self.class.name} with params: #{action_params.inspect}"
26
+
27
+ begin
28
+ # Run the action
29
+ controller.instance_exec(&method(:action))
30
+ # Run the response
31
+ controller.instance_exec(&method(:response))
32
+ rescue ReactiveActions::Error => e
33
+ # Let ReactiveActions errors bubble up without modification
34
+ raise e
35
+ rescue StandardError => e
36
+ # Modify all other errors
37
+ ReactiveActions.logger.error "Error in action #{self.class.name}: #{e.message}"
38
+ raise ReactiveActions::ActionExecutionError, "Error executing #{self.class.name}: #{e.message}"
39
+ end
40
+ end
41
+
42
+ # The action to be implemented by subclasses
43
+ def action
44
+ raise NotImplementedError, "#{self.class.name} must implement the 'action' method"
45
+ end
46
+
47
+ # The response to be implemented by subclasses
48
+ def response
49
+ controller.head :ok
50
+ end
51
+
52
+ # Make class methods private
53
+ class << self
54
+ # This hook runs when ReactiveAction is subclassed
55
+ def inherited(subclass)
56
+ # Call super
57
+ super
58
+ # Apply controller method delegations from configuration
59
+ ReactiveActions.configuration.delegated_controller_methods.each do |method_name|
60
+ subclass.delegate method_name, to: :controller, allow_nil: true if ActionController::Base.instance_methods.include?(method_name.to_sym)
61
+ end
62
+ end
63
+
64
+ private :inherited
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactiveActions
4
+ VERSION = '0.1.0-alpha.1'
5
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'reactive_actions/version'
4
+ require 'reactive_actions/configuration'
5
+ require 'reactive_actions/engine'
6
+ require 'reactive_actions/reactive_action'
7
+ require 'reactive_actions/errors'
8
+
9
+ # Main namespace for the ReactiveActions gem
10
+ # Provides functionality for creating and executing reactive actions in Rails applications
11
+ module ReactiveActions
12
+ class << self
13
+ attr_writer :logger
14
+
15
+ def logger
16
+ @logger ||= Rails.logger
17
+ end
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reactive-actions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre.alpha.1
5
+ platform: ruby
6
+ authors:
7
+ - Istvan Meszaros
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-05-30 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: '7.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '9.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '7.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '9.0'
33
+ description: A modern framework for creating HTTP API endpoints that execute server-side
34
+ actions in Rails applications with automatic JavaScript client integration.
35
+ email:
36
+ - meszarosistvan97@gmail.com
37
+ executables: []
38
+ extensions: []
39
+ extra_rdoc_files: []
40
+ files:
41
+ - MIT-LICENSE
42
+ - README.md
43
+ - Rakefile
44
+ - app/assets/javascripts/reactive_actions.js
45
+ - app/controllers/reactive_actions/application_controller.rb
46
+ - app/controllers/reactive_actions/reactive_actions_controller.rb
47
+ - config/initializers/reactive_actions_logger.rb
48
+ - config/routes.rb
49
+ - lib/generators/reactive_actions/install/install_generator.rb
50
+ - lib/generators/reactive_actions/install/templates/README
51
+ - lib/generators/reactive_actions/install/templates/example_action.rb
52
+ - lib/generators/reactive_actions/install/templates/initializer.rb
53
+ - lib/reactive-actions.rb
54
+ - lib/reactive_actions.rb
55
+ - lib/reactive_actions/configuration.rb
56
+ - lib/reactive_actions/engine.rb
57
+ - lib/reactive_actions/errors.rb
58
+ - lib/reactive_actions/reactive_action.rb
59
+ - lib/reactive_actions/version.rb
60
+ homepage: https://github.com/IstvanMs/reactive-actions
61
+ licenses:
62
+ - MIT
63
+ metadata:
64
+ homepage_uri: https://github.com/IstvanMs/reactive-actions
65
+ source_code_uri: https://github.com/IstvanMs/reactive-actions
66
+ changelog_uri: https://github.com/IstvanMs/reactive-actions/blob/main/CHANGELOG.md
67
+ rubygems_mfa_required: 'true'
68
+ post_install_message: |2
69
+ Thank you for installing ReactiveActions!
70
+
71
+ To complete the setup, please run:
72
+ rails generate reactive_actions:install
73
+
74
+ This will add the necessary routes to your application.
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.0
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">"
86
+ - !ruby/object:Gem::Version
87
+ version: 1.3.1
88
+ requirements: []
89
+ rubygems_version: 3.4.19
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: ReactiveActions for Rails applications
93
+ test_files: []