class Middleman::Sources
Sources
handle multiple on-disk collections of files which make up a Middleman
project. They are separated by ‘type` which can then be queried. For example, the `source` type represents all content that the sitemap uses to build a project. The `data` type represents YAML data. The `locales` type represents localization YAML, and so on.
Constants
- CODE_TYPES
-
Types which require a reload to eval ruby
- CallbackDescriptor
-
A callback requires a type and the proc to execute.
- HANDLER
-
Duck-typed definition of a valid source watcher
- Matcher
- OUTPUT_TYPES
-
Types which could cause output to change.
Attributes
Public Class Methods
Source
# File lib/middleman-core/sources.rb, line 59 def initialize(app, _options={}, watchers=[]) @app = app @watchers = watchers @sorted_watchers = @watchers.dup.freeze ::Middleman::Sources.file_cache = {} # Set of procs wanting to be notified of changes @on_change_callbacks = ::Hamster::Vector.empty # Global ignores @ignores = ::Hamster::Hash.empty # Whether we're "running", which means we're in a stable # watch state after all initialization and config. @running = false @update_count = 0 @last_update_count = -1 # When the app is about to shut down, stop our watchers. @app.before_shutdown(&method(:stop!)) end
Public Instance Methods
Source
# File lib/middleman-core/sources.rb, line 172 def by_type(type) self.class.new @app, nil, watchers.select { |d| d.type == type } end
Source
# File lib/middleman-core/sources.rb, line 280 def changed(matcher=nil, &_block) on_change OUTPUT_TYPES do |updated, _removed| updated .select { |f| matcher.nil? ? true : matches?(matcher, f) } .each { |f| yield f[:relative_path] } end end
Source
# File lib/middleman-core/sources.rb, line 292 def deleted(matcher=nil, &_block) on_change OUTPUT_TYPES do |_updated, removed| removed .select { |f| matcher.nil? ? true : matches?(matcher, f) } .each { |f| yield f[:relative_path] } end end
Source
# File lib/middleman-core/sources.rb, line 208 def exists?(types, path) watchers.any? { |d| Array(types).include?(d.type) && d.exists?(path) } end
Source
# File lib/middleman-core/sources.rb, line 180 def files watchers.flat_map(&:files).uniq { |f| f[:relative_path] } end
Source
# File lib/middleman-core/sources.rb, line 191 def find(types, path, glob=false) array_of_types = Array(types) watchers .lazy .select { |d| array_of_types.include?(d.type) } .map { |d| d.find(path, glob) } .reject(&:nil?) .first end
Source
# File lib/middleman-core/sources.rb, line 226 def find_new_files! return [] unless @update_count != @last_update_count @last_update_count = @update_count watchers.reduce([]) { |sum, w| sum + w.find_new_files! } end
Source
# File lib/middleman-core/sources.rb, line 104 def globally_ignored?(file) @ignores.values.any? do |descriptor| ((descriptor[:type] == :all) || file[:types].include?(descriptor[:type])) && matches?(descriptor[:validator], file) end end
Source
# File lib/middleman-core/sources.rb, line 91 def ignore(name, type, regex=nil, &block) @ignores = @ignores.put(name, type: type, validator: (block_given? ? block : regex)) bump_count poll_once! if @running end
Source
# File lib/middleman-core/sources.rb, line 304 def ignored?(path) descriptor = find(OUTPUT_TYPES, path) !descriptor || globally_ignored?(descriptor) end
Source
# File lib/middleman-core/sources.rb, line 270 def on_change(types, &block) Array(types).each do |type| @on_change_callbacks = @on_change_callbacks.push(CallbackDescriptor.new(type, block)) end end
Source
# File lib/middleman-core/sources.rb, line 237 def poll_once! return [] unless @update_count != @last_update_count @last_update_count = @update_count watchers.reduce([]) { |sum, w| sum + w.poll_once! } end
Source
# File lib/middleman-core/sources.rb, line 248 def start! watchers.each(&:listen!) @running = true end
Source
# File lib/middleman-core/sources.rb, line 257 def stop! watchers.each(&:stop_listener!) @running = false end
Source
# File lib/middleman-core/sources.rb, line 159 def unwatch(watcher) @watchers.delete(watcher) watcher.unwatch bump_count end
Source
# File lib/middleman-core/sources.rb, line 119 def watch(type_or_handler, options={}) handler = if type_or_handler.is_a? Symbol path = File.expand_path(options.delete(:path), app.root) SourceWatcher.new(self, type_or_handler, path, options) else type_or_handler end @watchers << handler # The index trick is used so that the sort is stable - watchers with the same priority # will always be ordered in the same order as they were registered. n = 0 @sorted_watchers = @watchers.sort_by do |w| priority = w.options.fetch(:priority, 50) n += 1 [priority, n] end.reverse.freeze handler.on_change(&method(:did_change)) if @running handler.poll_once! handler.listen! end handler end
Source
# File lib/middleman-core/sources.rb, line 218 def watcher_for_path(types, path) watchers.detect { |d| Array(types).include?(d.type) && d.exists?(path) } end
Protected Instance Methods
Source
# File lib/middleman-core/sources.rb, line 330 def bump_count @update_count += 1 end
Source
# File lib/middleman-core/sources.rb, line 339 def did_change(updated_files, removed_files, watcher) valid_updated = updated_files.select do |file| watcher_for_path(file[:types], file[:relative_path].to_s) == watcher end valid_removed = removed_files.select do |file| watcher_for_path(file[:types], file[:relative_path].to_s).nil? end return if valid_updated.empty? && valid_removed.empty? bump_count run_callbacks(@on_change_callbacks, valid_updated, valid_removed) end
Source
# File lib/middleman-core/sources.rb, line 317 def matches?(validator, file) path = file[:relative_path] if validator.is_a? Regexp !!(path.to_s =~ validator) else !!validator.call(path, @app) end end
Source
# File lib/middleman-core/sources.rb, line 360 def run_callbacks(callback_descriptors, updated_files, removed_files) callback_descriptors.each do |callback| if callback[:type] == :all callback[:proc].call(updated_files, removed_files) else valid_updated = updated_files.select { |f| f[:types].include?(callback[:type]) } valid_removed = removed_files.select { |f| f[:types].include?(callback[:type]) } callback[:proc].call(valid_updated, valid_removed) unless valid_updated.empty? && valid_removed.empty? end end end