Clarification on the Ruby << Operator - ruby

I am quite new to Ruby and am wondering about the << operator. When I googled this operator, it says that it is a Binary Left Shift Operator given this example:
a << 2 will give 15 which is 1111 0000
however, it does not seem to be a "Binary Left Shift Operator" in this code:
class TextCompressor
attr_reader :unique, :index
def initialize(text)
#unique = []
#index = []
add_text(text)
end
def add_text(text)
words = text.split
words.each { |word| do add_word(word) }
end
def add_word(word)
i = unique_index_of(word) || add_unique_word(word)
#index << i
end
def unique_index_of(word)
#unique.index(word)
end
def add_unique_word
#unique << word
unique.size - 1
end
end
and this question does not seem to apply in the code I have given. So with the code I have, how does the Ruby << operator work?

Ruby is an object-oriented language. The fundamental principle of object orientation is that objects send messages to other objects, and the receiver of the message can respond to the message in whatever way it sees fit. So,
a << b
means whatever a decides it should mean. It's impossible to say what << means without knowing what a is.
As a general convention, << in Ruby means "append", i.e. it appends its argument to its receiver and then returns the receiver. So, for Array it appends the argument to the array, for String it performs string concatenation, for Set it adds the argument to the set, for IO it writes to the file descriptor, and so on.
As a special case, for Fixnum and Bignum, it performs a bitwise left-shift of the twos-complement representation of the Integer. This is mainly because that's what it does in C, and Ruby is influenced by C.

<< is just a method. It usually means "append" in some sense, but can mean anything. For strings and arrays it means append/add. For integers it's bitwise shift.
Try this:
class Foo
def << (message)
print "hello " + message
end
end
f = Foo.new
f << "john" # => hello john

In Ruby, operators are just methods. Depending on the class of your variable, << can do different things:
# For integers it means bitwise left shift:
5 << 1 # gives 10
17 << 3 # gives 136
# arrays and strings, it means append:
"hello, " << "world" # gives "hello, world"
[1, 2, 3] << 4 # gives [1, 2, 3, 4]
It all depends on what the class defines << to be.

<< is an operator that is syntactic sugar for calling the << method on the given object. On Fixnum it is defined to bitshift left, but it has different meanings depending on the class it's defined on. For example, for Array it adds (or, rather, "shovels") the object into the array.
We can see here that << is indeed just syntactic sugar for a method call:
[] << 1 # => [1]
[].<<(1) # => [1]
and thus in your case it just calls << on #unique, which in this case is an Array.

The << function, according to http://ruby-doc.org/core-1.9.3/Array.html#method-i-3C-3C, is an append function. It appends the passed-in value to the array and then returns the array itself. Ruby objects can often have functions defined on them that, in other languages, would look like an operator.

Related

Why can't a string (from ARGV) be modified with shovel << (frozen string) in one case but it does can in another case?

I have two little ruby programs written in ruby 2.3.7
Im trying to extend strings that are passed from ARGV[].
This case works and extends the string removing last char and adding -ismo.
#!/usr/bin/ruby
if ARGV.length > 0
ARGV.each {|param| unless param.match(/ismo\z/); puts param.chop << "ismo" end}
else
puts "none"
end
but this other case doesnt work and says 'agranda' cant modify frozen String
#!/usr/bin/ruby
def reduce(string)
puts string.slice(0,8)
end
def agranda(string)
while string.length < 8
string << 'z'
end
puts string
end
if ARGV.length >= 1
ARGV.each {|a| if a.length < 8; agranda(a) elsif a.length > 8; reduce(a) else puts a end}
else
puts "none"
end
I cant figure it out why does it work in one case and doesnt in the other, both cases takes the string from the program arguments.
Thanks
ARGV is a special Array, not a String. When working with frozen strings, you can append or modify an Array element even if you can't change the underlying String objects it contains. Forget ARGV for a moment, and consider this example of an unfrozen Array containing frozen strings:
a = ['foo', 'bar'].map &:freeze
a.first.frozen?
#=> true
a[0] = 'baz'; a
#=> ["baz", "bar"]
a.map &:frozen?
#=> [false, true]
Now consider a frozen Array with unfrozen String elements:
a = ['foo', 'bar'].freeze
a.frozen?
#=> true
# Array is frozen, and yet...
a[0] << 'bar'; a
#=> ["foobar", "bar"]
In the first case, you can modify the Array but you can't mutate String elements in place; you have to replace them. In the second case, you can't add or remove elements of your Array, but you can mutate String objects stored within the Array.
From a practical perspective, you need to figure out what object is actually frozen. While you can't unfreeze a String or other object, you can certainly modify things it points to (e.g. an unfrozen String object within a frozen Array), or duplicate an unfrozen version of the object.
Your first one (which works) says this:
param.chop << "ismo"
Your second one (which doesn't work) says this:
string << 'z'
The first calls String#chop which gives you a copy of param with the last character removed and then shovels 'ismo' onto the end of that copy. The implicit copying in the String#chop call gives you an unfrozen string.
The second tries to shovel right into string without any copying. Your agranda method needs to copy the string and then modify that copy. The unary + operator for strings is specifically meant for this:
def agranda(string)
string = +string
# ...

What's the difference between "<" and "<<" in ruby in this use case?

From what I know "<" is inheritance of a class from another class?
but I also see "<<" being used for the same thing from what I am seeing,.
Example:
def catch_alarm(alarm_info, options)
alarms = []
alarms << AlarmMonitor.new({
region_id: region_name,
account_id: '10202'.
alarm_name: alarm_info
},
alarms
end
First of all, < and << are not the same.
Ruby – like many other programming languages – uses the infix notation for binary operators, i.e.:
left-hand side operator right-hand side
For example:
1 + 2
a - b
i >= j
x << y
But unlike many other languages, operators are implemented as methods in Ruby. So it's actually:
receiver method argument
If you want to know, what alarms << AlarmMonitor.new(...) does, you have to know what kind of object alarms is. In your example, it's an array (alarms = []) so the method is Array#<<:
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.
Note that different objects (or classes) can implement the same operator in different ways:
a = [1, 2]
a << 3 # pushes 3 onto the array, i.e. [1, 2, 3]
d = Date.new(2020, 5, 28)
d << 3 # returns a date 3 months earlier, i.e. 2020-02-28
i = 0b00001011
i << 3 # shifts the bits 3 to the left, i.e. 0b01011000
The behavior primarily depends on the receiver.
Let's briefly get back to <. In addition to methods, Ruby has keywords. Keywords sometimes work like methods, but they have their own parsing rules.
For class creation, Ruby has the class keyword:
class MyClass
# ...
end
Which accepts an optional subclass via:
class MySubclass < MyClass
# ...
end
Here, < is not an operator, but part of the class keyword syntax.
However, there's also a < operator for classes: Module#<. It can be used to check whether MySubclass is a subclass of MyClass: (thus mirroring the class creation syntax)
MySubclass < MyClass
#=> true
In this context << is the Array push operator, so isn’t related to the use of < for class inheritance.

What does << mean in Ruby?

I have code:
def make_all_thumbs(source)
sizes = ['1000','1100','1200','800','600']
threads = []
sizes.each do |s|
threads << Thread.new(s) {
create_thumbnail(source+'.png', source+'-'+s+'.png', s)
}
end
end
what does << mean?
It can have 3 distinct meanings:
'<<' as an ordinary method
In most cases '<<' is a method defined like the rest of them, in your case it means "add to the end of this array" (see also here).
That's in your particular case, but there are also a lot of other occasions where you'll encounter the "<<" method. I won't call it 'operator' since it's really a method that is defined on some object that can be overridden by you or implemented for your own objects. Other cases of '<<'
String concatenation: "a" << "b"
Writing output to an IO: io << "A line of text\n"
Writing data to a message digest, HMAC or cipher: sha << "Text to be hashed"
left-shifting of an OpenSSL::BN: bn << 2
...
Singleton class definition
Then there is the mysterious shift of the current scope (=change of self) within the program flow:
class A
class << self
puts self # self is the singleton class of A
end
end
a = A.new
class << a
puts self # now it's the singleton class of object a
end
The mystery class << self made me wonder and investigate about the internals there. Whereas in all the examples I mentioned << is really a method defined in a class, i.e.
obj << stuff
is equivalent to
obj.<<(stuff)
the class << self (or any object in place of self) construct is truly different. It is really a builtin feature of the language itself, in CRuby it's defined in parse.y as
k_class tLSHFT expr
k_class is the 'class' keyword, where tLSHFT is a '<<' token and expr is an arbitrary expression. That is, you can actually write
class << <any expression>
and will get shifted into the singleton class of the result of the expression. The tLSHFT sequence will be parsed as a 'NODE_SCLASS' expression, which is called a Singleton Class definition (cf. node.c)
case NODE_SCLASS:
ANN("singleton class definition");
ANN("format: class << [nd_recv]; [nd_body]; end");
ANN("example: class << obj; ..; end");
F_NODE(nd_recv, "receiver");
LAST_NODE;
F_NODE(nd_body, "singleton class definition");
break;
Here Documents
Here Documents use '<<' in a way that is again totally different. You can define a string that spans over multiple lines conveniently by declaring
here_doc = <<_EOS_
The quick brown fox jumps over the lazy dog.
...
_EOS_
To distinguish the 'here doc operator' an arbitrary String delimiter has to immediately follow the '<<'. Everything inbetween that initial delimiter and the second occurrence of that same delimiter will be part of the final string. It is also possible to use '<<-', the difference is that using the latter will ignore any leading or trailing whitespace.
Mostly used in arrays to append the value to the end of the array.
a = ["orange"]
a << "apple"
puts a
gives this ["orange", "apple"] result.
'a << b' means append b to the end of a
It's the operator which allows you to feed existing arrays, by appending new items.
In the example above you are just populating the empty array threads with 5 new threads.
In ruby you always have more the one way to do things. So, Ruby has some nice shortcuts for common method names. like this one is for .push instead of typing out the .push method name, you can simply use <<, the concatenation operator. in fact in some cases you can use any of these for the same operation .push and + with <<.
Like you can see in this example:
alphabet = ["a", "b", "c"]
alphabet << "d" # Update me!
alphabet.push("e") # Update me!
print alphabet
caption = "the boy is surrounded by "
caption << "weezards!" # Me, too!
caption += " and more. " # Me, too!
# .push can no be uses for concatenate
print caption
so you see the result is:
["a", "b", "c", "d", "e"]
the boy is surrounded by weezards! and more.
you can use the operator << to push a element into an array or to concatenate a string to another.
so, what this is this doing is creating a new element/object Thread type and pushing it into the array.
threads << Thread.new(s) {
create_thumbnail(source+'.png', source+'-'+s+'.png', s)
}
In ruby '<<' operator is basically used for:
Appending a value in the array (at last position)
[2, 4, 6] << 8
It will give [2, 4, 6, 8]
It also used for some active record operations in ruby. For example we have a Cart and LineItem model associated as cart has_many line_items. Cart.find(A).line_items will return ActiveRecord::Associations object with line items that belongs to cart 'A'.
Now, to add (or say to associate) another line_item (X) to cart (A),
Cart.find(A).line_items << LineItem.find(X)
Now to add another LineItem to the same cart 'A', but this time we will not going to create any line_item object (I mean will not create activerecord object manually)
Cart.find(A).line_items << LineItem.new
In above code << will save object and append it to left side active record association array.
And many others which are already covered in above answers.
Also, since Ruby 2.6, the << method is defined also on Proc.
Proc#<< allows to compose two or more procs.
It means add to the end (append).
a = [1,2,3]
a << 4
a = [1,2,3,4]

What does left shift mean in Ruby?

Can anyone explain to me what does the "shift left" syntax in ruby means?
For instance, I have this
File.open( folder, 'w' ){ |f| f << datavalue }
I know that it means to write each datavalue to folder, but the |f| f << datavalue part does not make sense to me. Why does the f is inside the bracket, in relation to shift left and write the datavalue to folder?
Basically, I don"t understand the meaning of this line
{ |f| f << datavalue }
File.open( folder, 'w' ){ |f| f << datavalue } is the same as writing:
File.open( folder, 'w' ) do |f|
f << datavalue
end
Both are examples of Ruby block notation. Blocks in Ruby are anonymous methods. The variables the block expects are declared between vertical bars. In this case the variable f represents the file object returned via the File.open command.
As regards the << operator. Here it is being used as a concatenator. I believe it's called an append operator when used on objects (such as strings, arrays, in this case a file). The exception is if the object is numeric, which is when it becomes the shift left operator to shift the bits of a number.
some_text = "world!"
hello = "Hello, "
hello << some_text
puts hello # prints "Hello, world!"
Then answer is: It depends. I don't want to nitpick but Ruby hardly has any real operators. In Ruby most "operators" are in fact methods which is possibly as in Ruby everything is an object.
E.g. consider this code
o.x = a + b
There are no operators here because in fact this is only an alternative way for writing this code
o.x=(a.+(b))
And x= is the name of a setter method and + is also just the name of a method of the object a. In Ruby characters that are operators in other languages can be used as a part of method name (just think of ? which is commonly used in Ruby method names).
So this code
a = b << c
Is in fact the same as writing
a = b.<<(c)
So what << does depends on how b implements this method.
E.g. for a String the << method means append.
a = "Hello, " << "Word"
# a == "Hello, Word"
But in case of a Fixnum the << method just means shift left:
a = 5 << 2
# a == 20
So it cannot be answered what << means, you have to look up in the documentation what it means for the object you are passing this method to. If you write your own class, you can just implement this operator in any way you like
class MyClass
# If you prefer, can also be written as
# def << x
def << ( x )
# do something with x
end
end
o = MyClass.new()
x = o << a
Your method << is called and you decide what it does with a.

Implicit return values in Ruby

I am somewhat new to Ruby and although I find it to be a very intuitive language I am having some difficulty understanding how implicit return values behave.
I am working on a small program to grep Tomcat logs and generate pipe-delimited CSV files from the pertinent data. Here is a simplified example that I'm using to generate the lines from a log entry.
class LineMatcher
class << self
def match(line, regex)
output = ""
line.scan(regex).each do |matched|
output << matched.join("|") << "\n"
end
return output
end
end
end
puts LineMatcher.match("00:00:13,207 06/18 INFO stateLogger - TerminationRequest[accountId=AccountId#66679198[accountNumber=0951714636005,srNumber=20]",
/^(\d{2}:\d{2}:\d{2},\d{3}).*?(\d{2}\/\d{2}).*?\[accountNumber=(\d*?),srNumber=(\d*?)\]/)
When I run this code I get back the following, which is what is expected when explicitly returning the value of output.
00:00:13,207|06/18|0951714636005|20
However, if I change LineMatcher to the following and don't explicitly return output:
class LineMatcher
class << self
def match(line, regex)
output = ""
line.scan(regex).each do |matched|
output << matched.join("|") << "\n"
end
end
end
end
Then I get the following result:
00:00:13,207
06/18
0951714636005
20
Obviously, this is not the desired outcome. It feels like I should be able to get rid of the output variable, but it's unclear where the return value is coming from. Also, any other suggestions/improvements for readability are welcome.
Any statement in ruby returns the value of the last evaluated expression.
You need to know the implementation and the behavior of the most used method in order to exactly know how your program will act.
#each returns the collection you iterated on. That said, the following code will return the value of line.scan(regexp).
line.scan(regex).each do |matched|
output << matched.join("|") << "\n"
end
If you want to return the result of the execution, you can use map, which works as each but returns the modified collection.
class LineMatcher
class << self
def match(line, regex)
line.scan(regex).map do |matched|
matched.join("|")
end.join("\n") # remember the final join
end
end
end
There are several useful methods you can use depending on your very specific case. In this one you might want to use inject unless the number of results returned by scan is high (working on arrays then merging them is more efficient than working on a single string).
class LineMatcher
class << self
def match(line, regex)
line.scan(regex).inject("") do |output, matched|
output << matched.join("|") << "\n"
end
end
end
end
In ruby the return value of a method is the value returned by the last statement. You can opt to have an explicit return too.
In your example, the first snippet returns the string output. The second snippet however returns the value returned by the each method (which is now the last stmt), which turns out to be an array of matches.
irb(main):014:0> "StackOverflow Meta".scan(/[aeiou]\w/).each do |match|
irb(main):015:1* s << match
irb(main):016:1> end
=> ["ac", "er", "ow", "et"]
Update: However that still doesn't explain your output on a single line. I think it's a formatting error, it should print each of the matches on a different line because that's how puts prints an array. A little code can explain it better than me..
irb(main):003:0> one_to_three = (1..3).to_a
=> [1, 2, 3]
irb(main):004:0> puts one_to_three
1
2
3
=> nil
Personally I find your method with the explicit return more readable (in this case)

Resources