Class: Middleman::SourceWatcher

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Contracts
Defined in:
lib/middleman-core/sources/source_watcher.rb

Overview

The default source watcher implementation. Watches a directory on disk and responds to events on changes.

Constant Summary collapse

IGNORED_DIRECTORIES =
%w(.git node_modules .sass-cache).freeze

Constants included from Contracts

Contracts::PATH_MATCHER

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Contracts

#Contract

Constructor Details

#initialize(parent, type, directory, options = {}) ⇒ SourceWatcher

Returns a new instance of SourceWatcher.



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/middleman-core/sources/source_watcher.rb', line 61

def initialize(parent, type, directory, options={})
  @parent = parent
  @options = options

  @type = type
  @directory = Pathname(directory)

  @files = {}
  @extensionless_files = {}

  @frontmatter = options.fetch(:frontmatter, true)
  @binary = options.fetch(:binary, false)
  @validator = options.fetch(:validator, proc { true })
  @ignored = options.fetch(:ignored, proc { false })
  @only = Array(options.fetch(:only, []))

  @disable_watcher = app.build? || @parent.options.fetch(:disable_watcher, false)
  @force_polling = @parent.options.fetch(:force_polling, false)
  @latency = @parent.options.fetch(:latency, nil)

  @listener = nil

  @callbacks = ::Middleman::CallbackManager.new
  @callbacks.install_methods!(self, [:on_change])

  @waiting_for_existence = !@directory.exist?
end

Instance Attribute Details

#directoryObject (readonly)

Returns the value of attribute directory.



43
44
45
# File 'lib/middleman-core/sources/source_watcher.rb', line 43

def directory
  @directory
end

#listenerObject (readonly)

Reference to lower level listener



50
51
52
# File 'lib/middleman-core/sources/source_watcher.rb', line 50

def listener
  @listener
end

#optionsObject (readonly)

Returns the value of attribute options.



47
48
49
# File 'lib/middleman-core/sources/source_watcher.rb', line 47

def options
  @options
end

#typeObject (readonly)

Returns the value of attribute type.



39
40
41
# File 'lib/middleman-core/sources/source_watcher.rb', line 39

def type
  @type
end

Instance Method Details

#Any

This method returns an undefined value.

Stop the listener.



109
# File 'lib/middleman-core/sources/source_watcher.rb', line 109

Contract Any

#exists?(path) ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
# File 'lib/middleman-core/sources/source_watcher.rb', line 148

def exists?(path)
  !find(path).nil?
end

#filesObject



118
119
120
# File 'lib/middleman-core/sources/source_watcher.rb', line 118

def files
  @files.values
end

#find(path, glob = false) ⇒ Object



128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/middleman-core/sources/source_watcher.rb', line 128

def find(path, glob=false)
  path = path.to_s.encode!('UTF-8', 'UTF-8-MAC') if RUBY_PLATFORM =~ /darwin/

  p = Pathname(path)

  return nil if p.absolute? && !p.to_s.start_with?(@directory.to_s)

  p = @directory + p if p.relative?
  if glob
    @extensionless_files[p]
  else
    @files[p]
  end
end

#find_new_files!Object



186
187
188
189
190
191
# File 'lib/middleman-core/sources/source_watcher.rb', line 186

def find_new_files!
  new_files = ::Middleman::Util.all_files_under(@directory.to_s, &method(:should_not_recurse?))
                               .reject { |p| @files.key?(p) }

  update(new_files, []).flatten.map { |s| s[:full_path] }
end

#listen!Object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/middleman-core/sources/source_watcher.rb', line 156

def listen!
  return if @disable_watcher || @listener || @waiting_for_existence

  config = {
    force_polling: @force_polling,
    wait_for_delay: 0.5
  }

  config[:latency] = @latency if @latency

  @listener = ::Listen.to(@directory.to_s, config, &method(:on_listener_change))

  @listener.ignore(/^\.sass-cache/)
  # @listener.only(@only) unless @only.empty?

  @listener.start
end

#poll_once!Object



197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/middleman-core/sources/source_watcher.rb', line 197

def poll_once!
  updated = ::Middleman::Util.all_files_under(@directory.to_s, &method(:should_not_recurse?))
  removed = @files.keys.reject { |p| updated.include?(p) }

  result = update(updated, removed)

  if @waiting_for_existence && @directory.exist?
    @waiting_for_existence = false
    listen!
  end

  result.flatten.map { |s| s[:full_path] }
end

#stop_listener!Object



178
179
180
181
182
183
# File 'lib/middleman-core/sources/source_watcher.rb', line 178

def stop_listener!
  return unless @listener

  @listener.stop
  @listener = nil
end

#to_sObject Also known as: inspect

Work around this bug: http://bugs.ruby-lang.org/issues/4521 where Ruby will call to_s/inspect while printing exception messages, which can take a long time (minutes at full CPU) if the object is huge or has cyclic references, like this.



215
216
217
# File 'lib/middleman-core/sources/source_watcher.rb', line 215

def to_s
  "#<Middleman::SourceWatcher:0x#{object_id} type=#{@type.inspect} directory=#{@directory.inspect}>"
end

#unwatchObject



110
111
112
# File 'lib/middleman-core/sources/source_watcher.rb', line 110

def unwatch
  stop_listener!
end

#update_path(directory) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/middleman-core/sources/source_watcher.rb', line 94

def update_path(directory)
  @directory = Pathname(directory)

  stop_listener! if @listener

  update([], @files.values.map { |source_file| source_file[:full_path] })

  poll_once!

  listen! unless @disable_watcher
end