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
140 141 142 143 144 145 146 |
# File 'lib/rgen/fragment/model_fragment.rb', line 140 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 all_child_elements(e, @elements) end @elements end |
#index ⇒ Object
Returns the index of the element contained in this fragment.
121 122 123 124 |
# File 'lib/rgen/fragment/model_fragment.rb', line 121 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
.
200 201 202 203 204 205 206 207 208 209 |
# File 'lib/rgen/fragment/model_fragment.rb', line 200 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
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/rgen/fragment/model_fragment.rb', line 178 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
155 156 157 158 159 160 161 |
# File 'lib/rgen/fragment/model_fragment.rb', line 155 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.
216 217 218 219 220 221 222 |
# File 'lib/rgen/fragment/model_fragment.rb', line 216 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
226 227 228 229 230 231 232 |
# File 'lib/rgen/fragment/model_fragment.rb', line 226 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
128 129 130 131 132 133 134 135 |
# File 'lib/rgen/fragment/model_fragment.rb', line 128 def unresolved_refs @unresolved_refs ||= collect_unresolved_refs if @removed_urefs @unresolved_refs -= @removed_urefs @removed_urefs = nil end @unresolved_refs end |