using class of a module in another class - ruby-on-rails

I'm creating a gem:
module Core
require "lib/doctor"
require "lib/slot"
end
module Core
class Doctor
def message
puts Slot.message
end
end
end
module Core
class Slot
def message
return "Hello World"
end
end
end
If I use the gem I obtain:
Gem Load Error is: uninitialized constant Core::Doctor::Slot

As you can see from your error, ruby is trying to load the constant Slot in the context of Core::Doctor. But, you want Slot in the context of Core. So, try:
module Core
class Doctor
def message
puts Core::Slot.message
end
end
end
Also, here:
puts Core::Slot.message
you're trying to call message as a class method. However, here:
module Core
class Slot
def message
return "Hello World"
end
end
end
you're defining message as an instance method.
If you want message to be a class method, you'll need to do:
module Core
class Slot
def self.message
return "Hello World"
end
end
end
or
module Core
class Slot
class << self
def message
return "Hello World"
end
end
end
end
(depending on your preference). If you want keep message as an instance method, then you'll need to do:
puts Core::Slot.new.message

Related

Error with Namespace Ruby

I'm experimenting with some Ruby code in a Ruby on Rails project and trying to code a nested namespace with inheritance.
In app/messages/message.rb I have the following code:
module Messages
class Message
def initialize
puts "message constructor"
end
end
end
In app/messages/emails/email.rb I have this code:
module Emails
class Email < Messages::Message
def initialize
super
puts "email constructor"
end
end
end
From within a controller in my Rails application I attempt to instantiate a new Email like so:
message = Messages::Emails::Email.new
I'm getting the following error:
LoadError (Unable to autoload constant Messages::Emails::Email, expected /home/ubuntu/workspace/app/messengers/messages/emails/email.rb to define it):
I assume this is something I have done incorrectly with the namespaces. Thanks in advance.
Rails ignores the folder name just below app. So, create app/messages/messages/message.rb something like:
module Messages
class Message
def initialize
puts "message constructor"
end
end
end
Then, app/messages/emails/email.rb should be:
module Emails
class Email < Messages::Message
def initialize
super
puts "email constructor"
end
end
end
Then you would do
Emails::Email.new
That file structure is a little unpretty, but it should do the trick.
Personally, I think I would create app/messages/messages/message_base.rb:
module Messages
class MessageBase
def initialize
puts "message constructor"
end
end
end
And app/messages/messages/email.rb:
module Messages
class Email < MessageBase
def initialize
super
puts "email constructor"
end
end
end
But, I suppose it's a matter of personal preference.

Module level method and a Class within same module in Ruby

I have the similar module in my Rails application
module Demo
def self.create
puts 'inside module method'
AnotherTestClass.new('testing')
end
class ModuleClass
def initialize(test)
#test = test
puts "inside class #{#test}"
end
end
end
module Demo
class AnotherTestClass < ModuleClass
end
end
So when I call Demo.create in my Controller, I am getting the following error
undefined method `create' for Demo:Module
Note: When I execute this code in irb, it works.

How to access Ruby method inside module and inside a class from another .rb file

I would like to know how would I go about accessing the methods in this module from another .rb file
module Decisioning
module Decision
class OfferProxy < FinanceApplication::Offer
def my_method
"some value"
end
end
end
end
So how would I access my_method from another .rb file?
maby something like
include ::Decisioning::Decision::OfferProxy
can I then use
my_method
Probably more like this:
module Decisioning
module Decision
class OfferProxy
def self.my_method
"some value"
end
end
end
end
class TestFile
include Decisioning::Decision
def test
puts OfferProxy.my_method
end
end
TestFile.new.test
Or...
module Decisioning
module Decision
class OfferProxy
def my_method
"some value"
end
end
end
end
class TestFile
include Decisioning::Decision
def test
offer_proxy = OfferProxy.new
puts offer_proxy.my_method
end
end
TestFile.new.test

How to alias a class method within a module?

I am using Ruby v1.9.2 and the Ruby on Rails v3.2.2 gem. I had the following module
module MyModule
extend ActiveSupport::Concern
included do
def self.my_method(arg1, arg2)
...
end
end
end
and I wanted to alias the class method my_method. So, I stated the following (not working) code:
module MyModule
extend ActiveSupport::Concern
included do
def self.my_method(arg1, arg2)
...
end
# Note: the following code doesn't work (it raises "NameError: undefined
# local variable or method `new_name' for #<Class:0x00000101412b00>").
def self.alias_class_method(new_name, old_name)
class << self
alias_method new_name, old_name
end
end
alias_class_method :my_new_method, :my_method
end
end
In other words, I thought to extend the Module class someway in order to add an alias_class_method method available throughout MyModule. However, I would like to make it to work and to be available in all my Ruby on Rails application.
Where I should put the file related to the Ruby core extension of the Module class? Maybe in the Ruby on Rails lib directory?
How should I properly "extend" the Module class in the core extension file?
Is it the right way to proceed? That is, for example, should I "extend" another class (Object, BasicObject, Kernel, ...) rather than Module? or, should I avoid implementing the mentioned core extension at all?
But, more important, is there a Ruby feature that makes what I am trying to accomplish so that I don't have to extend its classes?
You could use define_singleton_method to wrap your old method under a new name, like so:
module MyModule
def alias_class_method(new_name, old_name)
define_singleton_method(new_name) { old_name }
end
end
class MyClass
def my_method
puts "my method"
end
end
MyClass.extend(MyModule)
MyClass.alias_class_method(:my_new_method, :my_method)
MyClass.my_new_method # => "my method"
Answering your comment, you wouldn't have to extend every single class by hand. The define_singleton_method is implemented in the Object class. So you could simply extend the Object class, so every class should have the method available...
Object.extend(MyModule)
Put this in an initializer in your Rails app and you should be good to go...
I found an answer on this website: http://engineering.lonelyplanet.com/2012/12/09/monitoring-our-applications-ruby-methods/
The solution is to use class_eval with a block. That enables using variables from the enclosing scope.
module Alias
def trigger
#trigger = true
end
def method_added(name)
if #trigger
#trigger = false
with_x = "#{name}_with_x"
without_x = "#{name}_without_x"
define_method(with_x) do
"#{send(without_x)} with x"
end
alias_method without_x, name
alias_method name, with_x
end
end
def singleton_method_added(name)
if #trigger
#trigger = false
with_x = "#{name}_with_x"
without_x = "#{name}_without_x"
define_singleton_method(with_x) do
"singleton #{send(without_x)} with x"
end
singleton_class.class_eval do
alias_method without_x, name
alias_method name, with_x
end
end
end
end
class TestAlias
extend Alias
trigger
def self.foo
'foo'
end
trigger
def bar
'bar'
end
end
TestAlias.foo # => 'singleton foo with x'
TestAlias.new.bar # => 'bar with x'
If you don't have singleton_class then you should probably upgrade your version of Ruby. If that's not possible you can do this:
class Object
def singleton_class
class << self
self
end
end
end
The accepted answer was confusing and did not work.
class Module
def alias_class_method(new_name, old_name)
define_singleton_method(new_name, singleton_method(old_name))
end
end
module MyModule
def self.my_method
'my method'
end
end
MyModule.alias_class_method(:my_new_method, :my_method)
MyModule.my_new_method # => "my_method"

Accessing Methods in Ruby Module

I'm writing my first Ruby module and I have this:
/app/module/test_modules/test.rb
test.rb looks similar to:
module TestModules
module Test
def test
puts 'this is a test'
end
end
end
When I call the following from console, I get:
(main)> TestModule::Test.test
//NoMethodError: private method `test' called for TestModules::Test:Module
How do I make test() visible?
You are calling a class method, whereas you defined test as an instance method. You could call it the way you want if you used the module via include or extend. This article does a good job explaining.
module TestModules
module Test
def self.test
puts 'this is a test'
end
end
end
Also,
1)
module TestModules
module Test
def test
puts 'this is a test'
end
module_function :test
end
end
2)
module TestModules
module Test
extend self
def test
puts 'this is a test'
end
end
end
The way that you have defined your method, it is a method on an instance of Test - thus it would work if you did:
blah = TestModule::Test.new
blah.test
note - and do use it this way, you would need to define Test as a class not a module
If you want the function to work on the class itself, then you need to define it like so:
def self.test
....
end
And then you can do TestModules::Test.test
the test method you defined is instance method...try this
module TestModules
module Test
def self.test
puts 'this is a test'
end
end
end
now you can call the method by this TestModules::Test.test

Resources