Why does to_sym behave differently? - ruby

I have two strings. They behave differently with respect to to_sym:
key = "awesome123xyz"
key.to_sym #=> :awesome123xyz
object.id #=> "589d62c016bd4d0005bccc15"
object.id.to_sym #=> :"589d62c016bd4d0005bccc15"
Why is object.id.to_sym something that looks to me like a String:
:"589d62c016bd4d0005bccc15"
instead of being a symbol like this?:
:589d62c016bd4d0005bccc15`

Because in Ruby :589d62c016bd4d0005bccc15 is not a valid Symbol literal. If you have a string starting from integers or integer itself, converted to Symbol literal it will always have the following form:
'23'.to_sym
#=> :"23"
23.to_s.to_sym
#=> :"23"

Related

How to use ":template"-type strings in ruby?

Both rails routes and whenever and a few other things I can't remember have a user-specified template string like so:
template_str = "I am going to :place at :time"
And then there's some magic function which embeds data in place of :place and :time, like so:
template_str.magic_embed_function(place: 'bed', time: '10 pm')
#=> "I am going to bed at 10 pm"
How can I do this in my ruby projects? Is there a gem that implements String#magic_embed_function?
Use Percent-Style Interpolation
There is a special type of interpolation that uses the String#% method. This allows you to interpolate ordinal (Array) and non-ordinal (Hash) inputs into a format string similar to that provided by Kernel#sprintf. However, the use of a hash argument with this method enables support for named variables in the format string. As a minimalist example:
"%{foo} %{bar}" % {foo: 'baz', bar: 'quux'}
#=> "baz quux"
With a hash argument, the format-string placeholders are treated as hash keys to be replaced by the associated values in your hash. This makes the order of the variables passed in unimportant. Based on the code in your original post, you could use it as follows:
template_str = 'I am going to %{place} at %{time}.'
template_str % {time: '10:00 PM', place: 'bed'}
#=> "I am going to bed at 10:00 PM."
This is a useful technique when you want to pass an array or hash for interpolation, but may or may not offer advantages over other types of interpolation in the general case. Your mileage may vary.
I extended String class with a magic_embed_function as you asked..rs
It's very simple, first we split our string and collect the words and check if matches with this simple regex for symbols, basically says "if something starts with : , that's a symbol", after we found a symbol we replace using gsub! (global substitution, with the bang to change our object) passing our symbol as first param and the param received that corresponds to that symbol and at the end we return self, to return the string that called the method.
template_str = "I am goind to :place at :time"
class String
def magic_embed_function(params)
self.split(" ").collect do |value|
if value =~ /:.*/
self.gsub! value, params[value[1..value.length].to_sym]
end
end
self
end
end
p template_str.magic_embed_function({place: "bed", time: "10 pm"})
#"I am goind to bed at 10 pm"

What can a ruby symbol (syntax) contain?

I want to create regular expression to match ruby symbols, but I need to know what the exact syntax for a symbol is.
Until now I am aware of the following:
:'string'
:"string"
:__underline
:method
:exclamation!
:question?
:#instance
:$global
It's not entirely clear what you are talking about.
If you are talking about what a Symbol can contain, the answer is: anything and everything, including newlines, arbitrary whitespace, control characters, arbitrarily weird and obscure Unicode characters, and everything else.
If you are talking about the various ways of writing Symbol literals, here's my best understanding:
bare : literal: any valid Ruby identifier (e.g. :foo, :Foo, :#foo, :##foo, :$foo, :$:, …)
single-quoted : literal: everything that's valid in a single-quoted String literal, including escape sequences such as :'\'' and :'\\'
double-quoted : literal: everything that's valid in a double-quoted String literal, including escape sequences such as :"\"", :"\\", and :"\n", as well as string interpolation, which allows you to inject the results of arbitrary Ruby code into the Symbol, e.g. :"#{if rand < 0.5 then RUBY_VERSION else ENV['HOME'] end}"
single-quoted Array of Symbols literal: everything that's valid in a single-quoted Array of Strings literal, e.g. %i|foo bar baz| (equivalent to [:foo, :bar, :baz]), %i(foo\ bar baz) (equivalent to [:'foo bar', :baz]), %i:foo bar: (equivalent to [:foo, :bar])
double-quoted Array of Symbols literal: everything that's valid in a double-quoted Array of Strings literal, e.g. %I|foo #{bar} baz|, etc.
Symbol hash keys in the key: value syntax: every valid Ruby label, e.g. {foo: 42}
Symbol hash keys in the quoted 'key': value syntax: every valid Ruby String literal, including escape sequences and interpolation, e.g. {"foo\n#{bar}": 42}
There are of course a lot of other expressions that evaluate to Symbols:
method definition expressions: def foo;end # => :foo
String#to_sym (alias String#intern): 'foo bar'.to_sym # => :'foo bar'
really, any method that may return a Symbol
http://www.cse.buffalo.edu/~regan/cse305/RubyBNF.pdf enumerates the context-free grammar productions that define Ruby's syntax. CFGs are inherently more powerful than REs, so you might want to consider a different tool for this job--but you can certainly look at this document and try to construct a regexp that matches all cases.

Symbol literal or a method

Are :"foo" and :'foo' notations with quotations a symbol literal, or is : a unary operator on a string?
: is really just part of the literal you enter yourself or create through a method. Although : can take a name or a "string" to create a literal, unlike an operator it does not provoke any action or modify a value.
In each case an instance of Symbol is returned. Writing : with string notation is sometimes important. If you want to represent, for instance, a string containg whitespace as a symbol you need to use the string notation.
> :foo
=> :foo
> :foo bar
SyntaxError: (irb):2: syntax error, unexpected tIDENTIFIER, expecting end-of-input
> :"foo bar"
=> :"foo bar"
Furthermore, it is interesting to explore this with the equality operator (==)
> :"foo" == :foo
=> true
> :"foo " == :foo
=> false
My advice, do not think of it as passing a string or name to create a symbol, but of different ways to express the same symbol. In the end what you enter is interpreted to an object. This can be achieved in different ways.
> :"foo"
=> :foo
After all, %w(foo bar) is also an alternative way of writing ['foo', 'bar'].
Ruby's documentation on Symbol literals says this:
You may reference a symbol using a colon: :my_symbol.
You may also create symbols by interpolation:
:"my_symbol1"
:"my_symbol#{1 + 1}"
Basically :"foo" and :'foo' are symbol literals, but they are useful when you want to create symbols using interpolation.
You also need quotes if your symbol has spaces:
hash = {
:"a b c" => 10,
:"x y z" => 20,
}
puts hash[:"a b c"]
--output:--
10
So the first one. From the docs:
[Symbols] are generated using the :name and :"name" literals syntax, and by
the various to_sym methods.

What does the Ruby method 'to_sym' do?

What does the to_sym method do? What is it used for?
to_sym converts a string to a symbol. For example, "a".to_sym becomes :a.
It's not specific to Rails; vanilla Ruby has it as well.
It looks like in some versions of Ruby, a symbol could be converted to and from a Fixnum as well. But irb from Ruby 1.9.2-p0, from ruby-lang.org, doesn't allow that unless you add your own to_sym method to Fixnum. I'm not sure whether Rails does that, but it doesn't seem very useful in any case.
Expanding with useful details on the accepted answer by #cHao:
to_sym is used when the original string variable needs to be converted to a symbol.
In some cases, you can avoid to_sym, by creating the variable as symbol, not string in the first place. For example:
my_str1 = 'foo'
my_str2 = 'bar baz'
my_sym1 = my_str1.to_sym
my_sym2 = my_str2.to_sym
# Best:
my_sym1 = :foo
my_sym2 = :'bar baz'
or
array_of_strings = %w[foo bar baz]
array_of_symbols = array_of_strings.map(&:to_sym)
# Better:
array_of_symbols = %w[foo bar baz].map(&:to_sym)
# Best
array_of_symbols = %i[foo bar baz]
SEE ALSO:
When to use symbols instead of strings in Ruby?
When not to use to_sym in Ruby?
Best way to convert strings to symbols in hash
uppercase %I - Interpolated Array of symbols, separated by whitespace

What does the question mark at the end of a method name mean in Ruby?

What is the purpose of the question mark operator in Ruby?
Sometimes it appears like this:
assert !product.valid?
sometimes it's in an if construct.
It is a code style convention; it indicates that a method returns a boolean value (true or false) or an object to indicate a true value (or “truthy” value).
The question mark is a valid character at the end of a method name.
https://docs.ruby-lang.org/en/2.0.0/syntax/methods_rdoc.html#label-Method+Names
Also note ? along with a character acts as shorthand for a single-character string literal since Ruby 1.9.
For example:
?F # => is the same as "F"
This is referenced near the bottom of the string literals section of the ruby docs:
There is also a character literal notation to represent single
character strings, which syntax is a question mark (?) followed by a
single character or escape sequence that corresponds to a single
codepoint in the script encoding:
?a #=> "a"
?abc #=> SyntaxError
?\n #=> "\n"
?\s #=> " "
?\\ #=> "\\"
?\u{41} #=> "A"
?\C-a #=> "\x01"
?\M-a #=> "\xE1"
?\M-\C-a #=> "\x81"
?\C-\M-a #=> "\x81", same as above
?あ #=> "あ"
Prior to Ruby 1.9, this returned the ASCII character code of the character. To get the old behavior in modern Ruby, you can use the #ord method:
?F.ord # => will return 70
It's a convention in Ruby that methods that return boolean values end in a question mark. There's no more significance to it than that.
In your example it's just part of the method name. In Ruby you can also use exclamation points in method names!
Another example of question marks in Ruby would be the ternary operator.
customerName == "Fred" ? "Hello Fred" : "Who are you?"
It may be worth pointing out that ?s are only allowed in method names, not variables. In the process of learning Ruby, I assumed that ? designated a boolean return type so I tried adding them to flag variables, leading to errors. This led to me erroneously believing for a while that there was some special syntax involving ?s.
Relevant: Why can't a variable name end with `?` while a method name can?
In your example
product.valid?
Is actually a function call and calls a function named valid?. Certain types of "test for condition"/boolean functions have a question mark as part of the function name by convention.
I believe it's just a convention for things that are boolean. A bit like saying "IsValid".
It's also used in regular expressions, meaning "at most one repetition of the preceding character"
for example the regular expression /hey?/ matches with the strings "he" and "hey".
It's also a common convention to use with the first argument of the test method from Kernel#test
test ?d, "/dev" # directory exists?
# => true
test ?-, "/etc/hosts", "/etc/hosts" # are the files identical
# => true
as seen in this question here

Resources