Name error when creating empty set in Ruby - ruby-on-rails

I'm trying to use the Set class from the standard Ruby library. I am creating an empty Set like so:
Set.new
but then I end up with this error:
main.rb:36:in `<main>': uninitialized constant Set (NameError)
Set.new
^^^
How do I properly create an empty instance of Set

Set is standard Ruby class, but you need to require it just like any other class / module from the standard library (like JSON, Date, Timeout, etc.)
You need to add to the top of your main.rb
require 'set'
You can see it in the examples in the official docs

You need to add
require 'set'
Top the top of your Ruby file main.rb

Related

With a ruby-doc.org library how do you work out whether to require or include?

With the ruby CSV library with ruby on rails, you use the library by declaring require 'csv', but when using the Math module, you declare include Math. Neither library documents which declaration to use. How do you work this out, e.g. use include for module and require for a Class? If that is the case, why do you not have to require a file in the case of a module? How do you work out the file name is 'csv' and not 'CSV'?
This is not a general question about require and include but is seeking information on how to interpret the ruby-doc.org documentation to use a particular class or module.
As Jörg Mittag already pointed our in this comment: require and include are doing totally different things and have nothing in common. They aren't related to each other nor they are interchangeable.
require loads a file (reads the docs for details). Ruby doesn't magically find files or modules/classes that are defined in a file. Every piece of code that is defined in an external file requires the file to be loaded before the code is executed and can be used.
Modules in Ruby's core (like Math - note the core in the URL) are required automatically, therefore you do not need to load them yourself. But if you want to use a module or class from the standard library (like CSV) or an external gem you need to require it by yourself. This might not be obvious because tools like bundler require files for you or a gem requires internally all other files it needs.
All Ruby files need to be loaded before they can be used. require is the most common way to load Ruby files.
Imagine there is a file named foo.rb that looks like this:
puts 'loading file...'
def foo_loaded?
true
end
module Foo
def self.bar
puts 'bar'
end
end
Playing around in the console:
# `foo` wasn't required yet
> foo_loaded?
#=> NoMethodError: undefined method `foo_loaded?' for main:Object
> Foo
#=> NameError: uninitialized constant Foo
# It doesn't find the file if it ist not in the current $LOAD_PATH
require 'foo'
#=> LoadError: cannot load such file -- foo
# It loads and executes (see the output from `puts`) the file when found
> require './foo'
#=> loading file...
#=> true
# Now we can start using the methods and modules defined in the file
> foo_loaded?
#=> true
> Foo
#=> Foo
> Foo.bar
#=> bar
There is no need to include anything. Everything defined in the file is available to Ruby right away. There is not need to name give that file a special name matching the module, class or methods inside. But it is a common pattern and a good practice to name the file by its content.
include doesn't work on file-level but on the language level. It basically takes all methods from a module and includes them into another module or class. Btw: If the module you want to include is defined in an external file then you need to require that file first, otherwise Ruby won't even know that the module exists and cannot include it.
Imagine a module and class structure like this:
module Bar
def bar
puts 'bar'
end
end
class Foo
end
Foo.new.bar
#=> NoMethodError: undefined method `bar' for #<Foo:...
# Bar is not related to Foo
Foo.ancestors
#=> [Foo, Object, Kernel, BasicObject]
And when we include Bar into Foo:
module Bar
def bar
puts 'bar'
end
end
class Foo
include Bar
end
Foo.new.bar
#=> bar
# Bar is now a superclass of Foo
Foo.ancestors
#=> [Foo, Bar, Object, Kernel, BasicObject]
Things to note: There is no need to use require in this example because both the module and the class are defined in the same file. include takes the module not a string defining a file or a module name.
Because include does a very special thing it is not useful to ask: Do I need to require or include X before using it? Or: How do I know what to include? Ofter there is no need to include anything: A gem might only provide classes/modules to use directly or it might include its functionality itself. This depends on the design and the purpose of the module. You cannot tell without reading the documentation or the source code.
tl:dr
require and include do totally different things.
Ruby files must be loaded before usage. require is one way to load a Ruby file.
include includes methods from a module into the current module/class.
You must read the documentation about how to use a library, there isn't just one way to implement things.

Module automatically adding namespace to a method being called

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.

uninitialized constant (NameError) while including module

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.

Rails unable to autoload constant from file despite being defined in that file

This is a tricky one to explain. I have a module in another module namespace like so:
# app/models/points/calculator.rb
module Points
module Calculator
def self.included(base)
base.send(:include, CommonMethods)
base.send(:include, "Points::Calculator::#{base}Methods".constantize)
end
end
end
So then in other classes all I need to do is:
class User
include Points::Calculator
end
I've specified this directory in application.rb to be autoloadable...(even though i think rails recurses through models...)
config.autoload_paths += Dir[ Rails.root.join('app', 'models', "points") ]
In development env, everything works fine. When running tests(and production env), I get the following error:
Unable to autoload constant Points::Calculator, expected /Users/pete/work/recognize/app/models/points/calculator.rb to define it (LoadError)
I actually followed the advice here to fix the problem: Stop Rails from unloading a module in development mode by explicitly requiring calculator.rb in application.rb.
However, why is this happening??
I stuck some debug output in ActiveSupport's dependencies.rb file and noticed that this file is being required twice. The first time its required I can see that the constant is indeed loaded.
But the 2nd time its required the constant has been unloaded as far as Rails can tell, but when the actual require is called, ruby returns false because ruby knows its already required it. Then Rails throws the "unable to autoload constant" error because the constant still isn't present and ruby didn't "re-require" the file.
Can anyone shed light on why this might be happening?
Rails augments the constant lookup mechanism of ruby.
Constant lookup in Ruby:
Similar to method missing, a Module#constant-missing is invoked when a reference to a constant fails to be resolved. When we refer to a constant in a given lexical scope, that constant is searched for in:
Each entry in Module.nesting
Each entry in Module.nesting.first.ancestors
Each entry in Object.ancestors if Module.nesting.first is nil or a module.
When we refer to a constant, Ruby first attempts to find it according to this built-in lookup rules.
When ruby fails to find... rails kicks in, and using its own lookup convention and its knowledge about which constants have already been loaded (by ruby), Rails overrides Module#const_missing to load missing constants without the need for explicit require calls by the programmer.
Its own lookup convention?
Contrasting Ruby’s autoload (which requires the location of each autoloaded constant to be specified in advance) rails following a convention that maps constants to file names.
Points::Calculator # =>points/calculator.rb
Now for the constant Points::Calculator, rails searches this file path (ie 'points/calculator.rb') within the autoload paths, defined by the autoload_paths configuration.
In this case, rails searched for file path points/calculator in its autoloaded paths, but fails to find file and hence this error/warning is shown.
This answer is an abstract from this Urbanautomation blog.
Edit:
I wrote a blog about Zeitwerk, the new code reloader in Rails. Check it out at -> https://blog.bigbinary.com/2019/10/08/rails-6-introduces-new-code-loader-called-zeitwerk.html
If someone is having this issue in rails 6 which has zeitwerk autoloader,
Change ruby constant lookup back to classic in your application.rb
# config/application.rb
#...
config.autoloader = :classic
#...
Read more details here Rails Official Guides
Calculator should be a class to be autoloaded correctly
module Points
class Calculator
...
end
end

My first RoR Gem: NameError in MicropostsController#up_vote uninitialized constant VoterLove::Voter::Vote

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

Resources