middleman-core 4.0.0.beta.1 → 4.0.0.beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,7 @@
1
1
  # Used for merging results of metadata callbacks
2
2
  require 'active_support/core_ext/hash/deep_merge'
3
3
  require 'monitor'
4
+ require 'hamster'
4
5
 
5
6
  # Ignores
6
7
  Middleman::Extensions.register :sitemap_ignore, auto_activate: :before_configuration do
@@ -37,6 +38,8 @@ require 'middleman-core/contracts'
37
38
  module Middleman
38
39
  # Sitemap namespace
39
40
  module Sitemap
41
+ ManipulatorDescriptor = Struct.new :name, :manipulator, :priority, :custom_name
42
+
40
43
  # The Store class
41
44
  #
42
45
  # The Store manages a collection of Resource objects, which represent
@@ -46,20 +49,21 @@ module Middleman
46
49
  class Store
47
50
  include Contracts
48
51
 
49
- # @return [Middleman::Application]
52
+ Contract IsA['Middleman::Application']
50
53
  attr_reader :app
51
54
 
55
+ Contract Num
52
56
  attr_reader :update_count
53
57
 
54
58
  # Initialize with parent app
55
59
  # @param [Middleman::Application] app
60
+ Contract IsA['Middleman::Application'] => Any
56
61
  def initialize(app)
57
62
  @app = app
58
63
  @resources = []
59
64
  @update_count = 0
60
65
 
61
- # TODO: Should this be a set or hash?
62
- @resource_list_manipulators = []
66
+ @resource_list_manipulators = ::Hamster.vector
63
67
  @needs_sitemap_rebuild = true
64
68
 
65
69
  @lock = Monitor.new
@@ -76,24 +80,29 @@ module Middleman
76
80
  # @param [Numeric] priority Sets the order of this resource list manipulator relative to the rest. By default this is 50, and manipulators run in the order they are registered, but if a priority is provided then this will run ahead of or behind other manipulators.
77
81
  # @param [Symbol] custom_name The method name to execute.
78
82
  # @return [void]
79
- Contract Symbol, RespondTo['manipulate_resource_list'], Maybe[Num], Maybe[Symbol] => Any
83
+ Contract Symbol, RespondTo[:manipulate_resource_list], Maybe[Num], Maybe[Symbol] => Any
80
84
  def register_resource_list_manipulator(name, manipulator, priority=50, custom_name=nil)
81
85
  # The third argument used to be a boolean - handle those who still pass one
82
86
  priority = 50 unless priority.is_a? Numeric
83
- @resource_list_manipulators << [name, manipulator, priority, custom_name]
87
+ @resource_list_manipulators = @resource_list_manipulators.push(
88
+ ManipulatorDescriptor.new(name, manipulator, priority, custom_name)
89
+ )
90
+
84
91
  # The index trick is used so that the sort is stable - manipulators with the same priority
85
92
  # will always be ordered in the same order as they were registered.
86
93
  n = 0
87
94
  @resource_list_manipulators = @resource_list_manipulators.sort_by do |m|
88
95
  n += 1
89
- [m[2], n]
96
+ [m[:priority], n]
90
97
  end
98
+
91
99
  rebuild_resource_list!(:registered_new)
92
100
  end
93
101
 
94
102
  # Rebuild the list of resources from scratch, using registed manipulators
95
103
  # @return [void]
96
- def rebuild_resource_list!(_=nil)
104
+ Contract Maybe[Symbol] => Any
105
+ def rebuild_resource_list!(_name=nil)
97
106
  @lock.synchronize do
98
107
  @needs_sitemap_rebuild = true
99
108
  end
@@ -178,11 +187,13 @@ module Middleman
178
187
 
179
188
  @app.logger.debug '== Rebuilding resource list'
180
189
 
181
- @resources = @resource_list_manipulators.reduce([]) do |result, (_, manipulator, _, custom_name)|
182
- newres = manipulator.send(custom_name || :manipulate_resource_list, result)
190
+ @resources = @resource_list_manipulators.reduce([]) do |result, m|
191
+ newres = m[:manipulator].send(m[:custom_name] || :manipulate_resource_list, result)
183
192
 
184
193
  # Reset lookup cache
185
194
  reset_lookup_cache!
195
+
196
+ # Rebuild cache
186
197
  newres.each do |resource|
187
198
  @_lookup_by_path[resource.path] = resource
188
199
  @_lookup_by_destination_path[resource.destination_path] = resource
@@ -1,3 +1,4 @@
1
+ require 'hamster'
1
2
  require 'middleman-core/contracts'
2
3
  require 'backports/2.0.0/enumerable/lazy'
3
4
 
@@ -47,10 +48,10 @@ module Middleman
47
48
  @options = options
48
49
 
49
50
  # Set of procs wanting to be notified of changes
50
- @on_change_callbacks = []
51
+ @on_change_callbacks = ::Hamster.vector
51
52
 
52
53
  # Global ignores
53
- @ignores = {}
54
+ @ignores = ::Hamster.hash
54
55
 
55
56
  # Whether we're "running", which means we're in a stable
56
57
  # watch state after all initialization and config.
@@ -72,7 +73,8 @@ module Middleman
72
73
  # @return [void]
73
74
  Contract Symbol, Symbol, Or[Regexp, Proc] => Any
74
75
  def ignore(name, type, regex=nil, &block)
75
- @ignores[name] = { type: type, validator: (block_given? ? block : regex) }
76
+ @ignores = @ignores.put(name, type: type,
77
+ validator: (block_given? ? block : regex))
76
78
 
77
79
  bump_count
78
80
  find_new_files! if @running
@@ -238,11 +240,10 @@ module Middleman
238
240
  # Add callback to be run on file change or deletion
239
241
  #
240
242
  # @param [Symbol] type The change type.
241
- # @return [Set<CallbackDescriptor>]
242
- Contract Symbol, Proc => ArrayOf[CallbackDescriptor]
243
+ # @return [void]
244
+ Contract Symbol, Proc => Any
243
245
  def on_change(type, &block)
244
- @on_change_callbacks << CallbackDescriptor.new(type, block)
245
- @on_change_callbacks
246
+ @on_change_callbacks = @on_change_callbacks.push(CallbackDescriptor.new(type, block))
246
247
  end
247
248
 
248
249
  # Backwards compatible change handler.
@@ -328,7 +329,7 @@ module Middleman
328
329
  # @param [Set] callback_descriptors The registered callbacks.
329
330
  # @param [Array<Middleman::SourceFile>] files The files that were changed.
330
331
  # @return [void]
331
- Contract ArrayOf[CallbackDescriptor], ArrayOf[SourceFile], ArrayOf[SourceFile] => Any
332
+ Contract VectorOf[CallbackDescriptor], ArrayOf[SourceFile], ArrayOf[SourceFile] => Any
332
333
  def run_callbacks(callback_descriptors, updated_files, removed_files)
333
334
  callback_descriptors.each do |callback|
334
335
  if callback[:type] == :all
@@ -345,4 +346,4 @@ module Middleman
345
346
  end
346
347
 
347
348
  # And, require the actual default implementation for a watcher.
348
- require 'middleman-core/sources/source_watcher.rb'
349
+ require 'middleman-core/sources/source_watcher'
@@ -1,6 +1,7 @@
1
1
  # Watcher Library
2
2
  require 'listen'
3
3
  require 'middleman-core/contracts'
4
+ require 'middleman-core/contracts'
4
5
  require 'backports/2.0.0/enumerable/lazy'
5
6
 
6
7
  module Middleman
@@ -55,7 +56,8 @@ module Middleman
55
56
 
56
57
  @listener = nil
57
58
 
58
- @on_change_callbacks = Set.new
59
+ @callbacks = ::Middleman::CallbackManager.new
60
+ @callbacks.install_methods!(self, [:on_change])
59
61
 
60
62
  @waiting_for_existence = !@directory.exist?
61
63
  end
@@ -174,16 +176,6 @@ module Middleman
174
176
  listen!
175
177
  end
176
178
 
177
- # Add callback to be run on file change
178
- #
179
- # @param [Proc] matcher A Regexp to match the change path against
180
- # @return [Set<Proc>]
181
- Contract Proc => SetOf[Proc]
182
- def on_change(&block)
183
- @on_change_callbacks << block
184
- @on_change_callbacks
185
- end
186
-
187
179
  # Work around this bug: http://bugs.ruby-lang.org/issues/4521
188
180
  # where Ruby will call to_s/inspect while printing exception
189
181
  # messages, which can take a long time (minutes at full CPU)
@@ -237,11 +229,11 @@ module Middleman
237
229
  logger.debug "== Deletion (#{f[:types].inspect}): #{f[:relative_path]}"
238
230
  end
239
231
 
240
- run_callbacks(
241
- @on_change_callbacks,
232
+ execute_callbacks(:on_change, [
242
233
  valid_updates,
243
- valid_removes
244
- ) unless valid_updates.empty? && valid_removes.empty?
234
+ valid_removes,
235
+ self
236
+ ]) unless valid_updates.empty? && valid_removes.empty?
245
237
  end
246
238
 
247
239
  def add_file_to_cache(f)
@@ -289,17 +281,5 @@ module Middleman
289
281
 
290
282
  ::Middleman::SourceFile.new(Pathname(relative_path), path, @directory, types)
291
283
  end
292
-
293
- # Notify callbacks for a file given an array of callbacks
294
- #
295
- # @param [Pathname] path The file that was changed
296
- # @param [Symbol] callbacks_name The name of the callbacks method
297
- # @return [void]
298
- Contract Set, ArrayOf[IsA['Middleman::SourceFile']], ArrayOf[IsA['Middleman::SourceFile']] => Any
299
- def run_callbacks(callbacks, updated_files, removed_files)
300
- callbacks.each do |callback|
301
- callback.call(updated_files, removed_files, self)
302
- end
303
- end
304
284
  end
305
285
  end
@@ -1,5 +1,5 @@
1
1
  module Middleman
2
2
  # Current Version
3
3
  # @return [String]
4
- VERSION = '4.0.0.beta.1' unless const_defined?(:VERSION)
4
+ VERSION = '4.0.0.beta.2' unless const_defined?(:VERSION)
5
5
  end
@@ -24,7 +24,6 @@ Gem::Specification.new do |s|
24
24
  s.add_dependency('rack', ['>= 1.4.5', '< 2.0'])
25
25
  s.add_dependency('tilt', ['~> 1.4.1'])
26
26
  s.add_dependency('erubis')
27
- s.add_dependency('hooks', ['~> 0.3'])
28
27
 
29
28
  # Helpers
30
29
  s.add_dependency('activesupport', ['~> 4.2.0'])
@@ -0,0 +1,132 @@
1
+ # require 'spec_helper'
2
+ require 'middleman-core/callback_manager'
3
+
4
+ describe ::Middleman::CallbackManager do
5
+ it "adds a simple key" do
6
+ counters = {
7
+ test1: 0,
8
+ test2: 0,
9
+ test3: 0
10
+ }
11
+
12
+ m = ::Middleman::CallbackManager.new
13
+ m.add(:test3) { counters[:test3] += 1 }
14
+ m.add(:test1) { counters[:test1] += 1 }
15
+ m.add(:test2) { counters[:test2] += 1 }
16
+ m.add(:test1) { counters[:test1] += 1 }
17
+ m.add(:test2) { counters[:test2] += 1 }
18
+ m.add(:test1) { counters[:test1] += 1 }
19
+ m.add(:test3) { counters[:test3] += 1 }
20
+
21
+ m.execute(:test1)
22
+ m.execute(:test2)
23
+
24
+ expect(counters[:test1]).to eq 3
25
+ expect(counters[:test2]).to eq 2
26
+ expect(counters[:test3]).to eq 0
27
+ end
28
+
29
+ it "callbacks run in order" do
30
+ result = []
31
+
32
+ m = ::Middleman::CallbackManager.new
33
+ m.add(:test) { result.push(1) }
34
+ m.add(:test) { result.push(2) }
35
+ m.add(:test) { result.push(3) }
36
+
37
+ m.execute(:test)
38
+
39
+ expect(result.join('')).to eq '123'
40
+ end
41
+
42
+ it "adds a nested key" do
43
+ counters = {
44
+ test1: 0,
45
+ test1a: 0
46
+ }
47
+
48
+ m = ::Middleman::CallbackManager.new
49
+ m.add([:test1, :a]) { |n| counters[:test1a] += n }
50
+ m.add(:test1) { counters[:test1] += 1 }
51
+
52
+ m.execute([:test1, :a], [2])
53
+ m.execute([:test1, :b], [5])
54
+
55
+ expect(counters[:test1]).to eq 0
56
+ expect(counters[:test1a]).to eq 2
57
+ end
58
+
59
+ it "works in isolation" do
60
+ m1 = ::Middleman::CallbackManager.new
61
+ m2 = ::Middleman::CallbackManager.new
62
+
63
+ counters = {
64
+ test1: 0,
65
+ test2: 0
66
+ }
67
+
68
+ m1.add(:test1) { |n| counters[:test1] += n }
69
+ m2.add(:test1) { |n| counters[:test2] += n }
70
+
71
+ m1.execute(:test1, [2])
72
+ m2.execute(:test1, [5])
73
+ m1.execute(:test2, [20])
74
+ m2.execute(:test2, [50])
75
+
76
+ expect(counters[:test1]).to eq 2
77
+ expect(counters[:test2]).to eq 5
78
+ end
79
+
80
+ it "installs to arbitrary instances" do
81
+ instance = Class.new(Object).new
82
+
83
+ m = ::Middleman::CallbackManager.new
84
+ m.install_methods!(instance, [:ready])
85
+
86
+ counter = 0
87
+ instance.ready { |n| counter += n }
88
+ instance.execute_callbacks(:ready, [2])
89
+ instance.execute_callbacks(:ready2, [10])
90
+ instance.execute_callbacks([:ready], [20])
91
+ instance.execute_callbacks([:ready, :two], [20])
92
+ expect(counter).to eq 2
93
+ end
94
+
95
+ it "executes in default scope" do
96
+ instance = Class.new(Object).new
97
+ m = ::Middleman::CallbackManager.new
98
+ m.install_methods!(instance, [:ready])
99
+
100
+ internal_self = nil
101
+ instance.ready do
102
+ internal_self = self
103
+ end
104
+
105
+ instance.execute_callbacks(:ready)
106
+
107
+ expect(internal_self) === instance
108
+ end
109
+
110
+ it "executes in custom scope" do
111
+ instance = Class.new(Object).new
112
+ m = ::Middleman::CallbackManager.new
113
+ m.install_methods!(instance, [:ready])
114
+
115
+ external_class = Struct.new(:counter, :scope) do
116
+ def when_ready(n)
117
+ self[:scope] = self
118
+ self[:counter] += n
119
+ end
120
+ end
121
+
122
+ external_instance = external_class.new(0, nil)
123
+
124
+ instance.ready(&external_instance.method(:when_ready))
125
+
126
+ instance.execute_callbacks(:ready, [5])
127
+
128
+ expect(external_instance[:scope]).to eq external_instance
129
+ expect(external_instance[:counter]).to eq 5
130
+ end
131
+
132
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: middleman-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.beta.1
4
+ version: 4.0.0.beta.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Reynolds
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-05-02 00:00:00.000000000 Z
13
+ date: 2015-05-04 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -88,20 +88,6 @@ dependencies:
88
88
  - - ">="
89
89
  - !ruby/object:Gem::Version
90
90
  version: '0'
91
- - !ruby/object:Gem::Dependency
92
- name: hooks
93
- requirement: !ruby/object:Gem::Requirement
94
- requirements:
95
- - - "~>"
96
- - !ruby/object:Gem::Version
97
- version: '0.3'
98
- type: :runtime
99
- prerelease: false
100
- version_requirements: !ruby/object:Gem::Requirement
101
- requirements:
102
- - - "~>"
103
- - !ruby/object:Gem::Version
104
- version: '0.3'
105
91
  - !ruby/object:Gem::Dependency
106
92
  name: activesupport
107
93
  requirement: !ruby/object:Gem::Requirement
@@ -1129,6 +1115,7 @@ files:
1129
1115
  - lib/middleman-core.rb
1130
1116
  - lib/middleman-core/application.rb
1131
1117
  - lib/middleman-core/builder.rb
1118
+ - lib/middleman-core/callback_manager.rb
1132
1119
  - lib/middleman-core/cli/server.rb
1133
1120
  - lib/middleman-core/config_context.rb
1134
1121
  - lib/middleman-core/configuration.rb
@@ -1222,6 +1209,7 @@ files:
1222
1209
  - spec/middleman-core/binary_spec/stars.svgz
1223
1210
  - spec/middleman-core/binary_spec/unicode
1224
1211
  - spec/middleman-core/binary_spec/unicode.txt
1212
+ - spec/middleman-core/callbacks_spec.rb
1225
1213
  - spec/middleman-core/core_extensions/data_spec.rb
1226
1214
  - spec/middleman-core/util_spec.rb
1227
1215
  - spec/spec_helper.rb