Ruby freeze method
freeze
- prevents modification to the Hash (returns the frozen object)[]
- accesses a value from the hashstat.class.name.underscore.to_sym
- I assume this returns a lowercase, snake case version of the given object's class name (underscore
is not in the standard library, so I'm not completely sure)call
invokes the lambda associated withstat.class.name.underscore.to_sym
key.
For instance, passing ['foo', 'bar']
as the argument to track_for
would invoke the send(stat[0], stat[1])
lambda.
How to freeze just part of an array or string?
Just because a string is frozen doesn't mean it can't be moved somewhere else in an array. Freezing an object just prevents the object itself from being modified.
What I would do is take out the element that you don't want to move, rotate the array, then put it back in at the same index after the rotation, like this:
arr = ['a', 'b', 'c', 'd', 'e']
index = 0
item = arr.delete_at(index)
arr.rotate!
arr.insert(index, item)
After that arr will be ["a", "c", "d", "e", "b"]
Freezing variables in Ruby doesn't work
You freeze objects, not variables, i.e. you can't update a frozen object but you can assign a new object to the same variable. Consider this:
a = [1,2,3]
a.freeze
a << 4
# RuntimeError: can't modify frozen Array
# `b` and `a` references the same frozen object
b = a
b << 4
# RuntimeError: can't modify frozen Array
# You can replace the object referenced by `a` with an unfrozen one
a = [4, 5, 6]
a << 7
# => [4, 5, 6, 7]
As an aside: it is quite useless to freeze Fixnum
s, since they are immutable objects.
How to unfreeze an object in Ruby?
No, according to the documentation for Object#freeze
:
There is no way to unfreeze a frozen object.
The frozen state is stored within the object. Calling freeze
sets the frozen state and thereby prevents further modification. This includes modifications to the object's frozen state.
Regarding your example, you could assign a new string instead:
script = 'Do you want to build a snowman?'
script.freeze
script = script.dup if script.frozen?
script[/snowman/] = 'castle of ice'
script #=> "Do you want to build a castle of ice?"
Ruby 2.3 introduced String#+@
, so you can write +str
instead of str.dup if str.frozen?
What is the use or effect of freezing Symbols and Numbers in Ruby?
The answer is no. Those data types are immutable. There is no reason to freeze those datatypes. The reason Ruby does not report those datatypes as frozen is because the obj.frozen?
method returns the freeze status of the object and it is set to false
initially for immutable datatypes. Calling obj.freeze
will set the freeze
status to true
for that object.
The bottom line is that calling freeze
on an immutable datatype sets the freeze
status of the obj to true
, but does nothing because the object is already immutable.
Freeze in Python?
You could always subclass list
and add the "frozen" flag which would block __setitem__
doing anything:
class freezablelist(list):
def __init__(self,*args,**kwargs):
list.__init__(self, *args)
self.frozen = kwargs.get('frozen', False)
def __setitem__(self, i, y):
if self.frozen:
raise TypeError("can't modify frozen list")
return list.__setitem__(self, i, y)
def __setslice__(self, i, j, y):
if self.frozen:
raise TypeError("can't modify frozen list")
return list.__setslice__(self, i, j, y)
def freeze(self):
self.frozen = True
def thaw(self):
self.frozen = False
Then playing with it:
>>> from freeze import freezablelist as fl
>>> a = fl([1,2,3])
>>> a[1] = 'chicken'
>>> a.freeze()
>>> a[1] = 'tuna'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "freeze.py", line 10, in __setitem__
raise TypeError("can't modify frozen list")
TypeError: can't modify frozen list
>>> a[1:1] = 'tuna'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "freeze.py", line 16, in __setslice__
raise TypeError("can't modify frozen list")
TypeError: can't modify frozen list
>>>
Freezing HashWithIndifferentAccess in Ruby
So we're looking at how the nested hash behaves differently between
v_1 = { a: { b: 2 } }.with_indifferent_access
v_2 = { a: { b: 2 }.with_indifferent_access }.with_indifferent_access
When you call Hash#with_indifferent_access, it creates a new ActiveSupport::HashWithIndifferentAccess
object; and then calls #update
to insert all of the key/value pairs from the original hash into the new object (ActiveSupport::HashWithIndifferentAccess#update), which calls #convert_values
with the nested hash:
def convert_value(value, options = {})
if value.is_a? Hash
if options[:for] == :to_hash
value.to_hash
else
value.nested_under_indifferent_access
end
...
So both { b: 2 }
and { b: 2 }.with_indifferent_access
will have #nested_under_indifferent_access
called on them. But that’s a different method for Hash than it is for HashWithIndifferentAccess. In the core_ext file, Hash#nested_under_indifferent_access
calls HashWithIndifferentAccess.new(self)
, but HashWithIndifferentAccess#nested_under_indifferent_access
just returns self
.
So {'b' => 2}.nested_under_indifferent_access
returns a new object, but {'b' => 2}.with_indifferent_access.nested_under_indifferent_access
doesn’t do anything to the object. Which is why if the first one is frozen, you get back a different (unfrozen by default) object, and if the second one is frozen, it stays frozen.
Related Topics
Heroku: Pg::Connectionbad: Could Not Connect to Server: Connection Refused
Breaking a Large Rails App into Smaller Apps
Rvm Install 1.9.2 Fails When Running Autoconf
Ruby: How to Join Elements of an Array Together with a Prefix
I Can't Remove Whitespaces from a String Parsed by Nokogiri
Single Custom Param Name in Routes for Nested Resources Rails 4.1
Rounding a Float to the Nearest Integer in Ruby
Using Rubyzip to Add Files and Nested Directories to a Zipoutputstream
When Do You Need to Pass Arguments to 'Thread.New'
Anything Speaking Against the Bitnami.Org Ruby/Rails/Redmine Stack
Converting Time in Utc to Pacific Time
Rails 3.1 Rspec Creating Test Case Validate Field for Model
What's The Most Efficient Way Get The First Day of The Current Month
What's the Efficient Way to Multiply Two Arrays and Get Sum of Multiplied Values in Ruby
Form_For with Multiple Controller Actions for Submit