i read string methods in ruby. i understood replace will replace the string with the argument passed to it. But the same thing we can do with a short and sweet = oparator also. what is the point of using replace method? its just a personnel choice or it's different from an = operator?
> a = "hello world"
=> "hello world"
> a = "123"
=> "123"
> a.replace("345")
=> "345"
Using =
str = "cat in the hat"
str.object_id
#=> 70331872197480
def a(str)
str = "hat on the cat"
puts "in method str=#{str}, str.object_id=#{str.object_id}"
end
a(str)
in method str=hat on the cat, str.object_id=70331873031040
str
#=> "cat in the hat"
str.object_id
#=> 70331872197480
The values of str outside the method and str inside the method are different objects.
Using String#replace
str = "cat in the hat"
str.object_id
#=> 70331872931060
def b(str)
str.replace("hat on the cat")
puts "in method str=#{str}, str.object_id=#{str.object_id}"
end
b(str)
in method str=hat on the cat, str.object_id=70331872931060
str
#=> "hat on the cat"
str.object_id
#=> 70331872931060
The values of str outside the method and str inside the method are the same object.
This line of code changes the variable a to point to a new string:
a = "new string"
This line of code actually changes the string object that a (and possibly other variables) are pointing to:
a.replace "new string"
The use case is really just, to achieve something much like pass-by-reference in other languages, where a variable's value can be changed directly. So you could pass a String to a method and that method may entirely change the string to something else.
def bar(bazzer)
bazzer.replace("reference")
end
bar(baz)
=> It's reference because local assignment is above the food chain , but it's clearly pass-by-reference
This makes sense.
Related
As a ruby newbie I am trying to understand a snippet of code in our baseline. Could someone please do that for me ? The snippet appears below
%w{word1 word2}.each { |att| define_method(att.to_sym) { return nil }}
In the context where this line will be run, two methods will be defined
def word1
return nil
end
def word2
return nil
end
For example
class MyClass
%w{word1 word2}.each { |att| define_method(att.to_sym) { return nil }}
end
After my_class.rb file will be loaded you will be able to consume generated methods
test = MyClass.new
test.word1
# or
test.word2
Like jdv said in the comments, for tutorials you might be better of on other websites. Here are all references needed to understand the piece of code provided:
Percent strings, used in %w{word1 word2}
Percent Strings
Besides %(...) which creates a String, the % may
create other types of object. As with strings, an uppercase
letter allows interpolation and escaped characters while a
lowercase letter disables them.
These are the types of percent strings in ruby:
%i: Array of Symbols
%q: String
%r: Regular Expression
%s: Symbol
%w: Array of Strings
%x: Backtick (capture subshell result)
For the two array forms of percent string, if you wish to
include a space in one of the array entries you must escape
it with a “\” character:
%w[one one-hundred\ one]
#=> ["one", "one-hundred one"]
If you are using “(”, “[”, “{”, “<” you must close it with
“)”, “]”, “}”, “>” respectively. You may use most other
non-alphanumeric characters for percent string delimiters
such as “%”, “|”, “^”, etc.
Array#each
each {|item| block} → ary
each → Enumerator
Calls the given block once for each element in self,
passing that element as a parameter. Returns the array
itself.
If no block is given, an Enumerator is returned.
a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }
produces:
a -- b -- c --
Module#define_method
define_method(symbol, method) → symbol
define_method(symbol) { block } → symbol
Defines an instance method in the receiver. The method
parameter can be a Proc, a Method or an UnboundMethod
object. If a block is specified, it is used as the method
body. This block is evaluated using instance_eval.
class A
def fred
puts "In Fred"
end
def create_method(name, &block)
self.class.define_method(name, &block)
end
define_method(:wilma) { puts "Charge it!" }
end
class B < A
define_method(:barney, instance_method(:fred))
end
a = B.new
a.barney
a.wilma
a.create_method(:betty) { p self }
a.betty
produces:
In Fred
Charge it!
#<B:0x401b39e8>
String#to_sym
to_sym → symbol
Returns the Symbol corresponding to str, creating the
symbol if it did not previously exist. See Symbol#id2name.
"Koala".intern #=> :Koala
s = 'cat'.to_sym #=> :cat
s == :cat #=> true
s = '#cat'.to_sym #=> :#cat
s == :#cat #=> true
This can also be used to create symbols that cannot be
represented using the :xxx notation.
'cat and dog'.to_sym #=> :"cat and dog"
%w{word1 word2} = creating an array that looks like this ['word1', 'word2']
.each = iterating through each value in the array
{} = this is a code block each value in the array will be run through this block
|attr| = block parameter. each value in the array will be placed here
define_method = define a method from the argument
(att.to_sym) = the name of the new method. this will be word1 and then word2
{ return nil } = the body of the new method
So what is happening is you are defining two new methods. One method called word1 and another called word2. Each of these methods will have a body of return nil. They will look like this:
def word1
return nil
end
def word2
return nil
end
this sounds weird doesn't it?
class Dummy
def foo=(value); end
end
Dummy.new.foo = 1 { |x| x } # => syntax error
Dummy.new.foo=(1) { |x| x } # => syntax error
i tried every permutation of blanks, parenthesis, commas; no luck. i'm puzzled. i never suspected methods ending with '=' were special. is it a bug? is it intended? if intended, why? is it documented? where? please share insight.
thanks
ps. ruby is 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin11.0.1]
The syntax sugar for methods ending in = does make it special. You can still do things like pass multiple arguments to that method, or pass a block, but not in any pretty or convenient manner:
class Foo
def bar=(a,b=nil)
p [a,b]
if block_given?
yield "hi"
else
puts "No block"
end
end
end
f = Foo.new
f.bar = 42
#=> [42, nil]
#=> No block
f.bar = 42, 17
#=> [[42,17], nil]
#=> No block
f.send(:bar=,42,17) do |x|
puts "x is #{x.inspect}"
end
#=> [42, 17]
#=> x is "hi"
Another way in which these methods are special is that when called with the syntax sugar they evaluate to the right hand value, not the return value of the method:
class Foo
def bar=(a)
return 17 # really explicit
end
end
f = Foo.new
x = (f.bar = 42)
p x
#=> 42
x = f.send(:bar=,42)
p x
#=> 17
It's not so much that the methods themselves are special, but more to do with how Ruby deals with assignments (like foo = bar). First the right hand side is evalulated, then the left hand side is evaluated and the appropriate action is taken. If the left hand side is an object attribute, then the appropriate setter method is called.
So in your example:
Dummy.new.foo = 1 { |x| x }
First ruby tries to evalulate 1 { |x| x }, which is what causes the syntax error.
Dummy.new.foo=something doesn't actually mean "call the method named foo=", but actually means something more like "evalualate something, and then determine what `Dummy.new.foo is, and if it looks like an object attribute, add = to the name and call that method". This is why Dummy.new.foo= and Dummy.new.foo = both work the same way.
You can call these methods using send, and can pass a block with this:
Dummy.new.send "foo=", 2 do
puts "HI"
end
This is because with send you can explicitly name the method you want to call.
Of course the end result is that methods ending in = seem to have some "special" behaviour you need to be aware of, but it might be useful to understand what's actually going on.
In ruby, you can append strings using <<:
>> "Hello" << "World"
=> "HelloWorld"
So why can't you prepend them using >>?
>> "Hello" >> "World"
NoMethodError: undefined method `>>' for "Hello":String
I realise String doesn't have the >> method defined, but what's the reasoning behind that?
Ruby 1.9.3 added a String#prepend method.
The proposal about adding prepend[1] also included the ">>" method, and there's some discussion on the thread about that implementation [2]:
Matz says: " >> is interesting notation did not think about it."
sorya says: "This patch is out it had been discussed several times towards the IRC"
However at the end of the thread, the conclusion was to accept String#prepend, and that "other proposals including String # >> are pending."
I couldn't find any other discussion about it though... anyone else?
Personally, I like it, and it's trivial to add:
class String
def >> (s)
s.prepend(self)
end
end
The result:
>> "Hello" >> "World"
=> "HelloWorld"
[1] http://bugs.ruby-lang.org/issues/3675
[2] http://translate.google.com/translate?hl=en&sl=ja&tl=en&u=http%3A%2F%2Fbugs.ruby-lang.org%2Fissues%2F3675
Ruby's syntax wouldn't allow a method like >> to be implemented the way you expect.
<< in "Hello" << "World" is equivalent to the following:
"Hello".<<("World")
If you wanted to create a prepend method >>, I would expect "Hello" in "Hello" >> "World" to be the argument to the string "World":
("Hello")>>."World" which isn't valid Ruby syntax.
If "World" was an argument to "Hello", then you would just be appending a string like fl00r demonstrated. Aliasing >> to mean the same as << would cause confusion.
This is why you have the insert method instead. If you want to insert "Hello" in front of "World" you would call insert on "World":
"World".insert(0, "Hello ")
The takeaway here is to keep in mind that << is a method call just like a string method such as length, so you have to keep the ordering similar to regular method calls.
Ruby always asigns value from the right to the left.
But you can implement it by yourself
class String
def >>(s)
s << self
end
end
"Hello" >> "world"
#=> "worldHello"
I don't think I would do this, but if someone forced me to:
class String
def prepend(string)
insert(0, string)
end
end
I don't think >> is a good idea—the reason << is nice is because it looks like what's going to happen. >> looks like it would have the same result as << to me, except that the calling object is being prepended onto the parameter.
I think this is a good question, and the issue is more general than just the problem with the notation << as suggested in McStretch's answer because there is a same situation with the methods given in an alphabet. Namely, there is String#concat, which appends an argument string to self, but there is no method that prepends an argument string.
For example:
ruby-1.9.2-p0 > a = ['hello', 'world']
=> ["hello", "world"]
ruby-1.9.2-p0 > "foo" + a
TypeError: can't convert Array into String
from (irb):3:in `+'
from (irb):3
from /Users/peter/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'
ruby-1.9.2-p0 > "foo" + a.to_s
=> "foo[\"hello\", \"world\"]"
ruby-1.9.2-p0 > puts "foo" + a.to_s
foo["hello", "world"]
why can't Ruby automatically convert the array to String?
It's not that Ruby can't, it's more that it won't. It's a strongly typed language, which means you need to take care of type conversions yourself. This is helpful in catching errors early that result from mixing incompatible types, but requires a little more care and typing from the programmer.
Strings are a special case because you can use string interpolation to call to_s implicitly:
obj = Object.new.tap {|o|
def o.to_s
'object!'
end
def o.inspect
'[object]'
end
}
"foo: " + obj # TypeError
"foo: #{obj}"
=> "foo: object!"
I redefined inspect to show that to_s is being called, and not inspect. On ruby 1.9, Object#inspect calls to_s, so if I didn't redefine inspect, the above code wouldn't show clearly which method was actually being called during interpolation.
You can make your Ruby automatically convert to String.
class Array
def to_string
self.unshift("").join(" ")
end
end
a = ["Hello", "World"]
"foo" + a.to_string
I used Ruby for a bit before Rails came out. I just downloaded it again and was playing around, then saw your question.
I may be ignorant or a nutter, but hey... that's my stab at it.
Why do this Ruby object both a to_s and inspect methods that appear to do the same thing?
The p method calls inspect and puts/print calls to_s for representing the object.
If I run
class Graph
def initialize
#nodeArray = Array.new
#wireArray = Array.new
end
def to_s # called with print / puts
"Graph : #{#nodeArray.size}"
end
def inspect # called with p
"G"
end
end
if __FILE__ == $0
gr = Graph.new
p gr
print gr
puts gr
end
I get
G
Graph : 0
Graph : 0
Then, why does Ruby have two functions do the same thing? What is the difference between to_s and inspect?
And what's the difference between puts, print, and p?
If I comment out the to_s or inspect function, I get as follows.
#<Graph:0x100124b88>
#<Graph:0x100124b88>
inspect is used more for debugging and to_s for end-user or display purposes.
For example, [1,2,3].to_s and [1,2,3].inspect produce different output.
inspect is a method that, by default, tells you the class name, the instance's object_id, and lists off the instance's instance variables.
print and puts are used, as you already know, to put the value of the object's to_s method to STDOUT. As indicated by Ruby's documentation, Object#to_s returns a string representing the object -- used for end-user readability.
print and puts are identical to each other except for puts automatically appends a newline, while print does not.
To compare with Python, to_s is like __str__ and inspect is like __repr__. to_s gives you a string, whereas inspect gives you the string representation of the object. You can use the latter to construct an object if you wish.
Further, there is a to_str method on certain objects, which you would call when you need a String-like object, and not just a string representation. (Try in IRB: [1,2,3].to_str and it will fail, yet [1,2,3].to_s will not.) I feel I should mention this because I've been bitten by it before :)
For anyone arriving here after starting out with Ruby Koans, a simple example of where to_s and inspect differ in output is this:
nil.to_s # will yield an empty string, ie ""
nil.inspect # will yield the string "nil"
puts generally prints the result of applying to_s on an object, while p prints the result of inspecting the object.
There is a subtle difference between inspect and to_s:
inspect, when applied on an object, returns the object hex code
along with the instance variable
to_s, when applied on an object,returns only the object hex code
class Item
def initialize(abc)
#abc=abc
end
end
x= Item.new(22)
puts x #prints object x hex code
puts x.inspect #prints object x hex code WITH INSTANCE VARIABLE #abc
puts x.to_s #prints object x hex code
p x #prints object x hex code WITH INSTANCE VARIABLE #abc
p x.inspect #prints object x hex code WITH INSTANCE VARIABLE #abc
p x.to_s #prints object x hex code
Answer from Chris Pine's Learn To Program book
"The inspect method is a lot like to_s, except that the string it returns tries to show you the ruby code for building the object you passed it."
Thus the inspect method will return an array for example like this...
[25, 16, 9, 4, 1, 0]
Where as puts / to_s will return
25
16
9
4
1
0
2.0.0p195 :075 > puts (1..5).to_a # Put an array as a string.
1
2
3
4
5
=> nil
2.0.0p195 :076 > puts (1..5).to_a.inspect # Put a literal array.
[1, 2, 3, 4, 5]
=> nil
2.0.0p195 :077 > puts :name, :name.inspect
name
:name
=> nil
2.0.0p195 :078 > puts "It worked!", "It worked!".inspect
It worked!
"It worked!"
=> nil
2.0.0p195 :079 > p :name # Same as 'puts :name.inspect'
:name
=> :name
From the Rails Tutorial
Refer following link for more information and examples explaining difference between "to_s" and "inspect" as well as difference between "puts" and "p".
https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/45-more-classes/lessons/108-displaying-objects