Class: Impromptu::Folder

Inherits:
Object
  • Object
show all
Defined in:
lib/impromptu/folder.rb

Constant Summary collapse

DEFAULT_OPTIONS =
{nested_namespaces: true, reloadable: true, implicitly_loaded: true, namespace: nil, preload: false}
SOURCE_EXTENSIONS =
%w{rb so bundle}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, component, options = {}, block) ⇒ Folder

Register a new folder containing source files for a component. Path is a Pathname object representing the folder, and options may be:

  • nested_namespaces: true by default. If true, sub- folders indicate a new namespace for resources. For instance, a folder with a root of ‘src’, containing a folder called ‘plugins’ which has a file ‘klass.rb’ would define the resource Plugins::Klass. When false, the file would simply represent Klass.

  • reloadable: true by default. If true, this folder will be reloaded every time Impromptu.update is called, and any modified files will be reloaded, removed files unloaded, and new files tracked.

  • implicitly_loaded: true by default. When true, reloads and the initial load of this folder will scan for source files and automatically infer resource definitions.

  • namespace: override a component’s default namespace with a namespace specific to this folder. The normal rules with nested namespaces apply.

  • preload: forces the loading of all files within a folder. The resources defined can still be reloaded, but loading won’t wait until the resource is referenced.



29
30
31
32
33
34
35
# File 'lib/impromptu/folder.rb', line 29

def initialize(path, component, options={}, block)
  @folder     = path.realpath
  @component  = component
  @options    = DEFAULT_OPTIONS.merge(options)
  @block      = block
  @files      = OrderedSet.new
end

Instance Attribute Details

#componentObject

Returns the value of attribute component.



3
4
5
# File 'lib/impromptu/folder.rb', line 3

def component
  @component
end

#filesObject

Returns the value of attribute files.



3
4
5
# File 'lib/impromptu/folder.rb', line 3

def files
  @files
end

#folderObject

Returns the value of attribute folder.



3
4
5
# File 'lib/impromptu/folder.rb', line 3

def folder
  @folder
end

Instance Method Details

#create_namespaceObject

If an overriding namespace has been defined for this folder, create a resource representing it and define it as a namespace.



109
110
111
112
# File 'lib/impromptu/folder.rb', line 109

def create_namespace
  return if self.namespace.nil?
  Impromptu.root_resource.get_or_create_child(self.namespace).namespace!
end

#eql?(other) ⇒ Boolean

Override eql? so two folders with the same path will be considered equal by ordered set.

Returns:

  • (Boolean)


39
40
41
# File 'lib/impromptu/folder.rb', line 39

def eql?(other)
  other.folder == @folder
end

#file(name, options = {}) ⇒ Object

Explicitly include a file from this folder. Combined with the implicitly_loaded option set to false, this method allows you to manually define a set of files to load from a folder. If implicitly_loaded is true, this method can be used to provide definitions of exceptional files (for example files which define multiple resources, or files with exceptional names). Options may be:

  • provides (required): an array of symbols, or a symbol indicating the name of the resource(s) provided by the file



139
140
141
142
143
# File 'lib/impromptu/folder.rb', line 139

def file(name, options={})
  file_preload = options[:preload] || preload?
  file = Impromptu::File.new(@folder.join(*name).realpath, self, file_preload, options[:provides])
  @files.push(file).add_resource_definition
end

#hashObject

Override hash so two folders with the same path will result in the same hash value.



45
46
47
# File 'lib/impromptu/folder.rb', line 45

def hash
  @folder.hash
end

#implicitly_loaded?Boolean

True if the folder is implicitly loaded (we scan the folder for source files and automatically infer resources)

Returns:

  • (Boolean)


74
75
76
# File 'lib/impromptu/folder.rb', line 74

def implicitly_loaded?
  @options[:implicitly_loaded]
end

#loadObject

Load a folders definition and files after the set of components has been defined. For folders provided a block, the block is run in the context of this folder (allowing ‘file’ to be called). Otherwise the folder is scanned to produce an initial set of files and resources provided by this folder.



54
55
56
57
58
59
60
# File 'lib/impromptu/folder.rb', line 54

def load
  unless @block.nil?
    instance_eval &@block
    @block = nil # prevent the block from being run twice
  end
  self.reload_file_set
end

#namespaceObject

A string or symbol for this folder which overrides the components default namespace. Nil if no namespace has been defined.



103
104
105
# File 'lib/impromptu/folder.rb', line 103

def namespace
  @options[:namespace]
end

#nested_namespaces?Boolean

True if the folder uses nested namespaces

Returns:

  • (Boolean)


63
64
65
# File 'lib/impromptu/folder.rb', line 63

def nested_namespaces?
  @options[:nested_namespaces]
end

#preloadObject

Preload the resources defined by this folder. Should only be called by the Impromptu module, and only once (at app startup).



94
95
96
97
98
99
# File 'lib/impromptu/folder.rb', line 94

def preload
  return unless preload? || force
  @files.each do |file|
    file.reload
  end
end

#preload!Object

Turn preloading on for this folder (can be done after initialisation) and run an initial preload. Ensures files are always loaded.



86
87
88
89
90
# File 'lib/impromptu/folder.rb', line 86

def preload!
  @options[:preload] = true
  @files.each {|file| file.preload = true}
  preload
end

#preload?Boolean

True if the resources of the folder are loaded immediately on startup, and won’t be autoloaded.

Returns:

  • (Boolean)


80
81
82
# File 'lib/impromptu/folder.rb', line 80

def preload?
  @options[:preload]
end

#relative_path_to(path) ⇒ Object

Return the ‘base’ folder for a file contained within this folder. For instance, a folder with nested namespaces would return the path to a file from the root folder. Without namespaces, the relative path to a file would be the enclosing folder of the file. i.e relative path to framework/a/b.rb (where framework is the root folder) would return ‘a/b.rb’ for a nested namespace folder, or just ‘b.rb’ for a non nested namespace folder.



122
123
124
125
126
127
128
# File 'lib/impromptu/folder.rb', line 122

def relative_path_to(path)
  if nested_namespaces?
    path.relative_path_from(@folder)
  else
    path.basename
  end
end

#reloadObject

Reload the files provided by this folder. If the folder is tracking a specific set of files, only those files will be reloaded. Otherwise, the folder is scanned again and any previously unseen files loaded, existing files reloaded, and removed files unloaded.



150
151
152
153
# File 'lib/impromptu/folder.rb', line 150

def reload
  reload_file_set if implicitly_loaded?
  @files.each {|file| file.reload_if_modified}
end

#reload_file_setObject

Determine changes between the set of files this folder knows about, and the set of files existing on disk. Any files which have been removed are unloaded (and their resources reloaded if other files define the resources as well), and any new files insert their resources in to the known resources tree.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/impromptu/folder.rb', line 161

def reload_file_set
  return unless implicitly_loaded?
  old_file_set = @files.to_a
  new_file_set = []
  changes = false
  
  # find all source files and add unseen files to the files list
  @folder.find do |path|
    next unless source_file?(path)
    file = Impromptu::File.new(path.realpath, self, preload?)
    new_file_set << file
    unless @files.include?(file)
      changes = true
      @files.push(file).add_resource_definition
    end
  end

  # remove any files which have been deleted
  deleted_files = old_file_set - new_file_set
  deleted_files.each {|file| @files.delete(file).remove}
  changes = true if deleted_files.size > 0
  
  # refreeze each files association lists if the set of
  # files has changed
  if changes
    @files.each do |file|
      file.refreeze
    end
  end
end

#reloadable?Boolean

True if the folder is reloadable

Returns:

  • (Boolean)


68
69
70
# File 'lib/impromptu/folder.rb', line 68

def reloadable?
  @options[:reloadable]
end