Class: Jsus::Container
- Inherits:
-
Object
- Object
- Jsus::Container
- Defined in:
- lib/jsus/container.rb
Overview
Container is an array that contains source files. Main difference from an array is the fact that container maintains topological sort for the source files.
This class is mostly used internally.
Constant Summary collapse
- CACHE_CLEAR_METHODS =
List of methods that clear cached state of container when called.
[ "map!", "reject!", "inject!", "collect!", "delete", "delete_at" ]
- DELEGATED_METHODS =
List of methods that are delegated to underlying array of sources.
[ "==", "to_a", "map", "map!", "each", "inject", "inject!", "collect", "collect!", "reject", "reject!", "detect", "size", "length", "[]", "empty?", "index", "include?", "select", "delete_if", "delete", "-", "+", "|", "&" ]
Instance Method Summary collapse
-
#all_sources ⇒ Array
Includes all sources, even those that would normally be replaced.
-
#clear_cache! ⇒ Object
private
Clears all caches for given container.
-
#dependency_cache ⇒ Hash
private
Cached map of dependencies pointing to source files.
-
#flatten ⇒ Array
Flattens the container items.
-
#initialize(*sources) ⇒ Container
constructor
Instantiates a container from given sources.
- #insert_extensions! ⇒ Object private
- #insert_replacements! ⇒ Object private
-
#inspect ⇒ Object
Shows inspection of the container.
- #output_cycles(graph) ⇒ Object private
-
#provides ⇒ Array
Returns all the tags provided by source files.
-
#provides_tree ⇒ Jsus::Util::Tree
private
Cached tree of what source files provide.
-
#provides_tree! ⇒ Jsus::Util::Tree
private
Returns tree of what source files provide.
-
#push(source) ⇒ Object
(also: #<<)
Pushes an item to the container.
-
#required_files(root = nil) ⇒ Array
Lists all the required files (dependencies and extensions) for the sources in the container.
-
#requires ⇒ Array
Returns all the tags required by source files, except for those which are provided by other files in the container (i.e. unresolved dependencies).
-
#sort! ⇒ self
Topologically sorts items in container if required.
-
#sorted? ⇒ Boolean
Returns whether container requires sorting.
-
#sources ⇒ Array
(also: #to_a)
Contains the source files.
-
#topsort ⇒ Object
private
Performs topological sort inside current container.
Constructor Details
#initialize(*sources) ⇒ Container
Instantiates a container from given sources.
13 14 15 16 17 18 19 20 21 |
# File 'lib/jsus/container.rb', line 13 def initialize(*sources) @sources = [] @normal_sources = [] @extensions = [] @replacements = [] sources.each do |source| push(source) end end |
Instance Method Details
#all_sources ⇒ Array
Includes all sources, even those that would normally be replaced. Without any order.
71 72 73 |
# File 'lib/jsus/container.rb', line 71 def all_sources @normal_sources + @extensions + @replacements end |
#clear_cache! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Clears all caches for given container.
252 253 254 |
# File 'lib/jsus/container.rb', line 252 def clear_cache! @sorted = false end |
#dependency_cache ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Cached map of dependencies pointing to source files.
193 194 195 |
# File 'lib/jsus/container.rb', line 193 def dependency_cache @dependency_cache ||= {} end |
#flatten ⇒ Array
Flattens the container items
52 53 54 |
# File 'lib/jsus/container.rb', line 52 def flatten map {|item| item.respond_to?(:flatten) ? item.flatten : item }.flatten end |
#insert_extensions! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/jsus/container.rb', line 225 def insert_extensions! @extensions.each do |ext| ext_tag = ext.extends @sources.dup.each_with_index do |src, i| if src.provides.any? {|tag| tag == ext_tag } @sources.insert(i+1, ext) break end end end end |
#insert_replacements! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
238 239 240 241 242 243 244 245 246 247 |
# File 'lib/jsus/container.rb', line 238 def insert_replacements! @replacements.each do |repl| @sources.each_with_index do |src, i| if src.provides.any? {|tag| tag == repl.replaces } @sources[i] = repl break end end end end |
#inspect ⇒ Object
Shows inspection of the container.
120 121 122 |
# File 'lib/jsus/container.rb', line 120 def inspect "#<#{self.class.name}:#{self.object_id} #{self.sources.inspect}>" end |
#output_cycles(graph) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/jsus/container.rb', line 173 def output_cycles(graph) cycles = graph.cycles error_msg = [] unless cycles.empty? error_msg << "Jsus has discovered you have circular dependencies in your code." error_msg << "Please resolve them immediately!" error_msg << "List of circular dependencies:" cycles.each do |cycle| error_msg << "-" * 30 error_msg << (cycle + [cycle.first]).map {|sf| sf.filename}.join(" => ") end error_msg << "-" * 30 error_msg = error_msg.join("\n") Jsus.logger.fatal(error_msg) end end |
#provides ⇒ Array
Returns all the tags provided by source files.
127 128 129 130 |
# File 'lib/jsus/container.rb', line 127 def provides sort! sources.map {|s| s.provides }.flatten end |
#provides_tree ⇒ Jsus::Util::Tree
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Cached tree of what source files provide.
201 202 203 |
# File 'lib/jsus/container.rb', line 201 def provides_tree @provides_tree ||= provides_tree! end |
#provides_tree! ⇒ Jsus::Util::Tree
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns tree of what source files provide.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/jsus/container.rb', line 209 def provides_tree! tree = Util::Tree.new # Provisions @normal_sources.each do |file| provisions = file.provides if replacement = @replacements.detect {|r| provisions.any? {|tag| tag == r.replaces } } file = replacement end provisions.each do |tag| tree[tag] = file end end tree end |
#push(source) ⇒ Object Also known as: <<
Pushes an item to the container
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/jsus/container.rb', line 28 def push(source) if source if source.kind_of?(Array) source.each {|s| self.push(s) } elsif source.kind_of?(Container) source.all_sources.each {|s| self.push(s) } else if source.extension? @extensions << source unless @extensions.include?(source) elsif source.replacement? @replacements << source unless @replacements.include?(source) else @normal_sources << source unless @normal_sources.include?(source) end end end clear_cache! self end |
#required_files(root = nil) ⇒ Array
Lists all the required files (dependencies and extensions) for the sources in the container. Consider it a projection from source files space onto filesystem space.
Optionally accepts a filesystem point to calculate relative paths from.
108 109 110 111 112 113 114 115 116 |
# File 'lib/jsus/container.rb', line 108 def required_files(root = nil) sort! files = sources.map {|s| s.required_files }.flatten if root root = Pathname.new(File.(root)) files = files.map {|f| Pathname.new(File.(f)).relative_path_from(root).to_s } end files end |
#requires ⇒ Array
Returns all the tags required by source files, except for those which are provided by other files in the container (i.e. unresolved dependencies)
136 137 138 139 |
# File 'lib/jsus/container.rb', line 136 def requires sort! sources.map {|s| s.requires }.flatten - provides end |
#sort! ⇒ self
Topologically sorts items in container if required.
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/jsus/container.rb', line 79 def sort! unless sorted? @sources = topsort insert_extensions! insert_replacements! @sources.uniq! @sorted = true end self end |
#sorted? ⇒ Boolean
Returns whether container requires sorting.
94 95 96 |
# File 'lib/jsus/container.rb', line 94 def sorted? !!@sorted end |
#sources ⇒ Array Also known as: to_a
Contains the source files.
60 61 62 63 |
# File 'lib/jsus/container.rb', line 60 def sources sort! @sources end |
#topsort ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Performs topological sort inside current container.
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/jsus/container.rb', line 146 def topsort graph = RGL::DirectedAdjacencyGraph.new # init vertices items = @normal_sources items.each {|item| graph.add_vertex(item) } # init edges items.each do |item| item.dependencies.each do |dependency| # If we can find items that provide the required dependency... # (dependency could be a wildcard as well, hence items) dependency_cache[dependency] ||= provides_tree.glob(dependency) # ... we draw an edge from every required item to the dependant item dependency_cache[dependency].each do |required_item| graph.add_edge(required_item, item) end end end begin graph.topsorted_vertices rescue RGL::TopsortedGraphHasCycles => e output_cycles(graph) raise e # fail fast end end |