Why doesn't Module.method_defined?(:method) work correctly?
To know whether the module has a module method, you can use respond_to?
on the
module:
Something.respond_to?(another)
=> true
method_defined? will tell you whether INSTANCES of the class with the module included responds to the given method.
Namespacing module method definition
::
is the scope resolution operator. So self::connect
resolves connect
from self. Which means that its equivalent to self.connect
. You can see how it works from this very contrived example:
class Foo; end
class Bar
def Foo::baz
"Hello World"
end
end
puts Foo.baz # "Hello World"
Of course we could also just use def Foo.baz
to get the exact same result.
Using double colons for method definition is discouraged by the Ruby Style guide:
Do not use :: to define class methods.
# bad
class Foo
def self::some_method
end
end
# good
class Foo
def self.some_method
end
end
Its also not recommended for anything other than referencing constants and constructors:
Use :: only to reference constants (this includes classes and modules)
and constructors (like Array() or Nokogiri::HTML()). Do not use :: for
regular method invocation.
How do I check if a module responds to a class method?
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.
Can I invoke an instance method on a Ruby module without including it?
If a method on a module is turned into a module function you can simply call it off of Mods as if it had been declared as
module Mods
def self.foo
puts "Mods.foo(self)"
end
end
The module_function approach below will avoid breaking any classes which include all of Mods.
module Mods
def foo
puts "Mods.foo"
end
end
class Includer
include Mods
end
Includer.new.foo
Mods.module_eval do
module_function(:foo)
public :foo
end
Includer.new.foo # this would break without public :foo above
class Thing
def bar
Mods.foo
end
end
Thing.new.bar
However, I'm curious why a set of unrelated functions are all contained within the same module in the first place?
Edited to show that includes still work if public :foo
is called after module_function :foo
Access module method directly without operator ('.' or '::')
Try running it like this
module Example
def do_something
puts 'foo!'
end
end
include Example
do_something #=> foo!
Refer to a method with varying name
You can use the public_send
method to call an arbitrary method on an object. For example, foo.public_send(:bar)
is equivalent to foo.bar
, and works exactly the same way.
Knowing this you can define an array of symbols, where each symbol is a method you want to call. So:
[:bar, :baz, :qorg].each {|method|
DailyQueries.public_send(method)
end
will work the same as:
DailyQueries.bar
DailyQueries.baz
DailyQueries.qorg
Here's some reading material if you'd like to learn more about the public_send
method, and its less privacy-respecting cousin, the send
method:
- What is the difference between ruby send and ruby public_send method?
- What does send() do in Ruby?
- Object#public_send on RubyDoc
Changing ruby method context / calling a method with instance_exec
I think this is simpler than you might expect (and I realize that my answer is 2 years after you asked)
You can use instance methods from modules and bind them to any object.
module Providers
def facebook
@facebook ||= FacebookProvider
end
module FacebookProvider
def greet
"#{message} from facebook!"
end
end
end
class MyClass
include Providers
attr_accessor :message
def initialize(message="hello")
self.message = message
end
def greet(provider=nil)
if provider
provider.instance_method(:greet).bind(self).call
else
message
end
end
end
If your provider
is a module, you can user instance_method
to create an UnboundMethod
and bind it to the current self
.
This is delegation.
It's the basis for the casting gem which would work like this:
delegate(:greet, provider)
Or, if you opt-in to using method_missing
from casting, your code could just look like this:
greet
But you'd need to set your delegate first:
class MyClass
include Providers
include Casting::Client
delegate_missing_methods
attr_accessor :message
def initialize(message="hello", provider=facebook)
cast_as(provider)
self.message = message
end
end
MyClass.new.greet # => "hello from facebook!"
I wrote about what delegation is and is not on my blog which is relevant to understanding DCI and what I wrote about in Clean Ruby
Ruby: Use module method inside a class method
By including the module, you make module_method
is an instance method on TestClass
, meaning you need to invoke it on an instance of the class, not the class itself.
If you want to make it a method on the class itself, you need to extend TestModule
, not include
it.
module TestModule
def module_method
"module"
end
end
class TestClass
extend TestModule # extend, not include
def self.testSelfMethod
str = module_method
puts str
end
TestClass.testSelfMethod # "method"
end
(In Ruby) allowing mixed-in class methods access to class constants
This seems to work:
#! /usr/bin/env ruby
module CommonMethods
def shout_my_constant
puts self::Const.upcase
end
end
class NonInstantiableClass
Const = "hello, world!"
class << self
include CommonMethods
end
end
NonInstantiableClass.shout_my_constant
HTH
Related Topics
Single Occurrence Event with Ice_Cube Gem Using Start_Time and End_Time
How to Create a Form in Rails Without Having to Use Form_For and a Model Instance
Perform One Validation Only If All Other Validations Pass
Consuming Non-Rest APIs in Rails with Activeresource
Elasticsearch Terms Aggregation by Entire Field
Built in Way to List Directories in a Directory in Ruby
Passing Binding or Arguments to Erb from the Command Line
Map an Array Modifying Only Elements Matching a Certain Condition
Running Webrick Server in Background
Dynamically Defined Setter Methods Using Define_Method
How to Tell If I'm Running from Jruby VS. Ruby
How to Beautify Xml Code in Rails Application
Begin Rescue Not Catching Error
Carrierwave How to Get the File Extension
Ruby, Tor and Net::Http::Proxy
Ruby on Rails 4 - What Authentication Gem to Use