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.
@@ -0,0 +1,3 @@
1
+ === 0.4.0 :: 2009-05-29
2
+
3
+ * Initial release.
@@ -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
+
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 0
3
+ :patch: 1
4
+ :major: 0
@@ -0,0 +1,9 @@
1
+ module FreezeRay
2
+ def attr_frozen(*attrs)
3
+ attrs.each do |attr|
4
+ define_method(attr) do
5
+ super.freeze
6
+ end
7
+ end
8
+ end
9
+ end
@@ -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
+