consider the following example:
module M
end
class C
include M
end
c = C.new
p c.singleton_class.ancestors
the output is: [#<Class:#<C:0x000055b6b069c5f0>>, C, M, Object, Kernel, BasicObject]
but now if we include the module in singleton_class of object c as following
class << c
include M
p ancestors
end
the output is: [#<Class:#<C:0x000055b6b069c5f0>>, C, M, Object, Kernel, BasicObject]
But The well-grounded Rubyist books say it should be as follows in chapter 13 Object individual:
[#<Class:#<C:0x000055b6b069c5f0>>, M, C, M, Object, Kernel, BasicObject]
To answer this question we need to understand how include works.
Module#include
Invokes #append_features on each parameter in reverse order.
Module#append_features
add the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors.
If you swap the order in which you include the module you will have the expected result
module M
end
class C
end
c = C.new
p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, C, Object, Kernel, BasicObject]
class << c
include M
end
p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, M, C, Object, Kernel, BasicObject]
# M is not in the ancestors of the class C is ancestors of the singleton class
class C
include M
end
p c.singleton_class.ancestors
# -> [#<Class:#<C:0x000056285c79a678>>, M, C, M, Object, Kernel, BasicObject]
# The include statement put M as first ancestors of C
If we change the order
module M
end
class C
end
c = C.new
p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, Object, Kernel, BasicObject]
class C
include M
end
p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, M, Object, Kernel, BasicObject]
# M is ancestor of C and of the singleton class #C
class << c
include M
end
p c.singleton_class.ancestors
# [#<Class:#<C:0x000055b278d8a290>>, C, M, Object, Kernel, BasicObject]
# M is not included
Related
I don't understand what feature of the language is behind this code to work. Specifically, how are the values from [a,b,c].sort automatically populated into the variables ?
def isTriangle(a,b,c)
a, b, c = [a, b, c].sort
a + b > c
end
As mentioned by Cary Swoveland an spickermann this works because of array decomposition.
The sort method gives back an array, its content is then assigned to the variables. In the link given above you can see that in the documentation it is written as:
(a, b) = [1, 2]
I assume that by only writing
a, b = [1, 2]
some kind of syntactic sugar is used to make this work.
I tried it in IRB and the two variants behave the same.
Every entity in development has it's own name, that help developers to communicate.
The classical splat operator in multiple assignment in Ruby is a common thing.
a, *rest, z = %w{a the long road z}
p a # "a"
p z # "z"
p rest # ['the', 'long', 'road']
Today I found that it tread as working code by Ruby, when I skip a variable name after a splat operator. Like this:
a, *, z = %w{a the long road z}
p a # "a"
p z # "z"
How this Lonely splat operator in multiple assignment correctly called?
If I have three or more objects like so:
a = 4
b = 4
c = 4
d = 2
what would be a clean ruby-style way of determining whether they are all equal? Any bespoke methods for running equality tests on three or more elements?
I suppose I could do something like this:
arrays = [a,b,c,d].map{|x| [x]}
arrays.first == arrays.reduce(:&) ? true : false
which appears to work, but feels sort of ham handed, and might be difficult for other developers to read.
[a,b,c,d].any?{|x| x != a}
or
array.any?{|x| x != array.first}
Alternatively, the #all? method may read more intuitively for some:
array.all? {|x| x == array.first }
[a, b, c, d].group_by(&:itself).length == 1
# => false
or
[a, b, c, d].chunk(&:itself).to_a.length == 1
# => false
or
[a, b, c, d].chunk_while(&:==).to_a.length == 1
# => false
or the naive:
[a, b, c, d].uniq.length == 1
I was reminded of one?. Provided that you do not have any falsy element, the above can be written:
[a, b, c, d].uniq.length.one?
I think the answer by #kipar is better by all means, but for the sake of “doing it the way you started” I would post this here:
[a, b, c, d].reduce { |r, e| r == e && r } && true
I am starting with an array of letters:
letters = %w[c s t p b l f g d m
y o u i h t r a e l
o t l a e m r s n i
m a y l p x s e k d]
Passing them, finding all combinations that return an array like this ["cstp", "cstb", "cstl"], this is a shortened example.
def combinations(letters)
combos = letters.combination(4)
combos.collect do |letter_set|
letter_set.join(",").gsub("," ,"")
end
end
I am trying to figure out how to pass the return value of combinations into start_wtih_letter_c. Do I have to pass a block like &block? I tried various things that keep saying wrong number of arguments.
def start_with_letter_c(pass the return value)
combinations.select {|word| word.match(/^ca/) }
end
Here you go, no errors:
letters = %w[c s t p b l f g d m
y o u i h t r a e l
o t l a e m r s n i
m a y l p x s e k d]
def combinations(letters)
combos = letters.combination(4)
combos.collect do |letter_set|
letter_set.join(",").gsub("," ,"")
end
end
def start_with_letter_c(combinations)
combinations.select {|word| word.match(/^ca/) }
end
start_with_letter_c(combinations(letters))
# => ["cael", "caeo", "caet", "cael", "ca ...and so on
I would write something like this:
letters = %w[c s t p b l f g d m
y o u i h t r a e l
o t l a e m r s n i
m a y l p x s e k d]
def combinations(letters)
letters.combination(4).map(&:join)
end
def start_with_letter_c(combinations)
combinations.select { |word| word.start_with?('ca') }
end
start_with_letter_c(combinations(letters))
If I initialize objects with assignment like a = b = c = []
then this variables have the same object_ids: a.object_id == b.object_id == c.object_id
Also I tried:
[a, b, c].map {|e| e = [] }
a, b, c = Array.new(3, [])
a, b, c = Array.new(3, Array.new)
but it doensn't initialize a, b, c variables with different object_ids
Is there a way to initialize variables a, b, c with different object ids but with the same value == []?
How about these possible solutions:
a,b,c=[],[],[]
a,b,c=(0..2).map{[]}
a,b,c=Array.new(3){[]}
How about this?
a = []
b = []
c = []