mirror of
https://gitea.invidious.io/iv-org/shard-spectator.git
synced 2024-08-15 00:53:35 +00:00
Prevent multiple redefinitions of the same method
This commit is contained in:
parent
a585ef0996
commit
df10c8e75b
1 changed files with 51 additions and 49 deletions
|
@ -338,64 +338,66 @@ module Spectator
|
||||||
# Redefines all methods and ones inherited from its parents and mixins to support stubs.
|
# Redefines all methods and ones inherited from its parents and mixins to support stubs.
|
||||||
private macro stub_type(type_name = @type)
|
private macro stub_type(type_name = @type)
|
||||||
{% type = type_name.resolve
|
{% type = type_name.resolve
|
||||||
# Reverse order of ancestors (there's currently no reverse method for ArrayLiteral).
|
definitions = [] of Nil
|
||||||
count = type.ancestors.size
|
scope = (type == @type ? :previous_def : :super).id
|
||||||
ancestors = type.ancestors.map_with_index { |_, i| type.ancestors[count - i - 1] } %}
|
|
||||||
{% for ancestor in ancestors %}
|
|
||||||
{% for method in ancestor.methods.reject do |meth|
|
|
||||||
meth.name.starts_with?("_spectator") ||
|
|
||||||
::Spectator::DSL::RESERVED_KEYWORDS.includes?(meth.name.symbolize)
|
|
||||||
end %}
|
|
||||||
{{(method.abstract? ? :abstract_stub : :default_stub).id}} {{method.visibility.id if method.visibility != :public}} def {{"#{method.receiver}.".id if method.receiver}}{{method.name}}(
|
|
||||||
{% for arg, i in method.args %}{% if i == method.splat_index %}*{% end %}{{arg}}, {% end %}
|
|
||||||
{% if method.double_splat %}**{{method.double_splat}}, {% end %}
|
|
||||||
{% if method.block_arg %}&{{method.block_arg}}{% elsif method.accepts_block? %}&{% end %}
|
|
||||||
){% if method.return_type %} : {{method.return_type}}{% end %}{% if !method.free_vars.empty? %} forall {{method.free_vars.splat}}{% end %}
|
|
||||||
super{% if method.accepts_block? %} { |*%yargs| yield *%yargs }{% end %}
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
{% for method in ancestor.class.methods.reject do |meth|
|
# Add entries for methods in the target type and its class type.
|
||||||
meth.name.starts_with?("_spectator") ||
|
[[:self.id, type.class], [nil, type]].each do |(receiver, t)|
|
||||||
::Spectator::DSL::RESERVED_KEYWORDS.includes?(meth.name.symbolize)
|
t.methods.each do |method|
|
||||||
end %}
|
definitions << {
|
||||||
default_stub {{method.visibility.id if method.visibility != :public}} def self.{{method.name}}(
|
type: t,
|
||||||
{% for arg, i in method.args %}{% if i == method.splat_index %}*{% end %}{{arg}}, {% end %}
|
method: method,
|
||||||
{% if method.double_splat %}**{{method.double_splat}}, {% end %}
|
scope: scope,
|
||||||
{% if method.block_arg %}&{{method.block_arg}}{% elsif method.accepts_block? %}&{% end %}
|
receiver: receiver,
|
||||||
){% if method.return_type %} : {{method.return_type}}{% end %}{% if !method.free_vars.empty? %} forall {{method.free_vars.splat}}{% end %}
|
}
|
||||||
super{% if method.accepts_block? %} { |*%yargs| yield *%yargs }{% end %}
|
end
|
||||||
end
|
end
|
||||||
{% end %}
|
|
||||||
{% end %}
|
|
||||||
|
|
||||||
{% for method in type.methods.reject do |meth|
|
# Iterate through all ancestors and add their methods.
|
||||||
meth.name.starts_with?("_spectator") ||
|
type.ancestors.each do |ancestor|
|
||||||
::Spectator::DSL::RESERVED_KEYWORDS.includes?(meth.name.symbolize)
|
[[:self.id, ancestor.class], [nil, ancestor]].each do |(receiver, t)|
|
||||||
end %}
|
t.methods.each do |method|
|
||||||
{{(method.abstract? ? :"abstract_stub abstract" : :default_stub).id}} {{method.visibility.id if method.visibility != :public}} def {{"#{method.receiver}.".id if method.receiver}}{{method.name}}(
|
# Skip methods already found to prevent redefining them multiple times.
|
||||||
|
unless definitions.any? do |d|
|
||||||
|
m = d[:method]
|
||||||
|
m.name == method.name &&
|
||||||
|
m.args == method.args &&
|
||||||
|
m.splat_index == method.splat_index &&
|
||||||
|
m.double_splat == method.double_splat &&
|
||||||
|
m.block_arg == method.block_arg
|
||||||
|
end
|
||||||
|
definitions << {
|
||||||
|
type: t,
|
||||||
|
method: method,
|
||||||
|
scope: :super.id,
|
||||||
|
receiver: receiver,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
definitions = definitions.reject do |definition|
|
||||||
|
name = definition[:method].name
|
||||||
|
name.starts_with?("_spectator") || ::Spectator::DSL::RESERVED_KEYWORDS.includes?(name.symbolize)
|
||||||
|
end %}
|
||||||
|
|
||||||
|
{% for definition in definitions %}
|
||||||
|
{% original_type = definition[:type]
|
||||||
|
method = definition[:method]
|
||||||
|
scope = definition[:scope]
|
||||||
|
receiver = definition[:receiver] %}
|
||||||
|
# Redefinition of {{type}}{{(receiver ? "." : "#").id}}{{method.name}}
|
||||||
|
{{(method.abstract? ? "abstract_stub abstract" : "default_stub").id}} {{method.visibility.id if method.visibility != :public}} def {{"#{receiver}.".id if receiver}}{{method.name}}(
|
||||||
{% for arg, i in method.args %}{% if i == method.splat_index %}*{% end %}{{arg}}, {% end %}
|
{% for arg, i in method.args %}{% if i == method.splat_index %}*{% end %}{{arg}}, {% end %}
|
||||||
{% if method.double_splat %}**{{method.double_splat}}, {% end %}
|
{% if method.double_splat %}**{{method.double_splat}}, {% end %}
|
||||||
{% if method.block_arg %}&{{method.block_arg}}{% elsif method.accepts_block? %}&{% end %}
|
{% if method.block_arg %}&{{method.block_arg}}{% elsif method.accepts_block? %}&{% end %}
|
||||||
){% if method.return_type %} : {{method.return_type}}{% end %}{% if !method.free_vars.empty? %} forall {{method.free_vars.splat}}{% end %}
|
){% if method.return_type %} : {{method.return_type}}{% end %}{% if !method.free_vars.empty? %} forall {{method.free_vars.splat}}{% end %}
|
||||||
{% unless method.abstract? %}
|
{% unless method.abstract? %}
|
||||||
{% if type == @type %}previous_def{% else %}super{% end %}{% if method.accepts_block? %} { |*%yargs| yield *%yargs }{% end %}
|
{{scope}}{% if method.accepts_block? %} { |*%yargs| yield *%yargs }{% end %}
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
||||||
{% for method in type.class.methods.reject do |meth|
|
|
||||||
meth.name.starts_with?("_spectator") ||
|
|
||||||
::Spectator::DSL::RESERVED_KEYWORDS.includes?(meth.name.symbolize)
|
|
||||||
end %}
|
|
||||||
default_stub {{method.visibility.id if method.visibility != :public}} def self.{{method.name}}(
|
|
||||||
{% for arg, i in method.args %}{% if i == method.splat_index %}*{% end %}{{arg}}, {% end %}
|
|
||||||
{% if method.double_splat %}**{{method.double_splat}}, {% end %}
|
|
||||||
{% if method.block_arg %}&{{method.block_arg}}{% elsif method.accepts_block? %}&{% end %}
|
|
||||||
){% if method.return_type %} : {{method.return_type}}{% end %}{% if !method.free_vars.empty? %} forall {{method.free_vars.splat}}{% end %}
|
|
||||||
{% if type == @type %}previous_def{% else %}super{% end %}{% if method.accepts_block? %} { |*%yargs| yield *%yargs }{% end %}
|
|
||||||
end
|
|
||||||
{% end %}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Utility macro for casting a stub (and its return value) to the correct type.
|
# Utility macro for casting a stub (and its return value) to the correct type.
|
||||||
|
|
Loading…
Reference in a new issue