From 5e39f8c43a755c3c55e629e3f44311211cb93680 Mon Sep 17 00:00:00 2001 From: HoneyryderChuck Date: Sat, 5 Oct 2024 17:04:47 +0100 Subject: [PATCH 1/5] draft of the Data() syntax --- test/rbs/parser_test.rb | 66 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/test/rbs/parser_test.rb b/test/rbs/parser_test.rb index adfde5f74..ec9dfe428 100644 --- a/test/rbs/parser_test.rb +++ b/test/rbs/parser_test.rb @@ -428,6 +428,72 @@ def `: () -> void end end + def test_data_class_decl + RBS::Parser.parse_signature(buffer(<<-RBS)).tap do |_, _, decls| + class Foo < Data{a: Integer} + end + RBS + decls[0].tap do |decl| + assert_instance_of RBS::AST::Declarations::Class, decl + assert_equal TypeName("Foo"), decl.name + assert_predicate decl.type_params, :empty? + assert_nil decl.super_class.name + assert_equal TypeName("Data"), decl.super_class.superclass.name + + assert_equal 8, decl.members.size + + decl.members[0].tap do |member| + assert_instance_of RBS::AST::Members::AttrReader, member + assert_equal :instance, member.kind + assert_equal :a, member.name + assert_equal "Integer", member.type.to_s + end + + decl.members[1].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :method, member.kind + assert_equal :initialize, member.name + assert_equal ["(::Integer) -> void | (id: ::Integer) -> void"], member.method_types.map(&:to_s) + end + + decl.members[2].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :method, member.kind + assert_equal :members, member.name + assert_equal ["() -> Array[Symbol]"], member.method_types.map(&:to_s) + end + + decl.members[3].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :method, member.kind + assert_equal :deconstruct, member.name + assert_equal ["() -> [Integer]"], member.method_types.map(&:to_s) + end + + decl.members[4].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :method, member.kind + assert_equal :deconstruct_keys, member.name + assert_equal ["(nil) -> {a: Integer} | (Array(Symbol)) -> Hash[untyped]"], member.method_types.map(&:to_s) + end + + decl.members[5].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :method, member.kind + assert_equal :with, member.name + assert_equal ["(?a: Integer) -> Foo"], member.method_types.map(&:to_s) + end + end + + decls[1].tap do |decl| + # as funcall: Foo[1] + assert_instance_of RBS::Types::UntypedFunction, decl.block.type + assert_equal TypeName("Foo"), decl.name + assert_equal ["(::Integer a) -> Foo |(a: ::Integer) -> Foo"], member.method_types.map(&:to_s) + end + end + end + def test_parse_type assert_equal "hello", RBS::Parser.parse_type(buffer('"hello"')).literal assert_equal "hello", RBS::Parser.parse_type(buffer("'hello'")).literal From 7b85c76f2cc9b45d24bb74324c9d51c40c952e90 Mon Sep 17 00:00:00 2001 From: HoneyryderChuck Date: Tue, 15 Oct 2024 15:37:43 +0100 Subject: [PATCH 2/5] change CLASS_NEW_INSTANCE macro to call .new so that if .new gets overridden, it gets properly called --- ext/rbs_extension/ruby_objs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/rbs_extension/ruby_objs.c b/ext/rbs_extension/ruby_objs.c index 1391a1514..e6b296c44 100644 --- a/ext/rbs_extension/ruby_objs.c +++ b/ext/rbs_extension/ruby_objs.c @@ -3,7 +3,7 @@ #ifdef RB_PASS_KEYWORDS // Ruby 2.7 or later #define CLASS_NEW_INSTANCE(klass, argc, argv)\ - rb_class_new_instance_kw(argc, argv, klass, RB_PASS_KEYWORDS) + rb_respond_to(klass, rb_intern("new")) ? rb_funcallv_kw(klass, rb_intern("new"), argc, argv, RB_PASS_KEYWORDS) : rb_class_new_instance_kw(argc, argv, klass, RB_PASS_KEYWORDS) #else // Ruby 2.6 #define CLASS_NEW_INSTANCE(receiver, argc, argv)\ From 562e7623af00d0eeaa8fd3629f3ec83e934f82a4 Mon Sep 17 00:00:00 2001 From: HoneyryderChuck Date: Tue, 15 Oct 2024 15:39:54 +0100 Subject: [PATCH 3/5] special syntax for Data and Struct subclasses allows declaring and typing variables, inject inherited methods OTTB --- core/process.rbs | 2 +- ext/rbs_extension/parser.c | 21 +- lib/rbs/ast/declarations.rb | 1177 +++++++++++++++++++++++++++++++++++ lib/rbs/builtin_names.rb | 1 + lib/rbs/type_name.rb | 8 + test/rbs/parser_test.rb | 216 ++++++- 6 files changed, 1399 insertions(+), 26 deletions(-) diff --git a/core/process.rbs b/core/process.rbs index 35d18506b..0012cd345 100644 --- a/core/process.rbs +++ b/core/process.rbs @@ -2236,7 +2236,7 @@ end # # Placeholder for rusage # -class Process::Tms < Struct[Float] +class Process::Tms < Struct(utime: Float, stime: Float, cutime: Float, cstime: Float) end class Process::Waiter < Thread diff --git a/ext/rbs_extension/parser.c b/ext/rbs_extension/parser.c index d99f29ade..f23ecea05 100644 --- a/ext/rbs_extension/parser.c +++ b/ext/rbs_extension/parser.c @@ -1747,6 +1747,8 @@ VALUE parse_member_def(parserstate *state, bool instance_only, bool accept_overl /** * class_instance_name ::= {} + * | {} Data `{` kwarg args `}` + * | {} Struct `{` kwarg args `}` * | {} class_name `[` type args <`]`> * * @param kind @@ -1756,13 +1758,28 @@ void class_instance_name(parserstate *state, TypeNameKind kind, VALUE *name, VAL *name = parse_type_name(state, kind, name_range); - if (state->next_token.type == pLBRACKET) { + if (state->next_token.type == pLBRACE && CLASS_OF(*name) == RBS_TypeName && rb_funcall(*name, rb_intern("data?"), 0) == Qtrue) { + parser_advance_assert(state, pLBRACE); + args_range->start = state->current_token.range.start; + *args = parse_record_attributes(state); + parser_advance_assert(state, pRBRACE); + args_range->end = state->current_token.range.end; + } + else if (state->next_token.type == pLBRACE && CLASS_OF(*name) == RBS_TypeName && rb_funcall(*name, rb_intern("struct?"), 0) == Qtrue) { + parser_advance_assert(state, pLBRACE); + args_range->start = state->current_token.range.start; + *args = parse_record_attributes(state); + parser_advance_assert(state, pRBRACE); + args_range->end = state->current_token.range.end; + } + else if (state->next_token.type == pLBRACKET) { parser_advance(state); args_range->start = state->current_token.range.start; parse_type_list(state, pRBRACKET, args); parser_advance_assert(state, pRBRACKET); args_range->end = state->current_token.range.end; - } else { + } + else { *args_range = NULL_RANGE; } } diff --git a/lib/rbs/ast/declarations.rb b/lib/rbs/ast/declarations.rb index bf9f0218f..d639a9dd3 100644 --- a/lib/rbs/ast/declarations.rb +++ b/lib/rbs/ast/declarations.rb @@ -81,6 +81,22 @@ def to_json(state = _ = nil) location: location }.to_json(state) end + + def self.new(name: , args:, location:) + if name.data? + superclass = super(name: name, args: [], location: location) + + return DataDecl.new(superclass, args: args, location: location) + end + + if name.struct? + superclass = super(name: name, args: [], location: location) + + return StructDecl.new(superclass, args: args, location: location) + end + + super + end end include NestedDeclarationHelper @@ -462,6 +478,1167 @@ def to_json(state = _ = nil) }.to_json(state) end end + + class DataDecl < Class + attr_reader :args + + def initialize(superklass, args: , location:) + if args.is_a?(Hash) + args = args.map do |k, (type, required)| + type = (required.nil? || required) ? type : Types::Optional.new(type: type, location: type.location) + Types::Function::Param.new(name: k, type: type, location: type.location) + end + end + + # attribute readers + members = args.map do |param| + Members::AttrReader.new( + name: param.name, + type: param.type, + ivar_name: :"@#{param.name}", + kind: :instance, + location: location, + comment: nil, + annotations: [] + ) + end + + # initialize + members << Members::MethodDefinition.new( + name: :initialize, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: args.to_h { |param| + [ + param.name, + # set param + Types::Function::Param.new( + name: nil, + type: param.type, + location: location + ) + ] + }, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Void.new(location: location), + ), + location: location, + block: nil, + ), + annotations: [] + ), + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_positionals: args.map { |param| + # set param + Types::Function::Param.new( + name: param.name, + type: param.type, + location: location + ) + }, + required_keywords: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Void.new(location: location), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # members + members << Members::MethodDefinition.new( + name: :members, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Array, + args: [Types::ClassInstance.new(name: BuiltinNames::Symbol, args: [], location: location)], + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # deconstruct + members << Members::MethodDefinition.new( + name: :deconstruct, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Tuple.new( + types: args.map do |param| + Types::ClassInstance.new(name: param.type, args: [], location: location) + end, + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # deconstruct_keys + members << Members::MethodDefinition.new( + name: :deconstruct_keys, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [ + Types::Function::Param.new( + name: nil, + type: Types::Bases::Nil.new(location: location), + location: location + ) + ], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Record.new( + all_fields: args.to_h do |param| + [ + param.name, + [ + Types::ClassInstance.new(name: param.type, args: [], location: location), + true + ] + ] + end, + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ), + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [ + Types::Function::Param.new( + name: :names, + type: Types::ClassInstance.new( + name: BuiltinNames::Array, + location: location, + args: [ + Types::ClassInstance.new( + name: BuiltinNames::Symbol, + args: [], + location: location + ) + ] + ), + location: location + ) + ], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Hash, + location: location, + args: [ + Types::ClassInstance.new( + name: BuiltinNames::Symbol, + args: [], + location: location + ), + Types::ClassInstance.new( + name: Types::Bases::Any.new(location: location), + args: [], + location: location + ) + ] + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # with + members << Members::MethodDefinition.new( + name: :with, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: args.to_h do |param| + [ + param.name, + Types::Function::Param.new( + name: nil, + type: Types::ClassInstance.new( + name: param.type, + args: [], + location: location + ), + location: location + ) + ] + end, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Instance.new( + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # .[] + members << Members::MethodDefinition.new( + name: :[], + kind: :singleton, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: args.map do |param| + Types::Function::Param.new( + name: param.name, + type: Types::ClassInstance.new( + name: param.type, + args: [], + location: location + ), + location: location + ) + end, + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Instance.new( + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ), + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + optional_keywords: {}, + required_positionals: [], + required_keywords: args.to_h do |param| + [ + param.name, + Types::Function::Param.new( + name: nil, + type: Types::ClassInstance.new( + name: param.type, + args: [], + location: location + ), + location: location + ) + ] + end, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Instance.new( + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # .members + members << Members::MethodDefinition.new( + name: :members, + kind: :singleton, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Array, + args: [Types::ClassInstance.new(name: BuiltinNames::Symbol, args: [], location: location)], + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + @args = args + + super( + name: superklass.name, + type_params: nil, + super_class: superklass, + annotations: nil, + comment: nil, + location: location, + members: members + ) + end + end + + class StructDecl < Class + attr_reader :args + + def initialize(superklass, args: , location:) + if args.is_a?(Hash) + args = args.map do |k, (type, required)| + type = (required.nil? || required) ? type : Types::Optional.new(type: type, location: type.location) + Types::Function::Param.new(name: k, type: type, location: type.location) + end + end + + # attribute accessors + members = args.map do |param| + Members::AttrAccessor.new( + name: param.name, + type: Types::Optional.new(type: param.type, location: param.type.location), + ivar_name: :"@#{param.name}", + kind: :instance, + location: location, + comment: nil, + annotations: [] + ) + end + + # initialize + members << Members::MethodDefinition.new( + name: :initialize, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: args.to_h { |param| + [ + param.name, + # set param + Types::Function::Param.new( + name: nil, + type: param.type, + location: location + ) + ] + }, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Void.new(location: location), + ), + location: location, + block: nil, + ), + annotations: [] + ), + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_positionals: [], + required_keywords: [], + optional_keywords: {}, + optional_positionals: args.map { |param| + # set param + Types::Function::Param.new( + name: param.name, + type: param.type, + location: location + ) + }, + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Void.new(location: location), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # [] + members << Members::MethodDefinition.new( + name: :[], + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: args.map do |param| + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_positionals: [ + Types::Function::Param.new( + name: :key, + type: Types::Union.new( + types: [ + Types::Literal.new(literal: param.name, location: location), + Types::Literal.new(literal: param.name.to_s, location: location), + ], + location: location + ), + location: location + ) + ], + required_keywords: {}, + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Optional.new( + type: Types::ClassInstance.new(name: param.type, args: [], location: location), + location: location + ) + ), + location: location, + block: nil + ), + annotations: [] + ) + end + ) + + # []= + members << Members::MethodDefinition.new( + name: :[]=, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: args.map do |param| + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_positionals: [ + Types::Function::Param.new( + name: :key, + type: Types::Union.new( + types: [ + Types::Literal.new(literal: param.name, location: location), + Types::Literal.new(literal: param.name.to_s, location: location), + ], + location: location + ), + location: location + ), + Types::Function::Param.new( + name: :value, + type: param.type, + location: location + ) + ], + required_keywords: {}, + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new(name: param.type, args: [], location: location) + ), + location: location, + block: nil + ), + annotations: [] + ) + end + ) + + # size + members << Members::MethodDefinition.new( + name: :size, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Integer, + args: [], + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # to_a + members << Members::MethodDefinition.new( + name: :to_a, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Tuple.new( + types: args.map do |param| + Types::Optional.new( + type: Types::ClassInstance.new(name: param.type, args: [], location: location), + location: location + ) + end, + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # dig + members << Members::MethodDefinition.new( + name: :dig, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_positionals: [ + Types::Function::Param.new( + name: :key, + type: Types::Union.new( + types: args.flat_map do |param| + [ + Types::Literal.new(literal: param.name, location: location), + Types::Literal.new(literal: param.name.to_s, location: location) + ] + end, + location: location + ), + location: location + ) + ], + required_keywords: {}, + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: Types::Function::Param.new( + name: nil, + location: location, + type: Types::Bases::Any.new(location: location) + ), + trailing_positionals: [], + return_type: Types::Bases::Any.new(location: location) + ), + location: location, + block: nil + ), + annotations: [] + ) + ] + ) + + # members + members << Members::MethodDefinition.new( + name: :members, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Array, + args: [Types::ClassInstance.new(name: BuiltinNames::Symbol, args: [], location: location)], + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # values_at + members << Members::MethodDefinition.new( + name: :values_at, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: Types::Function::Param.new( + name: :keys, + location: location, + type: Types::Union.new( + location: location, + types: [ + Types::ClassInstance.new(args: [], location: location, name: BuiltinNames::Symbol), + Types::ClassInstance.new(args: [], location: location, name: BuiltinNames::String) + ] + ) + ), + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Array, + args: [Types::Bases::Any.new(location: location)], + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # deconstruct + members << Members::MethodDefinition.new( + name: :deconstruct, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Tuple.new( + types: args.map do |param| + Types::Optional.new( + type: Types::ClassInstance.new(name: param.type, args: [], location: location), + location: location + ) + end, + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # deconstruct_keys + members << Members::MethodDefinition.new( + name: :deconstruct_keys, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [ + Types::Function::Param.new( + name: nil, + type: Types::Bases::Nil.new(location: location), + location: location + ) + ], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Record.new( + all_fields: args.to_h do |param| + [ + param.name, + [ + Types::Optional.new( + type: Types::ClassInstance.new(name: param.type, args: [], location: location), + location: location + ), + true + ] + ] + end, + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ), + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [ + Types::Function::Param.new( + name: :names, + type: Types::ClassInstance.new( + name: BuiltinNames::Array, + location: location, + args: [ + Types::ClassInstance.new( + name: BuiltinNames::Symbol, + args: [], + location: location + ) + ] + ), + location: location + ) + ], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Hash, + location: location, + args: [ + Types::ClassInstance.new( + name: BuiltinNames::Symbol, + args: [], + location: location + ), + Types::ClassInstance.new( + name: Types::Bases::Any.new(location: location), + args: [], + location: location + ) + ] + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # with + members << Members::MethodDefinition.new( + name: :with, + kind: :instance, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: args.to_h do |param| + [ + param.name, + Types::Function::Param.new( + name: nil, + type: Types::ClassInstance.new( + name: param.type, + args: [], + location: location + ), + location: location + ) + ] + end, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Instance.new( + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # .[] + members << Members::MethodDefinition.new( + name: :[], + kind: :singleton, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: args.map do |param| + Types::Function::Param.new( + name: param.name, + type: Types::ClassInstance.new( + name: param.type, + args: [], + location: location + ), + location: location + ) + end, + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Instance.new( + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ), + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + optional_keywords: args.to_h do |param| + [ + param.name, + Types::Function::Param.new( + name: nil, + type: Types::ClassInstance.new( + name: param.type, + args: [], + location: location + ), + location: location + ) + ] + end, + required_positionals: [], + required_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Bases::Instance.new( + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # .members + members << Members::MethodDefinition.new( + name: :members, + kind: :singleton, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::ClassInstance.new( + name: BuiltinNames::Array, + args: [Types::ClassInstance.new(name: BuiltinNames::Symbol, args: [], location: location)], + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + # .keyword_init? + members << Members::MethodDefinition.new( + name: :keyword_init?, + kind: :singleton, + location: location, + overloading: false, + comment: nil, + annotations: nil, + visibility: nil, + overloads: [ + Members::MethodDefinition::Overload.new( + method_type: MethodType.new( + type_params: [], + type: Types::Function.new( + required_keywords: {}, + required_positionals: [], + optional_keywords: {}, + optional_positionals: [], + rest_keywords: nil, + rest_positionals: nil, + trailing_positionals: [], + return_type: Types::Alias.new( + name: TypeName.new(name: :boolish, namespace: Namespace.root), + args: [], + location: location + ), + ), + location: location, + block: nil, + ), + annotations: [] + ) + ] + ) + + @args = args + + super( + name: superklass.name, + type_params: nil, + super_class: superklass, + annotations: nil, + comment: nil, + location: location, + members: members + ) + end + end end end end diff --git a/lib/rbs/builtin_names.rb b/lib/rbs/builtin_names.rb index b36d898b0..a05fd2a9f 100644 --- a/lib/rbs/builtin_names.rb +++ b/lib/rbs/builtin_names.rb @@ -54,5 +54,6 @@ def self.define(name, namespace: Namespace.root) TrueClass = Name.define(:TrueClass) FalseClass = Name.define(:FalseClass) Numeric = Name.define(:Numeric) + Data = Name.define(:Data) end end diff --git a/lib/rbs/type_name.rb b/lib/rbs/type_name.rb index e2aa17cf9..2f6ee7717 100644 --- a/lib/rbs/type_name.rb +++ b/lib/rbs/type_name.rb @@ -52,6 +52,14 @@ def alias? kind == :alias end + def data? + class? && namespace.empty? && name == :Data + end + + def struct? + class? && namespace.empty? && name == :Struct + end + def absolute! self.class.new(namespace: namespace.absolute!, name: name) end diff --git a/test/rbs/parser_test.rb b/test/rbs/parser_test.rb index ec9dfe428..eb8aa4089 100644 --- a/test/rbs/parser_test.rb +++ b/test/rbs/parser_test.rb @@ -437,59 +437,229 @@ class Foo < Data{a: Integer} assert_instance_of RBS::AST::Declarations::Class, decl assert_equal TypeName("Foo"), decl.name assert_predicate decl.type_params, :empty? - assert_nil decl.super_class.name - assert_equal TypeName("Data"), decl.super_class.superclass.name + assert_equal TypeName("Data"), decl.super_class.name + assert_equal TypeName("Data"), decl.super_class.super_class.name - assert_equal 8, decl.members.size + members = decl.super_class.members - decl.members[0].tap do |member| + # assert_equal 8, members.size + + members[0].tap do |member| assert_instance_of RBS::AST::Members::AttrReader, member assert_equal :instance, member.kind assert_equal :a, member.name assert_equal "Integer", member.type.to_s end - decl.members[1].tap do |member| + members[1].tap do |member| assert_instance_of RBS::AST::Members::MethodDefinition, member - assert_equal :method, member.kind + assert_equal :instance, member.kind assert_equal :initialize, member.name - assert_equal ["(::Integer) -> void | (id: ::Integer) -> void"], member.method_types.map(&:to_s) + assert_equal 2, member.overloads.size + assert_equal "(a: Integer) -> void", member.overloads[0].method_type.to_s + assert_equal"(Integer a) -> void", member.overloads[1].method_type.to_s end - decl.members[2].tap do |member| + members[2].tap do |member| assert_instance_of RBS::AST::Members::MethodDefinition, member - assert_equal :method, member.kind + assert_equal :instance, member.kind assert_equal :members, member.name - assert_equal ["() -> Array[Symbol]"], member.method_types.map(&:to_s) + assert_equal 1, member.overloads.size + assert_equal "() -> ::Array[::Symbol]", member.overloads[0].method_type.to_s end - decl.members[3].tap do |member| + members[3].tap do |member| assert_instance_of RBS::AST::Members::MethodDefinition, member - assert_equal :method, member.kind + assert_equal :instance, member.kind assert_equal :deconstruct, member.name - assert_equal ["() -> [Integer]"], member.method_types.map(&:to_s) + assert_equal 1, member.overloads.size + assert_equal "() -> [ Integer ]", member.overloads[0].method_type.to_s end - decl.members[4].tap do |member| + members[4].tap do |member| assert_instance_of RBS::AST::Members::MethodDefinition, member - assert_equal :method, member.kind + assert_equal :instance, member.kind assert_equal :deconstruct_keys, member.name - assert_equal ["(nil) -> {a: Integer} | (Array(Symbol)) -> Hash[untyped]"], member.method_types.map(&:to_s) + assert_equal 2, member.overloads.size + assert_equal "(nil) -> { a: Integer }", member.overloads[0].method_type.to_s + assert_equal"(::Array[::Symbol] names) -> ::Hash[::Symbol, untyped]", member.overloads[1].method_type.to_s end - decl.members[5].tap do |member| + members[5].tap do |member| assert_instance_of RBS::AST::Members::MethodDefinition, member - assert_equal :method, member.kind + assert_equal :instance, member.kind assert_equal :with, member.name - assert_equal ["(?a: Integer) -> Foo"], member.method_types.map(&:to_s) + assert_equal 1, member.overloads.size + assert_equal "(?a: Integer) -> instance", member.overloads[0].method_type.to_s + end + + members[6].tap do |member| + # as funcall: Foo[1] + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :singleton, member.kind + assert_equal :[], member.name + assert_equal 2, member.overloads.size + assert_equal "(Integer a) -> instance", member.overloads[0].method_type.to_s + assert_equal "(a: Integer) -> instance", member.overloads[1].method_type.to_s + end + + members[7].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :singleton, member.kind + assert_equal :members, member.name + assert_equal 1, member.overloads.size + assert_equal "() -> ::Array[::Symbol]", member.overloads[0].method_type.to_s end end + end + end - decls[1].tap do |decl| - # as funcall: Foo[1] - assert_instance_of RBS::Types::UntypedFunction, decl.block.type + def test_struct_class_decl + RBS::Parser.parse_signature(buffer(<<-RBS)).tap do |_, _, decls| + class Foo < Struct{a: Integer} + end + RBS + decls[0].tap do |decl| + assert_instance_of RBS::AST::Declarations::Class, decl assert_equal TypeName("Foo"), decl.name - assert_equal ["(::Integer a) -> Foo |(a: ::Integer) -> Foo"], member.method_types.map(&:to_s) + assert_predicate decl.type_params, :empty? + assert_equal TypeName("Struct"), decl.super_class.name + assert_equal TypeName("Struct"), decl.super_class.super_class.name + + members = decl.super_class.members + + # assert_equal 8, members.size + + members[0].tap do |member| + assert_instance_of RBS::AST::Members::AttrAccessor, member + assert_equal :instance, member.kind + assert_equal :a, member.name + assert_equal "Integer?", member.type.to_s + end + + members[1].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :initialize, member.name + assert_equal 2, member.overloads.size + assert_equal "(?a: Integer) -> void", member.overloads[0].method_type.to_s + assert_equal"(?Integer a) -> void", member.overloads[1].method_type.to_s + end + + members[2].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :[], member.name + assert_equal 1, member.overloads.size + assert_equal "(:a | \"a\" key) -> Integer?", member.overloads[0].method_type.to_s + end + + members[3].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :[]=, member.name + assert_equal 1, member.overloads.size + assert_equal "(:a | \"a\" key, Integer value) -> Integer", member.overloads[0].method_type.to_s + end + + members[4].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :size, member.name + assert_equal 1, member.overloads.size + assert_equal "() -> ::Integer", member.overloads[0].method_type.to_s + end + + members[5].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :to_a, member.name + assert_equal 1, member.overloads.size + assert_equal "() -> [ Integer? ]", member.overloads[0].method_type.to_s + end + + members[6].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :dig, member.name + assert_equal 1, member.overloads.size + assert_equal "(:a | \"a\" key, *untyped) -> untyped", member.overloads[0].method_type.to_s + end + + members[7].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :members, member.name + assert_equal 1, member.overloads.size + assert_equal "() -> ::Array[::Symbol]", member.overloads[0].method_type.to_s + end + + # members[8].tap do |member| + # assert_instance_of RBS::AST::Members::MethodDefinition, member + # assert_equal :instance, member.kind + # assert_equal :select, member.name + # assert_equal 1, member.overloads.size + # assert_equal "() { (Integer) -> void } -> Array[untyped]", member.overloads[0].method_type.to_s + # end + + members[8].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :values_at, member.name + assert_equal 1, member.overloads.size + assert_equal "(*::Symbol | ::String keys) -> ::Array[untyped]", member.overloads[0].method_type.to_s + end + + members[9].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :deconstruct, member.name + assert_equal 1, member.overloads.size + assert_equal "() -> [ Integer? ]", member.overloads[0].method_type.to_s + end + + members[10].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :deconstruct_keys, member.name + assert_equal 2, member.overloads.size + assert_equal "(nil) -> { a: Integer? }", member.overloads[0].method_type.to_s + assert_equal"(::Array[::Symbol] names) -> ::Hash[::Symbol, untyped]", member.overloads[1].method_type.to_s + end + + members[11].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :instance, member.kind + assert_equal :with, member.name + assert_equal 1, member.overloads.size + assert_equal "(?a: Integer) -> instance", member.overloads[0].method_type.to_s + end + + members[12].tap do |member| + # as funcall: Foo[1] + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :singleton, member.kind + assert_equal :[], member.name + assert_equal 2, member.overloads.size + assert_equal "(?Integer a) -> instance", member.overloads[0].method_type.to_s + assert_equal "(?a: Integer) -> instance", member.overloads[1].method_type.to_s + end + + members[13].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :singleton, member.kind + assert_equal :members, member.name + assert_equal 1, member.overloads.size + assert_equal "() -> ::Array[::Symbol]", member.overloads[0].method_type.to_s + end + + members[14].tap do |member| + assert_instance_of RBS::AST::Members::MethodDefinition, member + assert_equal :singleton, member.kind + assert_equal :keyword_init?, member.name + assert_equal 1, member.overloads.size + assert_equal "() -> ::boolish", member.overloads[0].method_type.to_s + end end end end From b943c0ccd384a66f2bdcd94e6e003de1bdee4453 Mon Sep 17 00:00:00 2001 From: HoneyryderChuck Date: Tue, 26 Nov 2024 13:58:35 +0000 Subject: [PATCH 4/5] rewrite Struct usage using new syntax --- core/process.rbs | 2 +- core/struct.rbs | 362 +-------------------- stdlib/csv/0/csv.rbs | 2 +- stdlib/etc/0/etc.rbs | 132 +------- stdlib/json/0/json.rbs | 4 +- stdlib/minitest/0/minitest/expectation.rbs | 2 +- 6 files changed, 8 insertions(+), 496 deletions(-) diff --git a/core/process.rbs b/core/process.rbs index 0012cd345..25f348cca 100644 --- a/core/process.rbs +++ b/core/process.rbs @@ -2236,7 +2236,7 @@ end # # Placeholder for rusage # -class Process::Tms < Struct(utime: Float, stime: Float, cutime: Float, cstime: Float) +class Process::Tms < Struct{utime: Float, stime: Float, cutime: Float, cstime: Float} end class Process::Waiter < Thread diff --git a/core/struct.rbs b/core/struct.rbs index 0a7c069a7..c1d509832 100644 --- a/core/struct.rbs +++ b/core/struct.rbs @@ -112,9 +112,7 @@ # * #inspect, #to_s: Returns a string representation of `self`. # * #to_h: Returns a hash of the member name/value pairs in `self`. # -class Struct[Elem] - include Enumerable[Elem] - +class Struct # The types that can be used when "indexing" into a `Struct` via `[]`, `[]=`, `dig`, and # `deconstruct_keys`. # @@ -298,48 +296,6 @@ class Struct[Elem] # def ==: (untyped other) -> bool - # - # Returns `true` if and only if the following are true; otherwise returns - # `false`: - # - # * `other.class == self.class`. - # * For each member name `name`, `other.name.eql?(self.name)`. - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe_jr.eql?(joe) # => true - # joe_jr[:name] = 'Joe Smith, Jr.' - # joe_jr.eql?(joe) # => false - # - # - # Related: Object#==. - # - def eql?: (untyped other) -> bool - - # - # Returns the integer hash value for `self`. - # - # Two structs of the same class and with the same content will have the same - # hash code (and will compare using Struct#eql?): - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.hash == joe_jr.hash # => true - # joe_jr[:name] = 'Joe Smith, Jr.' - # joe.hash == joe_jr.hash # => false - # - # Related: Object#hash. - # - def hash: () -> Integer - # - # Returns the values in `self` as an array: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345] - # - # Related: #members. - # - def to_a: () -> Array[Elem] - - # - # Returns a hash containing the name and value for each member: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # h = joe.to_h - # h # => {:name=>"Joe Smith", :address=>"123 Maple, Anytown NC", :zip=>12345} - # - # If a block is given, it is called with each name/value pair; the block should - # return a 2-element array whose elements will become a key/value pair in the - # returned hash: - # - # h = joe.to_h{|name, value| [name.upcase, value.to_s.upcase]} - # h # => {:NAME=>"JOE SMITH", :ADDRESS=>"123 MAPLE, ANYTOWN NC", :ZIP=>"12345"} - # - # Raises ArgumentError if the block returns an inappropriate value. - # - def to_h: () -> Hash[Symbol, Elem] - | [K, V] () { (Symbol key, Elem value) -> [K, V] } -> Hash[K, V] - - # - # Returns the values in `self` as an array: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345] - # - # Related: #members. - # - alias values to_a - - # - # Returns the number of members. - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.size #=> 3 - # - def size: () -> Integer - - # - # Returns the number of members. - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.size #=> 3 - # - alias length size - - # - # Calls the given block with the value of each member; returns `self`: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.each {|value| p value } - # - # Output: - # - # "Joe Smith" - # "123 Maple, Anytown NC" - # 12345 - # - # Returns an Enumerator if no block is given. - # - # Related: #each_pair. - # - def each: () -> Enumerator[Elem, self] - | () { (Elem value) -> void } -> self - - # - # Calls the given block with each member name/value pair; returns `self`: - # - # Customer = Struct.new(:name, :address, :zip) # => Customer - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.each_pair {|(name, value)| p "#{name} => #{value}" } - # - # Output: - # - # "name => Joe Smith" - # "address => 123 Maple, Anytown NC" - # "zip => 12345" - # - # Returns an Enumerator if no block is given. - # - # Related: #each. - # - def each_pair: () -> Enumerator[[Symbol, Elem], self] - | () { ([Symbol, Elem] key_value) -> void } -> self - - # - # Returns a value from `self`. - # - # With symbol or string argument `name` given, returns the value for the named - # member: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe[:zip] # => 12345 - # - # Raises NameError if `name` is not the name of a member. - # - # With integer argument `n` given, returns `self.values[n]` if `n` is in range; - # see Array@Array+Indexes: - # - # joe[2] # => 12345 - # joe[-2] # => "123 Maple, Anytown NC" - # - # Raises IndexError if `n` is out of range. - # - def []: (index name_or_position) -> Elem - - # - # Assigns a value to a member. - # - # With symbol or string argument `name` given, assigns the given `value` to the - # named member; returns `value`: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe[:zip] = 54321 # => 54321 - # joe # => # - # - # Raises NameError if `name` is not the name of a member. - # - # With integer argument `n` given, assigns the given `value` to the `n`-th - # member if `n` is in range; see Array@Array+Indexes: - # - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe[2] = 54321 # => 54321 - # joe[-3] = 'Joseph Smith' # => "Joseph Smith" - # joe # => # - # - # Raises IndexError if `n` is out of range. - # - def []=: (index name_or_position, Elem value) -> Elem - - # - # With a block given, returns an array of values from `self` for which the block - # returns a truthy value: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # a = joe.select {|value| value.is_a?(String) } - # a # => ["Joe Smith", "123 Maple, Anytown NC"] - # a = joe.select {|value| value.is_a?(Integer) } - # a # => [12345] - # - # With no block given, returns an Enumerator. - # - def select: () -> Enumerator[Elem, Array[Elem]] - | () { (Elem value) -> boolish } -> Array[Elem] - - # - # With a block given, returns an array of values from `self` for which the block - # returns a truthy value: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # a = joe.select {|value| value.is_a?(String) } - # a # => ["Joe Smith", "123 Maple, Anytown NC"] - # a = joe.select {|value| value.is_a?(Integer) } - # a # => [12345] - # - # With no block given, returns an Enumerator. - # - alias filter select - - # - # Returns an array of values from `self`. - # - # With integer arguments `integers` given, returns an array containing each - # value given by one of `integers`: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.values_at(0, 2) # => ["Joe Smith", 12345] - # joe.values_at(2, 0) # => [12345, "Joe Smith"] - # joe.values_at(2, 1, 0) # => [12345, "123 Maple, Anytown NC", "Joe Smith"] - # joe.values_at(0, -3) # => ["Joe Smith", "Joe Smith"] - # - # Raises IndexError if any of `integers` is out of range; see - # Array@Array+Indexes. - # - # With integer range argument `integer_range` given, returns an array containing - # each value given by the elements of the range; fills with `nil` values for - # range elements larger than the structure: - # - # joe.values_at(0..2) - # # => ["Joe Smith", "123 Maple, Anytown NC", 12345] - # joe.values_at(-3..-1) - # # => ["Joe Smith", "123 Maple, Anytown NC", 12345] - # joe.values_at(1..4) # => ["123 Maple, Anytown NC", 12345, nil, nil] - # - # Raises RangeError if any element of the range is negative and out of range; - # see Array@Array+Indexes. - # - def values_at: (*int | range[int?] positions) -> Array[Elem] - - # - # Returns the member names from `self` as an array: - # - # Customer = Struct.new(:name, :address, :zip) - # Customer.new.members # => [:name, :address, :zip] - # - # Related: #to_a. - # - def members: () -> Array[Symbol] - - # - # Finds and returns an object among nested objects. The nested objects may be - # instances of various classes. See [Dig Methods](rdoc-ref:dig_methods.rdoc). - # - # Given symbol or string argument `name`, returns the object that is specified - # by `name` and `identifiers`: - # - # Foo = Struct.new(:a) - # f = Foo.new(Foo.new({b: [1, 2, 3]})) - # f.dig(:a) # => #[1, 2, 3]}> - # f.dig(:a, :a) # => {:b=>[1, 2, 3]} - # f.dig(:a, :a, :b) # => [1, 2, 3] - # f.dig(:a, :a, :b, 0) # => 1 - # f.dig(:b, 0) # => nil - # - # Given integer argument `n`, returns the object that is specified by `n` and - # `identifiers`: - # - # f.dig(0) # => #[1, 2, 3]}> - # f.dig(0, 0) # => {:b=>[1, 2, 3]} - # f.dig(0, 0, :b) # => [1, 2, 3] - # f.dig(0, 0, :b, 0) # => 1 - # f.dig(:b, 0) # => nil - # - def dig: (index name_or_position) -> Elem - | (index name_or_position, untyped, *untyped) -> untyped - - # - # Returns the values in `self` as an array: - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345] - # - # Related: #members. - # - alias deconstruct to_a - - # - # Returns a hash of the name/value pairs for the given member names. - # - # Customer = Struct.new(:name, :address, :zip) - # joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) - # h = joe.deconstruct_keys([:zip, :address]) - # h # => {:zip=>12345, :address=>"123 Maple, Anytown NC"} - # - # Returns all names and values if `array_of_names` is `nil`: - # - # h = joe.deconstruct_keys(nil) - # h # => {:name=>"Joseph Smith, Jr.", :address=>"123 Maple, Anytown NC", :zip=>12345} - # - def deconstruct_keys: (Array[index & Hash::_Key]? indices) -> Hash[index & Hash::_Key, Elem] end diff --git a/stdlib/csv/0/csv.rbs b/stdlib/csv/0/csv.rbs index af354ea74..9c8225f6d 100644 --- a/stdlib/csv/0/csv.rbs +++ b/stdlib/csv/0/csv.rbs @@ -2858,7 +2858,7 @@ class CSV::Row < Object alias values_at fields end -class CSV::FieldInfo < Struct[untyped] +class CSV::FieldInfo < Struct{index: Integer, line: Integer, header: String?, quoted?: bool} end # diff --git a/stdlib/etc/0/etc.rbs b/stdlib/etc/0/etc.rbs index 10794134e..a1bcff11c 100644 --- a/stdlib/etc/0/etc.rbs +++ b/stdlib/etc/0/etc.rbs @@ -672,58 +672,7 @@ module Etc # : is an Array of Strings containing the short login names of the members of # the group. # - class Group < Struct[untyped] - extend Enumerable[untyped] - - def self.[]: (*untyped) -> untyped - - # - # Iterates for each entry in the `/etc/group` file if a block is given. - # - # If no block is given, returns the Enumerator. - # - # The code block is passed a Group struct. - # - # Example: - # - # require 'etc' - # - # Etc::Group.each {|g| - # puts g.name + ": " + g.mem.join(', ') - # } - # - # Etc::Group.collect {|g| g.name} - # Etc::Group.select {|g| !g.mem.empty?} - # - def self.each: () -> untyped - - def self.inspect: () -> untyped - - def self.keyword_init?: () -> untyped - - def self.members: () -> untyped - - def self.new: (*untyped) -> untyped - - def gid: () -> Integer - - def gid=: (Integer new_gid) -> void - - def mem: () -> Array[String] - - def mem=: (Array[String] new_mem) -> void - - def name: () -> String - - def name=: (String new_name) -> void - - def passwd: () -> String - - def passwd=: (String new_passwd) -> void + class Group < Struct{name: String, passwd: String, gid: Integer, mem: Array[String]} end # @@ -766,83 +715,6 @@ module Etc # expire # : account expiration time(integer). # - class Passwd < Struct[untyped] - extend Enumerable[untyped] - - def self.[]: (*untyped) -> untyped - - # - # Iterates for each entry in the `/etc/passwd` file if a block is given. - # - # If no block is given, returns the Enumerator. - # - # The code block is passed an Passwd struct. - # - # See Etc.getpwent above for details. - # - # Example: - # - # require 'etc' - # - # Etc::Passwd.each {|u| - # puts u.name + " = " + u.gecos - # } - # - # Etc::Passwd.collect {|u| u.gecos} - # Etc::Passwd.collect {|u| u.gecos} - # - def self.each: () -> untyped - - def self.inspect: () -> untyped - - def self.keyword_init?: () -> untyped - - def self.members: () -> untyped - - def self.new: (*untyped) -> untyped - - def change: () -> Integer - - def change=: (Integer new_change) -> void - - def dir: () -> String - - def dir=: (String new_dir) -> void - - def expire: () -> Integer - - def expire=: (Integer new_expire) -> void - - def gecos: () -> String - - def gecos=: (String new_gecos) -> void - - def gid: () -> Integer - - def gid=: (Integer new_gid) -> void - - def name: () -> String - - def name=: (String new_name) -> void - - def passwd: () -> String - - def passwd=: (String new_passwd) -> void - - def shell: () -> String - - def shell=: (String new_shell) -> void - - def uclass: () -> String - - def uclass=: (String new_uclass) -> void - - def uid: () -> Integer - - def uid=: (Integer new_uid) -> void + class Passwd < Struct{name: String, passwd: String, uid: Integer, gid: Integer, mem: Array[String], gecos: String, dir: String, shell: String, change: Integer, uclass: String, expire: Integer} end end diff --git a/stdlib/json/0/json.rbs b/stdlib/json/0/json.rbs index fbfd22a2b..1223cf33f 100644 --- a/stdlib/json/0/json.rbs +++ b/stdlib/json/0/json.rbs @@ -1787,14 +1787,14 @@ class Set[unchecked out A] end %a{annotate:rdoc:skip} -class Struct[Elem] +class Struct # # See #as_json. # - def self.json_create: [Elem] (Hash[String, String | Array[Elem]] object) -> Struct[Elem] + def self.json_create: (Hash[String, String | Array[untyped]] object) -> Struct[untyped] #