freeze-ray 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +3 -0
- data/README.markdown +65 -0
- data/VERSION.yml +4 -0
- data/lib/freeze_ray.rb +9 -0
- data/spec/freeze_ray_spec.rb +41 -0
- metadata +58 -0
data/History.txt
ADDED
data/README.markdown
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
Freeze Ray
|
2
|
+
==========
|
3
|
+
|
4
|
+
> "With my freeze ray I will stop the pain." --Dr. Horrible
|
5
|
+
|
6
|
+
The problem
|
7
|
+
-----------
|
8
|
+
|
9
|
+
ActiveRecord's dirty tracking feature is broken. Awesome, but broken. Let me demonstrate.
|
10
|
+
|
11
|
+
>> p = Post.last
|
12
|
+
=> #<Post id: 261, ... >
|
13
|
+
>> p.title
|
14
|
+
=> "A quick update"
|
15
|
+
>> p.changes
|
16
|
+
=> {}
|
17
|
+
>> p.title << " about my pet frogs"
|
18
|
+
=> "A quick update about my pet frogs"
|
19
|
+
>> p.changes
|
20
|
+
=> {}
|
21
|
+
|
22
|
+
Hang on, now! We changed the title! Why didn't we see this?
|
23
|
+
|
24
|
+
=> {"title"=>["A quick update", "A quick update about my pet frogs"]}
|
25
|
+
|
26
|
+
Because ActiveRecord doesn't have any way of knowing that we changed the attribute. That's because we **mutated it in place**. Rather than replace the string with a new one, *we changed the one it already had*. That doesn't involve calling `#title=` on the Post, so the Post doesn't realize that the actual value changed.
|
27
|
+
|
28
|
+
ActiveRecord provides one solution: call `#title_will_change!` first. That tells the Post to remember the current value of the title to compare to the old one. Observe:
|
29
|
+
|
30
|
+
>> p.title << " whom I love dearly"
|
31
|
+
=> "A quick update about my pet frogs whom I love dearly"
|
32
|
+
>> p.changes
|
33
|
+
=> {"title"=>["A quick update about my pet frogs", "A quick update about my pet frogs whom I love dearly"]}
|
34
|
+
|
35
|
+
Well, sure, that works. But you have to be careful. What if you forget to that at some point?
|
36
|
+
|
37
|
+
|
38
|
+
Another Solution
|
39
|
+
----------------
|
40
|
+
|
41
|
+
Freeze Ray offers another solution. Just mark the attributes you want to track as `attr_frozen`:
|
42
|
+
|
43
|
+
class Post < ActiveRecord::Base
|
44
|
+
attr_frozen :title
|
45
|
+
end
|
46
|
+
|
47
|
+
Now try to mess up dirty tracking:
|
48
|
+
|
49
|
+
>> p = Post.last
|
50
|
+
=> #<Post id: 261, ... >
|
51
|
+
>> p.title
|
52
|
+
=> "A quick update"
|
53
|
+
>> p.title << " about my pet frogs"
|
54
|
+
TypeError: can't modify frozen string
|
55
|
+
from (irb):36:in `<<'
|
56
|
+
from (irb):36
|
57
|
+
>> p.title
|
58
|
+
=> "A quick update"
|
59
|
+
>> p.title.frozen?
|
60
|
+
=> true
|
61
|
+
|
62
|
+
You can't do it!
|
63
|
+
|
64
|
+
Obviously, this isn't very useful in a case where you need to change attribute objects in place. On the other hand, I can't think of a reason you'd *want* to change them in place. Now, if you try, you'll know.
|
65
|
+
|
data/VERSION.yml
ADDED
data/lib/freeze_ray.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
$LOAD_PATH << File.dirname(__FILE__) + "/../lib"
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'acts_as_fu'
|
5
|
+
require 'spec'
|
6
|
+
|
7
|
+
Spec::Runner.configure do |config|
|
8
|
+
config.include ActsAsFu
|
9
|
+
end
|
10
|
+
|
11
|
+
require File.dirname(__FILE__) + "/../rails/init"
|
12
|
+
|
13
|
+
|
14
|
+
describe "attr_frozen" do
|
15
|
+
before(:each) do
|
16
|
+
build_model :things do
|
17
|
+
string :string_attribute, :default => "foobar"
|
18
|
+
string :serialized_attribute
|
19
|
+
serialize :serialized_attribute
|
20
|
+
|
21
|
+
# Turn off acts_as_foo's method_missing extension for schema
|
22
|
+
# definition. For some reason, it delegates #define_method to
|
23
|
+
# the table definition.
|
24
|
+
class << self
|
25
|
+
alias_method :method_missing, :method_missing_without_columns
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_frozen :string_attribute, :serialized_attribute
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "freezes attributes which are" do
|
33
|
+
before do
|
34
|
+
@thing = Thing.new(:string_attribute => "foobar",
|
35
|
+
:serialized_attribute => [:a, :b, :c])
|
36
|
+
end
|
37
|
+
|
38
|
+
specify("strings") { @thing.string_attribute.should be_frozen }
|
39
|
+
specify("serialized") { @thing.serialized_attribute.should be_frozen }
|
40
|
+
end
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: freeze-ray
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Peter Jaros
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-29 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Fixes ActiveRecord's dirty tracking. Provides an attr_frozen macro which causes an attribute to be returned frozen.
|
17
|
+
email: peter.a.jaros@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- History.txt
|
26
|
+
- README.markdown
|
27
|
+
- VERSION.yml
|
28
|
+
- lib/freeze_ray.rb
|
29
|
+
- spec/freeze_ray_spec.rb
|
30
|
+
has_rdoc: true
|
31
|
+
homepage:
|
32
|
+
post_install_message:
|
33
|
+
rdoc_options:
|
34
|
+
- --inline-source
|
35
|
+
- --charset=UTF-8
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: "0"
|
43
|
+
version:
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: "0"
|
49
|
+
version:
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
rubyforge_project: freeze-ray
|
53
|
+
rubygems_version: 1.3.1
|
54
|
+
signing_key:
|
55
|
+
specification_version: 2
|
56
|
+
summary: Fixes ActiveRecord's dirty tracking.
|
57
|
+
test_files: []
|
58
|
+
|