Create Module Variables in Ruby

Create module variables in Ruby

Ruby natively supports class variables in modules, so you can use class variables directly, and not some proxy or pseudo-class-variables:

module Site
@@name = "StackOverflow"

def self.setName(value)
@@name = value
end

def self.name
@@name
end
end

Site.name # => "StackOverflow"
Site.setName("Test")
Site.name # => "Test"

Instance variables in modules?

Think of the instance variable as something which will exist in any class that includes your module, and things make a bit more sense:

module Stacklike
def stack
@stack ||= []
end

def add_to_stack(obj)
stack.push(obj)
end

def take_from_stack
stack.pop
end
end

class ClownStack
include Stacklike

def size
@stack.length
end
end

cs = ClownStack.new
cs.add_to_stack(1)
puts cs.size

will output "1"

How can I initialize a module's instance variables in Ruby?

Initialize them in the module definition.

module MyModule
# self here is MyModule
@species = "frog"
@color = "red polka-dotted"
@log = []

def self.log(msg)
# self here is still MyModule, so the instance variables are still available
@log << msg
end
def self.show_log
puts @log.map { |m| "A #@color #@species says #{m.inspect}" }
end
end

MyModule.log "I like cheese."
MyModule.log "There's no mop!"
MyModule.show_log #=> A red polka-dotted frog says "I like cheese."
# A red polka-dotted frog says "There's no mop!"

This will set the instance variables when the module is defined. Remember, you can alwasys reopen the module later to add more instance variables and method definitions,
or to redefine existing ones:

# continued from above...
module MyModule
@verb = "shouts"
def self.show_log
puts @log.map { |m| "A #@color #@species #@verb #{m.inspect}" }
end
end
MyModule.log "What's going on?"
MyModule.show_log #=> A red polka-dotted frog shouts "I like cheese."
# A red polka-dotted frog shouts "There's no mop!"
# A red polka-dotted frog shouts "What's going on?"

Shared module variables in ruby

You are confusing namespace and including a module. It is possible to share a class variable if you actually include a shared module, and actually initialize the class variable. And it will not cause an error if you not use an undefined method NestedClass1#bar but use a defined method NestedClass1#foo.

module Module1
@@shared = nil
end

class NestedClass1
include Module1
def initialize
@@shared = "hello world"
end
def foo
p @@shared
end
end

class NestedClass2
include Module1
def bar
p @@shared
end
end

NestedClass1.new.foo # => "hello world"
NestedClass2.new.bar # => "hello world"

Modules and Accessing Variables from Modules (Ruby Language)

When writing a module the convention is to declare constants like this:

module Week
FIRST_DAY = 'Sunday'
end

Note that they're in ALL_CAPS. Anything that begins with a capital letter is treated as a constant. Lower-case names of that sort are treated as local variables.

Generally it's bad form to access the constants of another module, it limits your ability to refactor how those are stored. Instead define a public accessor method:

module Week
def first_day
FIRST_DAY
end
end

Now you can call that externally:

Week.first_day

Note you can also change how that's implemented:

module Week
DAYS = %w[
Sunday
Monday
Tuesday
...
Saturday
]

def first_day
DAYS.first
end

extend self # Makes methods callable like Week.first_day
end

The nice thing about that is the first_day method does exactly the same thing, no other code has to change. This makes refactoring significantly easier. Imagine if you had to track down and replace all those instances to Week::FIRST_DAY.

There's some other things to note here. The first is that any time you call include on a module then you get the methods and constants loaded in locally. The second thing is when you define a mix-in module, be careful with your names to avoid potential conflict with the target class.

Since you've mixed it in, you don't need the namespace prefix, just calling first_day should do it.

Module and class variable scope in ruby

Firstly - class variables are evil and should be avoided (because they are also inherited by all subclasses and usually causes more harm than good.

You want to create a class instance variable (not class variable) on a class or module which is including given module. It is easy to do with included method:

module Foo
@default_settings = {}

module ClassMethods
def foo_settings
@foo_settings
end
end

def self.included(target)
target.instance_variable_set('@foo_settings', @default_settings.dup)
target.extend ClassMethods
end
end

Why can't my Ruby module method access my module class variable?

The first @main_menu_options is not the same as the @main_menu_options referenced in the mixin method. The second method operates in the context of whatever called include.

If you want these both on the same page you'll need to redefine that method to be in the same scope:

module UserInterface
@main_menu_options = {
1 => "Display Task List",
2 => "Add New Task",
3 => "Edit A Task",
4 => "Delete A Task",
"Q" => "Quit"
}

# Module-level method has access to module-level defined variables
def self.main_menu(string = "")
@main_menu_options.each_value { |v| puts v }

if @main_menu_options == nil then puts "NOTHING THERE" end
end
end

This misses the bigger problem. Since those options never change you really should be defining this as a constant:

module UserInterface
MAIN_MENU_OPTIONS = {
1 => "Display Task List",
2 => "Add New Task",
3 => "Edit A Task",
4 => "Delete A Task",
"Q" => "Quit"
}

def main_menu(string = "")
MAIN_MENU_OPTIONS.each_value { |v| puts v }

if MAIN_MENU_OPTIONS == nil then puts "NOTHING THERE" end
end
end

You'll need to fix your if since that's not really functional code. When writing Ruby try to avoid one-liners like that, skip the then to avoid clutter.

Set class variable from module

Do not use class variable, use instance_variable that is attached to the class.

module MyApp
module MyLog

def self.included(base)
base.extend(ClassMethods)
end

module ClassMethods
def logger
@logger ||= Logger.new("#{Rails.root}/log/#{self.name.underscore}.log")
end
end

end
end

Example:

module A
def self.included(base)
base.extend ClassMethods
end

module ClassMethods

def logger
puts @logger
@logger ||= name
end
end
end

class B
include A
end

class C
include A
end

B.logger
#
B.logger
# B
C.logger
#
B.logger
# B
C.logger
# C

First time you call the method it is nil, thus the empty line, second time you call method the value equals to class name, B, and if called on new class it is again nil, check also this answer

Ruby class instance variable vs. class variable

How to make module variables that can be accessible in class and in each model instance?

You try to call pluggin_by_name, which is class singleton method, on the instance (your self is an instance of Plugin in pry console). This should work:

Plugin.pluggin_by_name(name)

Also, this part:

included do
@pluggins = [{name: "dupa"},{name: "hello"}]
end

makes no sense. You want your @pluggins, as far as I understand, as an instance variable of Plugin, but in this block self certainly isn't Plugin instance but, if I remember correctly, Plugin class. If you want pluggins attr reader to work, maybe you should set some kind of default value, like this:

module Plugginable
attr_writer :pluggins
def pluggins
@pluggins ||= [{name: 'dupa'}, {name: 'hello'}]
end
end


Related Topics



Leave a reply



Submit