Class: RGen::Fragment::FragmentedModel

Inherits:
Object
  • Object
show all
Defined in:
lib/rgen/fragment/fragmented_model.rb

Overview

A FragmentedModel represents a model which consists of fragments (ModelFragment).

The main purpose of this class is to resolve references across fragments and to keep the references consistent while fragments are added or removed. This way it also plays an important role in keeping the model fragments consistent and thus ModelFragment objects should only be accessed via this interface. Overall unresolved references after the resolution step are also maintained.

A FragmentedModel can also keep an RGen::Environment object up to date while fragments are added or removed. The environment must be registered with the constructor.

Reference resolution is based on arbitrary identifiers. The identifiers must be provided in the fragments’ indices. The FragmentedModel takes care to maintain the overall index.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ FragmentedModel

Creates a fragmented model. Options:

:env 
  environment which will be updated as model elements are added and removed


31
32
33
34
35
36
37
# File 'lib/rgen/fragment/fragmented_model.rb', line 31

def initialize(options={})
  @environment = options[:env]
  @fragments = []
  @index = nil
  @fragment_change_listeners = []
  @fragment_index = {}
end

Instance Attribute Details

#environmentObject (readonly)

Returns the value of attribute environment.



24
25
26
# File 'lib/rgen/fragment/fragmented_model.rb', line 24

def environment
  @environment
end

#fragmentsObject (readonly)

Returns the value of attribute fragments.



23
24
25
# File 'lib/rgen/fragment/fragmented_model.rb', line 23

def fragments
  @fragments
end

Instance Method Details

#add_fragment(fragment) ⇒ Object

Add a fragment.



52
53
54
55
56
57
# File 'lib/rgen/fragment/fragmented_model.rb', line 52

def add_fragment(fragment)
  invalidate_cache
  @fragments << fragment
  fragment.elements.each{|e| @environment << e} if @environment
  @fragment_change_listeners.each{|l| l.call(fragment, :added)}
end

#add_fragment_change_listener(listener) ⇒ Object

Adds a proc which is called when a fragment is added or removed The proc receives the fragment and one of :added, :removed



42
43
44
# File 'lib/rgen/fragment/fragmented_model.rb', line 42

def add_fragment_change_listener(listener)
  @fragment_change_listeners << listener
end

#indexObject

Returns the overall index. This is a Hash mapping identifiers to model elements accessible via the identifier.



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rgen/fragment/fragmented_model.rb', line 113

def index
  fragments.each do |f|
    if !@fragment_index[f] || (@fragment_index[f].object_id != f.index.object_id)
      @fragment_index[f] = f.index
      invalidate_cache
    end
  end
  return @index if @index
  @index = {}
  fragments.each do |f|
    f.index.each do |i| 
      (@index[i[0]] ||= []) << i[1]
    end
  end
  @index
end

#remove_fragment(fragment) ⇒ Object

Removes the fragment. The fragment will be unresolved using unresolve_fragment.



61
62
63
64
65
66
67
68
69
# File 'lib/rgen/fragment/fragmented_model.rb', line 61

def remove_fragment(fragment)
  raise "fragment not part of model" unless @fragments.include?(fragment)
  invalidate_cache
  @fragments.delete(fragment)
  @fragment_index.delete(fragment)
  unresolve_fragment(fragment)
  fragment.elements.each{|e| @environment.delete(e)} if @environment
  @fragment_change_listeners.each{|l| l.call(fragment, :removed)}
end

#remove_fragment_change_listener(listener) ⇒ Object



46
47
48
# File 'lib/rgen/fragment/fragmented_model.rb', line 46

def remove_fragment_change_listener(listener)
  @fragment_change_listeners.delete(listener)
end

#resolve(options = {}) ⇒ Object

Resolve references between fragments. It is assumed that references within fragments have already been resolved. This method can be called several times. It will update the overall unresolved references.

Options:

:fragment_provider:
  Only if a +fragment_provider+ is given, the resolve step can be reverted later on
  by a call to unresolve_fragment. The fragment provider is a proc which receives a model
  element and must return the fragment in which the element is contained.

:use_target_type:
  reference resolver uses the expected target type to narrow the set of possible targets


85
86
87
88
89
90
# File 'lib/rgen/fragment/fragmented_model.rb', line 85

def resolve(options={})
  local_index = index
  @fragments.each do |f|
    f.resolve_external(local_index, options)
  end
end

#unresolve_fragment(fragment) ⇒ Object

Remove all references between this fragment and all other fragments. The references will be replaced with unresolved references (MMProxy objects).



95
96
97
98
99
100
101
102
# File 'lib/rgen/fragment/fragmented_model.rb', line 95

def unresolve_fragment(fragment)
  fragment.unresolve_external
  @fragments.each do |f|
    if f != fragment
      f.unresolve_external_fragment(fragment)
    end
  end
end

#unresolved_refsObject

Returns the overall unresolved references.



106
107
108
# File 'lib/rgen/fragment/fragmented_model.rb', line 106

def unresolved_refs
  @fragments.collect{|f| f.unresolved_refs}.flatten
end