What Can a Ruby Symbol (Syntax) Contain

What can a ruby symbol (syntax) contain?

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

Ruby Syntax, using numbers in symbols?

If you want to start a symbol with a digit, you need to enclose it in quotes:

:'2grok' => ['Hi']

If you use double quotes, ruby interpolates string inside:

:"#{1 + 1}grok"

Also, you can use percent-notation:

%s{2grok}

Finally, you can get the symbol by calling to_sym method on a String:

'2grok'.to_sym => ['Hi']

Need explanation of some Ruby syntax

  1. The colon character (:) is the beginning of a syntax literal for a Ruby "Symbol":

    :abc.class # => Symbol
    "abc".to_sym # => :abc

    Symbols are like strings but they are "interned", meaning the Ruby interpreter only has a single copy of it in memory despite multiple possible references (whereas there can be many equivalent strings in memory at once).

  2. The 'validates' token in your example above is a class method (of something in the class hierarchy of the "Post class") that is being called with a symbol argument (:name) and a hash argument with a single key/value pair of :presence => true.

  3. The 'create_table' token is a method which is being called with a single argument (the symbol ":posts") and is given a block which takes a single argument "t" (do |t| ... end).

Syntax for symbol literal

A Symbol is defined in Ruby as an "internalized string", or in other words, a string singleton of sorts. They have some interesting properties, but most importantly they have very minimal memory impact.

Any given symbol, like :example, is the same object as every other instance of that symbol. This is not the case for strings where "example" and "example" might be identical in terms of content, yet in terms of objects are different. Ruby identifies objects by their internal object_id:

"example".object_id == "example".object_id
# => false
:example.object_id == :example.object_id
# => true

This makes them ideal for use in hashes as keys, for flags where memory efficiency and performance are concerns.

Comparing two symbols is very easy. They're either the same object or not. For strings a lot of additional work is required to evaluate if they're identical or not, each character needs to be compared, and as they can contain arbitrary UTF or binary data, this is not always simple.

The one thing to note is you should only use symbols where you'd otherwise type something in, that "symbolizing" arbitrary values is wasteful. For example, if your hash contains a UUID as a key, something that's unlikely to ever duplicate, store it as a string. Each symbol, generally speaking, stays in Ruby memory for the duration of the program, so you pay a small one-time cost for the symbol itself.

This cost can add up if you declare millions of them, though. If the symbol is only ever used once that could cause a lot of excess memory use, defeating the purpose.

Is { 'symbol name': some value } valid Ruby 2 syntax for Hashes?

{ :my_key => "my value" } 
{ my_key: "my value" }
{ :'my_key' => "my value" }
{ :"my_key" => "my value" }

None of the above lines uses 2.x-only syntax. They are all also valid 1.9 syntax. (See demonstration.)

{ "my_key": "my value" }
{ 'my_key': "my value" }

That's feature request #4276 which landed in 2.2. That means it's invalid syntax in 2.1 or even older versions. It also means that an implementation that claims to implement 2.2 has to support it.

How to represent a value with symbol in ruby?

I think you are confused about the use of symbols by some of the conventions in Ruby and Rails.

Symbols are not variables. Variables are used to store values. Symbols are lighter weight versions of strings. They can be used in place of strings in places like hash keys.

hash1 = {'name' => 'Mary', 'age' => 30}
puts hash1['name']
#=> 'Mary'

hash2 = {:name => 'John', :age => 32}
puts hash2[:age]
#=> '32'

Ruby introduced a new hash notation to make things cleaner when using symbols for hash notation that eliminated the "hash rocket" =>

hash2 = {name: 'John', age: 32}

To take advantage of the conventions in Rails they came up with "hash with indifferent access". So it is a hash that allows you to use either a string or its symbol version interchangeably in a hash:

hash2 = = ActiveSupport::HashWithIndifferentAccess.new
hash2['name'] = 'John'
puts hash2[:name]
#=> 'John'
puts hash2['name']
#=> 'John'

In Rails you assign values to columns in a table using symbols:

p = Person.new(name: 'John', age: '32')

you then access them through method names that are string versions of the column name:

puts p.name
#=> 'John'

I think you are missing some real foundations of Ruby. I would study that more and then maybe do one of the tutorials that involves rebuilding Rails so you see how the syntax of Ruby relates to the conventions in Rails.

Ruby symbol syntax with strings ex a-b: d

Because Matz decided against it:

Iff {'key': 'value'} means {:key => 'value'} I have no objection.

[but later on...]

The discussion has gone away in the wind without making any consensus.
So I marked this 'rejected'. My point is clearly stated in the first comment.

Cited from https://bugs.ruby-lang.org/issues/4801

Confused about the million ways to reach inside Ruby Hash with the symbol sign

Rule of thumb

If there's a colon (:) it's a Symbol. If there's a hashrocket (=>), it's whatever is to the left of the hashrocket (which can be anything).

Declaring keys in a Hash literal

When we say "Hash literal" we mean code that declares a Hash with curly braces ({ foo: 1 }) or as method arguments (bar(baz: 2)).

There are two ways to declare a key in a Hash literal.

Keys with hashrockets (=>)

The first way to declare a key is with the hashrocket (=>). When you use the hashrocket, the key is whatever value is to the left of it, and you can put any kind of object (or expression) to the left of it:

hashrocket_hash = {
"I am a String" => 1,
:I_am_a_Symbol => 2,
:"I am also a Symbol" => 4,
/I am a Regexp!/ => 5,
Kernel => 6,
if true then "I am also a String" end => 7,
nil => 8
}

p hashrocket_hash.keys
# => [ "I am a String",
# :I_am_a_Symbol,
# :"I am also a Symbol",
# /I am a Regexp!/,
# Kernel,
# "I am also a String",
# nil
# ]

p hashrocket_keys.map(&:class)
# => [ String,
# Symbol,
# Symbol,
# Regexp,
# Module,
# String,
# NilClass
# ]

Keys with colons (:)

The other way to declare a key is with a colon (:). When you use a colon the resulting key is always a Symbol. The usual Symbol rules apply (read the very thorough answer here: What can a ruby symbol (syntax) contain?) except the colon goes at the end instead of the beginning:

colon_hash = {
I_am_a_Symbol: 9,
"I am also a Symbol": 10
}

p colon_hash.keys
# => [ :I_am_a_Symbol,
# :"I am also a Symbol" ]

p colon_hash.keys.map(&:class)
# => [ Symbol,
# Symbol ]

Accessing a Hash value

There are no special rules for accessing a Hash value. If you want to access a value whose key is a Symbol, you must use a Symbol. If you want to access a value whose key is a String, you must use a String. If the key is something else, you must use that thing.

In the below examples, pay close attention to which keys are followed by colons and which are followed by hashrockets:

hsh1 = { foo: 1 }
p hsh1[:foo] # => 1
p hsh1[:"foo"] # => 1
p hsh1["foo"] # => nil

hsh2 = { "bar": 2 }
p hsh2[:bar] # => 2
p hsh2[:"bar"] # => 2
p hsh2["bar"] # => nil

hsh3 = {
Kernel: 3,
Kernel => 4
}
p hsh3[:Kernel] # => 3
p hsh3[Kernel] # => 4
p hsh3["Kernel"] # => nil

Understanding Ruby variables and symbols?

Variables starting with @ are instance variables, "properties" in other languages. Whereas 'classic' variables are local to the scope of their method/block, instance variables are local to a specific instance of an object, for example:

class Foo

def initialize(bar)
@bar = bar
end

def bar
@bar # the variable is specific to this instance
end

def buzz
buzz = 'buzz' # this variable is not accessible outside of this method
end

end

You may also see variables starting with @@, which are class variables, and are accessible by every instance of the class and shared with every instance of the subclass. Usage of those variables is usually discouraged, primarily because subclasses share the variable, which can cause a lot of mess.

In Ruby everything is an object, classes are objects (instances of class Class), so you can also have class instance variables:

class Foo

def self.bar
@bar #we are in class Foo's scope, which is an instance of class Class
end

def self.bar=(bar)
@bar = bar
end

def bar
@bar # Foo.new.bar != Foo.bar
end

end

What you call "variables with a colon" are not variables. They are a particular type of string, called a symbol, that is immutable and optimized for quick identification by the interpreter, in fact, those are stored internally as pointers, so that :this == :this is a very quick operation.

This property makes them good candidates for hash keys because they offer quick retrieval or for "flags" to pass to a method; Think of them as a sort of loose constant that "stands for" what they say. Their immutability is also dangerous: All symbols ever created never get garbage collected; It's easy to create a memory-leak by creating thousands of symbols, so use them wisely.

UPDATE since ruby 2.2 symbols may be garbage-collected in certain cases (when no reference is kept and no comparison is needed)



Related Topics



Leave a reply



Submit