{"record":{"id":"7c36617924c221b0","repo":"instructure/canvas-lms","slug":"block-is-required-if-module-name-is-not-passed","errorCode":null,"errorMessage":"block is required if module_name is not passed","messagePattern":"block is required if module_name is not passed","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"gems/autoextend/lib/autoextend.rb","lineNumber":65,"sourceCode":"    #\n    # If User is already defined, it will immediately include\n    # the MyUserExtension module into it. It then sets up a hook\n    # to automatically include in User if it becomes defined again\n    # (like from ActiveSupport reloading).\n    #\n    # You can make an extension optional, which is for information only,\n    # so that if you have a spec that checks if all extensions were used\n    # it can ignore optional extensions.\n    def hook(const_name,\n             module_name = nil,\n             method: :include,\n             singleton: false,\n             after_load: false,\n             optional: false,\n             before: [],\n             after: [],\n             &block)\n      raise ArgumentError, \"block is required if module_name is not passed\" if !module_name && !block\n      raise ArgumentError, \"cannot pass both a module_name and a block\" if module_name && block\n\n      extension = Extension.new(const_name,\n                                module_name,\n                                method,\n                                block,\n                                singleton,\n                                optional,\n                                Array(before),\n                                Array(after))\n\n      const_extensions = extensions_hash[const_name.to_sym] ||= []\n      const_extensions << extension\n\n      if module_name.is_a?(Module)\n        module_name = module_name.name\n      end\n","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/gems/autoextend/lib/autoextend.rb#L47-L83","documentation":"The Autoextend.hook DSL requires exactly one extension source: either a module_name (an existing module to prepend/extend with) or a &block (an inline module definition). Passing neither leaves the Extension with no code to apply, so hook raises ArgumentError immediately rather than failing later at class-load time.","triggerScenarios":"Calling Autoextend.hook(ConstName, method: ...) with a nil/omitted module_name and no block, e.g. Autoextend.hook('User', :create) or a variable module_name that is nil at call time.","commonSituations":"Refactoring an old hook from a module to a block (or vice versa) and deleting the wrong argument; conditional logic that computes module_name which evaluates to nil; typos like passing module name as positional after a keyword arg mismatch.","solutions":["Pass the block: Autoextend.hook('User', :create) { prepend UserExtensions }","Pass an existing module: Autoextend.hook('User', 'UserExtensions', :create)","Fix code that computes module_name dynamically so it resolves to a non-nil value","Mark the hook optional:/guard it so it only registers when the module is actually defined"],"exampleFix":"// before\nAutoextend.hook('ConversationParticipant', :create)\n// after\nAutoextend.hook('ConversationParticipant', :create) do\n  def after_create_hook; end\nend","handlingStrategy":"validation","validationCode":"raise 'Autoextend.hook needs module_name or block' if mod_name.nil? && !block_given?","typeGuard":null,"tryCatchPattern":"begin\n  Autoextend.hook(const_name, mod_name, method, &blk)\nrescue ArgumentError => e\n  Rails.logger.error(\"bad autoextend hook: #{e.message}\")\nend","preventionTips":["Always pass either a module_name or a block to hook","Guard dynamically computed module names against nil","Keep hook registrations in reviewed initializer files"],"tags":["ruby","dsl","argument-error"],"backgroundTag":"missing-required-argument","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}