I read this article about enumerable-enumerator. map is method of the Enumerable:
module Enumerable
def map(*several_variants) ## `*several_variants` [https://stackoverflow.com/questions/28527931/definition-of-ruby-inbuilt-methods][2]
#This is a stub, used for indexing
end
end
class Enumerator # Enumerator class has included Enumerable module Ok fine !!!
include Enumerable # many thing are there ...
end
And in the Array class:
class Array # Array class has included Enumerable module it means all the instances methods of Enumerable module will expose as the instance methods in Array class !!! Okk
include Enumerable # many thing are there ...
end
Now when I call the map method on an array, I get an Enumerator:
[1,2,3,4].map => #<Enumerator: [1, 2, 3, 4]:map>
1: What is Enumerator in the #<Enumerator: [1, 2, 3, 4]:map> line of output above?
module Test
def initialize(str)
#str = str
end
def methods_1(str)
p "Hello!!#{str}"
end
end
class MyTest
include Test
include Enumerable
end
my_test = MyTest.new('Ruby')
p "Which class ? : #{my_test}"
my_test.methods_1('Rails')
p my_test.map
Output
"Which class ? : #<MyTest:0x000000019e6e38>"
"Hello!!Rails"
#<Enumerator: #<MyTest:0x000000019e6e38 #str="Ruby">:map>
2: This should be object of MyTest class only if i'm not wrong.
3: In this line #<Enumerator: #<MyTest:0x000000019e6e38 #str="Ruby">:map>, what does Enumerator do here?
Thanks for all to making this concept clear, in short span of time.
I would like to share some useful link to grasp the concept at great level.
Map, Select, and Other Enumerable Methods
What does the “map” method do in Ruby?
Enumerable and Enumerator
Ruby tricks to make your code more fun and less readable
I don't think your question is specific to Enumerable#map. If you browse the Enumerable module, you'll find many methods (including map) that return one thing if a block is given and an enumerator if no block is given. Suppose you wrote,
[1,2,3].map.with_index { |x,idx| x+idx } #=> [1,3,5]
map is not given a block, so it returns an enumerator:
enum1 = [1,2,3].map
#=> #<Enumerator: [1, 2, 3]:map>
The method Enumerator#with_index is then sent to enum1:
enum2 = enum1.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3]:map>:with_index>
As you see, enum2 is also an enumerator, a sort of "compound enumerator".
enum2 does have a block, so it's elements are passed into the block by the method Enumerator#each, which calls Array#each.
We can view the contents of any enumerator by converting it to an array:
enum2.to_a
#=> [[1, 0], [2, 1], [3, 2]]
This shows us the elements that each will pass into the block, the first being the array [1, 0], causing the block variable x to be assigned the value 1 and the block variable idx to be assigned 0.
The final step in the calculation is performed by Array#each:
enum2.each { |x,idx| x+idx } #=> [1,3,5]
The docs for Enumerator#with_index (as well as for map and most other Enumerable methods) says that it is returns an object (generally not an enumerator) when it is given a block, and returns an enumerator when it is not given a block. As I've just shown, however, it's really producing an enumerator in any case; when it is followed by a block, it call's upon the receiver's class' each method to do its thing.
Yes, you can include Enumerable in your owns classes, but to use that module's methods you must also define the method each for your class.
It's enumerators that allow us to chain methods, and to do that efficiently, without creating temporary arrays and other such objects between the links.
I once gave the following fanciful account of how the Enumerable module came into existence:
One day, long ago, a very wise Rubyest from the land of the Rising Sun noticed that many methods he used for arrays were very similar to those he used for hashes, ranges and other collections. He saw that he could write them so that the only difference was how the method "each" was implemented, so he put them all in a module he called "可算の" ("Enumerable"), and then in all the classes for different types of collections he added "include Enumerable" and a method "each". After doing this, he thought, "生活は快適です" ("life is good").
The basic idea of map method is that, for every iteration of an element, map inserts the value of the last expression executed in the block into a new array. After the last element is executed, map returns to you the new array of values.
In your example:
Enumerator is just a class in Ruby. You've instantiated it when you didn't add a block on [1,2,3,4].map. Take note that it's different from Enumerable
Yes, it is your MyTest class. If you like to test it, do my_test.class
You just instantiated an Enumerator object by doing my_test.map and ruby saw that you've included the Enumerable module in your class.
The most common usage of map is with a block, like so:
[1, 2, 3, 4].map { |n| n*n }
# => [1, 4, 9, 16]
However, if you call map without passing a block, it still returns something. In this case it returns an Enumerator which knows about the original array and that it's a "map" type of array. It can be used to chain other Enumerator methods, for instance:
[1, 2, 3, 4].map.with_index { |n, idx| "entry #{idx} squared: #{n*n}" }
# => ["entry 0 squared: 1", "entry 1 squared: 4", "entry 2 squared: 9", "entry 3 squared: 16"]
You can read more documentation on the Enumerator class but in practice, you probably want to understand how to use map with blocks more.
Related
I know when writing a function that takes a string, it looks like:
def function("string")
but how do I write one that takes an array? should I first define an empty array e.g. s=[] and then when writing the function, just use s as the input?
Please try this.
#here argument name can be anything. It not compulsory to use array as argument name, it can be anything like `string`, `xyz` etc
def function(array)
p array
end
function([1,2,3,4,5])
This is really a question about Ruby than Rails. Ruby is a dynamic typing language, which in method definition, means you don't declare the argument types:
def add_three ( x, y , z)
x + y + z
end
add_three(1, 2, 3) # 6
add_three('a', 'b', 'c') # 'abc'
add_three([2], [3], [4], # [2, 3, 4]
add_three(Date.new(2017,3,4), 1, 1), # new date 2017.3.6
What matters is that x has a method + that accepts y, and the result from x + y has a method + that accepts z. This is called duck typing. What's important here is not which class the object is, but what message it can respond to.
As Ruby is dynamic language and it supports Duck Typing we never declare the data type of the variables or arguments of the method. So you could pass the array in any method, ruby just cares about the methods you can use on that argument which is an object for it. So to be sure about the array methods you are using will execute on array only you can do like this:
def doSomething(value)
if (value.is_a?(Array))
value.any_array_method # For eg: value.include?('a')
else
raise "Expected array value"
end
end
And you can call it like:
doSomething(['a', 'b', 'c'])
and if you call it with any other argument than array then it will give:
RuntimeError: Expected array value
You can pass an error message too instead of raising an exception that depends on you.
Hope this helps.
You can do it by doing
def my_function(arr=[], s)
puts arr.inspect
puts s.inspect
end
you can call the method with
my_function([1,3,4], "string")
I am studying Ruby and can't figure this out. I have an exercise where I have to add a method into a Library class which contains games. Each game is an instance of a class Game. So the solution is the following:
class Library
attr_accessor :games
def initialize(games)
self.games = games
end
def has_game?(search_game)
for game in games
return true if game == search_game
end
false
end
def add_game(game)
#games << game
end
end
I can't understand how << works in this case. Is this a bitwise left shift? Does Library class just assumes that games is an array, I believe I can pass anything to the Library class when I am initialising, single game or an array of games?
When you have:
#games << game
<< is actually a method. If it is a method, you ask, why isn't it written in the normal way:
#games.<<(game)
? You could, in fact, write it that way and it would work fine. Many Ruby methods have names that are symbols. A few others are +, -, **, &, || and %. Ruby knows you'd prefer writing 2+3 instead of 2.+(3), so she let's you do the former (and then quietly converts it to the latter). This accommodation is often referred to as "syntactic sugar".
<< is one of #games' methods (and game is <<'s argument), because #games is the receiver of the method << (technically :<<). Historically, it's called the "receiver" because with OOP you "send" the method to the receiver.
To say that << is a method of #games means that << is an instance method of #games's class. Thus, we have:
#games.methods.include?(:<<) #=> true
#games.class.instance_methods.include?(:<<) #=> true
I expect #games is an instance of the class Array. Array's instance methods are listed here. For example:
#games = [1,2,3]
#games.class #=> [1,2,3].class => Array
#games << 4 #=> [1,2,3,4]
#games.<<(5) #=> [1,2,3,4,5]
On the other hand, suppose #games were an instance of Fixnum. For example:
#games = 7
#games.class #=> 7.class => Fixnum
which in binary looks like this:
#games.to_s(2) #=> "111"
Then:
#games << 2 #=> 28
28.to_s(2) #=> "11100"
because << is an instance method of the class Fixnum.
As a third example, suppose #games were a hash:
#games = { :a => 1 }
#games.class #=> { :a => 1 }.class => Hash
Then:
#games << { :b => 2 }
#=> NoMethodError: undefined method `<<' for {:a=>1}:Hash
The problem is clear from the error message. The class Hash has no instance method <<.
One last thing: consider the method Object#send. Recall that, at the outset, I said that methods are sent to receivers. Instead of writing:
#games = [1,2,3]
#games << 4 #=> [1,2,3,4]
you could write:
#games.send(:<<, 4) #=> [1, 2, 3, 4]
This is how you should think of methods and receivers. Because send is an instance method of the class Object, and all objects inherit Object's instance methods, we see that send is "sending" a method (:<<, which can alternatively be expressed as a string, "<<") and its arguments (here just 4) to the receiver.
There are times, incidentally, when you must use send to invoke a method. For one, send works with private and protected methods. For another, you can use send when you want to invoke a method dynamically, where the name of the method is the value of a variable.
In sum, to understand what method does in:
receiver.method(*args)
look for the doc for the instance method method in receiver's class. If you Google "ruby array", for example, the first hit will likely be the docs for the class Array.
It's not a bitwise left shift, it's "shovel" operator. You, probably, know that in Ruby operators are implemented as methods, i.e. when you write
1 + 1
what is actually going on:
1.+(1)
The same is true for "shovel" (<<) operator, it's just a method on Array class, that appends its arguments to the end of the array and returns the array itself, so it can be chained:
>> arr = []
=> []
>> arr << 1
=> [1]
>> arr
=> [1]
>> arr << 2 << 3
=> [1, 2, 3]
It looks like #games is an array. The shift operator for an array adds an element to the end of the array, similar to array#push.
ary << obj → ary
Append—Pushes the given object on to the end of this array. This expression returns the array itself, so several appends may be chained together.
I am currently working on a Poker game in Ruby. Instead of using numerous if-else statements to check the value of the player's hand, I decided to do the following:
#calculate the players score
def score
POSS.map {|check|
if (check[1].call())
#score = check[0]
puts #score
return check[0]
else
false
end
}
end
POSS = [
[10, :royal_flush?],
[9, :straight_flush?],
[8, :four_kind?],
[7, :full_house?],
[6, :flush?],
[5, :straight?],
[4, :three_kind?],
[3, :two_pairs?],
[2, :pair?]
]
The second item in each item of 'POSS' is a method I created to check whether the player has that hand. I am attempting to call the method with .call(), but get the following error:
Player.rb:43:in `block in score': undefined method `call' for
:royal_flush?:Symbol (NoMethodError) from Player.rb:42:in `map' from
Player.rb:42:in `score' from Player.rb:102:in `get_score' from
Player.rb:242:in `<main>'
http://ruby-doc.org/core-2.2.2/Object.html Object#send is the method you are looking for.
Since you are wanting a 'class method', then Object should be self when declaring instance methods of the class that contains the 'class methods'
Try this code
#calculate the players score
def score
POSS.map do |check|
if self.send check[1]
#score = check[0]
puts #score
return check[0]
else
false
end
end
end
POSS = [
[10, :royal_flush?],
[9, :straight_flush?],
[8, :four_kind?],
[7, :full_house?],
[6, :flush?],
[5, :straight?],
[4, :three_kind?],
[3, :two_pairs?],
[2, :pair?]
]
Styles vary from person to person, however, I think when using multi line blocks, it would be best to use 'do,end' pair instead of '{ }'
https://github.com/bbatsov/ruby-style-guide
I think some confusion may come from code that looks like this
foobar = ->(foo,bar){puts "Passed in #{foo}, #{bar}"}
foobar.call("one","two")
If the first line was abstracted into other parts of the program you may have thought that foobar was a method, but its really a lambda. Procs and Lambdas are just like methods but better.. in their own way.. Check out this article on Procs, Blocks and Lambdas.
http://www.reactive.io/tips/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/
But also if interested check out https://www.codecademy.com/forums/ruby-beginner-en-L3ZCI for more detailed hands on with PBLS
You can use send.
class Foo
def self.bar
"bar"
end
def baz
"baz"
end
end
Foo.send(:bar) # => "bar"
f = Foo.new
f.send(:baz) # => "baz"
Though I'm not sure this is the best approach for the app you're writing. When you get it working you can post it on CodeReview.
No method is no method; and there is no Symbol#call which causes the immediate error.
The (or rather, a) way to call is via Object#__send__, supplying the name and arguments. One could also resolve a method and then call that; but __send__ is the most direct route as Ruby is based on message passing.
That is, instead of symbol.call(..), use obj.__send__(symbol, ..). (In this case the object would probably be self.)
See Understanding Ruby symbol as method call
Back for more help on my coursework at Bloc. Decided to bring you guys in on a problem I'm having with Monkey Patching the Array Class. This assignment had 8 specs to be met and I'm stuck now with one left and I'm not sure what to do.
I'm only going to give you the RSpecs and written requirements for the part that I'm having trouble w/ since everything else seems to be passing. Also I'll include the starter scaffolding that they gave me to begin with so there's no confusion or useless additions to the code.
Here are the written requirements for the Array Class Monkey Patch:
Write a new new_map method that is called on an instance of the Array class. It should use the array it's called on as an implicit (self) argument, but otherwise behave identically. (INCOMPLETE)
Write a new_select! method that behaves like the select, but mutates the array on which it's called. It can use Ruby's built-in collection select method. (COMPLETE)
Here are the RSpecs that need to be met regarding the Array class:
Note: "returns an array with updated values" Is the only Spec not passing.
describe Array do
describe '#new_map' do
it "returns an array with updated values" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array.new_map{ |e| e + 2 } ).to eq( [3, 4, 5, 6] )
end
it "does not call #map" do
array = [1,2,3,4]
array.stub(:map) { '' }
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
end
it "does not change the original array" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array ).to eq([1,2,3,4])
end
end
describe '#new_select!' do
it "selects according to the block instructions" do
expect( [1,2,3,4].new_select!{ |e| e > 2 } ).to eq( [3,4] )
expect( [1,2,3,4].new_select!{ |e| e < 2 } ).to eq( [1] )
end
it "mutates the original collection" do
array = [1,2,3,4]
array.new_select!(&:even?)
expect(array).to eq([2,4])
end
end
end
Here is the scaffolding they started me with:
class Array
def new_map
end
def new_select!(&block)
end
end
Lastly, here is my code:
class Array
def new_map
new_array = []
self.each do |num|
new_array << num.to_s
end
new_array
end
def new_select!(&block)
self.select!(&block)
end
end
Ruby Array Class:
map { |item| block } → new_ary
A block is like a method, and you specify a block after a method call, for example:
[1, 2, 3].map() {|x| x*2} #<---block
^
|
method call(usually written without the trailing parentheses)
The block is implicitly sent to the method, and inside the method you can call the block with yield.
yield -> calls the block specified after a method call. In ruby, yield is equivalent to yield(), which is conceptually equivalent to calling the block like this: block().
yield(x) -> calls the block specified after a method call sending it the argument x, which is conceptually equivalent to calling the block like this: block(x).
So, here is how you can implement new_map():
class Array
def new_map
result = []
each do |item|
result << yield(item)
end
result
end
end
arr = [1, 2, 3].new_map {|x| x*2}
p arr
--output:--
[2, 4, 6]
This comment is a bit advanced, but you don't actually have to write self.each() to call the each() method inside new_map(). All methods are called by some object, i.e. the object to the left of the dot, which is called the receiver. For instance, when you write:
self.each {....}
self is the receiver of the method call each().
If you do not specify a receiver and just write:
each {....}
...then for the receiver ruby uses whatever object is assigned to the self variable at that moment. Inside new_map() above, ruby will assign the Array that calls the new_map() method to self, so each() will step through the items in that Array.
You have to be a little bit careful with the self variable because ruby constantly changes the value of the self variable without telling you. So, you have to know what ruby has assigned to the self variable at any particular point in your code--which comes with experience. Although, if you ever want to know what object ruby has assigned to self at some particular point in your code, you can simply write:
puts self
Experienced rubyists will crow and cluck their tongues if they see you write self.each {...} inside new_map(), but in my opinion code clarity trumps code trickiness, and because it makes more sense to beginners to write self there, go ahead and do it. When you get a little more experience and want to show off, then you can eliminate explicit receivers when they aren't required. It's sort of the same situation with explicit returns:
def some_method
...
return result
end
and implicit returns:
def some_method
...
result
end
Note that you could write new_map() like this:
class Array
def new_map(&my_block) #capture the block in a variable
result = []
each do |item|
result << my_block.call(item) #call the block
end
result
end
end
arr = [1, 2, 3].new_map {|x| x*2}
p arr
--output:--
[2, 4, 6]
Compare that to the example that uses yield(). When you use yield(), it's as if ruby creates a parameter variable named yield for you in order to capture the block. However, with yield you use a different syntax to call the block, namely (), or if their are no arguments for the block, you can eliminate the parentheses--just like you can when you call a method. On the other hand, when you create your own parameter variable to capture a block, e.g. def new_map(&my_block), you have to use a different syntax to call the block:
my_block.call(arg1, ...)
or:
myblock[arg1, ...]
Note that #2 is just like the syntax for calling a method--except that you substitute [] in place of ().
Once again, experienced rubyists will use yield to call the block instead of capturing the block in a parameter variable. However, there are situations where you will need to capture the block in a parameter variable, e.g. if you want to pass the block to yet another method.
Looking at the spec here:
it "returns an array with updated values" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array.new_map{ |e| e + 2 } ).to eq( [3, 4, 5, 6] )
end
It looks like they just want you to re-write Array.map so that it will work with any given block. In your implementation you are telling the method to work in a very specific way, namely to call .to_s on all of the array elements. But you don't want it to always stringify the array elements. You want it to do to each element whatever block is provided when the method is called. Try this:
class Array
def new_map
new_array = []
each do |num|
new_array << yield(num)
end
new_array
end
end
Notice in my example that the method definition doesn't specify any particular operation to be performed on each element of self. It simply loops over each element of the array, yields the element (num) to whatever block was passed when .new_map was called, and shovels the result into the new_array variable.
With that implementation of .new_map and given array = [1,2,3,4], you can call either array.new_map(&:to_s) (the block is where the arbitrary operation to be performed on each element of the array is specified) and get ["1","2","3","4"] or you can call array.new_map { |e| e + 2 } and get [3,4,5,6].
I would like to say a few words about new_select!.
select vs select!
You have:
class Array
def new_select!(&block)
self.select!(&block)
end
end
which you could instead write:
class Array
def new_select!
self.select! { |e| yield(e) }
end
end
This uses the method Array#select!. You said Array#select could be used, but made no mention of select!. If you cannot use select!, you must do something like this:
class Array
def new_select!(&block)
replace(select(&block))
end
end
Let's try it:
a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
Explicit vs implicit receivers
Notice that I have written this without any explicit receivers for the methods Array#replace and Array#select. When there is no explicit receiver, Ruby assumes that it is self, which is the a. Therefore, Ruby evaluates replace(select(&block)) as though it were written with explicit receivers:
self.replace(self.select(&block))
It's up to you to decide if you want to include self.. Some Rubiests do, some don't. You'll notice that self. is not included in Ruby built-in methods implemented in Ruby. One other thing: self. is required in some situations to avoid ambiguity. For example, if taco= is the setter for an instance variable #taco, you must write self.taco = 7 to tell Ruby you are referring to the setter method. If you write taco = 7, Ruby will assume you want to create a local variable taco and set its value to 7.
Two forms of select!
Is your method new_select! a direct replacement for select!? That is, are the two methods functionally equivalent? If you look at the docs for Array#select!, you will see it has two forms, the one you have mimicked, and another that you have not implemented.
If select! is not given a block, it returns an enumerator. Now why would you want to do that? Suppose you wish to write:
a = [1,2,3,4,5]
a.select!.with_index { |n,i| i < 2 }
#=> [1, 2]
Has select! been given a block? No, so it must return an enumerator, which becomes the receiver of the method Enumerator#with_index.
Let's try it:
enum0 = a.select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:select!>
Now:
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3, 4, 5]:select!>:with_index>
You can think of enum1 as a "compound enumerator". Look carefully at the description (above) of the object Ruby returns when you define enum1.
We can see the elements of the enumerator by converting it to an array:
enum1.to_a
# => [[1, 0], [2, 1], [3, 2], [4, 3], [5, 4]]
Each of these five elements is passed to the block and assigned to the block variables by Enumerator#each (which calls Array#each).
Enough of that, but the point is that having methods return enumerators when no block is given is what allows us to chain methods.
You do not have a test that ensures new_select! returns an enumerator when no block is given, so maybe that's not expected, but why not give it a go?
class Array
def new_select!(&block)
if block_given?
replace(select(&block))
else
to_enum(:new_select!)
end
end
end
Try it:
a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
a = [1,2,3,4,5]
enum2 = a.new_select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!>
enum2.each { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
a = [1,2,3,4,5]
enum2 = a.new_select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!>
enum2.with_index.each { |n,i| i>2 }
#=> [4, 5]
a #=> [4, 5]
Many methods in Ruby array return an enumerator when invoked without parameters or blocks (index, keep_if, each, drop_while and many more).
When is it appropriate to use methods in this form, as opposed to calling them with a block?
From the docs to Enumerator:
Most methods have two forms: a block form where the contents are
evaluated for each item in the enumeration, and a non-block form which
returns a new Enumerator wrapping the iteration.
This allows you to chain Enumerators together. For example, you can
map a list’s elements to strings containing the index and the element
as a string via:
puts %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" }
# => ["0:foo", "1:bar", "2:baz"]
An Enumerator can also be used as an external iterator. For example,
Enumerator#next returns the next value of the iterator or raises
StopIteration if the Enumerator is at the end.
e = [1,2,3].each # returns an enumerator object.
puts e.next # => 1
puts e.next # => 2
puts e.next # => 3
puts e.next # raises StopIteration
I'm sorry for copy-paste, but I couldn't explain better.
The main original reason for the Enumerator class to exist is method chaining:
array.each.with_object [[], []] { |element, memo| ... }
So basically, you don't need to worry about that.