middleman-core-with-external-sources-watch-fix 4.1.0 → 4.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/features/asset_hash.feature +47 -10
  3. data/features/builder.feature +8 -4
  4. data/features/collections.feature +27 -0
  5. data/features/custom_layouts.feature +17 -1
  6. data/features/dynamic_pages.feature +15 -12
  7. data/features/front-matter-neighbor.feature +6 -2
  8. data/features/helpers_link_to.feature +11 -1
  9. data/features/i18n_link_to.feature +34 -34
  10. data/features/markdown_redcarpet_in_slim.feature +41 -0
  11. data/features/page-id.feature +26 -0
  12. data/features/partials.feature +17 -5
  13. data/features/relative_assets.feature +1 -1
  14. data/features/relative_assets_helpers_only.feature +123 -0
  15. data/features/sass_in_slim.feature +40 -0
  16. data/features/template-key-collision.feature +26 -0
  17. data/fixtures/asset-hash-minified-app/source/images/100px.jpg +0 -0
  18. data/fixtures/asset-hash-minified-app/source/stylesheets/test.css +3 -0
  19. data/fixtures/asset-hash-prefix/config.rb +7 -0
  20. data/fixtures/asset-hash-prefix/lib/middleware.rb +16 -0
  21. data/fixtures/asset-hash-prefix/source/index.html.erb +6 -0
  22. data/fixtures/asset-hash-prefix/source/javascripts/application.js +2 -0
  23. data/fixtures/asset-hash-prefix/source/javascripts/application.js.map +1 -0
  24. data/fixtures/asset-hash-prefix/source/layout.erb +17 -0
  25. data/fixtures/asset-hash-source-map/config.rb +6 -0
  26. data/fixtures/asset-hash-source-map/lib/middleware.rb +16 -0
  27. data/fixtures/asset-hash-source-map/source/index.html.erb +6 -0
  28. data/fixtures/asset-hash-source-map/source/javascripts/application.js +2 -0
  29. data/fixtures/asset-hash-source-map/source/javascripts/application.js.map +1 -0
  30. data/fixtures/asset-hash-source-map/source/layout.erb +17 -0
  31. data/fixtures/asset-host-app/source/images/blank0.gif +0 -0
  32. data/fixtures/asset-host-app/source/images/blank1.gif +0 -0
  33. data/fixtures/asset-host-app/source/images/blank10.gif +0 -0
  34. data/fixtures/asset-host-app/source/images/blank100.gif +0 -0
  35. data/fixtures/asset-host-app/source/images/blank101.gif +0 -0
  36. data/fixtures/asset-host-app/source/images/blank1010.gif +0 -0
  37. data/fixtures/asset-host-app/source/images/blank102.gif +0 -0
  38. data/fixtures/asset-host-app/source/images/blank1020.gif +0 -0
  39. data/fixtures/asset-host-app/source/images/blank1021.gif +0 -0
  40. data/fixtures/asset-host-app/source/images/blank1022.gif +0 -0
  41. data/fixtures/asset-host-app/source/images/blank1023.gif +0 -0
  42. data/fixtures/asset-host-app/source/images/blank1024.gif +0 -0
  43. data/fixtures/asset-host-app/source/images/blank103.gif +0 -0
  44. data/fixtures/asset-host-app/source/images/blank1030.gif +0 -0
  45. data/fixtures/asset-host-app/source/images/blank1031.gif +0 -0
  46. data/fixtures/asset-host-app/source/images/blank1032.gif +0 -0
  47. data/fixtures/asset-host-app/source/images/blank1033.gif +0 -0
  48. data/fixtures/asset-host-app/source/images/blank1034.gif +0 -0
  49. data/fixtures/asset-host-app/source/images/blank104.gif +0 -0
  50. data/fixtures/asset-host-app/source/images/blank1043.gif +0 -0
  51. data/fixtures/asset-host-app/source/images/blank1054.gif +0 -0
  52. data/fixtures/asset-host-app/source/images/blank2.gif +0 -0
  53. data/fixtures/asset-host-app/source/images/blank20.gif +0 -0
  54. data/fixtures/asset-host-app/source/images/blank21.gif +0 -0
  55. data/fixtures/asset-host-app/source/images/blank22.gif +0 -0
  56. data/fixtures/asset-host-app/source/images/blank23.gif +0 -0
  57. data/fixtures/asset-host-app/source/images/blank24.gif +0 -0
  58. data/fixtures/asset-host-app/source/images/blank3.gif +0 -0
  59. data/fixtures/asset-host-app/source/images/blank30.gif +0 -0
  60. data/fixtures/asset-host-app/source/images/blank31.gif +0 -0
  61. data/fixtures/asset-host-app/source/images/blank32.gif +0 -0
  62. data/fixtures/asset-host-app/source/images/blank33.gif +0 -0
  63. data/fixtures/asset-host-app/source/images/blank34.gif +0 -0
  64. data/fixtures/asset-host-app/source/images/blank4.gif +0 -0
  65. data/fixtures/asset-host-app/source/images/blank43.gif +0 -0
  66. data/fixtures/asset-host-app/source/images/blank54.gif +0 -0
  67. data/fixtures/dynamic-pages-app/config.rb +4 -0
  68. data/fixtures/dynamic-pages-app/source/should_be_ignored9.html +1 -0
  69. data/fixtures/external-pipeline-error/config.rb +5 -0
  70. data/fixtures/external-pipeline-error/source/javascripts/file.js +0 -0
  71. data/fixtures/page-id-app/config.rb +5 -0
  72. data/fixtures/page-id-app/source/fm.html.erb +5 -0
  73. data/fixtures/page-id-app/source/index.html.erb +6 -0
  74. data/fixtures/page-id-app/source/overwrites/from-default.html.erb +1 -0
  75. data/fixtures/page-id-app/source/overwrites/from-frontmatter.html.erb +5 -0
  76. data/fixtures/partials-app/source/_block.erb +3 -0
  77. data/fixtures/partials-app/source/block.html.erb +3 -0
  78. data/fixtures/partials-app/source/index_missing.html.erb +3 -0
  79. data/fixtures/relative-assets-app/source/images/blank2.gif +0 -0
  80. data/fixtures/sass-in-slim-app/config.rb +0 -0
  81. data/lib/middleman-core/application.rb +30 -4
  82. data/lib/middleman-core/builder.rb +8 -2
  83. data/lib/middleman-core/config_context.rb +5 -1
  84. data/lib/middleman-core/configuration.rb +1 -1
  85. data/lib/middleman-core/core_extensions/collections.rb +28 -17
  86. data/lib/middleman-core/core_extensions/collections/step_context.rb +14 -7
  87. data/lib/middleman-core/core_extensions/data.rb +4 -2
  88. data/lib/middleman-core/core_extensions/default_helpers.rb +1 -0
  89. data/lib/middleman-core/core_extensions/front_matter.rb +8 -6
  90. data/lib/middleman-core/core_extensions/i18n.rb +3 -1
  91. data/lib/middleman-core/core_extensions/inline_url_rewriter.rb +20 -35
  92. data/lib/middleman-core/core_extensions/routing.rb +6 -3
  93. data/lib/middleman-core/extension.rb +41 -6
  94. data/lib/middleman-core/extensions.rb +2 -2
  95. data/lib/middleman-core/extensions/asset_hash.rb +10 -5
  96. data/lib/middleman-core/extensions/asset_host.rb +4 -3
  97. data/lib/middleman-core/extensions/cache_buster.rb +2 -2
  98. data/lib/middleman-core/extensions/directory_indexes.rb +8 -2
  99. data/lib/middleman-core/extensions/external_pipeline.rb +54 -8
  100. data/lib/middleman-core/extensions/minify_css.rb +9 -1
  101. data/lib/middleman-core/extensions/minify_javascript.rb +8 -0
  102. data/lib/middleman-core/extensions/relative_assets.rb +38 -13
  103. data/lib/middleman-core/file_renderer.rb +4 -4
  104. data/lib/middleman-core/load_paths.rb +3 -1
  105. data/lib/middleman-core/logger.rb +1 -1
  106. data/lib/middleman-core/meta_pages/templates/index.html.erb +3 -1
  107. data/lib/middleman-core/preview_server.rb +25 -18
  108. data/lib/middleman-core/rack.rb +2 -0
  109. data/lib/middleman-core/renderers/redcarpet.rb +2 -2
  110. data/lib/middleman-core/renderers/sass_functions.rb +4 -6
  111. data/lib/middleman-core/renderers/slim.rb +1 -5
  112. data/lib/middleman-core/sitemap/extensions/import.rb +2 -2
  113. data/lib/middleman-core/sitemap/extensions/proxies.rb +4 -1
  114. data/lib/middleman-core/sitemap/extensions/redirects.rb +1 -2
  115. data/lib/middleman-core/sitemap/resource.rb +15 -5
  116. data/lib/middleman-core/sitemap/store.rb +33 -2
  117. data/lib/middleman-core/sources.rb +2 -1
  118. data/lib/middleman-core/sources/source_watcher.rb +17 -6
  119. data/lib/middleman-core/template_context.rb +26 -21
  120. data/lib/middleman-core/template_renderer.rb +22 -9
  121. data/lib/middleman-core/util/binary.rb +4 -5
  122. data/lib/middleman-core/util/data.rb +33 -18
  123. data/lib/middleman-core/util/files.rb +27 -24
  124. data/lib/middleman-core/util/paths.rb +74 -14
  125. data/lib/middleman-core/util/rack.rb +16 -6
  126. data/lib/middleman-core/version.rb +1 -1
  127. data/middleman-core.gemspec +11 -8
  128. data/spec/middleman-core/core_extensions/data_spec.rb +107 -1
  129. data/spec/middleman-core/util_spec.rb +37 -0
  130. metadata +196 -18
@@ -1,3 +1,5 @@
1
+ require 'set'
2
+
1
3
  module Middleman
2
4
  module Util
3
5
  include Contracts
@@ -54,8 +56,10 @@ module Middleman
54
56
 
55
57
  Contract String => String
56
58
  def step_through_extensions(path)
57
- while ::Tilt[path]
59
+ while ::Middleman::Util.tilt_class(path)
58
60
  ext = ::File.extname(path)
61
+ break if ext.empty?
62
+
59
63
  yield ext if block_given?
60
64
 
61
65
  # Strip templating extensions as long as Tilt knows them
@@ -80,13 +84,18 @@ module Middleman
80
84
  # @return [String]
81
85
  Contract String => ArrayOf[String]
82
86
  def collect_extensions(path)
83
- return [] if ::File.basename(path).start_with?('.')
87
+ @@extensions_cache ||= {}
84
88
 
85
- result = []
89
+ base_name = ::File.basename(path)
90
+ @@extensions_cache[base_name] ||= begin
91
+ result = []
86
92
 
87
- step_through_extensions(path) { |e| result << e }
93
+ unless base_name.start_with?('.')
94
+ step_through_extensions(base_name) { |e| result << e }
95
+ end
88
96
 
89
- result
97
+ result
98
+ end
90
99
  end
91
100
 
92
101
  # Finds files which should also be considered to be dirty when
@@ -99,35 +108,29 @@ module Middleman
99
108
  def find_related_files(app, files)
100
109
  return [] if files.empty?
101
110
 
102
- all_extensions = files.flat_map { |f| collect_extensions(f.to_s) }
111
+ file_set = ::Set.new(files)
103
112
 
113
+ all_extensions = files.flat_map { |f| collect_extensions(f.to_s) }
104
114
  sass_type_aliasing = ['.scss', '.sass']
105
115
  erb_type_aliasing = ['.erb', '.haml', '.slim']
106
116
 
107
- if (all_extensions & sass_type_aliasing).length > 0
108
- all_extensions |= sass_type_aliasing
109
- end
110
-
111
- if (all_extensions & erb_type_aliasing).length > 0
112
- all_extensions |= erb_type_aliasing
113
- end
117
+ all_extensions |= sass_type_aliasing unless (all_extensions & sass_type_aliasing).empty?
118
+ all_extensions |= erb_type_aliasing unless (all_extensions & erb_type_aliasing).empty?
114
119
 
115
120
  all_extensions.uniq!
116
121
 
117
- app.sitemap.resources.select(&:file_descriptor).select { |r|
118
- local_extensions = collect_extensions(r.file_descriptor[:full_path].to_s)
122
+ app.sitemap.resources.select { |r|
123
+ if r.file_descriptor
124
+ local_extensions = collect_extensions(r.file_descriptor[:full_path].to_s)
125
+ local_extensions |= sass_type_aliasing unless (local_extensions & sass_type_aliasing).empty?
126
+ local_extensions |= erb_type_aliasing unless (local_extensions & erb_type_aliasing).empty?
119
127
 
120
- if (local_extensions & sass_type_aliasing).length > 0
121
- local_extensions |= sass_type_aliasing
122
- end
128
+ local_extensions.uniq!
123
129
 
124
- if (local_extensions & erb_type_aliasing).length > 0
125
- local_extensions |= erb_type_aliasing
130
+ !(all_extensions & local_extensions).empty? && !file_set.include?(r.file_descriptor[:full_path])
131
+ else
132
+ false
126
133
  end
127
-
128
- local_extensions.uniq!
129
-
130
- ((all_extensions & local_extensions).length > 0) && files.none? { |f| f == r.file_descriptor[:full_path] }
131
134
  }.map(&:file_descriptor)
132
135
  end
133
136
  end
@@ -1,24 +1,41 @@
1
1
  # Core Pathname library used for traversal
2
2
  require 'pathname'
3
3
  require 'uri'
4
+ require 'addressable'
5
+ require 'memoist'
6
+ require 'tilt'
4
7
 
5
8
  require 'middleman-core/contracts'
6
9
 
7
10
  # rubocop:disable ModuleLength
8
11
  module Middleman
9
12
  module Util
13
+ extend Memoist
10
14
  include Contracts
11
15
 
12
16
  module_function
13
17
 
18
+ Contract String => ::Addressable::URI
19
+ def parse_uri(uri)
20
+ ::Addressable::URI.parse(uri)
21
+ end
22
+ memoize :parse_uri
23
+
24
+ Contract String => Any
25
+ def tilt_class(path)
26
+ ::Tilt[path]
27
+ end
28
+ memoize :tilt_class
29
+
14
30
  # Normalize a path to not include a leading slash
15
31
  # @param [String] path
16
32
  # @return [String]
17
33
  Contract String => String
18
34
  def normalize_path(path)
19
- # The tr call works around a bug in Ruby's Unicode handling
35
+ # The tr call works around a bug in Ruby's Unicode handling
20
36
  ::URI.decode(path).sub(%r{^/}, '').tr('', '')
21
- end
37
+ end
38
+ memoize :normalize_path
22
39
 
23
40
  # This is a separate method from normalize_path in case we
24
41
  # change how we normalize paths
@@ -26,6 +43,26 @@ module Middleman
26
43
  def strip_leading_slash(path)
27
44
  path.sub(%r{^/}, '')
28
45
  end
46
+ memoize :strip_leading_slash
47
+
48
+ IGNORE_DESCRIPTOR = Or[Regexp, RespondTo[:call], String]
49
+ Contract IGNORE_DESCRIPTOR, String => Bool
50
+ def should_ignore?(validator, value)
51
+ if validator.is_a? Regexp
52
+ # Treat as Regexp
53
+ !!(value =~ validator)
54
+ elsif validator.respond_to? :call
55
+ # Treat as proc
56
+ validator.call(value)
57
+ elsif validator.is_a? String
58
+ # Treat as glob
59
+ File.fnmatch(value, validator)
60
+ else
61
+ # If some unknown thing, don't ignore
62
+ false
63
+ end
64
+ end
65
+ memoize :should_ignore?
29
66
 
30
67
  # Get the path of a file of a given type
31
68
  #
@@ -74,10 +111,16 @@ module Middleman
74
111
  raise ArgumentError, '#asset_url must be run in a context with current_resource if relative: true'
75
112
  end
76
113
 
77
- uri = URI(path)
114
+ uri = ::Middleman::Util.parse_uri(path)
78
115
  path = uri.path
79
116
 
80
- result = if resource = app.sitemap.find_resource_by_destination_path(url_for(app, path, options))
117
+ # Ensure the url we pass into find_resource_by_destination_path is not a
118
+ # relative path, since it only takes absolute url paths.
119
+ dest_path = url_for(app, path, options.merge(relative: false))
120
+
121
+ result = if resource = app.sitemap.find_resource_by_path(dest_path)
122
+ resource.url
123
+ elsif resource = app.sitemap.find_resource_by_destination_path(dest_path)
81
124
  resource.url
82
125
  else
83
126
  path = ::File.join(prefix, path)
@@ -88,9 +131,15 @@ module Middleman
88
131
  end
89
132
  end
90
133
 
91
- final_result = ::URI.encode(relative_path_from_resource(options[:current_resource], result, options[:relative]))
134
+ final_result = ::Addressable::URI.encode(
135
+ relative_path_from_resource(
136
+ options[:current_resource],
137
+ result,
138
+ options[:relative]
139
+ )
140
+ )
92
141
 
93
- result_uri = URI(final_result)
142
+ result_uri = ::Middleman::Util.parse_uri(final_result)
94
143
  result_uri.query = uri.query
95
144
  result_uri.fragment = uri.fragment
96
145
  result_uri.to_s
@@ -99,8 +148,13 @@ module Middleman
99
148
  # Given a source path (referenced either absolutely or relatively)
100
149
  # or a Resource, this will produce the nice URL configured for that
101
150
  # path, respecting :relative_links, directory indexes, etc.
102
- Contract ::Middleman::Application, Or[String, ::Middleman::Sitemap::Resource], Hash => String
151
+ Contract ::Middleman::Application, Or[String, Symbol, ::Middleman::Sitemap::Resource], Hash => String
103
152
  def url_for(app, path_or_resource, options={})
153
+ if path_or_resource.is_a?(String) || path_or_resource.is_a?(Symbol)
154
+ r = app.sitemap.find_resource_by_page_id(path_or_resource)
155
+ path_or_resource = r if r
156
+ end
157
+
104
158
  # Handle Resources and other things which define their own url method
105
159
  url = if path_or_resource.respond_to?(:url)
106
160
  path_or_resource.url
@@ -110,8 +164,8 @@ module Middleman
110
164
 
111
165
  # Try to parse URL
112
166
  begin
113
- uri = URI(url)
114
- rescue ::URI::InvalidURIError
167
+ uri = ::Middleman::Util.parse_uri(url)
168
+ rescue ::Addressable::URI::InvalidURIError
115
169
  # Nothing we can do with it, it's not really a URI
116
170
  return url
117
171
  end
@@ -154,7 +208,13 @@ module Middleman
154
208
 
155
209
  if resource
156
210
  uri.path = if this_resource
157
- ::URI.encode(relative_path_from_resource(this_resource, resource_url, effective_relative))
211
+ ::Addressable::URI.encode(
212
+ relative_path_from_resource(
213
+ this_resource,
214
+ resource_url,
215
+ effective_relative
216
+ )
217
+ )
158
218
  else
159
219
  resource_url
160
220
  end
@@ -232,20 +292,20 @@ module Middleman
232
292
  # @return [Boolean] Whether the path matches the matcher
233
293
  Contract PATH_MATCHER, String => Bool
234
294
  def path_match(matcher, path)
235
- case
236
- when matcher.is_a?(String)
295
+ if matcher.is_a?(String)
237
296
  if matcher.include? '*'
238
297
  ::File.fnmatch(matcher, path)
239
298
  else
240
299
  path == matcher
241
300
  end
242
- when matcher.respond_to?(:match)
301
+ elsif matcher.respond_to?(:match)
243
302
  !!(path =~ matcher)
244
- when matcher.respond_to?(:call)
303
+ elsif matcher.respond_to?(:call)
245
304
  matcher.call(path)
246
305
  else
247
306
  ::File.fnmatch(matcher.to_s, path)
248
307
  end
249
308
  end
309
+ memoize :path_match
250
310
  end
251
311
  end
@@ -20,9 +20,9 @@ module Middleman
20
20
  result
21
21
  end
22
22
 
23
- Contract String, String, ArrayOf[String], Proc => String
24
- def rewrite_paths(body, _path, exts, &_block)
25
- matcher = /([\'\"\(,]\s*)([^\s\'\"\)>]+(#{::Regexp.union(exts)}))/
23
+ Contract String, String, ArrayOf[String], IsA['::Middleman::Application'], Proc => String
24
+ def rewrite_paths(body, path, exts, app, &_block)
25
+ matcher = /([\'\"\(,]\s*|# sourceMappingURL=)([^\s\'\"\)\(>]+(#{::Regexp.union(exts)}))/
26
26
 
27
27
  url_fn_prefix = 'url('
28
28
 
@@ -35,11 +35,21 @@ module Middleman
35
35
  asset_path = asset_path[url_fn_prefix.length..-1]
36
36
  end
37
37
 
38
+ current_resource = app.sitemap.find_resource_by_destination_path(path)
39
+
38
40
  begin
39
- uri = ::Addressable::URI.parse(asset_path)
41
+ uri = ::Middleman::Util.parse_uri(asset_path)
42
+
43
+ if uri.relative? && uri.host.nil? && !(asset_path =~ /^[^\/].*[a-z]+\.[a-z]+\/.*/)
44
+ dest_path = ::Middleman::Util.url_for(app, asset_path, relative: false, current_resource: current_resource)
45
+
46
+ resource = app.sitemap.find_resource_by_destination_path(dest_path)
40
47
 
41
- if uri.relative? && uri.host.nil? && !(asset_path =~ /^[^\/].*[a-z]+\.[a-z]+\/.*/) && (result = yield(asset_path))
42
- "#{opening_character}#{result}"
48
+ if resource && (result = yield(asset_path))
49
+ "#{opening_character}#{result}"
50
+ else
51
+ match
52
+ end
43
53
  else
44
54
  match
45
55
  end
@@ -1,5 +1,5 @@
1
1
  module Middleman
2
2
  # Current Version
3
3
  # @return [String]
4
- VERSION = '4.1.0'.freeze unless const_defined?(:VERSION)
4
+ VERSION = '4.1.10'.freeze unless const_defined?(:VERSION)
5
5
  end
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.email = ['me@tdreyno.com', 'ben@benhollis.net', 'karlfreeman@gmail.com']
12
12
  s.homepage = 'http://middlemanapp.com'
13
13
  s.summary = 'Hand-crafted frontend development'
14
- s.description = 'Patch containing: https://github.com/middleman/middleman/pull/2190. A static site generator. Provides dozens of templating languages (Haml, Sass, Compass, Slim, CoffeeScript, and more). Makes minification, compression, cache busting, Yaml data (and more) an easy part of your development cycle.'
14
+ s.description = 'Contains patch https://github.com/middleman/middleman/pull/2190. A static site generator. Provides dozens of templating languages (Haml, Sass, Compass, Slim, CoffeeScript, and more). Makes minification, compression, cache busting, Yaml data (and more) an easy part of your development cycle.'
15
15
 
16
16
  s.files = `git ls-files -z`.split("\0")
17
17
  s.test_files = `git ls-files -z -- {fixtures,features}/*`.split("\0")
@@ -25,36 +25,39 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency('erubis')
26
26
  s.add_dependency('fast_blank')
27
27
  s.add_dependency('parallel')
28
+ s.add_dependency('servolux')
29
+ s.add_dependency('dotenv')
28
30
 
29
31
  # Helpers
30
32
  s.add_dependency('activesupport', ['~> 4.2'])
31
33
  s.add_dependency('padrino-helpers', ['~> 0.13.0'])
32
- s.add_dependency("addressable", ["~> 2.4.0"])
34
+ s.add_dependency("addressable", ["~> 2.3"])
35
+ s.add_dependency('memoist', ['~> 0.14'])
33
36
 
34
37
  # Watcher
35
- s.add_dependency('listen', ['~> 3.0'])
38
+ s.add_dependency('listen', ['~> 3.0.0'])
36
39
 
37
40
  # Tests
38
- s.add_dependency("capybara", ["~> 2.5.0"])
41
+ s.add_development_dependency("capybara", ["~> 2.5.0"])
39
42
 
40
43
  # i18n
41
44
  s.add_dependency('i18n', ['~> 0.7.0'])
42
45
 
43
46
  # Automatic Image Sizes
44
- s.add_dependency('fastimage', ['~> 1.8'])
47
+ s.add_dependency('fastimage', ['~> 2.0'])
45
48
 
46
49
  # Minify CSS
47
50
  s.add_dependency('sass', ['>= 3.4'])
48
51
 
49
52
  # Minify JS
50
- s.add_dependency('uglifier', ['~> 2.6'])
53
+ s.add_dependency('uglifier', ['~> 3.0'])
51
54
  s.add_dependency('execjs', ['~> 2.0'])
52
55
 
53
56
  # Testing
54
- s.add_dependency('contracts', ['~> 0.12.0'])
57
+ s.add_dependency('contracts', ['~> 0.13.0'])
55
58
 
56
59
  # Hash stuff
57
60
  s.add_dependency('hashie', ['~> 3.4'])
58
- s.add_dependency('hamster', ['~> 2.0'])
61
+ s.add_dependency('hamster', ['~> 3.0'])
59
62
  s.add_dependency('backports', ['~> 3.6'])
60
63
  end
@@ -7,6 +7,112 @@ end
7
7
 
8
8
  describe Middleman::CoreExtensions::Data::DataStore do
9
9
 
10
+ describe "#store" do
11
+ before :each do
12
+ @subject = described_class.new instance_double("Middleman::Application"),
13
+ Middleman::CoreExtensions::Data::DATA_FILE_MATCHER
14
+ end
15
+
16
+ context "when given a name and data" do
17
+ it "adds data at the given name" do
18
+ @subject.store :foo, { 'bar' => 'baz' }
19
+ @subject.store :baz, [:wu, :tang]
20
+
21
+ expect( @subject.store['foo'] ).to eq({ 'bar' => 'baz' })
22
+ expect( @subject.store['baz'] ).to match_array [:wu, :tang]
23
+ end
24
+
25
+ it "overwrites previous keys if given the same key" do
26
+ @subject.store :foo, { 'bar' => 'baz' }
27
+ @subject.store :foo, [:wu, :tang]
28
+
29
+ expect( @subject.store['foo'] ).to match_array [:wu, :tang]
30
+ end
31
+ end
32
+
33
+ context "when given no args" do
34
+ it "returns @local_sources instance var" do
35
+ @subject.instance_variable_set :"@local_sources", { foo: 'bar' }
36
+ expect( @subject.store ).to eq({ foo: 'bar' })
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#callbacks" do
42
+ before :each do
43
+ @subject = described_class.new instance_double("Middleman::Application"),
44
+ Middleman::CoreExtensions::Data::DATA_FILE_MATCHER
45
+ end
46
+
47
+ context "when given a name and proc" do
48
+ it "adds a callback at the given name" do
49
+ @subject.callbacks :foo, lambda { "bar" }
50
+ callback = @subject.instance_variable_get(:@callback_sources)['foo']
51
+
52
+ expect( callback.call ).to eq "bar"
53
+ end
54
+
55
+ it "overwrites previous keys if given the same key" do
56
+ @subject.callbacks :foo, lambda { "bar" }
57
+ @subject.callbacks :foo, lambda { "baz" }
58
+ callback = @subject.instance_variable_get(:@callback_sources)['foo']
59
+
60
+ expect( callback.call ).to eq "baz"
61
+ end
62
+ end
63
+
64
+ context "when given no args" do
65
+ it "returns @callback_sources instance var" do
66
+ @subject.instance_variable_set :"@callback_sources", { foo: 'bar' }
67
+ expect( @subject.callbacks ).to eq({ foo: 'bar' })
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "#data_for_path" do
73
+ before :each do
74
+ @subject = described_class.new instance_double("Middleman::Application"),
75
+ Middleman::CoreExtensions::Data::DATA_FILE_MATCHER
76
+ end
77
+
78
+ context "given path matches local data" do
79
+ it "returns hash for key" do
80
+ @subject.store :foo, { 'bar' => 'baz' }
81
+ expect( @subject.data_for_path(:foo) ).to eq({ 'bar' => 'baz' })
82
+ end
83
+
84
+ it "returns array for key" do
85
+ @subject.store :foo, [:bar, :baz]
86
+ expect( @subject.data_for_path(:foo) ).to match_array [:bar, :baz]
87
+ end
88
+ end
89
+
90
+ context "given path matches callback data" do
91
+ it "returns value of calback lambda" do
92
+ @subject.callbacks :foo, lambda { { 'bar' => 'baz' } }
93
+ @subject.callbacks :wu, lambda { [:tang, :clan] }
94
+
95
+ expect( @subject.data_for_path(:foo) ).to eq({ 'bar' => 'baz' })
96
+ expect( @subject.data_for_path(:wu) ).to match_array [:tang, :clan]
97
+ end
98
+ end
99
+
100
+ context "given path matches both sources" do
101
+ it "returns match from local data" do
102
+ @subject.store :foo, { 'local' => 'data' }
103
+ @subject.callbacks :foo, lambda { { 'callback' => 'data' } }
104
+
105
+ expect( @subject.data_for_path(:foo) ).to eq({ 'local' => 'data' })
106
+ end
107
+ end
108
+
109
+ context "given path matches no sources" do
110
+ it "returns nil" do
111
+ expect( @subject.data_for_path(:missing) ).to be_nil
112
+ end
113
+ end
114
+ end
115
+
10
116
  describe "#key?" do
11
117
 
12
118
  it "returns true if key included in local_data, local_sources, or callback_sources" do
@@ -38,4 +144,4 @@ describe Middleman::CoreExtensions::Data::DataStore do
38
144
 
39
145
  end
40
146
 
41
- end
147
+ end