Access a module's class variables inside a class in Ruby - ruby

I have a module with a class variable in it
module Abc
##variable = "huhu"
def self.get_variable
##variable
end
class Hello
def hola
puts Abc.get_variable
end
end
end
a = Abc::Hello.new
a.hola
Is it possible to get ##variable inside Hello without using get_variable method? I mean something like Abc.variable would be nice. Just curious.

You cannot access ##variable directly (i.e., Abc.variable) within the scope of the Hello class in the module Abc. Why? Because, when the Ruby interpreter sees something like Abc.variable, it would think variable as class/module method of Abc.
It is important to think the Ruby way when programming in Ruby.

try this
Abc.class_variable_get(:variable)

Related

Is it possible to execute a method from a module with a String ? - Ruby 2.7.1

Greetings to everyone.
This question is the continuation of a previous one :
Is it possible to extend a class by using a string as a module ? - Ruby 2.7.1
So here it is. I am currently doing some tests with Ruby 2.7.1 on my FreeBSD 12.1 workstation. My objective is to find a way to load all the script within a directory. These scripts are modules with predictable names. For instance, if I got a script named mymodule.rb, it will contain a module named : Mymodule and a method : mymodule. So I can make a list of all scripts within a directory by using an Array. I can use that list to load/require all my script files easily. And with the help of some .sub, .chop or .capitalize, I can can extract what I need from each index of my array. But the result of this operation is always a String. The problem is that I cannot execute a method with a String. Previously I was having problem with extending my main class with module name from a String, but answers were given and solved this little issue. Here is my main class :
load "mymodule.rb"
class Myclass
def mymethod
var1 = "Mymodule"
extend self.class.const_get(var1)
var2 = "mymodule"
#I need something here to call the method from the module.
#puts #varmod
end
end
a = Myclass.new
a.mymethod
and here is my module :
module Mymodule
def mymodule
#varmod = "TEST"
end
end
So, I would like to know if there is a way to execute the method within Mymodule the same fashion we did with "extend self.class.const_get(var1)".
Thanks in advance for your responses !
In order to send a message with a name that is not statically known at design time, you can use the Object#public_send method:
public_send(var2)
It is not necessary to use Object#send in this case, since your methods are not private.
I think it is the send method your are looking for. The following should work:
send(var2)

Ruby code order

Why can the following part # def games # #games = games # end come at the very end (bottom) of the code and still work? I thought Ruby reads the code from top to bottom. If I do not define games at the top, shouldn't it give an error?
class Library
# def games
# #games
# end
def initialize(games)
#games = games
end
def add_game(game)
games << game
end
# The following lines should come at the top of this code.
def games
#games
end
end
games = ['WoW','SC2','D3']
lib = Library.new(games)
lib.games #=> WoW,SC2,D3
lib.add_game('Titan')
lib.games #=> WoW,SC2,D3,Titan
When the method is defined, ruby is not running it. It's just available for the instance to use after you've invoked the class.
I generally put my methods in alphabetical order to make it easier to navigate my code as it grows. This is a personal preference.
Ruby allows you to structure and organize your classes/modules however is logical/beneficial to you.
To clarify, Ruby classes are executed when they're defined, but methods are not.
example.rb
class Example
puts "hello"
def my_method
puts "world"
end
end
Run it
$ ruby example.rb
hello
Because Ruby executes classes, that's how things like macros work in Ruby classes.
class Example2
attr_accessor :foo
end
attr_accessor is a method that gets called when the class is executed. In this case attr_acessor will setup get and set functions for the #foo instance variable.
If Ruby didn't execute your classes, this code would have to be called manually in some sort of initializer.
All you need to do is learn to differentiate between calling a method and defining a method. Defined methods will not be automatically executed.
The reason it is so is because of the way a class is built by Ruby: Every instance method definition inside a Ruby class gets defined first, during the top-down parsing. Then when you invoke each method it just matters whether its defined or not and not how its ordered.
Having said that order is important if you are redefining a method below. Then precedence will be given to lower definition.

How do I define an instance method in Ruby? [duplicate]

This question already has answers here:
What does a Java static method look like in Ruby?
(2 answers)
Closed 8 years ago.
I'm trying to define a method called function. It works when I do this:
a = A.new
def a.function
puts 100
end
But I want the method to work for any instance variable, not just a. For example, when I call function on an instance of A other than a, nothing happens. So I used A::f to define the function rather than a.function.
class A
attr_accessor :function
attr_accessor :var
end
def A::function
self.var = 0x123
end
a = A.new
a.function
puts a.var
This compiles fine but when I try to call the function I get an error. Why is it not working and how can I do what I'm attempting?
You're really tangled up here. I suggest you check out _why's poignant guide to ruby and get a handle on what is going on here.
As an attempt to steer you right, though…
a isn't an instance variable. It's a local variable that you're using to reference an instance of A.
def a.foo defines a method on the eigenclass of a.
attr_accessor :function already defined A#function (that is, an instance method on A called function) that essentially looks like this: def function; #function; end
def A::function defines a class method on A that you could access via A.function (not an instance of A as in a.function.
MRI doesn't really compile ruby like you might anticipate. It runs it, dynamically interpreting statements in realtime.
You probably want to stick with defining standard instance methods in the traditional manner, and avoid using “function” as a placeholder name since it is a reserved word and has special meaning in other languages. I'll use “foo” here:
class A
def foo
'Awww foo.'
end
end
That's it, you can now create an instance of A (a = A.new) and call foo on it (a.foo) and you'll get back 'Aww foo.'.
class A
def function
puts 100
end
end
a = A.new
a.function #=> "100"
That's a classic instance method. Is that what you're looking for or am I missing something?
If you're trying to define methods dynamically, you could use Class#define_method. Otherwise, if you are just wanting to define the method for the class, defining it in the scope of class A will suffice.
Anyway, could you be more specific on what are you trying to accomplish and what kind of error you're having, please?

rspec: "describe MyClass::Something do"

I'm new to rspec. The following syntax is confusing:
describe MyClass::Something do
What does Something refer to? The rspec tests I'm looking over contain the above line. However MyClass doesn't contain anything related to Something.
You are confused by Ruby syntax, not RSpec syntax. MyClass is a module, and Something is a class or module inside the MyClass module. The :: is the scope resolution operator to tell Ruby which Something you are looking for.
module Foo
class Bar
def say_hello
puts "hello"
end
end
end
foo = Foo::Bar.new
foo.say_hello
#prints "hello"
See http://ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html for more on modules.
This is not related to Rspec. The answer you are seeking is that Something is an inner class or module within MyClass. Something refers to a class/module named Something within the class/module MyClass. Here is an example:
class MyClass
module Something
end
end

Scoping of Open classes in Ruby versus MOP in Groovy

What I'm trying to find out is whether there is some sort of equivalence to what I see in Groovy as ExpandoMetaClasses. I've been reading about Open Classes but I can't quite see what level of scoping Ruby allows of the class modifications.
Borrowing an example from the blog above, in Groovy, I could modify Java's String class and add a method to it like so:
String.metaClass.shout = {->
return delegate.toUpperCase()
}
println "Hello MetaProgramming".shout()
// output
// HELLO METAPROGRAMMING
And I think that Ruby would have you redefine the class and possibly alias it (please help clarify my misunderstandings at this point):
class String
def foo
"foo"
end
end
puts "".foo # prints "foo"
In Groovy, there are ways to scope the redefinition of core Java library methods to single instances or to a group of instances using Categories, which feel similar to what I would define as mixins in Ruby.
What are the ways to scope open classes to specific instances or to subsets of modules?
If I were to install a gem that had redefined some core class, would only that module be affected, or would any .rb file I include that gem with be affected with it?
Apologies in advance for making some possible assumptions on both Ruby and Groovy, I'm new to both but have been trying to find equivalence between the two.
Ruby's classes are never "closed". So when you say:
class String
def omg!
self.replace "OMG"
end
end
You are defining the omg! method on the String class. Unlike in Groovy, which requires the usage of a special metaclass concept, Ruby classes are always open, period.
If you wanted to modify a particular set of Strings, you could do this:
module Magic
def presto
puts "OMG A HAT!"
end
end
class Array
include Magic
end
x = "Hello".extend(Magic)
puts x #=> Hello
x.presto #=> OMG A HAT!
[].presto #=> OMG A HAT!
def x.really?
true
end
x.really? #=> true
Effectively, a module is a collection of methods that can be added to a class or specific instances.
So you can either open a class directly or add new methods to a class using a module. You can also open an instance directly or add new methods to an instance using a module. That's because a class is just an instance of Class ;) Pretty nifty!
In addition to what Yehuda said, instances in Ruby also have metaclasses (technically called "singleton classes"), accessed with class <<whatever. For example, to redo Yehuda's Magic example with a singleton class:
x = "Hello"
class <<x
include Magic
def magical?
true
end
end
x.presto #=> OMG A HAT!
x.magical? #=> true
"Something else".magical? #=> NoMethodError
There's no scoping on modifications to classes. As soon as a class is modified, the modified class is accessible to all later requires and following code.

Resources