RubyMonk 8.2 Modules as Namespace - ruby

Overall I am having trouble understanding some concepts in Ruby, Modules being one of them.
I am on the final step in RubyMonk 8.2: Modules as Namespace and I am very lost. What should I do? My plan was to just get the solution and reverse engineer it, but there is no solution button so I am stuck :(
The instructions go as follows:
If you prepend a constant with :: without a parent, the scoping happens on the topmost level. In this exercise, change push to return 10 as per A = 10 in the topmost level, outside the Kata module.
The code already filled in is:
module Kata
A = 5
module Dojo
B = 9
A = 7
class ScopeIn
def push
A
end
end
end
end
A = 10

So, you want this:
module Kata
A = 5
module Dojo
B = 9
A = 7
class ScopeIn
def push
::A # change this line from A to ::A, meaning ::A will refer to the top-level namespaced A which is defined outside the Kata module (A = 10)
end
end
end
end
A = 10
p Kata::Dojo::ScopeIn.new.push
# => 10
If you prepend a constant with :: without a parent, the scoping happens on the topmost level. In this example, push will return 10 since A = 10 is in the topmost level, outside the Kata module.

module Kata
A = 5
module Dojo
A = 7
class ScopeIn
def push0
A
end
def push1
Kata::Dojo::A
end
def push2
Kata::A
end
def push3
::A
end
end
end
end
A = 10
scope = Kata::Dojo::ScopeIn.new #=> #<Kata::Dojo::ScopeIn:0x007fe63c8381d0>
scope.push0 #=> 7
scope.push1 #=> 7
scope.push2 #=> 5
scope.push3 #=> 10

Related

Copy a class so that the old class is not modified when I modify the new one in Ruby

I have some a ConnectFour class and I have a method:
def apply_move!(column_number, symbol, row_number = 0)
# Some gravity logic
#board[row_number][column_number] = symbol
end
That modifies the class in place.
I tried writing a wrapper around it that returns a board and does not change the original, so that Function Programming techniques could be used.
My attempt is:
def apply_move(column_number, symbol)
dummy = ConnectFour.new(#board)
dummy.apply_move!(column_number, symbol)
dummy
end
But the trouble is that modifying dummy also modifies the original class itself! How could I modify dummy and dummy only?
More code and context
You probably are interested in:
class CpuWinIfPossible < Player
def decide_move(board)
(0...6).find do |move|
board.apply_move(move, self.symbol).is_won?(self.symbol)
end || (0...6).to_a.sample
end
end
Here I loop and execute apply_move to my board, as you can see from my definition above, apply_move should not change the board, but the board shows 7 (+ 1) moves after this code is run: it looks like this:
Player X: Where would you like to play (Number from 1 to 7) ?
2
O O
OXOOOO
The winner is O
The constructor
class ConnectFour
attr_accessor :board
def initialize(board)
#board = board
end
I think it is related to the current status of #board, if you change your ConnectFour#initialize to looks like following I think it should be work
def initialize(board)
#board = board.dup
end
If you are using rails you can use deep_dup
def initialize(board)
#board = board.deep_dup
end
A hack to solve my problem is:
def initialize(board)
#board = board.map(&:dup)
end
But as #JörgWMittag noted I should really make my code more OO to fit with Ruby style and this workaround will not be needed anymore.
You could make a deep copy of the class:
new_class = Marshal.load(Marshal.dump(ConnectFour))
and go from there (dummy = new_class.new(#board), etc.).

Why can't I puts an instance variable of a Ruby class if it contains the value of a variable in a module?

When I try to run this code, nothing or nil shows up. I can't seem to understand why, since I thought classes that include modules can access its instance/class variables. I can print out the value just fine if I don't use garbtest and just use the garb= method to assign it a different value. It works fine without assigning it another value since I initialized it to 16 too. Is there something about the instance/class variables in the module Test that makes it equal to nil? Furthermore, when I try to assign garb to #myg + ##vit it says there is no such method for the nil class. I think this further confirms my suspicion that those variables are somehow nil. Thank you.
module Test
RED = "rose"
BLUE = "ivy"
#myg = 9
##vit = 24.6
end
class Xy
include Test;
def initialize(n)
#garb = n
end
attr_accessor :garb;
def garbTest
#garb = #myg;
end
def exo
return 50;
end
end
ryu = Xy.new(16);
ryu.garbTest;
puts "#{ryu.garb}";
Because #myg is not shared variable. It is private property of module Test, thus while you included Test, #myg didn't come into Xy due to the mixin, it wouldn't come also by default. But, "Why nil?" - Because, instance variable, class variables are like that. Before initialising/defining them, if you attempt to use them, it will simply give you nil.
Small program to prove myself and Ruby :-
module Test
#x = 10
##y = 11
end
class Foo
include Test
end
Foo.instance_variable_defined?(:#x) # => false
Test.instance_variable_defined?(:#x) # => true
Foo.class_variable_defined?(:##y) # => true
Test.class_variable_defined?(:##y) # => true
You can define reader method inside Test singleton class, and then you can use it. Look below
module Test
class << self
attr_reader :myg
end
RED = "rose"
BLUE = "ivy"
#myg = 9
##vit = 24.6
end
class Xy
include Test
def initialize(n)
#garb = n
end
attr_accessor :garb
def garbTest
#garb = Test.myg
end
def exo
return 50
end
end
ryu = Xy.new(16)
ryu.garbTest # => 9

Any difference declaring class using :: or module?

module Api
module V1
class ABC
end
end
end
class Api::V1::ABC
end
Any different between these to declare a class?
Any pros and cons?
Yes, there is a difference while you will be doing constant lookups. Module::nesting will be helpful here to things get cleared for you.
module Api
module V1
class ABC
p Module.nesting
end
end
end
# >> [Api::V1::ABC, Api::V1, Api]
module Api
module V1
end
end
class Api::V1::ABC
p Module.nesting
end
# >> [Api::V1::ABC]
Module.nesting returns the lexically enclosing classes/modules which are searched before Ruby walks up the class/module hierarchy to find the constant.
It means, with the following code :
module Api
module V1
X = 12
end
end
X = 10
class Api::V1::ABC
p X
end
Api::V1::ABC.superclass # => Object
# >> 10
While constant looks-up will be happening, it will first search to the array of constants, which has been given by Module.nesting, if not found then, up to the ancestor chains/included modules. It means following to the Api::V1::ABC.ancestors outputs.
Now in the above example, you can see that value of X printed, which is defined in the Object, not inside the API::V1. The reason as I said above.
Now coming to another example below :-
X = 10
module Api
module V1
X = 12
class ABC
p X
end
end
end
# >> 12
Here the constant look up will follow through the array [Api::V1::ABC, Api::V1, Api]. You can see the output found as 12, as Api::V1 has a constant X defined into it.
Thus we can say - Yes there is a difference between the 2 declarations.

attr_accessor or custom methods duplicate method names confusion

I do understand that Ruby supports short-hand style of calling methods i.e: 1.+(2) is same as 1+2 (and I still think if it related to my situation), but I got really confused why attr_accessor methods are neither duplicate (well, they should not be, as writer differs with = in its name) nor they differ with anything (except writer needs an argument) while accessing them outside active object.
My question is included in this code (in the second comment)
class Test
def initialize(number)
#number = number
end
def number
#number
end
def number=(n)
#number = n
end
end
t = Test.new(12)
puts t.number # => 12
t.number = 13 # Why does it do what t.number=(13) should do
puts t.number # => 13
I wonder why t.number = 13 works, when it points to a method which should only return a number and moreover how does it set a new value when t.number=(13) is not called instead.
t.number = 13 is just a shorthand for t.number=(13), they are effectively the same statement in Ruby.
attr_accessor :b creates the equivalent of the following two methods:
def b
#b
end
def b=(new_val)
#b = new_val
end
So in your code example, you could replace the two methods #number and #number= with attr_accessor :number

What is the difference between def func(var) and def func=(var)?

In a class definition, what is the difference between these two methods?
def func(var)
...
end
def func=(var)
...
end
Is there any, or is one of them not valid?
Both of them are valid method definitions. But the second one is defining a 'setter' method - you can call this method with the following syntax:
obj.func = 123
This statement will be translated into
obj.func=(123)
You can take a look at this answer where I explain this syntax in a bit more detail.
To explain some things about reader/writer AKA getter/setter methods in Ruby:
Ruby doesn't force us to use = in the method definition for a setter. We get to choose whether the method has one.
Consider this:
class Foo
# automagically creates:
# .v
# .v=
attr_accessor :v
def initialize(v)
puts "inside initialize(#{ v })"
#v = v
end
def setter(v)
puts "inside setter(#{ v })"
#v = v
end
def setter=(v)
puts "inside setter=(#{ v })"
#v = v
end
end
f = Foo.new(1)
puts f.v
f.setter(2)
puts f.v
f.setter = 3
puts f.v
f.setter=(4)
puts f.v
f.v = 5
puts f.v
f.v=(6)
puts f.v
Running the code outputs:
inside initialize(1)
1
inside setter(2)
2
inside setter=(3)
3
inside setter=(4)
4
5
6
The = is simply another letter in the method name because Ruby is smart enough to know if it sees f.setter = 3 it should use the setter=(v) method.
Ruby doesn't force using = to set a variable, you can decide if it makes more sense to you when you define the method. It is idiomatic that we use = because it helps make a setter look like an assignment, removing the urge to name all the setters something like set_v(v).
These are defining the getter and setter methods if you will. Say you have a Person class with a phone attribute.
class Person
def phone
#phone
end
def phone=(number)
#phone = number
end
end
Now you could change the phone attribute (managed internally in the #phone) by simply setting the property which will invoke the phone= method.
john = Person.new
john.phone = "123-456-7890"
It looks like a property assignment on the outside. Other characters that you can stack at the end of a method name are ? for boolean getters, ! for destructive operations. Again, these are just conventions and you're free to use these three characters as you want. However, code simply looks more natural with these symbols around. For example,
question.closed?
document.destroy!

Resources