I'm trying to create a gem, my gem requires a different gem that I have added into the gemspec.
My issue is when I try to call a method inside the code, ruby automatically adds the module namespace to the method I am calling, then I get an uninitialized constant error. I put a basic example of what is going on below.
lib/example_gem.rb
module FooModule
def bar
# this is the method I am trying to run
BAZ::Request.execute(123)
end
end
class Test
include FooModule
end
x = Test.new
x.bar
=>>>>>>>> uninitialized constant FooModule::Baz (NameError)
I'm not trying to call FooModule::Baz, I want to call BAZ::Request.execute(123). Any help would be appreciated
Try:
::BAZ::Request.execute(123)
The keyword is "constant lookup operator". I assume BAZ isn't wrapped into another class or module, so you need to look for it on the topmost level. Therefore you prepend ::.
And now you understand why the request (BAZ::Request) needs to be within BAZ.
Related
I am trying to write a Ruby Gem which, when required, adds a function to the global scope.
I have followed the ideas here:
How can I add a method to the global scope in Ruby?, however, it just doesn't work! (on Ruby 2.4.3 anyway)
Here is my actual source code, but the below also summarises what I've done and what isn't working:
# example.rb
module Example
def self.hello()
puts "Hello"
end
end
extend Example
Then
# app.rb
require 'example' # Having built as a gem
hello() #=> `<main>': undefined method `hello' for main:Object (NoMethodError)
Where did I go wrong?
Sergio solved this for me, though I don't quite understand how!
It was considered good practice to encapsulate the methods in a module, so that users of the gem can use them directly (hello) or scoped (Example::hello) as they pleased.
By removing self. the method can be accessed directly only. By including self. it doesn't work at all. However, by doing:
module Example
extend self
def hello
puts "Hello"
end
end
extend Example
...it does work in both ways.
i am writing gem for my Rails app which calculates some stuff and uses class and modules.
Here is file structure.
root
->lib
-->finances
--->version.rb
--->finances.rb
--->calculator
----->formulas.rb
--->finalize
---->schedule.rb
-->finances.rb
Now root/lib/finances.rb
require "finances/version"
require "finances/finances"
require "finances/finalize/schedule"
require "finances/calculator/formulas"
root/lib/finances/calculator/formulas.rb
module Calculator
module Formulas
def method
end
end
end
root/lib/finances/finalize/schedule.rb
module Finalize
class Schedule
include ::Calculator::Formulas
end
end
but I get uninitialized constant Calculator (NameError)
if i try to just use
::Calculator::Formulas.method
it throws NoMethodError (undefined methodmethod' for Calculator::Formulas:Model):`
What exactly i am doing wrong. I cant seem to work around this. Could anyone help.
You try to use method as Formulas 'module method', while you defined it as regular instance method. So it should be called on RepaymentSchedule instance:
rs = RepaymentSchedule.new
rs.method
Also, you need to make sure your loading order is correct. Here, you should require file containing Formulas module before you load Schedule class, otherwise you get uninitialized constant error.
I'm working on my first RubyGem voter_love. When I install the Gem and use the up_vote method I get this error:
NameError in MicropostsController#up_vote
uninitialized constant VoterLove::Voter::Vote
Do I need to generate an initializer or require the Gem somewhere in my code to initialize the Votes model?
From here, your model is VoterLove::Votes not VoterLove::Voter::Vote.
And a simple advice: simply adopt a normal Rails app architecture and use the Engine power to have everything painlessly included (models, controllers, views...).
You've most likely referred to a class or module that doesn't exist. Most likely, you've forgotten to require a gem or library needed for the code to work, or you've made a typo. Another possibility is that the class you'd like to refer to is in another module. If that's the case, you'll have to refer to it with its full name as in the following code.
#!/usr/bin/env ruby
module MyModule
class MyClass; end
end
c = MyModule::MyClass.new
I am using a plugin in Rails, and I call its methods without problems:
plugin_module::class_inside_module.method_a(...)
I want to re-open the class_inside_module and add a new method, I tried in many different ways. I can't figure out why in this way doesn't work:
class plugin_module::class_inside_module
def new_method
puts 'new method'
end
end
I get the error: uninitialized constant plugin_module, but how is possible if I can call without problem plugin_module::class_inside_module.any_methods ?
Do you know why I get that error ? why "uninitialized constant" ? (it is a class declaration :-O )
Do you have any ideas how I can add a new methods in a class inside a module (that is part of a plugin) ?
Thank you,
Alessandro
If you have written your class and module-names like you did, so plugin_module instead of PluginModule this is against ruby/rails standards, and rails will not be able to automatically find the class and module.
If you write something like
module MyModule
class MyClass
end
end
Rails will expect this file to be located in lib\my_module\my_class.
But this can always easily be overwritten by explicitly doing a require.
So in your case, when you write
module plugin_module::class_inside_module
Rails will not know where to find the module plugin_module.
This way of writing only works if module plugin_module is previously defined (and loaded).
So either add the correct require, or rename your modules to standard rails naming, or write it as follows:
module plugin_module
class class_inside_module
This way will also work, because now the order no longer matters.
If the module is not known yet, this will define the module as well.
Either you are re-opening the class, or you define it first (and the actual definition will actually reopen it).
Hope this helps.
Have you tried reopening the module that's wrapping the class, rather than relying on ::?
module plugin_module
class class_inside_module
def new_method
puts 'new_method'
end
end
end
By the way, you know that the proper name for modules and classes is use CamelCase with a capital first letter?
module PluginModule
class ClassInsideModule
def new_method
puts 'new_method'
end
end
end
I have a CommonFunctions Module inside the lib/ folder. I have a Question Model, which includes the CommonFunctions module. Now I am trying to access the favorite function of the CommonFunctions like Question.favorite. But I am getting NoMethodError. I have included the code. Can anyone please tell me where I am doing the mistake
Error
NoMethodError: undefined method `favorite' for Class:0x00000100e11508
Inside lib/CommonFunctions.rb
module CommonFunctions
def favorite(object_id)
end
end
Inside app/models/Question.rb
require 'lib/CommonFunctions.rb'
class Question
extend CommonFunctions
end
I am executing the following code from the script/console
Question.favorite(1)
Thanks
This was a duplicate of How do I properly include a module and call module functions from my Rails model?
Your code is correct. Make sure you have the current version of the classes loaded in the console (try reload!).
As a sidenote: if you rename CommonFunctions.rb to common_functions.rb, it will be autoloaded by rails and you don't need the require.
The module method is an instance method when you want it to be a class method. Use the code below instead
module CommonFunctions
def self.favorite(object_id)
end
end
Using the word "self" defines the method as a class method (or static)