NoMethodError: undefined method `required_positionals'
Hi, I am running into an issue with blocks in rbs. It should be noted that this spec passes with rbs disabled.
rbs 3.5.3
given the following RSpec spec:
describe '.parameter' do
it 'adds a parameter to the parameter set' do
described_class.parameter(:test) do
desc 'A test parameter'
end
expect(described_class.parameters.test).to be_an_instance_of(Domainic::Type::Constraint::Parameter)
.and(have_attributes(name: :test, description: 'A test parameter'))
end
end
and the following signatures:
class Base
class << self
def parameter(parameter_name, &)
parameter_builder.define(parameter_name, &).build!
end
private
def parameter_builder
@parameter_builder ||= DSL::ParameterBuilder.new(self)
end
end
end
class Base
def self.parameter: (::String | Symbol parameter_name) { (?) -> DSL::ParameterBuilder } -> void
private
def self.parameter_builder: -> DSL::ParameterBuilder
end
module DSL
class ParameterBuilder
def define(parameter_name, &)
@current_parameter = @data[parameter_name.to_sym] ||=
PARAMETER_DEFAULTS.transform_values(&:dup).merge(name: parameter_name.to_sym)
instance_exec(&) if block_given?
self
end
def description(description_string)
raise ArgumentError, 'No parameter is currently being defined' if @current_parameter.nil?
@current_parameter[:description] = description_string
self
end
alias desc description
end
end
module DSL
class ParameterBuilder
def define: (::String | ::Symbol parameter_name) { (?) -> self } -> self
def description: (::String description_string) -> self
alias desc description
end
end
I get:
NoMethodError: undefined method `required_positionals' for #<RBS::Types::UntypedFunction:0x0000000110c3fe68 @return_type=#<RBS::Types::ClassInstance:0x0000000110c3ff30 @name=#<RBS::TypeName:0x0000000110c12030 @namespace=#<RBS::Namespace:0x0000000110c12080 @path=[:Domainic, :Type, :DSL], @absolute=true, @parent=#<RBS::Namespace:0x0000000110c11fb8 @path=[:Domainic, :Type], @absolute=true, @parent=#<RBS::Namespace:0x0000000110c11ec8 @path=[:Domainic], @absolute=true, @parent=#<RBS::Namespace:0x0000000110c11dd8 @path=[], @absolute=true>>>>, @name=:ParameterBuilder, @kind=:class>, @args=[], @location=#<RBS::Location:11700 buffer=domainic-type/sig/domainic/type/constraint/base/base.rbs, start=15:72, pos=369...390, children=name,?args source="DSL::ParameterBuilder">>>
0) Domainic::Type::Constraint::Base.parameter adds a parameter to the parameter set
Failure/Error:
described_class.parameter(:test) do
desc 'A test parameter'
end
NoMethodError:
undefined method `required_positionals' for #<RBS::Types::UntypedFunction:0x0000000110c3fe68 @return_type=#<RBS::Types::ClassInstance:0x0000000110c3ff30 @name=#<RBS::TypeName:0x0000000110c12030 @namespace=#<RBS::Namespace:0x0000000110c12080 @path=[:Domainic, :Type, :DSL], @absolute=true, @parent=#<RBS::Namespace:0x0000000110c11fb8 @path=[:Domainic, :Type], @absolute=true, @parent=#<RBS::Namespace:0x0000000110c11ec8 @path=[:Domainic], @absolute=true, @parent=#<RBS::Namespace:0x0000000110c11dd8 @path=[], @absolute=true>>>>, @name=:ParameterBuilder, @kind=:class>, @args=[], @location=#<RBS::Location:11700 buffer=domainic-type/sig/domainic/type/constraint/base/base.rbs, start=15:72, pos=369...390, children=name,?args source="DSL::ParameterBuilder">>>
# ./domainic-type/spec/domainic/type/constraint/base_spec.rb:11:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# NoMethodError:
# undefined method `desc' for #<RSpec::ExampleGroups::DomainicTypeConstraintBase::Parameter "adds a parameter to the parameter set" (./domainic-type/spec/domainic/type/constraint/base_spec.rb:10)>
# ./domainic-type/spec/domainic/type/constraint/base_spec.rb:12:in `block (4 levels) in <top (required)>'
Additionally the recommended annotation to skip tests does not fix the issue:
%a{rbs:test:skip} def self.parameter: (::String | Symbol parameter_name) { (?) -> DSL::ParameterBuilder } -> void
Related issue on Ruby LSP which seems to be caused because of this: https://github.com/Shopify/ruby-lsp/issues/2630
module Domainic
module Type
module DSL
class ParameterBuilder
...
def coercer: (?(Proc | Symbol)? proc_or_symbol) { (?) -> void } -> self
alias coerce coercer
def define: (String | Symbol parameter_name) ?{ (self) -> self } -> self
...
end
end
end
end
class ParameterBuilder
...
def define(parameter_name, &)
@current_parameter = @data[parameter_name.to_sym] ||=
PARAMETER_DEFAULTS.transform_values { |value| value == UNSPECIFIED ? value : value.dup } .merge(name: parameter_name.to_sym)
instance_exec(&) if block_given?
self
end
...
end
class BaseConstraint
def parameter(parameter_name, &)
parameter_builder.define(parameter_name, &).build!
end
end
# This spec passes without signatures
it 'defines coercers for the parameter' do
coercer = ->(value) { value.to_s }
constraint_class.parameter(parameter_name) do
coercer coercer
end
parameter = constraint_class.parameters.public_send(parameter_name)
expect(parameter.instance_variable_get(:@coercers)).to include(coercer)
end
1) Domainic::Type::Constraint::BaseConstraint.parameter defines coercers for the parameter
Failure/Error:
constraint_class.parameter(parameter_name) do
coercer coercer
end
RBS::Test::Tester::TypeError:
TypeError: [Domainic::Type::Constraint::BaseConstraint.parameter] BlockArgumentError: expected method type (::String | ::Symbol parameter_name) ?{ (::Domainic::Type::DSL::ParameterBuilder) -> ::Domainic::Type::DSL::ParameterBuilder } -> void
# ./domainic-type/spec/domainic/type/constraint/base_constraint_spec.rb:25:in `block (3 levels) in <top (required)>'
# ------------------
# --- Caused by: ---
# NoMethodError:
# undefined method `coercer' for #<RSpec::ExampleGroups::DomainicTypeConstraintBaseConstraint::Parameter "defines coercers for the parameter" (./domainic-type/spec/domainic/type/constraint/base_constraint_spec.rb:23)>
# ./domainic-type/spec/domainic/type/constraint/base_constraint_spec.rb:26:in `block (4 levels) in <top (required)>'
Related issue on Ruby LSP which seems to be caused because of this: Shopify/ruby-lsp#2630
I'm using rubymine which I believe doesn't utilize lsp
@aaronmallen How about upgrading to rbs-3.6? There are some fixes related to the runtime test and UntypedFunction.
@aaronmallen How about upgrading to rbs-3.6? There are some fixes related to the runtime test and
UntypedFunction.
I've upgraded and still run into the same issues
Thanks. Hmm… Will look at the problem. 🙇♂️
@aaronmallen I have two things to share with you.
-
undefined method "desc" for #<RSpec::...>might be the source of the problem. I found the code you shared doesn't work with the currentinstance_evaldetection, and composed a patch #2052. - Adding
%a{rbs:test:skip}annotation to thedefinemethod would work.
I couldn't reproduce the required_positionals error myself, but at least one problem will be fixed...
I couldn't reproduce the
required_positionalserror myself, but at least one problem will be fixed...
I'm no longer running into the required_positionals error after applying the suggestions from https://github.com/ruby/rbs/discussions/2039 now its just:
Failure/Error:
desc ''
NoMethodError:
undefined method `desc' for BaseConstraint:Class
I look forward to your patch as I've pulled defining signatures out of scope for my project until a fix is released.