Class: Disposable::Twin

Inherits:
Object
  • Object
show all
Extended by:
Uber::InheritableAttr
Includes:
Initialize, Option
Defined in:
lib/disposable/twin.rb,
lib/disposable/twin/new.rb,
lib/disposable/twin/save.rb,
lib/disposable/twin/save_.rb,
lib/disposable/twin/struct.rb,
lib/disposable/twin/builder.rb,
lib/disposable/twin/composition.rb,
lib/disposable/twin/representer.rb

Defined Under Namespace

Modules: Builder, Finders, Initialize, Option, Struct Classes: Composition, Decorator, Definition

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Option

included

Methods included from Initialize

#initialize

Class Method Details

.collection(name, options = {}, &block) ⇒ Object



34
35
36
# File 'lib/disposable/twin.rb', line 34

def self.collection(name, options={}, &block)
  property(name, options.merge(:collection => true), &block)
end

.new_representerObject

transform incoming model into twin API hash.



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
# File 'lib/disposable/twin/new.rb', line 4

def self.new_representer
  representer = Class.new(representer_class) # inherit configuration

  # wrap incoming nested model in its Twin.
  representer.representable_attrs.
    find_all { |attr| attr[:twin] }.
    each { |attr| attr.merge!(
      :prepare      => lambda { |object, args|
        if twin = args.user_options[:object_map][object]
          twin
        else
          args.binding[:twin].evaluate(nil).new(object, args.user_options[:object_map])
        end
      }) }

  # song_title => model.title
  representer.representable_attrs.each do |attr|
    attr.merge!(
      :getter => lambda { |args|
        args.represented.send("#{args.binding[:private_name]}") }, # DISCUSS: can't we do that with representable's mechanics?
    )
  end

  representer
end

.pre_save_representerObject

call save on all nested twins.



4
5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/disposable/twin/save.rb', line 4

def self.pre_save_representer
  representer = Class.new(write_representer)
  representer.representable_attrs.
    each { |attr| attr.merge!(
      :representable => true,
      :serialize => lambda do |twin, args|
        processed = args.user_options[:processed_map]

        twin.save(processed) unless processed[twin] # don't call save if it is already scheduled.
      end
    )}

  representer
end

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



20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/disposable/twin.rb', line 20

def self.property(name, options={}, &block)
  deprecate_as!(options) # TODO: remove me in 0.1.0
  options[:private_name] = options.delete(:from) || name
  options[:pass_options] = true

  representer_class.property(name, options, &block).tap do |definition|
    mod = Module.new do
      define_method(name)       { read_property(name, options[:private_name]) }
      define_method("#{name}=") { |value| write_property(name, options[:private_name], value) } # TODO: this is more like prototyping.
    end
    include mod
  end
end

.save_representerObject

hash for #update_attributes (model API): “Future World”, album: <Album>



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/disposable/twin/save_.rb', line 4

def self.save_representer
  # TODO: do that only at compile-time!
  save = Class.new(write_representer) # inherit configuration
  save.representable_attrs.
    find_all { |attr| attr[:twin] }.
    each { |attr| attr.merge!(
      :representable => true,
      :serialize     => lambda { |obj, args| obj.send(:model) }) }

    save.representable_attrs.each do |attr|
      attr.merge!(:as => attr[:private_name])
    end

  save
end

.write_representerObject

read/write to twin using twin’s API (e.g. #record= not #album=).



51
52
53
# File 'lib/disposable/twin.rb', line 51

def self.write_representer
  representer = Class.new(representer_class) # inherit configuration
end

Instance Method Details

#save(processed_map = ObjectMap.new) ⇒ Object

it’s important to stress that #save is the only entry point where we hit the database after initialize.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/disposable/twin/save.rb', line 21

def save(processed_map=ObjectMap.new) # use that in Reform::AR.
  processed_map[self] = true

  pre_save = self.class.pre_save_representer.new(self)
  pre_save.to_hash(:include => pre_save.twin_names, :processed_map => processed_map) # #save on nested Twins.



  # what we do right now
  # call save on all nested twins - how does that work with dependencies (eg Album needs Song id)?
  # extract all ORM attributes
  # write to model

  sync_attrs    = self.class.save_representer.new(self).to_hash
  # puts "sync> #{sync_attrs.inspect}"
  # this is ORM-specific:
  model.update_attributes(sync_attrs) # this also does `album: #<Album>`

  # FIXME: sync again, here, or just id?
  self.id = model.id
end