beans-middleman 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +15 -0
- data/Rakefile +9 -0
- data/bin/mm-build +15 -0
- data/bin/mm-init +37 -0
- data/bin/mm-preview +12 -0
- data/bin/mm-server +67 -0
- data/features/builder.feature +16 -0
- data/features/coffee-script.feature +7 -0
- data/features/generator.feature +8 -0
- data/features/helpers_auto_stylesheet_link_tag.feature +17 -0
- data/features/helpers_page_classes.feature +17 -0
- data/features/less-css.feature +7 -0
- data/features/minify_css.feature +22 -0
- data/features/minify_javascript.feature +12 -0
- data/features/padrino_helpers.feature +10 -0
- data/features/page_alias_and_layouts.feature +12 -0
- data/features/scss-support.feature +7 -0
- data/features/step_definitions/asset_host_steps.rb +7 -0
- data/features/step_definitions/builder_steps.rb +23 -0
- data/features/step_definitions/env.rb +3 -0
- data/features/step_definitions/generator_steps.rb +30 -0
- data/features/step_definitions/middleman_steps.rb +29 -0
- data/features/step_definitions/page_layout_steps.rb +13 -0
- data/features/w_asset_host.feature +12 -0
- data/features/x_automatic_image_sizes.feature +14 -0
- data/features/y_cache_buster.feature +22 -0
- data/features/z_relative_assets.feature +12 -0
- data/fixtures/test-app/config.rb +28 -0
- data/fixtures/test-app/public/images/blank.gif +0 -0
- data/fixtures/test-app/public/static.html +1 -0
- data/fixtures/test-app/public/stylesheets/auto-css.css +0 -0
- data/fixtures/test-app/public/stylesheets/static.css +2 -0
- data/fixtures/test-app/public/stylesheets/sub1/auto-css.css +0 -0
- data/fixtures/test-app/public/stylesheets/sub1/sub2/auto-css.css +0 -0
- data/fixtures/test-app/views/_partial.haml +1 -0
- data/fixtures/test-app/views/asset_host.html.haml +1 -0
- data/fixtures/test-app/views/auto-css.html.haml +1 -0
- data/fixtures/test-app/views/auto-image-sizes.html.haml +1 -0
- data/fixtures/test-app/views/cache-buster.html.haml +2 -0
- data/fixtures/test-app/views/custom-layout.html.haml +1 -0
- data/fixtures/test-app/views/index.html.haml +1 -0
- data/fixtures/test-app/views/inline-css.html.haml +4 -0
- data/fixtures/test-app/views/inline-js.html.haml +7 -0
- data/fixtures/test-app/views/javascripts/coffee_test.js.coffee +3 -0
- data/fixtures/test-app/views/layout.haml +6 -0
- data/fixtures/test-app/views/layouts/custom.haml +5 -0
- data/fixtures/test-app/views/padrino_test.html.haml +5 -0
- data/fixtures/test-app/views/page-classes.html.haml +1 -0
- data/fixtures/test-app/views/services/index.html.haml +1 -0
- data/fixtures/test-app/views/stylesheets/asset_host.css.sass +3 -0
- data/fixtures/test-app/views/stylesheets/relative_assets.css.sass +3 -0
- data/fixtures/test-app/views/stylesheets/site.css.sass +1 -0
- data/fixtures/test-app/views/stylesheets/site_scss.css.scss +1 -0
- data/fixtures/test-app/views/stylesheets/test_less.css.less +5 -0
- data/lib/middleman/assets.rb +33 -0
- data/lib/middleman/builder.rb +60 -0
- data/lib/middleman/config.ru +2 -0
- data/lib/middleman/features/asset_host.rb +22 -0
- data/lib/middleman/features/automatic_image_sizes/fastimage.rb +287 -0
- data/lib/middleman/features/automatic_image_sizes.rb +33 -0
- data/lib/middleman/features/cache_buster.rb +44 -0
- data/lib/middleman/features/code_ray.rb +12 -0
- data/lib/middleman/features/default_helpers.rb +61 -0
- data/lib/middleman/features/live_reload.rb +21 -0
- data/lib/middleman/features/minify_css.rb +10 -0
- data/lib/middleman/features/minify_javascript/rack.rb +31 -0
- data/lib/middleman/features/minify_javascript.rb +21 -0
- data/lib/middleman/features/partials.rb +15 -0
- data/lib/middleman/features/relative_assets.rb +36 -0
- data/lib/middleman/features/slickmap/template.html.haml +27 -0
- data/lib/middleman/features/slickmap.rb +89 -0
- data/lib/middleman/features/smush_pngs.rb +38 -0
- data/lib/middleman/features/ugly_haml.rb +8 -0
- data/lib/middleman/features.rb +37 -0
- data/lib/middleman/renderers/haml.rb +42 -0
- data/lib/middleman/renderers/sass.rb +70 -0
- data/lib/middleman/server.rb +165 -0
- data/lib/middleman/template/config.rbt +64 -0
- data/lib/middleman/template/views/index.html.haml +4 -0
- data/lib/middleman/template/views/layout.haml +13 -0
- data/lib/middleman/template/views/stylesheets/site.css.sass +27 -0
- data/lib/middleman/templater+dynamic_renderer.rb +26 -0
- data/lib/middleman.rb +15 -0
- metadata +452 -0
@@ -0,0 +1 @@
|
|
1
|
+
@import "compass/reset"
|
@@ -0,0 +1 @@
|
|
1
|
+
@import "compass/reset";
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Middleman
|
2
|
+
module Assets
|
3
|
+
@@asset_handler_map = []
|
4
|
+
@@asset_handler_stack = []
|
5
|
+
|
6
|
+
def self.register(handler_name, &block)
|
7
|
+
if block_given?
|
8
|
+
@@asset_handler_stack << block
|
9
|
+
@@asset_handler_map << handler_name
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.get_url(path, prefix="", request=nil)
|
14
|
+
@@asset_handler_stack.last.call(path, prefix, request)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.before(position, *args)
|
18
|
+
current_index = @@asset_handler_map.index(position)
|
19
|
+
return nil unless current_index
|
20
|
+
|
21
|
+
previous = current_index - 1
|
22
|
+
if (previous >= 0) && (previous < @@asset_handler_map.length)
|
23
|
+
@@asset_handler_stack[previous].call(*args)
|
24
|
+
else
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Middleman::Assets.register :base do |path, prefix, request|
|
32
|
+
path.include?("://") ? path : File.join(Middleman::Server.http_prefix || "/", prefix, path)
|
33
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'middleman/server'
|
2
|
+
require 'templater'
|
3
|
+
require 'middleman/templater+dynamic_renderer.rb'
|
4
|
+
|
5
|
+
# Placeholder for any methods the builder needs to abstract to allow feature integration
|
6
|
+
module Middleman
|
7
|
+
class Builder < ::Templater::Generator
|
8
|
+
|
9
|
+
# Support all Tilt-enabled templates and treat js like a template
|
10
|
+
@@template_extensions = ::Tilt.mappings.keys << "js"
|
11
|
+
|
12
|
+
# Define source and desintation
|
13
|
+
def self.source_root; Dir.pwd; end
|
14
|
+
def destination_root; File.join(Dir.pwd, Middleman::Server.build_dir); end
|
15
|
+
|
16
|
+
# Override template to ask middleman for the correct extension to output
|
17
|
+
def self.template(name, *args, &block)
|
18
|
+
return if args[0].include?('layout')
|
19
|
+
|
20
|
+
args.first.split('/').each do |part|
|
21
|
+
return if part[0,1] == '_'
|
22
|
+
end
|
23
|
+
|
24
|
+
if (args[0] === args[1])
|
25
|
+
args[1] = args[0].gsub("#{File.basename(Middleman::Server.views)}/", "").gsub("#{File.basename(Middleman::Server.public)}/", "")
|
26
|
+
if File.extname(args[1]) != ".js"
|
27
|
+
args[1] = args[1].gsub!(File.extname(args[1]), "") if File.basename(args[1]).split('.').length > 2
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
super(name, *args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.file(name, *args, &block)
|
35
|
+
file_ext = File.extname(args[0])
|
36
|
+
|
37
|
+
return unless ::Tilt[file_ext].nil?
|
38
|
+
|
39
|
+
if (args[0] === args[1])
|
40
|
+
args[1] = args[0].gsub("#{File.basename(Middleman::Server.views)}/", "").gsub("#{File.basename(Middleman::Server.public)}/", "")
|
41
|
+
end
|
42
|
+
super(name, *args, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.init!
|
46
|
+
glob! File.basename(Middleman::Server.public), @@template_extensions
|
47
|
+
glob! File.basename(Middleman::Server.views), @@template_extensions
|
48
|
+
end
|
49
|
+
|
50
|
+
def after_run
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module Generators
|
55
|
+
extend ::Templater::Manifold
|
56
|
+
desc "Build a static site"
|
57
|
+
|
58
|
+
add :build, ::Middleman::Builder
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Middleman::Features::AssetHost
|
2
|
+
class << self
|
3
|
+
def registered(app)
|
4
|
+
app.after_feature_init do
|
5
|
+
if Middleman::Server.asset_host.is_a?(Proc)
|
6
|
+
::Compass.configuration.asset_host(&Middleman::Server.asset_host)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
Middleman::Assets.register :asset_host do |path, prefix, request|
|
11
|
+
original_output = Middleman::Assets.before(:asset_host, path, prefix, request)
|
12
|
+
|
13
|
+
valid_extensions = %w(.png .gif .jpg .jpeg .js .css)
|
14
|
+
|
15
|
+
asset_prefix = Middleman::Server.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,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
|
@@ -0,0 +1,33 @@
|
|
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.public, 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
|
+
|
27
|
+
super(asset_url(path, http_prefix), params)
|
28
|
+
else
|
29
|
+
super(path, params)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Middleman::Features::CacheBuster
|
2
|
+
class << self
|
3
|
+
def registered(app)
|
4
|
+
Middleman::Assets.register :cache_buster do |path, prefix, request|
|
5
|
+
http_path = Middleman::Assets.before(:cache_buster, path, prefix, request)
|
6
|
+
|
7
|
+
if http_path.include?("://") || !%w(.css .png .jpg .js .gif).include?(File.extname(http_path))
|
8
|
+
http_path
|
9
|
+
else
|
10
|
+
begin
|
11
|
+
prefix = Middleman::Server.images_dir if prefix == Middleman::Server.http_images_path
|
12
|
+
rescue
|
13
|
+
end
|
14
|
+
|
15
|
+
real_path_static = File.join(Middleman::Server.public, prefix, path)
|
16
|
+
|
17
|
+
if File.readable?(real_path_static)
|
18
|
+
http_path << "?" + File.mtime(real_path_static).strftime("%s")
|
19
|
+
elsif Middleman::Server.environment == :build
|
20
|
+
real_path_dynamic = File.join(Middleman::Server.root, Middleman::Server.build_dir, prefix, path)
|
21
|
+
http_path << "?" + File.mtime(real_path_dynamic).strftime("%s") if File.readable?(real_path_dynamic)
|
22
|
+
end
|
23
|
+
|
24
|
+
http_path
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
app.after_feature_init do
|
29
|
+
::Compass.configuration do |config|
|
30
|
+
config.asset_cache_buster do |path, real_path|
|
31
|
+
real_path = real_path.path if real_path.is_a? File
|
32
|
+
real_path = real_path.gsub(File.join(Middleman::Server.root, Middleman::Server.build_dir), Middleman::Server.public)
|
33
|
+
if File.readable?(real_path)
|
34
|
+
File.mtime(real_path).strftime("%s")
|
35
|
+
else
|
36
|
+
$stderr.puts "WARNING: '#{File.basename(path)}' was not found (or cannot be read) in #{File.dirname(real_path)}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
alias :included :registered
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Middleman::Features::DefaultHelpers
|
2
|
+
class << self
|
3
|
+
def registered(app)
|
4
|
+
app.helpers Middleman::Features::DefaultHelpers::Helpers
|
5
|
+
end
|
6
|
+
alias :included :registered
|
7
|
+
end
|
8
|
+
|
9
|
+
module Helpers
|
10
|
+
def auto_stylesheet_link_tag(separator="/")
|
11
|
+
path = request.path_info.dup
|
12
|
+
path << self.class.index_file if path.match(%r{/$})
|
13
|
+
path = path.gsub(%r{^/}, '')
|
14
|
+
path = path.gsub(File.extname(path), '')
|
15
|
+
path = path.gsub("/", separator)
|
16
|
+
|
17
|
+
css_file = File.join(self.class.public, self.class.css_dir, "#{path}.css")
|
18
|
+
sass_file = File.join(self.class.views, self.class.css_dir, "#{path}.css.sass")
|
19
|
+
scss_file = File.join(self.class.views, self.class.css_dir, "#{path}.css.scss")
|
20
|
+
less_file = File.join(self.class.views, self.class.css_dir, "#{path}.css.less")
|
21
|
+
|
22
|
+
if File.exists?(css_file) || File.exists?(sass_file) || File.exists?(scss_file) || File.exists?(less_file)
|
23
|
+
stylesheet_link_tag "#{path}.css"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def page_classes
|
28
|
+
path = request.path_info.dup
|
29
|
+
path << settings.index_file if path.match(%r{/$})
|
30
|
+
path = path.gsub(%r{^/}, '')
|
31
|
+
|
32
|
+
classes = []
|
33
|
+
parts = path.split('.')[0].split('/')
|
34
|
+
parts.each_with_index { |path, i| classes << parts.first(i+1).join('_') }
|
35
|
+
|
36
|
+
classes.join(' ')
|
37
|
+
end
|
38
|
+
|
39
|
+
def asset_url(path, prefix="")
|
40
|
+
Middleman::Assets.get_url(path, prefix, request)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Padrino's asset handling needs to pass through ours
|
44
|
+
def asset_path(kind, source)
|
45
|
+
return source if source =~ /^http/
|
46
|
+
asset_folder = case kind
|
47
|
+
when :css then settings.css_dir
|
48
|
+
when :js then settings.js_dir
|
49
|
+
when :images then settings.images_dir
|
50
|
+
else kind.to_s
|
51
|
+
end
|
52
|
+
source = source.to_s.gsub(/\s/, '')
|
53
|
+
ignore_extension = (asset_folder.to_s == kind.to_s) # don't append extension
|
54
|
+
source << ".#{kind}" unless ignore_extension or source =~ /\.#{kind}/
|
55
|
+
result_path = source if source =~ %r{^/} # absolute path
|
56
|
+
result_path ||= asset_url(source, asset_folder)
|
57
|
+
timestamp = asset_timestamp(result_path)
|
58
|
+
"#{result_path}#{timestamp}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Middleman::Features::LiveReload
|
2
|
+
class << self
|
3
|
+
def registered(app)
|
4
|
+
return unless Middleman::Server.environment == :development
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'livereload'
|
8
|
+
rescue LoadError
|
9
|
+
puts "Livereload not available. Install it with: gem install livereload"
|
10
|
+
end
|
11
|
+
|
12
|
+
new_config = ::LiveReload::Config.new do |config|
|
13
|
+
config.exts = ::Tilt.mappings.keys
|
14
|
+
end
|
15
|
+
|
16
|
+
# Middleman::Server.public
|
17
|
+
::LiveReload.run [Middleman::Server.views], new_config
|
18
|
+
end
|
19
|
+
alias :included :registered
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
begin
|
2
|
+
require "yui/compressor"
|
3
|
+
rescue LoadError
|
4
|
+
puts "YUI-Compressor not available. Install it with: gem install yui-compressor"
|
5
|
+
end
|
6
|
+
|
7
|
+
module Middleman
|
8
|
+
module Rack
|
9
|
+
|
10
|
+
class MinifyJavascript
|
11
|
+
def initialize(app, options={})
|
12
|
+
@app = app
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(env)
|
16
|
+
status, headers, response = @app.call(env)
|
17
|
+
|
18
|
+
if env["PATH_INFO"].match(/\.js$/)
|
19
|
+
compressor = ::YUI::JavaScriptCompressor.new(:munge => true)
|
20
|
+
|
21
|
+
uncompressed_source = response.is_a?(::Rack::File) ? File.read(response.path) : response
|
22
|
+
response = compressor.compress(uncompressed_source)
|
23
|
+
headers["Content-Length"] = ::Rack::Utils.bytesize(response).to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
[status, headers, response]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Middleman::Features::MinifyJavascript
|
2
|
+
class << self
|
3
|
+
def registered(app)
|
4
|
+
Middleman::Features::MinifyJavascript::Haml::Javascript.send :include, ::Haml::Filters::Base
|
5
|
+
|
6
|
+
require "middleman/features/minify_javascript/rack"
|
7
|
+
app.use Middleman::Rack::MinifyJavascript
|
8
|
+
end
|
9
|
+
alias :included :registered
|
10
|
+
end
|
11
|
+
|
12
|
+
module Haml
|
13
|
+
module Javascript
|
14
|
+
def render_with_options(text, options)
|
15
|
+
compressor = ::YUI::JavaScriptCompressor.new(:munge => true)
|
16
|
+
data = compressor.compress(text)
|
17
|
+
%Q{<script type=#{options[:attr_wrapper]}text/javascript#{options[:attr_wrapper]}>#{data.chomp}</script>}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def partial(template, *args)
|
2
|
+
options = args.last.is_a?(Hash) ? args.pop : { }
|
3
|
+
options.merge!(:layout => false)
|
4
|
+
if collection = options.delete(:collection) then
|
5
|
+
haml_concat(collection.inject([]) do |buffer, member|
|
6
|
+
buffer << haml(template, options.merge(
|
7
|
+
:layout => false,
|
8
|
+
:locals => {template.to_sym => member}
|
9
|
+
)
|
10
|
+
)
|
11
|
+
end.join("\n"))
|
12
|
+
else
|
13
|
+
haml_concat(haml(template, options))
|
14
|
+
end
|
15
|
+
end
|