Skip to content

[Bug Report] Packwerk::NodeHelpers::TypeError when using module_parent in a class definition #402

@Bernie

Description

@Bernie

Description
When using module_parent in a class definition, packwerk raises this error:

spec/my_spec.rb

Packwerk encountered an internal error.
For now, you can add this file to packwerk.yml exclude list.
Please file an issue and include this error message and stacktrace:

Packwerk::NodeHelpers::TypeError ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:58:in constant_name' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:53:in constant_name'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/const_node_inspector.rb:45:in constant_in_module_or_class_definition?' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/const_node_inspector.rb:24:in constant_name_from_node'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/reference_extractor.rb:83:in block in reference_from_node' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/reference_extractor.rb:82:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/reference_extractor.rb:82:in reference_from_node' ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_processor.rb:29:in call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:22:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:27:in block in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:71:in block in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_helpers.rb:70:in each_child' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/node_visitor.rb:26:in visit'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/file_processor.rb:79:in references_from_ast' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/file_processor.rb:50:in block in call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/cache.rb:78:in with_cache' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/file_processor.rb:46:in call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/run_context.rb:78:in process_file' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/parse_run.rb:57:in block in process_file_proc'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:587:in call_with_index' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:557:in process_incoming_jobs'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:537:in block in worker' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/activesupport-7.0.8.1/lib/active_support/fork_tracker.rb:20:in block in fork'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/activesupport-7.0.8.1/lib/active_support/fork_tracker.rb:18:in fork' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/activesupport-7.0.8.1/lib/active_support/fork_tracker.rb:18:in fork'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:528:in worker' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:519:in block in create_workers'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:518:in each' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:518:in each_with_index'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:518:in create_workers' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:457:in work_in_processes'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:294:in map' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/parallel-1.22.1/lib/parallel.rb:307:in flat_map'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/parse_run.rb:38:in find_offenses' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/commands/check_command.rb:27:in block in run'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/benchmark-0.2.1/lib/benchmark.rb:311:in realtime' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/formatters/progress_formatter.rb:29:in started_inspection'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/commands/check_command.rb:26:in run' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/cli.rb:58:in execute_command'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/lib/packwerk/cli.rb:41:in run' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in bind_call'
ruby/3.0.6/lib/ruby/gems/3.0.0/gems/sorbet-runtime-0.5.11122/lib/types/private/methods/_methods.rb:277:in block in _on_method_added' ruby/3.0.6/lib/ruby/gems/3.0.0/gems/packwerk-3.2.0/exe/packwerk:16:in <top (required)>'
bin/packwerk:31:in load' bin/packwerk:31:in

'"

To Reproduce

  1. Create a spec file like so:
RSpec.describe "this bug" do
  class self::MyTestClass
  end

  context "my nested context" do
    class self::MyTestClass < module_parent::MyTestClass
    end
  end
end
  1. Run packwerk check on the spec file
  2. Watch Packwerk explode

Expected Behaviour
Packwerk not to crash with an exception

Version Information

  • Packwerk: [3.2.0]
  • Ruby [3.0.6]

Additional Context
There is a workaround by simply omitting the module_parent prefix like so:

RSpec.describe "this bug" do
  class self::MyTestClass
  end

  context "my nested context" do
    class self::MyTestClass < self::MyTestClass
    end
  end
end

This appears to be equivalent in Ruby and does not crash packwerk. However, this less explicit syntax may be less understandable for some people.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions