Class: DataMapper::EmbeddedValue

Inherits:
Object
  • Object
show all
Defined in:
lib/data_mapper/embedded_value.rb

Constant Summary collapse

EMBEDDED_PROPERTIES =
[]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(instance) ⇒ EmbeddedValue

Returns a new instance of EmbeddedValue.



6
7
8
9
10
11
12
# File 'lib/data_mapper/embedded_value.rb', line 6

def initialize(instance)
  @instance = instance
  @container_prefix = ''

  # force lazy load on access to any lazy-loaded embed property
  @instance.lazy_load!(*self.class::EMBEDDED_PROPERTIES) # if @container_lazy
end

Class Method Details

.containing_classObject



71
72
73
74
75
76
77
# File 'lib/data_mapper/embedded_value.rb', line 71

def self.containing_class
  @containing_class || @containing_class = begin
    tree = name.split('::')
    tree.pop
    tree.inject(Object) { |klass, current| klass.const_get(current) }
  end
end

.define(container, name, options, &block) ⇒ Object



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
# File 'lib/data_mapper/embedded_value.rb', line 79

def self.define(container, name, options, &block)
  embedded_class, embedded_class_name, accessor_name = nil

  accessor_name = name.to_s
  embedded_class_name = Inflector.camelize(accessor_name)
  embedded_class = Class.new(EmbeddedValue)
  container.const_set(embedded_class_name, embedded_class) unless container.const_defined?(embedded_class_name)

  if options[:prefix]
    container_prefix = options[:prefix].kind_of?(String) ? options[:prefix] : "#{accessor_name}_"
    embedded_class.instance_variable_set('@container_prefix', container_prefix)
  end

  embedded_class.instance_variable_set('@containing_class', container)

  embedded_class.instance_variable_set('@container_lazy', !!options[:lazy])
  embedded_class.instance_variable_set('@container_reader_visibility', options[:reader] || options[:accessor] || :public)
  embedded_class.instance_variable_set('@container_writer_visibility', options[:writer] || options[:accessor] || :public)

  embedded_class.class_eval(&block) if block_given?

  container.class_eval <<-EOS
    def #{accessor_name}
      #{embedded_class_name}.new(self)
    end
  EOS
end

.define_property_getter(name, mapping, visibility = :public) ⇒ Object

define embedded property getters



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/data_mapper/embedded_value.rb', line 39

def self.define_property_getter(name, mapping, visibility = :public)
  # add convenience method on non-embedded base for #update_attributes
  self.containing_class.property_getter(mapping, visibility)

  # add the method on the embedded class
  class_eval <<-EOS
    #{visibility.to_s}
    def #{name}
      @instance.instance_variable_get(#{mapping.instance_variable_name.inspect})
    end
  EOS

  # add a shortcut boolean? method if applicable (ex: activated?)
  if mapping.type == :boolean
    class_eval("alias #{name}? #{name}")
  end
end

.define_property_setter(name, mapping, visibility = :public) ⇒ Object

define embedded property setters



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/data_mapper/embedded_value.rb', line 58

def self.define_property_setter(name, mapping, visibility = :public)
  # add convenience method on non-embedded base for #update_attributes
  self.containing_class.property_setter(mapping, visibility)

  # add the method on the embedded class
  class_eval <<-EOS
    #{visibility.to_s}
    def #{name.to_s.sub(/\?$/, '')}=(value)
      @instance.instance_variable_set(#{mapping.instance_variable_name.inspect}, value)
    end
  EOS
end

.inherited(base) ⇒ Object



14
15
16
# File 'lib/data_mapper/embedded_value.rb', line 14

def self.inherited(base)
  base.const_set('EMBEDDED_PROPERTIES', [])
end

.property(name, type, options = {}) ⇒ Object

add an embedded property

Raises:

  • (ArgumentError.new)


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/data_mapper/embedded_value.rb', line 19

def self.property(name, type, options = {})
  # set lazy option on the mapping if defined in the embed block
  options[:lazy] ||= @container_lazy

  visibility_options = [:public, :protected, :private]
  reader_visibility = options[:reader] || options[:accessor] || @container_reader_visibility
  writer_visibility = options[:writer] || options[:accessor] || @container_writer_visibility
  writer_visibility = :protected if options[:protected]
  writer_visibility = :private if options[:private]

  raise(ArgumentError.new, "property visibility must be :public, :protected, or :private") unless visibility_options.include?(reader_visibility) && visibility_options.include?(writer_visibility)

  mapping = database.schema[containing_class].add_column("#{@container_prefix}#{name}", type, options)

  self::EMBEDDED_PROPERTIES << "#{@container_prefix}#{name}"
  define_property_getter(name, mapping, reader_visibility)
  define_property_setter(name, mapping, writer_visibility)
end