public
Fork of NZKoz/koz-rails
Description: Koz's rails git-svn clone
Homepage: http://www.rubyonrails.org
Clone URL: git://github.com/eventualbuddha/koz-rails.git
Search Repo:
initial experimental commit of active_model

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8118 
5ecf4fe2-1ee6-0310-87b1-e25e094e27de
rick (author)
Fri Nov 09 06:59:15 -0800 2007
commit  d74b50f182914bb44d1ab2b5ba2fe410494460cd
tree    855cfa84f7002222dff496a4f8247447463045e7
parent  1ed37692df40f5b97a935e32eb3e70f51df86746
...
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
0
@@ -1 +1,13 @@
0
+Changes from extracting bits to ActiveModel
0
+
0
+* ActiveModel::Observer#add_observer!
0
+
0
+ It has a custom hook to define after_find that should really be in a
0
+ ActiveRecord::Observer subclass:
0
+
0
+   def add_observer!(klass)
0
+   klass.add_observer(self)
0
+   klass.class_eval 'def after_find() end' unless
0
+        klass.respond_to?(:after_find)
0
+   end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0
@@ -1 +1,22 @@
0
+Active Model
0
+==============
0
+
0
+Totally experimental library that aims to extract common model mixins from
0
+ActiveRecord for use in ActiveResource (and other similar libraries).
0
+This is in a very rough state (no autotest or spec rake tasks set up yet),
0
+so please excuse the mess.
0
+
0
+Here's what I plan to extract:
0
+ * ActiveModel::Observing
0
+ * ActiveModel::Callbacks
0
+ * ActiveModel::Validations
0
+
0
+  # for ActiveResource params and ActiveRecord options
0
+ * ActiveModel::Scoping
0
+
0
+  # to_json, to_xml, etc
0
+ * ActiveModel::Serialization
0
+
0
+I'm trying to keep ActiveRecord compatibility where possible, but I'm
0
+annotating the spots where I'm diverging a bit.
...
 
 
 
 
...
1
2
3
4
0
@@ -1 +1,5 @@
0
+#!/usr/bin/env ruby
0
+$LOAD_PATH << File.join(File.dirname(__FILE__), 'vendor', 'rspec', 'lib')
0
+require 'rake'
0
+require 'spec/rake/spectask'
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0
@@ -1 +1,18 @@
0
+$LOAD_PATH << File.join(File.dirname(__FILE__), '..', '..', 'activesupport', 'lib')
0
+
0
+# premature optimization?
0
+require 'active_support/inflector'
0
+require 'active_support/core_ext/string/inflections'
0
+String.send :include, ActiveSupport::CoreExtensions::String::Inflections
0
+
0
+require 'active_model/base'
0
+require 'active_model/observing'
0
+require 'active_model/callbacks'
0
+require 'active_model/validations'
0
+
0
+ActiveModel::Base.class_eval do
0
+ include ActiveModel::Observing
0
+ include ActiveModel::Callbacks
0
+ include ActiveModel::Validations
0
+end
...
 
 
 
 
...
1
2
3
4
0
@@ -1 +1,5 @@
0
+module ActiveModel
0
+ class Base
0
+ end
0
+end
...
 
 
 
 
 
...
1
2
3
4
5
0
@@ -1 +1,6 @@
0
+module ActiveModel
0
+ module Callbacks
0
+
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
0
@@ -1 +1,101 @@
0
+require 'observer'
0
+
0
+module ActiveModel
0
+ module Observing
0
+ module ClassMethods
0
+ def observers
0
+ @observers ||= []
0
+ end
0
+
0
+ def observers=(*values)
0
+ @observers = values.flatten
0
+ end
0
+
0
+ def instantiate_observers
0
+ observers.each { |o| instantiate_observer(o) }
0
+ end
0
+
0
+ protected
0
+ def instantiate_observer(observer)
0
+ # string/symbol
0
+ if observer.respond_to?(:to_sym)
0
+ observer = observer.to_s.camelize.constantize.instance
0
+ elsif observer.respond_to?(:instance)
0
+ observer.instance
0
+ else
0
+ raise ArgumentError, "#{observer} must be a lowercase, underscored class name (or an instance of the class itself) responding to the instance method. Example: Person.observers = :big_brother # calls BigBrother.instance"
0
+ end
0
+ end
0
+
0
+ # Notify observers when the observed class is subclassed.
0
+ def inherited(subclass)
0
+ super
0
+ changed
0
+ notify_observers :observed_class_inherited, subclass
0
+ end
0
+ end
0
+
0
+ def self.included(receiver)
0
+ receiver.extend Observable, ClassMethods
0
+ end
0
+ end
0
+
0
+ class Observer
0
+ include Singleton
0
+ attr_writer :observed_classes
0
+
0
+ class << self
0
+ attr_accessor :models
0
+ # Attaches the observer to the supplied model classes.
0
+ def observe(*models)
0
+ @models = models.flatten
0
+ @models.collect! { |model| model.respond_to?(:to_sym) ? model.to_s.camelize.constantize : model }
0
+ end
0
+
0
+ def observed_class_name
0
+ @observed_class_name ||=
0
+ if guessed_name = name.scan(/(.*)Observer/)[0]
0
+ @observed_class_name = guessed_name[0]
0
+ end
0
+ end
0
+
0
+ # The class observed by default is inferred from the observer's class name:
0
+ # assert_equal [Person], PersonObserver.observed_class
0
+ def observed_class
0
+ if observed_class_name
0
+ observed_class_name.constantize
0
+ else
0
+ nil
0
+ end
0
+ end
0
+ end
0
+
0
+ # Start observing the declared classes and their subclasses.
0
+ def initialize
0
+ self.observed_classes = self.class.models if self.class.models
0
+ observed_classes.each { |klass| add_observer! klass }
0
+ end
0
+
0
+ # Send observed_method(object) if the method exists.
0
+ def update(observed_method, object) #:nodoc:
0
+ send(observed_method, object) if respond_to?(observed_method)
0
+ end
0
+
0
+ # Special method sent by the observed class when it is inherited.
0
+ # Passes the new subclass.
0
+ def observed_class_inherited(subclass) #:nodoc:
0
+ self.class.observe(observed_classes + [subclass])
0
+ add_observer!(subclass)
0
+ end
0
+
0
+ protected
0
+ def observed_classes
0
+ @observed_classes ||= [self.class.observed_class]
0
+ end
0
+
0
+ def add_observer!(klass)
0
+ klass.add_observer(self)
0
+ end
0
+ end
0
+end
...
 
 
 
 
...
1
2
3
4
0
@@ -1 +1,5 @@
0
+module ActiveModel
0
+ module Validations
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
0
@@ -1 +1,121 @@
0
+require File.join(File.dirname(__FILE__), 'spec_helper')
0
+
0
+class ObservedModel < ActiveModel::Base
0
+ class Observer
0
+ end
0
+end
0
+
0
+class FooObserver < ActiveModel::Observer
0
+ class << self
0
+ public :new
0
+ end
0
+
0
+ attr_accessor :stub
0
+
0
+ def on_spec(record)
0
+ stub.event_with(record) if stub
0
+ end
0
+end
0
+
0
+class Foo < ActiveModel::Base
0
+end
0
+
0
+module ActiveModel
0
+ describe Observing do
0
+ before do
0
+ ObservedModel.observers.clear
0
+ end
0
+
0
+ it "initializes model with no cached observers" do
0
+ ObservedModel.observers.should be_empty
0
+ end
0
+
0
+ it "stores cached observers in an array" do
0
+ ObservedModel.observers << :foo
0
+ ObservedModel.observers.should include(:foo)
0
+ end
0
+
0
+ it "flattens array of assigned cached observers" do
0
+ ObservedModel.observers = [[:foo], :bar]
0
+ ObservedModel.observers.should include(:foo)
0
+ ObservedModel.observers.should include(:bar)
0
+ end
0
+
0
+ it "instantiates observer names passed as strings" do
0
+ ObservedModel.observers << 'foo_observer'
0
+ FooObserver.should_receive(:instance)
0
+ ObservedModel.instantiate_observers
0
+ end
0
+
0
+ it "instantiates observer names passed as symbols" do
0
+ ObservedModel.observers << :foo_observer
0
+ FooObserver.should_receive(:instance)
0
+ ObservedModel.instantiate_observers
0
+ end
0
+
0
+ it "instantiates observer classes" do
0
+ ObservedModel.observers << ObservedModel::Observer
0
+ ObservedModel::Observer.should_receive(:instance)
0
+ ObservedModel.instantiate_observers
0
+ end
0
+
0
+ it "should pass observers to subclasses" do
0
+ FooObserver.instance
0
+ bar = Class.new(Foo)
0
+ bar.count_observers.should == 1
0
+ end
0
+ end
0
+
0
+ describe Observer do
0
+ before do
0
+ ObservedModel.observers = :foo_observer
0
+ FooObserver.models = nil
0
+ end
0
+
0
+ it "guesses implicit observable model name" do
0
+ FooObserver.observed_class_name.should == 'Foo'
0
+ end
0
+
0
+ it "tracks implicit observable models" do
0
+ instance = FooObserver.new
0
+ instance.send(:observed_classes).should include(Foo)
0
+ instance.send(:observed_classes).should_not include(ObservedModel)
0
+ end
0
+
0
+ it "tracks explicit observed model class" do
0
+ FooObserver.new.send(:observed_classes).should_not include(ObservedModel)
0
+ FooObserver.observe ObservedModel
0
+ instance = FooObserver.new
0
+ instance.send(:observed_classes).should include(ObservedModel)
0
+ end
0
+
0
+ it "tracks explicit observed model as string" do
0
+ FooObserver.new.send(:observed_classes).should_not include(ObservedModel)
0
+ FooObserver.observe 'observed_model'
0
+ instance = FooObserver.new
0
+ instance.send(:observed_classes).should include(ObservedModel)
0
+ end
0
+
0
+ it "tracks explicit observed model as symbol" do
0
+ FooObserver.new.send(:observed_classes).should_not include(ObservedModel)
0
+ FooObserver.observe :observed_model
0
+ instance = FooObserver.new
0
+ instance.send(:observed_classes).should include(ObservedModel)
0
+ end
0
+
0
+ it "calls existing observer event" do
0
+ foo = Foo.new
0
+ FooObserver.instance.stub = stub!(:stub)
0
+ FooObserver.instance.stub.should_receive(:event_with).with(foo)
0
+ Foo.send(:changed)
0
+ Foo.send(:notify_observers, :on_spec, foo)
0
+ end
0
+
0
+ it "skips nonexistent observer event" do
0
+ foo = Foo.new
0
+ Foo.send(:changed)
0
+ Foo.send(:notify_observers, :whatever, foo)
0
+ end
0
+ end
0
+end
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
0
@@ -1 +1,18 @@
0
+ENV['LOG_NAME'] = 'spec'
0
+$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'vendor', 'rspec', 'lib')
0
+$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
0
+require 'active_model'
0
+begin
0
+ require 'spec'
0
+rescue LoadError
0
+ require 'rubygems'
0
+ require 'spec'
0
+end
0
+
0
+begin
0
+ require 'ruby-debug'
0
+ Debugger.start
0
+rescue LoadError
0
+ # you do not know the ways of ruby-debug yet, what a shame
0
+end

Comments

    No one has commented yet.