Class: Impromptu::Resource
- Inherits:
-
Object
- Object
- Impromptu::Resource
- Defined in:
- lib/impromptu/resource.rb
Overview
Resources represent the modules or classes that are tracked by Impromptu and which can be lazy loaded. You should never create resources yourself - use component definitions to define folders of files which will implement resources.
Instance Attribute Summary collapse
-
#base_symbol ⇒ Object
readonly
Returns the value of attribute base_symbol.
-
#children ⇒ Object
readonly
Returns the value of attribute children.
-
#files ⇒ Object
readonly
Returns the value of attribute files.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#preload ⇒ Object
Returns the value of attribute preload.
Instance Method Summary collapse
-
#add_child(resource) ⇒ Object
Add a child resource to this resource.
-
#add_file(file) ⇒ Object
Start tracking a file which implements this resource.
-
#child(name) ⇒ Object
Walks the resource tree and returns the resource corresponding to name (which must be a symbol and can be namespaced).
-
#child?(name) ⇒ Boolean
Walks the resource tree to determine if the resource referred to by name (which must be a symbol, and may be namespaced) is known by Impromptu.
-
#children? ⇒ Boolean
True if this resource is the parent of any resources.
-
#eql?(other) ⇒ Boolean
Override eql? so two resources with the same name will be considered equal by ordered set.
-
#get_or_create_child(name) ⇒ Object
In most instances, this method should only be called on the root resource to traverse the resource tree and retrieve or create the specified resource.
-
#hash ⇒ Object
Override hash so two resources with the same name will result in the same hash value.
-
#implicitly_defined? ⇒ Boolean
True if no files have been associated with this resource.
-
#initialize(name, parent) ⇒ Resource
constructor
A new instance of Resource.
-
#load_if_extending_stdlib ⇒ Object
Loads this resource if it is an extension of an existing class or module (such as an object in the standard library).
-
#loaded? ⇒ Boolean
True if this resource exists as a constant in its parent.
-
#mark_dont_undef ⇒ Object
Mark this resource as having been loaded before Impromptu if the resource is already defined.
-
#namespace! ⇒ Object
Mark a resource as representing a module acting as a namespace.
-
#namespace? ⇒ Boolean
True if this resource represents a module acting as a namespace.
-
#preload? ⇒ Boolean
True if this resource needs to be preloaded before other files are automatically loaded on demand.
-
#reference ⇒ Object
Attempts to retrieve a reference to the object represented by this resource.
-
#reload ⇒ Object
Reload the implementation of this resource from all files being tracked for this resource.
-
#reload_preloaded_resources ⇒ Object
Loads this resource, and any child resources, if the resource is marked as requiring preloading, and the resource is not currently loaded.
-
#remove ⇒ Object
Unload and remove all references to this resource.
-
#remove_child(resource) ⇒ Object
Remove a reference to a child resource.
-
#remove_file(file) ⇒ Object
Un-track a file implementing this resource.
-
#root? ⇒ Boolean
True if this resource is the root resource referring to Object.
-
#unload ⇒ Object
Unload the resource by undefining the constant representing it.
Constructor Details
#initialize(name, parent) ⇒ Resource
Returns a new instance of Resource.
9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/impromptu/resource.rb', line 9 def initialize(name, parent) @name = name.to_sym @parent = parent @base_symbol = @name.base_symbol @files = OrderedSet.new @children = {} @reference = nil @namespace = false @dont_undef = self.loaded? # existing constants, such as 'String', should never be unloaded @preload = false # true if any folder defining this resource is marked to be preloaded @implicitly_defined = true end |
Instance Attribute Details
#base_symbol ⇒ Object (readonly)
Returns the value of attribute base_symbol.
7 8 9 |
# File 'lib/impromptu/resource.rb', line 7 def base_symbol @base_symbol end |
#children ⇒ Object (readonly)
Returns the value of attribute children.
7 8 9 |
# File 'lib/impromptu/resource.rb', line 7 def children @children end |
#files ⇒ Object (readonly)
Returns the value of attribute files.
7 8 9 |
# File 'lib/impromptu/resource.rb', line 7 def files @files end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
7 8 9 |
# File 'lib/impromptu/resource.rb', line 7 def name @name end |
#parent ⇒ Object (readonly)
Returns the value of attribute parent.
7 8 9 |
# File 'lib/impromptu/resource.rb', line 7 def parent @parent end |
#preload ⇒ Object
Returns the value of attribute preload.
7 8 9 |
# File 'lib/impromptu/resource.rb', line 7 def preload @preload end |
Instance Method Details
#add_child(resource) ⇒ Object
Add a child resource to this resource. This does not load the resource. This should only be called by get_or_create_child.
150 151 152 |
# File 'lib/impromptu/resource.rb', line 150 def add_child(resource) @children[resource.base_symbol] = resource end |
#add_file(file) ⇒ Object
Start tracking a file which implements this resource. If the file has already been added it won’t be added a second time. This method does not load the added file, so the definition of the resource will be incomplete until reload is called.
108 109 110 111 |
# File 'lib/impromptu/resource.rb', line 108 def add_file(file) @files << file @implicitly_defined = false end |
#child(name) ⇒ Object
Walks the resource tree and returns the resource corresponding to name (which must be a symbol and can be namespaced). If the resource doesn’t exist, nil is returned
189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/impromptu/resource.rb', line 189 def child(name) return nil unless name.is_a?(Symbol) return @children[name.without_leading_colons.to_sym] if name.unnested? # if the name is nested, walk the resource tree to return the # resource under this branch. rerturn nil if we reach a # branch which doesn't exist nested_symbols = name.nested_symbols top_level_symbol = nested_symbols.first further_symbols = nested_symbols[1..-1].join('::').to_sym return nil unless @children.has_key?(top_level_symbol) @children[top_level_symbol].child(further_symbols) end |
#child?(name) ⇒ Boolean
Walks the resource tree to determine if the resource referred to by name (which must be a symbol, and may be namespaced) is known by Impromptu.
206 207 208 |
# File 'lib/impromptu/resource.rb', line 206 def child?(name) !self.child(name).nil? end |
#children? ⇒ Boolean
True if this resource is the parent of any resources.
144 145 146 |
# File 'lib/impromptu/resource.rb', line 144 def children? !@children.empty? end |
#eql?(other) ⇒ Boolean
Override eql? so two resources with the same name will be considered equal by ordered set. Names are fully namespaced so will always be unique.
25 26 27 |
# File 'lib/impromptu/resource.rb', line 25 def eql?(other) other.name == @name end |
#get_or_create_child(name) ⇒ Object
In most instances, this method should only be called on the root resource to traverse the resource tree and retrieve or create the specified resource. Name must be a symbol.
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/impromptu/resource.rb', line 164 def get_or_create_child(name) return nil unless name.is_a?(Symbol) current = self name.each_namespaced_symbol do |name| # attempt to get the current resource child_resource = current.child(name.base_symbol) # create the resource if needed if child_resource.nil? child_resource = Resource.new(name, current) current.add_child(child_resource) end # the next current resource is the one we just created or retrieved current = child_resource end # after iterating through the name, current will be the resulting resource current end |
#hash ⇒ Object
Override hash so two resources with the same name will result in the same hash value. Names are fully namespaced so will always be unique.
32 33 34 |
# File 'lib/impromptu/resource.rb', line 32 def hash @name.hash end |
#implicitly_defined? ⇒ Boolean
True if no files have been associated with this resource. In this case, loading the resource will be achieved by creating a blank module with the name of the resource. If any files have been associated, they will be loaded instead, and this method will return false.
127 128 129 |
# File 'lib/impromptu/resource.rb', line 127 def implicitly_defined? @implicitly_defined end |
#load_if_extending_stdlib ⇒ Object
Loads this resource if it is an extension of an existing class or module (such as an object in the standard library). Should only be called on app startup by Impromptu itself. Recurses to this resource’s children as well.
243 244 245 246 |
# File 'lib/impromptu/resource.rb', line 243 def load_if_extending_stdlib reload if loaded? && !self.root? @children.each_value(&:load_if_extending_stdlib) end |
#loaded? ⇒ Boolean
True if this resource exists as a constant in its parent. This does not guarantee that every file implementing this resource has been loaded, however, so an incomplete instance may exist. If you rely on the autoloader and reloader this will not occur.
226 227 228 229 230 |
# File 'lib/impromptu/resource.rb', line 226 def loaded? return true if root? return false unless @parent && @parent.loaded? && @parent.reference parent.reference.constants.include?(@base_symbol) end |
#mark_dont_undef ⇒ Object
Mark this resource as having been loaded before Impromptu if the resource is already defined.
234 235 236 237 |
# File 'lib/impromptu/resource.rb', line 234 def mark_dont_undef @dont_undef = self.loaded? @children.each_value(&:mark_dont_undef) end |
#namespace! ⇒ Object
Mark a resource as representing a module acting as a namespace.
139 140 141 |
# File 'lib/impromptu/resource.rb', line 139 def namespace! @namespace = true end |
#namespace? ⇒ Boolean
True if this resource represents a module acting as a namespace.
133 134 135 |
# File 'lib/impromptu/resource.rb', line 133 def namespace? @namespace end |
#preload? ⇒ Boolean
True if this resource needs to be preloaded before other files are automatically loaded on demand
43 44 45 |
# File 'lib/impromptu/resource.rb', line 43 def preload? @preload end |
#reference ⇒ Object
Attempts to retrieve a reference to the object represented by this resource. If the resource is unloaded, nil is returned.
49 50 51 52 53 |
# File 'lib/impromptu/resource.rb', line 49 def reference return Object if root? return nil unless @parent && @parent.reference @reference ||= @parent.reference.const_get(@base_symbol) end |
#reload ⇒ Object
Reload the implementation of this resource from all files being tracked for this resource. Call this method if you are manually managing file tracking, and need to guarantee all files for this resource have been loaded. It is normally unecessary to call this if you rely on the autoloader and reloader.
60 61 62 63 64 65 66 67 68 69 |
# File 'lib/impromptu/resource.rb', line 60 def reload @parent.reload unless @parent.loaded? if @implicitly_defined unload Object.module_eval "module #{@name}; end" else @files.first.reload end reload_preloaded_resources end |
#reload_preloaded_resources ⇒ Object
Loads this resource, and any child resources, if the resource is marked as requiring preloading, and the resource is not currently loaded. This loading may happen multiple times during the application life cycle depending on whether parent resources are reloaded and so on.
252 253 254 255 |
# File 'lib/impromptu/resource.rb', line 252 def reload_preloaded_resources reload if !loaded? && preload? @children.each_value(&:reload_preloaded_resources) end |
#remove ⇒ Object
Unload and remove all references to this resource.
211 212 213 214 |
# File 'lib/impromptu/resource.rb', line 211 def remove unload @parent.remove_child(self) if @parent end |
#remove_child(resource) ⇒ Object
Remove a reference to a child resource. This does not unload the object, but is called automatically by unload on its parent resource.
157 158 159 |
# File 'lib/impromptu/resource.rb', line 157 def remove_child(resource) @children.delete(resource.base_symbol) end |
#remove_file(file) ⇒ Object
Un-track a file implementing this resource. If the file was never tracked, no error is raised. This does not reload the resource, so the resource will be based on a stale definition if it was previously loaded.
117 118 119 120 |
# File 'lib/impromptu/resource.rb', line 117 def remove_file(file) @files.delete(file) @implicitly_defined = true if @files.size == 0 && namespace? end |
#root? ⇒ Boolean
True if this resource is the root resource referring to Object.
217 218 219 |
# File 'lib/impromptu/resource.rb', line 217 def root? @parent.nil? end |
#unload ⇒ Object
Unload the resource by undefining the constant representing it. Any resources contained within this resource will also be unloaded. This allows the resource to be garbage collected. If the resource is a class, you can define a class method called ‘descendants’ that returns an array of references to subclasses. Any subclasses known to Impromptu will also be unloaded, just as namespaced children are. This prevents subclasses holding a reference to a stale version of a super class.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/impromptu/resource.rb', line 79 def unload return unless loaded? # unload namespaced children @children.each_value(&:unload) # unload descendants if they can be reloaded by impromptu if reference.respond_to? :descendants reference.descendants.each do |descendant| resource = Impromptu.root_resource.child(descendant.name.to_sym) resource.unload unless resource.nil? end end # remove from the parent's descendants list if reference.respond_to?(:superclass) && reference.superclass.respond_to?(:descendants) reference.superclass.descendants.delete(reference) end unless @dont_undef @parent.reference.send(:remove_const, @base_symbol) @reference = nil end end |