Reputation: 8290
Using Ruby, not Rails.
My Ruby app provides the ability to extend its functionality by loading user-defined modules. For the sake of simplicity, below is the structure of a valid module:
module MyModule
class MyClass < AppSuperClass
def initialize
puts "Hello"
end
end
def self.create_class
return MyClass.new
end
end
As you can see, the module must implement a class that inherits from AppSuperClass
and must implement a module method called create_class
.
If the above module is in file mymodule.rb
and I include it in another file like so:
require 'mymodule'
I need to check that MyModule
responds to MyModule.create_class
. For some reason, MyModule.method_defined?(create_class)
and MyModule.method_defined(:create_class)
both return false
. What am I doing wrong?
Upvotes: 1
Views: 466
Reputation: 3734
As posted, your code does not work :
$ ruby -w m.rb
m.rb:5: warning: mismatched indentations at 'end' with 'def' at 3
m.rb:10: warning: mismatched indentations at 'end' with 'class' at 2
m.rb:10: syntax error, unexpected end-of-input, expecting keyword_end
$ ruby -w t.rb
t.rb:3:in `<main>': undefined local variable or method `create_class' for main:Object (NameError)
After changing MyModule.method_defined?(create_class)
to MyModule.method_defined?(:create_class)
:
$ ruby -w t.rb
false
t.rb:4:in `<main>': undefined method `method_defined' for MyModule:Module (NoMethodError)
What you probably want isrespond_to?
.
File m.rb
class AppSuperClass
end
module MyModule
class MyClass < AppSuperClass
def initialize
puts "Hello"
end
end
def self.create_class
return MyClass.new
end
def mm
end
end
File t.rb
require_relative 'm'
class MyClass
include MyModule
end
puts "you can send create_class to MyModule because it's a singleton (class) method"
puts "MyModule.respond_to?(:create_class) => #{MyModule.respond_to?(:create_class)}"
puts 'mm is not a singleton method of MyModule'
puts "MyModule.respond_to?(:mm) => #{MyModule.respond_to?(:mm)}"
puts 'mm is an instance method of MyClass, cannot be sent to MyClass'
puts "MyClass.respond_to?(:mm) => #{MyClass.respond_to?(:mm)}"
puts 'mm is an instance method of MyClass, can be sent to an instance of MyClass'
puts "MyClass.new.respond_to?(:mm) => #{MyClass.new.respond_to?(:mm)}"
puts "instance methods of MyModule : #{MyModule.instance_methods}"
puts "MyModule.method_defined?(:create_class) => #{MyModule.method_defined?(:create_class)}"
puts "MyModule.method_defined?(:mm) => #{MyModule.method_defined?(:mm)}"
puts "singleton methods of MyModule : #{MyModule.singleton_methods}"
module MyModule
class << self
puts 'we are in the singleton class / eigenclass'
puts "method_defined?(:create_class) => #{method_defined?(:create_class)}"
end
end
Execution :
$ ruby -w t.rb
you can send create_class to MyModule because it's a singleton (class) method
MyModule.respond_to?(:create_class) => true
mm is not a singleton method of MyModule
MyModule.respond_to?(:mm) => false
mm is an instance method of MyClass, cannot be sent to MyClass
MyClass.respond_to?(:mm) => false
mm is an instance method of MyClass, can be sent to an instance of MyClass
MyClass.new.respond_to?(:mm) => true
instance methods of MyModule : [:mm]
MyModule.method_defined?(:create_class) => false
MyModule.method_defined?(:mm) => true
singleton methods of MyModule : [:create_class]
we are in the singleton class / eigenclass
method_defined?(:create_class) => true
Upvotes: 2
Reputation: 26758
First of all, you're missing an end
for the def initialize
block so your create_class
method is getting defined in the MyClass
body - you should fix the indentation to make these kinds of errors more obvious.
After fixing this, you can use MyModule.respond_to?(:create_class)
. The reason method_defined?
doesn't work as expected with class methods is explained here.
Upvotes: 1