sam / dm-core

DataMapper - Core

This URL has Read+Write access

dm-core / lib / data_mapper / associations / many_to_one.rb
100644 89 lines (70 sloc) 3.024 kb
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
module DataMapper
  module Associations
    module ManyToOne
      OPTIONS = [ :class_name, :child_key, :parent_key, :min, :max ]
 
      private
 
      def many_to_one(name, options = {})
        raise ArgumentError, "+name+ should be a Symbol, but was #{name.class}", caller unless Symbol === name
        raise ArgumentError, "+options+ should be a Hash, but was #{options.class}", caller unless Hash === options
 
        if (unknown_options = options.keys - OPTIONS).any?
          raise ArgumentError, "+options+ contained unknown keys: #{unknown_options * ', '}"
        end
 
        child_model_name = DataMapper::Inflection.demodulize(self.name)
        parent_model_name = options[:class_name] || DataMapper::Inflection.classify(name)
 
        relationship = relationships(repository.name)[name] = Relationship.new(
          name,
          repository.name,
          child_model_name,
          parent_model_name,
          options
        )
 
        class_eval <<-EOS, __FILE__, __LINE__
def #{name}
#{name}_association
end
 
def #{name}=(parent_resource)
#{name}_association.replace(parent_resource)
end
 
private
 
def #{name}_association
@#{name}_association ||= begin
relationship = self.class.relationships(repository.name)[:#{name}]
association = Proxy.new(relationship, self)
child_associations << association
association
end
end
EOS
 
        relationship
      end
 
      class Proxy
        instance_methods.each { |m| undef_method m unless %w[ __id__ __send__ class kind_of? should should_not ].include?(m) }
 
        def replace(parent_resource)
          @parent_resource = parent_resource
          @relationship.attach_parent(@child_resource, @parent_resource) if @parent_resource.nil? || !@parent_resource.new_record?
        end
 
        def save
          if parent.new_record?
            repository(@relationship.repository_name) do
              parent.save
              @relationship.attach_parent(@child_resource, parent)
            end
          end
        end
 
        private
 
        def initialize(relationship, child_resource)
# raise ArgumentError, "+relationship+ should be a DataMapper::Association::Relationship, but was #{relationship.class}", caller unless Relationship === relationship
# raise ArgumentError, "+child_resource+ should be a DataMapper::Resource, but was #{child_resource.class}", caller unless Resource === child_resource
 
          @relationship = relationship
          @child_resource = child_resource
        end
 
        def parent
          @parent_resource ||= @relationship.get_parent(@child_resource)
        end
 
        def method_missing(method, *args, &block)
          parent.__send__(method, *args, &block)
        end
      end # class Proxy
    end # module ManyToOne
  end # module Associations
end # module DataMapper