Class: RGen::Fragment::ModelFragment
- Inherits:
-
Object
- Object
- RGen::Fragment::ModelFragment
- Defined in:
- lib/rgen/fragment/model_fragment.rb
Overview
A model fragment is a list of root model elements associated with a location (e.g. a file). It also stores a list of unresolved references as well as a list of unresolved references which have been resolved. Using the latter, a fragment can undo reference resolution.
Optionally, an arbitrary data object may be associated with the fragment. The data object will also be stored in the cache.
If an element within the fragment changes this must be indicated to the fragment by calling mark_changed
.
Note: the fragment knows how to resolve references (resolve_local
, resolve_external
). However considering a fragment a data structure, this functionality might be removed in the future. Instead the fragment should be told about each resolution taking place. Use method mark_resolved
for this purpose.
Defined Under Namespace
Classes: FragmentRef, ResolvedReference
Instance Attribute Summary collapse
-
#data ⇒ Object
Returns the value of attribute data.
-
#fragment_ref ⇒ Object
Returns the value of attribute fragment_ref.
-
#location ⇒ Object
Returns the value of attribute location.
-
#root_elements ⇒ Object
readonly
Returns the value of attribute root_elements.
Instance Method Summary collapse
-
#build_index ⇒ Object
Builds the index of all elements within this fragment having an identifier the index is an array of 2-element arrays holding the identifier and the element.
-
#changed? ⇒ Boolean
Indicates whether the fragment has been changed or not.
-
#elements ⇒ Object
Returns all elements within this fragment.
-
#index ⇒ Object
Returns the index of the element contained in this fragment.
-
#initialize(location, options = {}) ⇒ ModelFragment
constructor
Create a model fragment.
-
#mark_changed ⇒ Object
Must be called when any of the elements in this fragment has been changed.
-
#mark_resolved(uref, target_fragment, target) ⇒ Object
Marks a particular unresolved reference
uref
as resolved totarget
intarget_fragment
. -
#mark_unchanged ⇒ Object
Can be used to reset the change status to unchanged.
-
#resolve_external(external_index, options) ⇒ Object
Resolves references to external fragments using the external_index provided.
-
#resolve_local(options = {}) ⇒ Object
Resolves local references (within this fragment) as far as possible.
-
#set_root_elements(root_elements, options = {}) ⇒ Object
Set the root elements, normally done by an instantiator.
-
#unresolve_external ⇒ Object
Unresolve outgoing references to all external fragments, i.e.
-
#unresolve_external_fragment(fragment) ⇒ Object
Like unresolve_external but only unresolve references to external fragment
fragment
. -
#unresolved_refs ⇒ Object
Returns all unresolved references within this fragment, i.e.
Constructor Details
#initialize(location, options = {}) ⇒ ModelFragment
Create a model fragment
:data
data object associated with this fragment
:identifier_provider
identifier provider to be used when resolving references
it must be a proc which receives a model element and must return
that element's identifier or nil if the element has no identifier
56 57 58 59 60 61 62 63 64 |
# File 'lib/rgen/fragment/model_fragment.rb', line 56 def initialize(location, ={}) @location = location @fragment_ref = FragmentRef.new @fragment_ref.fragment = self @data = [:data] @resolved_refs = nil @changed = false @identifier_provider = [:identifier_provider] end |
Instance Attribute Details
#data ⇒ Object
Returns the value of attribute data.
24 25 26 |
# File 'lib/rgen/fragment/model_fragment.rb', line 24 def data @data end |
#fragment_ref ⇒ Object
Returns the value of attribute fragment_ref.
24 25 26 |
# File 'lib/rgen/fragment/model_fragment.rb', line 24 def fragment_ref @fragment_ref end |
#location ⇒ Object
Returns the value of attribute location.
24 25 26 |
# File 'lib/rgen/fragment/model_fragment.rb', line 24 def location @location end |
#root_elements ⇒ Object (readonly)
Returns the value of attribute root_elements.
23 24 25 |
# File 'lib/rgen/fragment/model_fragment.rb', line 23 def root_elements @root_elements end |
Instance Method Details
#build_index ⇒ Object
Builds the index of all elements within this fragment having an identifier the index is an array of 2-element arrays holding the identifier and the element
143 144 145 146 147 148 149 |
# File 'lib/rgen/fragment/model_fragment.rb', line 143 def build_index raise "cannot build index without an identifier provider" unless @identifier_provider @index = elements.collect { |e| ident = @identifier_provider.call(e, nil) ident && !ident.empty? ? [ident, e] : nil }.compact end |
#changed? ⇒ Boolean
Indicates whether the fragment has been changed or not
103 104 105 |
# File 'lib/rgen/fragment/model_fragment.rb', line 103 def changed? @changed end |
#elements ⇒ Object
Returns all elements within this fragment
109 110 111 112 113 114 115 116 117 |
# File 'lib/rgen/fragment/model_fragment.rb', line 109 def elements return @elements if @elements @elements = [] @root_elements.each do |e| @elements << e @elements.concat(e.eAllContents) end @elements end |
#index ⇒ Object
Returns the index of the element contained in this fragment.
FragmentedModel’s index caching depends on the fact that any change of a fragment’s index contents implies a new index object.
124 125 126 127 |
# File 'lib/rgen/fragment/model_fragment.rb', line 124 def index build_index unless @index @index end |
#mark_changed ⇒ Object
Must be called when any of the elements in this fragment has been changed
85 86 87 88 89 90 91 92 93 |
# File 'lib/rgen/fragment/model_fragment.rb', line 85 def mark_changed @changed = true @elements = nil @index = nil @unresolved_refs = nil # unresolved refs will be recalculated, no need to keep removed_urefs @removed_urefs = nil @resolved_refs = :dirty end |
#mark_resolved(uref, target_fragment, target) ⇒ Object
Marks a particular unresolved reference uref
as resolved to target
in target_fragment
.
203 204 205 206 207 208 209 210 211 212 |
# File 'lib/rgen/fragment/model_fragment.rb', line 203 def mark_resolved(uref, target_fragment, target) @resolved_refs = {} if @resolved_refs.nil? || @resolved_refs == :dirty target_fragment ||= :unknown if target_fragment != self @resolved_refs[target_fragment] ||= [] @resolved_refs[target_fragment] << ResolvedReference.new(uref, target) end @removed_urefs ||= [] @removed_urefs << uref end |
#mark_unchanged ⇒ Object
Can be used to reset the change status to unchanged.
97 98 99 |
# File 'lib/rgen/fragment/model_fragment.rb', line 97 def mark_unchanged @changed = false end |
#resolve_external(external_index, options) ⇒ Object
Resolves references to external fragments using the external_index provided. The external index must be a Hash mapping identifiers uniquely to model elements.
Options:
:fragment_provider:
If a +fragment_provider+ is given, the resolve step can be reverted later on
by a call to unresolve_external or unresolve_external_fragment. The fragment provider
is a proc which receives a model element and must return the fragment in which it is
contained.
:use_target_type:
reference resolver uses the expected target type to narrow the set of possible targets
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/rgen/fragment/model_fragment.rb', line 181 def resolve_external(external_index, ) fragment_provider = [:fragment_provider] resolver = RGen::Instantiator::ReferenceResolver.new( :identifier_resolver => proc {|ident| external_index[ident] }) if fragment_provider @resolved_refs = {} if @resolved_refs.nil? || @resolved_refs == :dirty on_resolve = proc { |ur, target| target_fragment = fragment_provider.call(target) target_fragment ||= :unknown raise "can not resolve local reference in resolve_external, call resolve_local first" \ if target_fragment == self @resolved_refs[target_fragment] ||= [] @resolved_refs[target_fragment] << ResolvedReference.new(ur, target) } @unresolved_refs = resolver.resolve(unresolved_refs, :on_resolve => on_resolve, :use_target_type => [:use_target_type]) else @unresolved_refs = resolver.resolve(unresolved_refs, :use_target_type => [:use_target_type]) end end |
#resolve_local(options = {}) ⇒ Object
Resolves local references (within this fragment) as far as possible
Options:
:use_target_type:
reference resolver uses the expected target type to narrow the set of possible targets
158 159 160 161 162 163 164 |
# File 'lib/rgen/fragment/model_fragment.rb', line 158 def resolve_local(={}) resolver = RGen::Instantiator::ReferenceResolver.new index.each do |i| resolver.add_identifier(i[0], i[1]) end @unresolved_refs = resolver.resolve(unresolved_refs, :use_target_type => [:use_target_type]) end |
#set_root_elements(root_elements, options = {}) ⇒ Object
Set the root elements, normally done by an instantiator.
For optimization reasons the instantiator of the fragment may provide data explicitly which is normally derived by the fragment itself. In this case it is essential that this data is consistent with the fragment.
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/rgen/fragment/model_fragment.rb', line 72 def set_root_elements(root_elements, ={}) @root_elements = root_elements @elements = [:elements] @index = [:index] @unresolved_refs = [:unresolved_refs] @resolved_refs = nil # new unresolved refs, reset removed_urefs @removed_urefs = nil @changed = false end |
#unresolve_external ⇒ Object
Unresolve outgoing references to all external fragments, i.e. references which used to be represented by an unresolved reference from within this fragment. Note, that there may be more references to external fragments due to references which were represented by unresolved references from within other fragments.
219 220 221 222 223 224 225 |
# File 'lib/rgen/fragment/model_fragment.rb', line 219 def unresolve_external return if @resolved_refs.nil? raise "can not unresolve, missing fragment information" if @resolved_refs == :dirty || @resolved_refs[:unknown] rrefs = @resolved_refs.values.flatten @resolved_refs = {} unresolve_refs(rrefs) end |
#unresolve_external_fragment(fragment) ⇒ Object
Like unresolve_external but only unresolve references to external fragment fragment
229 230 231 232 233 234 235 |
# File 'lib/rgen/fragment/model_fragment.rb', line 229 def unresolve_external_fragment(fragment) return if @resolved_refs.nil? raise "can not unresolve, missing fragment information" if @resolved_refs == :dirty || @resolved_refs[:unknown] rrefs = @resolved_refs[fragment] @resolved_refs.delete(fragment) unresolve_refs(rrefs) if rrefs end |
#unresolved_refs ⇒ Object
Returns all unresolved references within this fragment, i.e. references to MMProxy objects
131 132 133 134 135 136 137 138 |
# File 'lib/rgen/fragment/model_fragment.rb', line 131 def unresolved_refs @unresolved_refs ||= collect_unresolved_refs if @removed_urefs @unresolved_refs -= @removed_urefs @removed_urefs = nil end @unresolved_refs end |