-
-
Notifications
You must be signed in to change notification settings - Fork 175
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request from GHSA-f78j-4w3g-4q65
- Loading branch information
Showing
5 changed files
with
179 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# frozen_string_literal: true | ||
|
||
class StimulusReflex::ReflexFactory | ||
attr_reader :reflex_name, :method_name | ||
|
||
def initialize(target) | ||
reflex_name, method_name = target.split("#") | ||
reflex_name = reflex_name.camelize | ||
reflex_name = reflex_name.end_with?("Reflex") ? reflex_name : "#{reflex_name}Reflex" | ||
|
||
@method_name = method_name | ||
@reflex_name = reflex_name | ||
end | ||
|
||
def call | ||
verify_method_name! | ||
|
||
reflex_class | ||
end | ||
|
||
private | ||
|
||
def verify_method_name! | ||
return if default_reflex? | ||
|
||
argument_error = ArgumentError.new("Reflex method '#{method_name}' is not defined on class '#{reflex_name}' or on any of its ancestors") | ||
|
||
if reflex_method.nil? | ||
raise argument_error | ||
end | ||
|
||
if !safe_ancestors.include?(reflex_method.owner) | ||
raise argument_error | ||
end | ||
end | ||
|
||
def reflex_class | ||
@reflex_class ||= reflex_name.constantize.tap do |klass| | ||
unless klass.ancestors.include?(StimulusReflex::Reflex) | ||
raise ArgumentError.new("#{reflex_name} is not a StimulusReflex::Reflex") | ||
end | ||
end | ||
end | ||
|
||
def reflex_method | ||
if reflex_class.public_instance_methods.include?(method_name.to_sym) | ||
reflex_class.public_instance_method(method_name) | ||
end | ||
end | ||
|
||
def default_reflex? | ||
method_name == "default_reflex" && reflex_method.owner == ::StimulusReflex::Reflex | ||
end | ||
|
||
def safe_ancestors | ||
# We want to include every class and module up to the `StimulusReflex::Reflex` class, | ||
# but not the StimulusReflex::Reflex itself | ||
reflex_class_index = reflex_class.ancestors.index(StimulusReflex::Reflex) - 1 | ||
|
||
reflex_class.ancestors.to(reflex_class_index) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative "test_helper" | ||
|
||
class StimulusReflex::ReflexFactoryTest < ActionCable::Channel::TestCase | ||
tests StimulusReflex::Channel | ||
|
||
test "reflex class needs to be an ancestor of StimulusReflex::Reflex" do | ||
exception = assert_raises(NameError) { StimulusReflex::ReflexFactory.new("Object#inspect").call } | ||
assert_equal "uninitialized constant ObjectReflex Did you mean? ObjectSpace", exception.message.squish | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("NoReflex#no_reflex").call } | ||
assert_equal "NoReflex is not a StimulusReflex::Reflex", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("No#no_reflex").call } | ||
assert_equal "NoReflex is not a StimulusReflex::Reflex", exception.message | ||
end | ||
|
||
test "doesn't raise if owner of method is ancestor of reflex class and descendant of StimulusReflex::Reflex" do | ||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("ApplicationReflex#default_reflex").call } | ||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("ApplicationReflex#application_reflex").call } | ||
|
||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("PostReflex#default_reflex").call } | ||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("PostReflex#application_reflex").call } | ||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("PostReflex#post_reflex").call } | ||
|
||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("CounterReflex#default_reflex").call } | ||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("CounterReflex#application_reflex").call } | ||
assert_nothing_raised { StimulusReflex::ReflexFactory.new("CounterReflex#increment").call } | ||
end | ||
|
||
test "raises if method is not owned by a descendant of StimulusReflex::Reflex" do | ||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("ApplicationReflex#itself").call } | ||
assert_equal "Reflex method 'itself' is not defined on class 'ApplicationReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("ApplicationReflex#itself").call } | ||
assert_equal "Reflex method 'itself' is not defined on class 'ApplicationReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("PostReflex#itself").call } | ||
assert_equal "Reflex method 'itself' is not defined on class 'PostReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("PostReflex#binding").call } | ||
assert_equal "Reflex method 'binding' is not defined on class 'PostReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("PostReflex#byebug").call } | ||
assert_equal "Reflex method 'byebug' is not defined on class 'PostReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("PostReflex#debug").call } | ||
assert_equal "Reflex method 'debug' is not defined on class 'PostReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("ApplicationReflex#post_reflex").call } | ||
assert_equal "Reflex method 'post_reflex' is not defined on class 'ApplicationReflex' or on any of its ancestors", exception.message | ||
end | ||
|
||
test "raises if method is a private method" do | ||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("ApplicationReflex#private_application_reflex").call } | ||
assert_equal "Reflex method 'private_application_reflex' is not defined on class 'ApplicationReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("PostReflex#private_application_reflex").call } | ||
assert_equal "Reflex method 'private_application_reflex' is not defined on class 'PostReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("PostReflex#private_post_reflex").call } | ||
assert_equal "Reflex method 'private_post_reflex' is not defined on class 'PostReflex' or on any of its ancestors", exception.message | ||
|
||
exception = assert_raises(ArgumentError) { StimulusReflex::ReflexFactory.new("CounterReflex#private_post_reflex").call } | ||
assert_equal "Reflex method 'private_post_reflex' is not defined on class 'CounterReflex' or on any of its ancestors", exception.message | ||
end | ||
|
||
test "safe_ancestors" do | ||
reflex_factory = StimulusReflex::ReflexFactory.new("ApplicationReflex#default_reflex") | ||
assert_equal [ApplicationReflex], reflex_factory.send(:safe_ancestors) | ||
|
||
reflex_factory = StimulusReflex::ReflexFactory.new("PostReflex#default_reflex") | ||
assert_equal [PostReflex, ApplicationReflex], reflex_factory.send(:safe_ancestors) | ||
|
||
reflex_factory = StimulusReflex::ReflexFactory.new("CounterReflex#increment") | ||
assert_equal [CounterReflex, CounterConcern, ApplicationReflex], reflex_factory.send(:safe_ancestors) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters