Symbol literal or a method - ruby

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.

Related

Why does to_sym behave differently?

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"

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.

Why do parentheses affect hashes?

When I used respond_with and passed a literal hash, it gave me the error:
syntax error, unexpected tASSOC, expecting '}'
`respond_with {:status => "Not found"}`
However, when I enclosed the literal hash in parentheses like so:
respond_with({:status => "Not found"})
the function runs without a hitch. Why do the parentheses make a difference? Isn't a hash an enclosed call?
When calling a method, the opening curly bracket directly after the method name is interpreted as the start of a block. This has precedence over the interpretation as a hash. One way to circumvent the issue is to use parenthesis to enforce the interpretation as a method argument. As an example, please note the difference in meaning of these two method calls:
# interpreted as a block
[:a, :b, :c].each { |x| puts x }
# interpreted as a hash
{:a => :b}.merge({:c => :d})
Another way is to just get rid of the curly brackets as you can always skip the brackets on the last argument of a method. Ruby is "clever" enough to interpret everything which looks like an association list at the end of an argument list as a single hash. Please have a look at this example:
def foo(a, b)
puts a.inspect
puts b.inspect
end
foo "hello", :this => "is", :a => "hash"
# prints this:
# "hello"
# {:this=>"is", :a=>"hash"}

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

What is the colon 'operator' doing in this example?

I saw this example in an answer elsewhere and with the following it outputs foobar:
a = :foo
def bar(b)
:"#{b}bar"
end
c = bar(a)
c
The colon isn't an operator inside bar, it is simply a Symbol literal that uses string interpolation to build the Symbol. Some Symbols need to be quoted to avoid syntax issues, for example:
:'a+b'
You can also use double quotes with this syntax and those quotes behave just like double quotes for strings so they support string interpolation. So this:
:"#{b}bar"
is equivalent to:
"#{b}bar".to_sym
or
(b.to_s + 'bar').to_sym
If you #inspect your value you'll get a better idea of what it contains:
puts c.inspect
# :foobar

Resources