middleman 2.0.9.pre.2-x86-mingw32

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.
Files changed (197) hide show
  1. data/.gemtest +0 -0
  2. data/.gitignore +13 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG +47 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +20 -0
  7. data/README.md +19 -0
  8. data/Rakefile +15 -0
  9. data/bin/middleman +73 -0
  10. data/bin/mm-build +9 -0
  11. data/bin/mm-init +9 -0
  12. data/bin/mm-server +9 -0
  13. data/features/asset_host.feature +14 -0
  14. data/features/automatic_image_sizes.feature +16 -0
  15. data/features/builder.feature +23 -0
  16. data/features/cache_buster.feature +26 -0
  17. data/features/coffee-script.feature +17 -0
  18. data/features/data.feature +12 -0
  19. data/features/directory_index.feature +29 -0
  20. data/features/dynamic_pages.feature +33 -0
  21. data/features/front-matter.feature +7 -0
  22. data/features/generator.feature +8 -0
  23. data/features/helpers_auto_javascript_include_tag.feature +27 -0
  24. data/features/helpers_auto_stylesheet_link_tag.feature +27 -0
  25. data/features/helpers_page_classes.feature +17 -0
  26. data/features/liquid.feature +6 -0
  27. data/features/markdown.feature +7 -0
  28. data/features/minify_css.feature +24 -0
  29. data/features/minify_javascript.feature +23 -0
  30. data/features/padrino_helpers.feature +10 -0
  31. data/features/page_alias_and_layouts.feature +44 -0
  32. data/features/relative_assets.feature +44 -0
  33. data/features/scss-support.feature +12 -0
  34. data/features/sinatra.feature +6 -0
  35. data/features/slim.feature +7 -0
  36. data/features/sprockets.feature +21 -0
  37. data/features/sprockets_gems.feature +7 -0
  38. data/features/step_definitions/asset_host_steps.rb +8 -0
  39. data/features/step_definitions/builder_steps.rb +40 -0
  40. data/features/step_definitions/generator_steps.rb +30 -0
  41. data/features/step_definitions/middleman_steps.rb +46 -0
  42. data/features/step_definitions/page_layout_steps.rb +13 -0
  43. data/features/support/env.rb +3 -0
  44. data/features/tiny_src.feature +15 -0
  45. data/fixtures/indexable-app/config.rb +2 -0
  46. data/fixtures/indexable-app/source/a_folder/needs_index.html +1 -0
  47. data/fixtures/indexable-app/source/leave_me_alone.html +1 -0
  48. data/fixtures/indexable-app/source/needs_index.html +1 -0
  49. data/fixtures/indexable-app/source/regular/index.html +1 -0
  50. data/fixtures/relative-app/config.rb +0 -0
  51. data/fixtures/relative-app/source/images/blank.gif +0 -0
  52. data/fixtures/relative-app/source/stylesheets/relative_assets.css.sass +3 -0
  53. data/fixtures/sprockets-app/config.rb +1 -0
  54. data/fixtures/sprockets-app/source/jquery_include.js +1 -0
  55. data/fixtures/sprockets-app/source/library/javascripts/sprockets_base.js +5 -0
  56. data/fixtures/sprockets-app/source/library/javascripts/sprockets_sub.js +3 -0
  57. data/fixtures/test-app/config.rb +51 -0
  58. data/fixtures/test-app/data/test.yml +4 -0
  59. data/fixtures/test-app/source/_liquid_partial.liquid +1 -0
  60. data/fixtures/test-app/source/_partial.haml +1 -0
  61. data/fixtures/test-app/source/a_folder/needs_index.html +1 -0
  62. data/fixtures/test-app/source/asset_host.html.haml +1 -0
  63. data/fixtures/test-app/source/auto-css.html.haml +1 -0
  64. data/fixtures/test-app/source/auto-css/auto-css.html.haml +1 -0
  65. data/fixtures/test-app/source/auto-css/index.html.haml +1 -0
  66. data/fixtures/test-app/source/auto-css/sub/auto-css.html.haml +1 -0
  67. data/fixtures/test-app/source/auto-image-sizes.html.haml +1 -0
  68. data/fixtures/test-app/source/auto-js.html.haml +1 -0
  69. data/fixtures/test-app/source/auto-js/auto-js.html.haml +1 -0
  70. data/fixtures/test-app/source/auto-js/index.html.haml +1 -0
  71. data/fixtures/test-app/source/auto-js/sub/auto-js.html.haml +1 -0
  72. data/fixtures/test-app/source/cache-buster.html.haml +2 -0
  73. data/fixtures/test-app/source/custom-layout-dir/index.html.haml +1 -0
  74. data/fixtures/test-app/source/custom-layout.html.haml +1 -0
  75. data/fixtures/test-app/source/data.html.erb +1 -0
  76. data/fixtures/test-app/source/data2.html.liquid +2 -0
  77. data/fixtures/test-app/source/front-matter.html.erb +6 -0
  78. data/fixtures/test-app/source/images/Child folder/regular_file(example).txt +1 -0
  79. data/fixtures/test-app/source/images/Read me (example).txt +1 -0
  80. data/fixtures/test-app/source/images/blank.gif +0 -0
  81. data/fixtures/test-app/source/img/blank.gif +0 -0
  82. data/fixtures/test-app/source/index.html.haml +6 -0
  83. data/fixtures/test-app/source/inline-coffeescript.html.haml +3 -0
  84. data/fixtures/test-app/source/inline-css.html.haml +4 -0
  85. data/fixtures/test-app/source/inline-js.html.haml +7 -0
  86. data/fixtures/test-app/source/javascripts/auto-js.js +1 -0
  87. data/fixtures/test-app/source/javascripts/auto-js/auto-js.js +1 -0
  88. data/fixtures/test-app/source/javascripts/auto-js/index.js +1 -0
  89. data/fixtures/test-app/source/javascripts/auto-js/sub/auto-js.js +1 -0
  90. data/fixtures/test-app/source/javascripts/broken-coffee.js.coffee +3 -0
  91. data/fixtures/test-app/source/javascripts/coffee_test.js.coffee +3 -0
  92. data/fixtures/test-app/source/javascripts/jquery.plugin.with.dots.js +1 -0
  93. data/fixtures/test-app/source/javascripts/jquery_base.js +5 -0
  94. data/fixtures/test-app/source/javascripts/multiple_engines.js.coffee.erb +1 -0
  95. data/fixtures/test-app/source/javascripts/sprockets_base.js +5 -0
  96. data/fixtures/test-app/source/javascripts/sprockets_sub.js +3 -0
  97. data/fixtures/test-app/source/layout.haml +6 -0
  98. data/fixtures/test-app/source/layouts/custom.haml +5 -0
  99. data/fixtures/test-app/source/liquid_master.html.liquid +1 -0
  100. data/fixtures/test-app/source/markdown.html.markdown +1 -0
  101. data/fixtures/test-app/source/needs_index.html +1 -0
  102. data/fixtures/test-app/source/padrino_test.html.haml +5 -0
  103. data/fixtures/test-app/source/page-classes.html.haml +1 -0
  104. data/fixtures/test-app/source/real.html +1 -0
  105. data/fixtures/test-app/source/real/index.html.erb +5 -0
  106. data/fixtures/test-app/source/relative_image.html.erb +1 -0
  107. data/fixtures/test-app/source/services/index.html.haml +1 -0
  108. data/fixtures/test-app/source/should_be_ignored.html +1 -0
  109. data/fixtures/test-app/source/should_be_ignored2.html +1 -0
  110. data/fixtures/test-app/source/should_be_ignored3.html +1 -0
  111. data/fixtures/test-app/source/slim.html.slim +7 -0
  112. data/fixtures/test-app/source/spaces in file.html.erb +1 -0
  113. data/fixtures/test-app/source/static.html +1 -0
  114. data/fixtures/test-app/source/stylesheets/asset_host.css.sass +3 -0
  115. data/fixtures/test-app/source/stylesheets/auto-css.css +3 -0
  116. data/fixtures/test-app/source/stylesheets/auto-css/auto-css.css +3 -0
  117. data/fixtures/test-app/source/stylesheets/auto-css/index.css +0 -0
  118. data/fixtures/test-app/source/stylesheets/auto-css/sub/auto-css.css +3 -0
  119. data/fixtures/test-app/source/stylesheets/layout.css.sass +2 -0
  120. data/fixtures/test-app/source/stylesheets/relative_assets.css.sass +3 -0
  121. data/fixtures/test-app/source/stylesheets/site.css.sass +1 -0
  122. data/fixtures/test-app/source/stylesheets/site_scss.css.scss +1 -0
  123. data/fixtures/test-app/source/stylesheets/static.css +2 -0
  124. data/fixtures/test-app/source/sub1/page-classes.html.haml +1 -0
  125. data/fixtures/test-app/source/sub1/sub2/page-classes.html.haml +1 -0
  126. data/fixtures/test-app/source/tiny_src.html.haml +1 -0
  127. data/lib/middleman.rb +202 -0
  128. data/lib/middleman/base.rb +198 -0
  129. data/lib/middleman/builder.rb +163 -0
  130. data/lib/middleman/cli.rb +87 -0
  131. data/lib/middleman/config.ru +2 -0
  132. data/lib/middleman/core_extensions/assets.rb +57 -0
  133. data/lib/middleman/core_extensions/builder.rb +41 -0
  134. data/lib/middleman/core_extensions/compass.rb +102 -0
  135. data/lib/middleman/core_extensions/data.rb +120 -0
  136. data/lib/middleman/core_extensions/default_helpers.rb +77 -0
  137. data/lib/middleman/core_extensions/features.rb +102 -0
  138. data/lib/middleman/core_extensions/front_matter.rb +116 -0
  139. data/lib/middleman/core_extensions/rack_map.rb +35 -0
  140. data/lib/middleman/core_extensions/rendering.rb +19 -0
  141. data/lib/middleman/core_extensions/routing.rb +87 -0
  142. data/lib/middleman/core_extensions/sprockets.rb +102 -0
  143. data/lib/middleman/features/asset_host.rb +22 -0
  144. data/lib/middleman/features/automatic_image_sizes.rb +31 -0
  145. data/lib/middleman/features/automatic_image_sizes/fastimage.rb +287 -0
  146. data/lib/middleman/features/cache_buster.rb +42 -0
  147. data/lib/middleman/features/directory_indexes.rb +56 -0
  148. data/lib/middleman/features/lorem.rb +126 -0
  149. data/lib/middleman/features/minify_css.rb +10 -0
  150. data/lib/middleman/features/minify_javascript.rb +43 -0
  151. data/lib/middleman/features/relative_assets.rb +38 -0
  152. data/lib/middleman/features/tiny_src.rb +11 -0
  153. data/lib/middleman/guard.rb +70 -0
  154. data/lib/middleman/renderers/coffee_script.rb +8 -0
  155. data/lib/middleman/renderers/haml.rb +31 -0
  156. data/lib/middleman/renderers/liquid.rb +29 -0
  157. data/lib/middleman/renderers/markdown.rb +34 -0
  158. data/lib/middleman/renderers/sass.rb +63 -0
  159. data/lib/middleman/renderers/slim.rb +8 -0
  160. data/lib/middleman/templates.rb +53 -0
  161. data/lib/middleman/templates/default.rb +17 -0
  162. data/lib/middleman/templates/default/source/index.html.erb +5 -0
  163. data/lib/middleman/templates/default/source/layout.erb +19 -0
  164. data/lib/middleman/templates/default/source/stylesheets/site.css.scss +32 -0
  165. data/lib/middleman/templates/html5.rb +16 -0
  166. data/lib/middleman/templates/html5/source/404.html +38 -0
  167. data/lib/middleman/templates/html5/source/README.md +388 -0
  168. data/lib/middleman/templates/html5/source/apple-touch-icon-114x114-precomposed.png +0 -0
  169. data/lib/middleman/templates/html5/source/apple-touch-icon-57x57-precomposed.png +0 -0
  170. data/lib/middleman/templates/html5/source/apple-touch-icon-72x72-precomposed.png +0 -0
  171. data/lib/middleman/templates/html5/source/apple-touch-icon-precomposed.png +0 -0
  172. data/lib/middleman/templates/html5/source/apple-touch-icon.png +0 -0
  173. data/lib/middleman/templates/html5/source/crossdomain.xml +25 -0
  174. data/lib/middleman/templates/html5/source/css/style.css +293 -0
  175. data/lib/middleman/templates/html5/source/favicon.ico +0 -0
  176. data/lib/middleman/templates/html5/source/humans.txt +43 -0
  177. data/lib/middleman/templates/html5/source/img/.gitignore +2 -0
  178. data/lib/middleman/templates/html5/source/index.html +79 -0
  179. data/lib/middleman/templates/html5/source/js/libs/jquery-1.6.2.js +8981 -0
  180. data/lib/middleman/templates/html5/source/js/libs/jquery-1.6.2.min.js +18 -0
  181. data/lib/middleman/templates/html5/source/js/libs/modernizr-2.0.6.min.js +4 -0
  182. data/lib/middleman/templates/html5/source/js/mylibs/.gitignore +2 -0
  183. data/lib/middleman/templates/html5/source/js/plugins.js +20 -0
  184. data/lib/middleman/templates/html5/source/js/script.js +8 -0
  185. data/lib/middleman/templates/html5/source/robots.txt +5 -0
  186. data/lib/middleman/templates/html5/source/test/index.html +31 -0
  187. data/lib/middleman/templates/html5/source/test/qunit/qunit.css +148 -0
  188. data/lib/middleman/templates/html5/source/test/qunit/qunit.js +1265 -0
  189. data/lib/middleman/templates/html5/source/test/tests.js +24 -0
  190. data/lib/middleman/templates/local.rb +20 -0
  191. data/lib/middleman/templates/shared/Gemfile.tt +3 -0
  192. data/lib/middleman/templates/shared/config.ru +4 -0
  193. data/lib/middleman/templates/shared/config.tt +104 -0
  194. data/lib/middleman/version.rb +3 -0
  195. data/middleman-x86-mingw32.gemspec +78 -0
  196. data/middleman.gemspec +78 -0
  197. metadata +812 -0
@@ -0,0 +1,116 @@
1
+ require "yaml"
2
+ require "tilt"
3
+
4
+ module Middleman::CoreExtensions::FrontMatter
5
+ class << self
6
+ def registered(app)
7
+ app.extend ClassMethods
8
+
9
+ ::Tilt::register RDiscountTemplate, 'markdown', 'mkd', 'md'
10
+ ::Tilt::register RedcarpetTemplate, 'markdown', 'mkd', 'md'
11
+ ::Tilt::register MarukuTemplate, 'markdown', 'mkd', 'md'
12
+ ::Tilt::register KramdownTemplate, 'markdown', 'mkd', 'md'
13
+ app.set :markdown_engine_prefix, ::Middleman::CoreExtensions::FrontMatter
14
+
15
+ ::Tilt::register RedClothTemplate, 'textile'
16
+ ::Tilt.prefer(RedClothTemplate)
17
+
18
+ ::Tilt::register ERBTemplate, 'erb', 'rhtml'
19
+ ::Tilt.prefer(ERBTemplate)
20
+
21
+ ::Tilt::register LiquidTemplate, 'liquid'
22
+ ::Tilt.prefer(LiquidTemplate)
23
+
24
+ ::Tilt::register SlimTemplate, 'slim'
25
+ ::Tilt.prefer(SlimTemplate)
26
+
27
+ ::Tilt::register HamlTemplate, 'haml'
28
+ ::Tilt.prefer(HamlTemplate)
29
+
30
+ app.after_configuration do
31
+ app.before_processing(:front_matter) do |result|
32
+ if result && Tilt.mappings.has_key?(result[1].to_s)
33
+ extensionless_path, template_engine = result
34
+ full_file_path = "#{extensionless_path}.#{template_engine}"
35
+ system_path = File.join(settings.views, full_file_path)
36
+ data, content = app.parse_front_matter(File.read(system_path))
37
+
38
+ request['custom_options'] = {}
39
+ %w(layout layout_engine).each do |opt|
40
+ if data.has_key?(opt)
41
+ request['custom_options'][opt.to_sym] = data.delete(opt)
42
+ end
43
+ end
44
+
45
+ # Forward remaining data to helpers
46
+ app.data_content("page", data)
47
+ end
48
+
49
+ true
50
+ end
51
+ end
52
+ end
53
+ alias :included :registered
54
+
55
+ def parse_front_matter(content)
56
+ yaml_regex = /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
57
+ if content =~ yaml_regex
58
+ begin
59
+ data = YAML.load($1)
60
+ rescue => e
61
+ puts "YAML Exception: #{e.message}"
62
+ end
63
+
64
+ content = content.split(yaml_regex).last
65
+ end
66
+
67
+ data ||= {}
68
+ [data, content]
69
+ end
70
+ end
71
+
72
+ module ClassMethods
73
+ def parse_front_matter(content)
74
+ Middleman::CoreExtensions::FrontMatter.parse_front_matter(content)
75
+ end
76
+ end
77
+
78
+ module YamlAware
79
+ def prepare
80
+ @frontmatter, @data = Middleman::CoreExtensions::FrontMatter.parse_front_matter(@data)
81
+ super
82
+ end
83
+ end
84
+
85
+ class RDiscountTemplate < ::Tilt::RDiscountTemplate
86
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
87
+ end
88
+ class RedcarpetTemplate < ::Tilt::RedcarpetTemplate
89
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
90
+ end
91
+ class MarukuTemplate < ::Tilt::MarukuTemplate
92
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
93
+ end
94
+ class RedClothTemplate < ::Tilt::RedClothTemplate
95
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
96
+ end
97
+ class KramdownTemplate < ::Tilt::KramdownTemplate
98
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
99
+ end
100
+
101
+ class ERBTemplate < ::Tilt::ERBTemplate
102
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
103
+ end
104
+
105
+ class LiquidTemplate < ::Tilt::LiquidTemplate
106
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
107
+ end
108
+
109
+ class HamlTemplate < ::Tilt::HamlTemplate
110
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
111
+ end
112
+
113
+ class SlimTemplate < ::Slim::Template
114
+ include Middleman::CoreExtensions::FrontMatter::YamlAware
115
+ end
116
+ end
@@ -0,0 +1,35 @@
1
+ module Middleman::CoreExtensions::RackMap
2
+ class << self
3
+ def registered(app)
4
+ app.extend ClassMethods
5
+ end
6
+ alias :included :registered
7
+ end
8
+
9
+ module ClassMethods
10
+ def map(path, &block)
11
+ @maps ||= []
12
+ @maps << [path, block]
13
+ end
14
+
15
+ def maps
16
+ @maps || []
17
+ end
18
+
19
+ # Creates a Rack::Builder instance with all the middleware set up and
20
+ # an instance of this class as end point.
21
+ def build(*args, &bk)
22
+ builder = ::Rack::Builder.new
23
+ builder.use ::Sinatra::ShowExceptions if show_exceptions?
24
+ builder.use ::Rack::CommonLogger if logging?
25
+ builder.use ::Rack::Head
26
+ middleware.each { |c,a,b| builder.use(c, *a, &b) }
27
+ maps.each { |p,b| builder.map(p, &b) }
28
+ app = self
29
+ builder.map "/" do
30
+ run app.new!(*args, &bk)
31
+ end
32
+ builder
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ require "padrino-core/application/rendering"
2
+
3
+ module Middleman::CoreExtensions::Rendering
4
+ class << self
5
+ def registered(app)
6
+ # Tilt-aware renderer
7
+ app.register Padrino::Rendering
8
+
9
+ # Activate custom renderers
10
+ app.register Middleman::Renderers::Slim
11
+ app.register Middleman::Renderers::Haml
12
+ app.register Middleman::Renderers::Sass
13
+ app.register Middleman::Renderers::Markdown
14
+ app.register Middleman::Renderers::CoffeeScript
15
+ app.register Middleman::Renderers::Liquid
16
+ end
17
+ alias :included :registered
18
+ end
19
+ end
@@ -0,0 +1,87 @@
1
+ module Middleman::CoreExtensions::Routing
2
+ class << self
3
+ def registered(app)
4
+ app.extend ClassMethods
5
+
6
+ app.set :proxied_paths, {}
7
+ app.set :excluded_paths, []
8
+
9
+ app.build_reroute do |destination, request_path|
10
+ throw if app.settings.excluded_paths.include?(request_path)
11
+ end
12
+ end
13
+ alias :included :registered
14
+ end
15
+
16
+ module ClassMethods
17
+ def path_to_index(path)
18
+ parts = path ? path.split('/') : []
19
+ if parts.last.nil? || parts.last.split('.').length == 1
20
+ path = File.join(path, settings.index_file)
21
+ end
22
+ path.gsub(%r{^/}, '')
23
+ end
24
+
25
+ # Takes a block which allows many pages to have the same layout
26
+ # with_layout :admin do
27
+ # page "/admin/"
28
+ # page "/admin/login.html"
29
+ # end
30
+ def with_layout(layout_name, &block)
31
+ old_layout = settings.layout
32
+
33
+ set :layout, layout_name
34
+ class_eval(&block) if block_given?
35
+ ensure
36
+ set :layout, old_layout
37
+ end
38
+
39
+ def paths_for_url(url)
40
+ url = url.gsub(%r{\/#{settings.index_file}$}, "")
41
+ url = url.gsub(%r{(\/)$}, "") if url.length > 1
42
+
43
+ paths = [url]
44
+ paths << "#{url}/" if url.length > 1 && url.split("/").last.split('.').length <= 1
45
+ paths << "/#{path_to_index(url)}"
46
+ paths
47
+ end
48
+
49
+ # Keep a path from building
50
+ def ignore(path)
51
+ settings.excluded_paths << paths_for_url(path)
52
+ settings.excluded_paths.flatten!
53
+ settings.excluded_paths.uniq!
54
+ end
55
+
56
+ # The page method allows the layout to be set on a specific path
57
+ # page "/about.html", :layout => false
58
+ # page "/", :layout => :homepage_layout
59
+ def page(url, options={}, &block)
60
+ has_block = block_given?
61
+ options[:layout] = settings.layout if options[:layout].nil?
62
+
63
+ if options.has_key?(:proxy)
64
+ settings.proxied_paths[url] = options[:proxy]
65
+ if options.has_key?(:ignore) && options[:ignore]
66
+ settings.ignore(options[:proxy])
67
+ end
68
+ else
69
+ if options.has_key?(:ignore) && options[:ignore]
70
+ settings.ignore(url)
71
+ end
72
+ end
73
+
74
+ paths_for_url(url).each do |p|
75
+ get(p) do
76
+ if settings.proxied_paths.has_key?(url)
77
+ request["is_proxy"] = true
78
+ request.path_info = settings.proxied_paths[url]
79
+ end
80
+
81
+ instance_eval(&block) if has_block
82
+ process_request(options)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,102 @@
1
+ require 'pathname'
2
+ require 'rbconfig'
3
+ require "sprockets"
4
+
5
+ module Middleman::CoreExtensions::Sprockets
6
+ class << self
7
+ def registered(app)
8
+ app.set :js_compressor, false
9
+
10
+ # Cut off every extension after .js (which sprockets eats up)
11
+ app.build_reroute do |destination, request_path|
12
+ if !request_path.match(/\.js\./i)
13
+ false
14
+ else
15
+ [
16
+ destination.gsub(/\.js(\..*)$/, ".js"),
17
+ request_path.gsub(/\.js(\..*)$/, ".js")
18
+ ]
19
+ end
20
+ end
21
+
22
+ app.after_configuration do
23
+ js_env = Middleman::CoreExtensions::Sprockets::JavascriptEnvironment.new(app)
24
+
25
+ js_dir = File.join("vendor", "assets", "javascripts")
26
+ gems_with_js = ::Middleman.rubygems_latest_specs.select do |spec|
27
+ ::Middleman.spec_has_file?(spec, js_dir)
28
+ end.each do |spec|
29
+ js_env.append_path File.join(spec.full_gem_path, js_dir)
30
+ end
31
+
32
+ # add paths to js_env (vendor/assets/javascripts)
33
+ app.map "/#{app.js_dir}" do
34
+ run js_env
35
+ end
36
+
37
+ # app.map "/#{app.css_dir}" do
38
+ # run Middleman::CoreExtensions::Sprockets::StylesheetEnvironment.new(app)
39
+ # end
40
+ end
41
+ end
42
+ alias :included :registered
43
+ end
44
+
45
+ class MiddlemanEnvironment < ::Sprockets::Environment
46
+ def initialize(app)
47
+ full_path = app.views
48
+ full_path = File.join(app.root, app.views) unless app.views.include?(app.root)
49
+
50
+ super File.expand_path(full_path)
51
+
52
+ # Make the app context available to Sprockets
53
+ context_class.send(:define_method, :app) { app }
54
+ context_class.class_eval do
55
+ def method_missing(name)
56
+ if app.respond_to?(name)
57
+ app.send(name)
58
+ else
59
+ super
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ class JavascriptEnvironment < MiddlemanEnvironment
67
+ def initialize(app)
68
+ super
69
+
70
+ # Disable css
71
+ unregister_processor "text/css", ::Sprockets::DirectiveProcessor
72
+
73
+ self.js_compressor = app.settings.js_compressor
74
+
75
+ # configure search paths
76
+ append_path app.js_dir
77
+ end
78
+
79
+ def javascript_exception_response(exception)
80
+ expire_index!
81
+ super(exception)
82
+ end
83
+ end
84
+
85
+ # class StylesheetEnvironment < MiddlemanEnvironment
86
+ # def initialize(app)
87
+ # super
88
+ #
89
+ # # Disable js
90
+ # unregister_processor "application/javascript", ::Sprockets::DirectiveProcessor
91
+ #
92
+ # # configure search paths
93
+ # stylesheets_path = File.join(File.expand_path(app.views), app.css_dir)
94
+ # append_path stylesheets_path
95
+ # end
96
+ #
97
+ # def css_exception_response(exception)
98
+ # expire_index!
99
+ # super(exception)
100
+ # end
101
+ # end
102
+ end
@@ -0,0 +1,22 @@
1
+ module Middleman::Features::AssetHost
2
+ class << self
3
+ def registered(app)
4
+ app.compass_config do |config|
5
+ if app.asset_host.is_a?(Proc)
6
+ config.asset_host(&app.asset_host)
7
+ end
8
+ end
9
+
10
+ app.register_asset_handler :asset_host do |path, prefix, request|
11
+ original_output = app.before_asset_handler(:asset_host, path, prefix, request)
12
+
13
+ valid_extensions = %w(.png .gif .jpg .jpeg .js .css)
14
+
15
+ asset_prefix = app.asset_host.call(original_output)
16
+
17
+ File.join(asset_prefix, original_output)
18
+ end
19
+ end
20
+ alias :included :registered
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ module Middleman::Features::AutomaticImageSizes
2
+ class << self
3
+ def registered(app)
4
+ require "middleman/features/automatic_image_sizes/fastimage"
5
+
6
+ app.helpers Helpers
7
+ end
8
+ alias :included :registered
9
+ end
10
+
11
+ module Helpers
12
+ def image_tag(path, params={})
13
+ if (!params[:width] || !params[:height]) && !path.include?("://")
14
+ params[:alt] ||= ""
15
+ http_prefix = settings.http_images_path rescue settings.images_dir
16
+
17
+ begin
18
+ real_path = File.join(settings.views, settings.images_dir, path)
19
+ if File.exists? real_path
20
+ dimensions = ::FastImage.size(real_path, :raise_on_failure => true)
21
+ params[:width] ||= dimensions[0]
22
+ params[:height] ||= dimensions[1]
23
+ end
24
+ rescue
25
+ end
26
+ end
27
+
28
+ super(path, params)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,287 @@
1
+ # FastImage finds the size or type of an image given its uri.
2
+ # It is careful to only fetch and parse as much of the image as is needed to determine the result.
3
+ # It does this by using a feature of Net::HTTP that yields strings from the resource being fetched
4
+ # as soon as the packets arrive.
5
+ #
6
+ # No external libraries such as ImageMagick are used here, this is a very lightweight solution to
7
+ # finding image information.
8
+ #
9
+ # FastImage knows about GIF, JPEG, BMP and PNG files.
10
+ #
11
+ # FastImage can also read files from the local filesystem by supplying the path instead of a uri.
12
+ # In this case FastImage uses the open-uri library to read the file in chunks of 256 bytes until
13
+ # it has enough. This is possibly a useful bandwidth-saving feature if the file is on a network
14
+ # attached disk rather than truly local.
15
+ #
16
+ # === Examples
17
+ # require 'fastimage'
18
+ #
19
+ # FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
20
+ # => [266, 56]
21
+ # FastImage.type("http://stephensykes.com/images/pngimage")
22
+ # => :png
23
+ # FastImage.type("/some/local/file.gif")
24
+ # => :gif
25
+ #
26
+ # === References
27
+ # * http://snippets.dzone.com/posts/show/805
28
+ # * http://www.anttikupila.com/flash/getting-jpg-dimensions-with-as3-without-loading-the-entire-file/
29
+ # * http://pennysmalls.com/2008/08/19/find-jpeg-dimensions-fast-in-ruby/
30
+ # * http://imagesize.rubyforge.org/
31
+ #
32
+ require 'net/https'
33
+ require 'open-uri'
34
+
35
+ class FastImage
36
+ attr_reader :size, :type
37
+
38
+ class FastImageException < StandardError # :nodoc:
39
+ end
40
+ class MoreCharsNeeded < FastImageException # :nodoc:
41
+ end
42
+ class UnknownImageType < FastImageException # :nodoc:
43
+ end
44
+ class ImageFetchFailure < FastImageException # :nodoc:
45
+ end
46
+ class SizeNotFound < FastImageException # :nodoc:
47
+ end
48
+
49
+ DefaultTimeout = 2
50
+
51
+ LocalFileChunkSize = 256
52
+
53
+ # Returns an array containing the width and height of the image.
54
+ # It will return nil if the image could not be fetched, or if the image type was not recognised.
55
+ #
56
+ # By default there is a timeout of 2 seconds for opening and reading from a remote server.
57
+ # This can be changed by passing a :timeout => number_of_seconds in the options.
58
+ #
59
+ # If you wish FastImage to raise if it cannot size the image for any reason, then pass
60
+ # :raise_on_failure => true in the options.
61
+ #
62
+ # FastImage knows about GIF, JPEG, BMP and PNG files.
63
+ #
64
+ # === Example
65
+ #
66
+ # require 'fastimage'
67
+ #
68
+ # FastImage.size("http://stephensykes.com/images/ss.com_x.gif")
69
+ # => [266, 56]
70
+ # FastImage.size("http://stephensykes.com/images/pngimage")
71
+ # => [16, 16]
72
+ # FastImage.size("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg")
73
+ # => [500, 375]
74
+ # FastImage.size("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
75
+ # => [512, 512]
76
+ # FastImage.size("test/fixtures/test.jpg")
77
+ # => [882, 470]
78
+ # FastImage.size("http://pennysmalls.com/does_not_exist")
79
+ # => nil
80
+ # FastImage.size("http://pennysmalls.com/does_not_exist", :raise_on_failure=>true)
81
+ # => raises FastImage::ImageFetchFailure
82
+ # FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true)
83
+ # => raises FastImage::UnknownImageType
84
+ # FastImage.size("http://stephensykes.com/favicon.ico", :raise_on_failure=>true, :timeout=>0.01)
85
+ # => raises FastImage::ImageFetchFailure
86
+ # FastImage.size("http://stephensykes.com/images/faulty.jpg", :raise_on_failure=>true)
87
+ # => raises FastImage::SizeNotFound
88
+ #
89
+ # === Supported options
90
+ # [:timeout]
91
+ # Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
92
+ # [:raise_on_failure]
93
+ # If set to true causes an exception to be raised if the image size cannot be found for any reason.
94
+ #
95
+ def self.size(uri, options={})
96
+ new(uri, options).size
97
+ end
98
+
99
+ # Returns an symbol indicating the image type fetched from a uri.
100
+ # It will return nil if the image could not be fetched, or if the image type was not recognised.
101
+ #
102
+ # By default there is a timeout of 2 seconds for opening and reading from a remote server.
103
+ # This can be changed by passing a :timeout => number_of_seconds in the options.
104
+ #
105
+ # If you wish FastImage to raise if it cannot find the type of the image for any reason, then pass
106
+ # :raise_on_failure => true in the options.
107
+ #
108
+ # === Example
109
+ #
110
+ # require 'fastimage'
111
+ #
112
+ # FastImage.type("http://stephensykes.com/images/ss.com_x.gif")
113
+ # => :gif
114
+ # FastImage.type("http://stephensykes.com/images/pngimage")
115
+ # => :png
116
+ # FastImage.type("http://farm4.static.flickr.com/3023/3047236863_9dce98b836.jpg")
117
+ # => :jpeg
118
+ # FastImage.type("http://www-ece.rice.edu/~wakin/images/lena512.bmp")
119
+ # => :bmp
120
+ # FastImage.type("test/fixtures/test.jpg")
121
+ # => :jpeg
122
+ # FastImage.type("http://pennysmalls.com/does_not_exist")
123
+ # => nil
124
+ #
125
+ # === Supported options
126
+ # [:timeout]
127
+ # Overrides the default timeout of 2 seconds. Applies both to reading from and opening the http connection.
128
+ # [:raise_on_failure]
129
+ # If set to true causes an exception to be raised if the image type cannot be found for any reason.
130
+ #
131
+ def self.type(uri, options={})
132
+ new(uri, options.merge(:type_only=>true)).type
133
+ end
134
+
135
+ def initialize(uri, options={})
136
+ @property = options[:type_only] ? :type : :size
137
+ @timeout = options[:timeout] || DefaultTimeout
138
+ @uri = uri
139
+ begin
140
+ @parsed_uri = URI.parse(uri)
141
+ rescue URI::InvalidURIError
142
+ fetch_using_open_uri
143
+ else
144
+ if @parsed_uri.scheme == "http" || @parsed_uri.scheme == "https"
145
+ fetch_using_http
146
+ else
147
+ fetch_using_open_uri
148
+ end
149
+ end
150
+ raise SizeNotFound if options[:raise_on_failure] && @property == :size && !@size
151
+ rescue Timeout::Error, SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ECONNRESET,
152
+ ImageFetchFailure, Net::HTTPBadResponse, EOFError, Errno::ENOENT
153
+ raise ImageFetchFailure if options[:raise_on_failure]
154
+ rescue NoMethodError # 1.8.7p248 can raise this due to a net/http bug
155
+ raise ImageFetchFailure if options[:raise_on_failure]
156
+ rescue UnknownImageType
157
+ raise UnknownImageType if options[:raise_on_failure]
158
+ end
159
+
160
+ private
161
+
162
+ def fetch_using_http
163
+ setup_http
164
+ @http.request_get(@parsed_uri.request_uri) do |res|
165
+ raise ImageFetchFailure unless res.is_a?(Net::HTTPSuccess)
166
+ res.read_body do |str|
167
+ break if parse_packet(str)
168
+ end
169
+ end
170
+ end
171
+
172
+ def setup_http
173
+ @http = Net::HTTP.new(@parsed_uri.host, @parsed_uri.port)
174
+ @http.use_ssl = (@parsed_uri.scheme == "https")
175
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
176
+ @http.open_timeout = @timeout
177
+ @http.read_timeout = @timeout
178
+ end
179
+
180
+ def fetch_using_open_uri
181
+ open(@uri) do |s|
182
+ while str = s.read(LocalFileChunkSize)
183
+ break if parse_packet(str)
184
+ end
185
+ end
186
+ end
187
+
188
+ # returns true once result is achieved
189
+ #
190
+ def parse_packet(str)
191
+ @str = (@unused_str || "") + str
192
+ @strpos = 0
193
+ begin
194
+ result = send("parse_#{@property}")
195
+ if result
196
+ instance_variable_set("@#{@property}", result)
197
+ true
198
+ end
199
+ rescue MoreCharsNeeded
200
+ false
201
+ end
202
+ end
203
+
204
+ def parse_size
205
+ @type = parse_type unless @type
206
+ @strpos = 0
207
+ send("parse_size_for_#{@type}")
208
+ end
209
+
210
+ def get_chars(n)
211
+ if @strpos + n - 1 >= @str.size
212
+ @unused_str = @str[@strpos..-1]
213
+ raise MoreCharsNeeded
214
+ else
215
+ result = @str[@strpos..(@strpos + n - 1)]
216
+ @strpos += n
217
+ result
218
+ end
219
+ end
220
+
221
+ def get_byte
222
+ get_chars(1).unpack("C")[0]
223
+ end
224
+
225
+ def read_int(str)
226
+ size_bytes = str.unpack("CC")
227
+ (size_bytes[0] << 8) + size_bytes[1]
228
+ end
229
+
230
+ def parse_type
231
+ case get_chars(2)
232
+ when "BM"
233
+ :bmp
234
+ when "GI"
235
+ :gif
236
+ when 0xff.chr + 0xd8.chr
237
+ :jpeg
238
+ when 0x89.chr + "P"
239
+ :png
240
+ else
241
+ raise UnknownImageType
242
+ end
243
+ end
244
+
245
+ def parse_size_for_gif
246
+ get_chars(11)[6..10].unpack('SS')
247
+ end
248
+
249
+ def parse_size_for_png
250
+ get_chars(25)[16..24].unpack('NN')
251
+ end
252
+
253
+ def parse_size_for_jpeg
254
+ loop do
255
+ @state = case @state
256
+ when nil
257
+ get_chars(2)
258
+ :started
259
+ when :started
260
+ get_byte == 0xFF ? :sof : :started
261
+ when :sof
262
+ c = get_byte
263
+ if (0xe0..0xef).include?(c)
264
+ :skipframe
265
+ elsif [0xC0..0xC3, 0xC5..0xC7, 0xC9..0xCB, 0xCD..0xCF].detect {|r| r.include? c}
266
+ :readsize
267
+ else
268
+ :skipframe
269
+ end
270
+ when :skipframe
271
+ @skip_chars = read_int(get_chars(2)) - 2
272
+ :do_skip
273
+ when :do_skip
274
+ get_chars(@skip_chars)
275
+ :started
276
+ when :readsize
277
+ s = get_chars(7)
278
+ return [read_int(s[5..6]), read_int(s[3..4])]
279
+ end
280
+ end
281
+ end
282
+
283
+ def parse_size_for_bmp
284
+ d = get_chars(29)[14..28]
285
+ d.unpack("C")[0] == 40 ? d[4..-1].unpack('LL') : d[4..8].unpack('SS')
286
+ end
287
+ end