montage 0.2.1
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.
- data/.document +5 -0
- data/.gitignore +31 -0
- data/History.md +40 -0
- data/LICENSE +19 -0
- data/README.md +89 -0
- data/Rakefile +41 -0
- data/VERSION +1 -0
- data/bin/montage +22 -0
- data/lib/montage.rb +33 -0
- data/lib/montage/commands.rb +32 -0
- data/lib/montage/commands/generate.rb +234 -0
- data/lib/montage/commands/init.rb +119 -0
- data/lib/montage/core_ext.rb +80 -0
- data/lib/montage/project.rb +185 -0
- data/lib/montage/sass_builder.rb +37 -0
- data/lib/montage/source.rb +75 -0
- data/lib/montage/sprite.rb +132 -0
- data/lib/montage/templates/montage.yml +26 -0
- data/lib/montage/templates/sass_mixins.erb +20 -0
- data/lib/montage/templates/sources/book.png +0 -0
- data/lib/montage/templates/sources/box-label.png +0 -0
- data/lib/montage/templates/sources/calculator.png +0 -0
- data/lib/montage/templates/sources/calendar-month.png +0 -0
- data/lib/montage/templates/sources/camera.png +0 -0
- data/lib/montage/templates/sources/eraser.png +0 -0
- data/lib/montage/version.rb +3 -0
- data/montage.gemspec +145 -0
- data/spec/fixtures/custom_dirs/montage.yml +8 -0
- data/spec/fixtures/default/montage.yml +7 -0
- data/spec/fixtures/default/public/images/sprites/src/one.png +0 -0
- data/spec/fixtures/default/public/images/sprites/src/three.png +0 -0
- data/spec/fixtures/default/public/images/sprites/src/two.png +0 -0
- data/spec/fixtures/directory_config/config/montage.yml +5 -0
- data/spec/fixtures/missing_source/montage.yml +3 -0
- data/spec/fixtures/missing_source_dir/montage.yml +5 -0
- data/spec/fixtures/root_config/montage.yml +5 -0
- data/spec/fixtures/root_config/public/images/sprites/src/source_one.png +0 -0
- data/spec/fixtures/root_config/public/images/sprites/src/source_three.jpg +0 -0
- data/spec/fixtures/root_config/public/images/sprites/src/source_two +0 -0
- data/spec/fixtures/sources/hundred.png +0 -0
- data/spec/fixtures/sources/mammoth.png +0 -0
- data/spec/fixtures/sources/other.png +0 -0
- data/spec/fixtures/sources/twenty.png +0 -0
- data/spec/fixtures/subdirs/montage.yml +5 -0
- data/spec/fixtures/subdirs/sub/sub/keep +0 -0
- data/spec/lib/command_runner.rb +140 -0
- data/spec/lib/fixtures.rb +7 -0
- data/spec/lib/have_public_method_defined.rb +19 -0
- data/spec/lib/project_helper.rb +135 -0
- data/spec/lib/shared_project_specs.rb +32 -0
- data/spec/lib/shared_sprite_specs.rb +30 -0
- data/spec/montage/commands/generate_spec.rb +308 -0
- data/spec/montage/commands/init_spec.rb +120 -0
- data/spec/montage/core_ext_spec.rb +33 -0
- data/spec/montage/project_spec.rb +181 -0
- data/spec/montage/sass_builder_spec.rb +269 -0
- data/spec/montage/source_spec.rb +53 -0
- data/spec/montage/spec/have_public_method_defined_spec.rb +31 -0
- data/spec/montage/sprite_spec.rb +170 -0
- data/spec/rcov.opts +8 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +19 -0
- data/tasks/spec.rake +17 -0
- data/tasks/yard.rake +11 -0
- metadata +249 -0
data/.document
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
Icon*
|
4
|
+
|
5
|
+
## TEXTMATE
|
6
|
+
*.tmproj
|
7
|
+
tmtags
|
8
|
+
|
9
|
+
## EMACS
|
10
|
+
*~
|
11
|
+
\#*
|
12
|
+
.\#*
|
13
|
+
|
14
|
+
## VIM
|
15
|
+
*.swp
|
16
|
+
|
17
|
+
## RUBINIUS
|
18
|
+
*.rbc
|
19
|
+
rakefile.compiled.rbc
|
20
|
+
|
21
|
+
## PROJECT::GENERAL
|
22
|
+
.yardoc
|
23
|
+
coverage
|
24
|
+
doc
|
25
|
+
measurements
|
26
|
+
pkg
|
27
|
+
rdoc
|
28
|
+
tmp
|
29
|
+
|
30
|
+
## PROJECT::SPECIFIC
|
31
|
+
.sass-cache
|
data/History.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
v0.2.0 - 2010-04-08
|
2
|
+
-------------------
|
3
|
+
|
4
|
+
* Running `montage` will now generate `_montage.sass` in the specified
|
5
|
+
config.sass directory. A separate mixin will be generated for each sprite,
|
6
|
+
with the mixin accepting three arguments: the name of the source image, an
|
7
|
+
optional horizontal offset, and an optional vertical offset. Disable the
|
8
|
+
Sass generation by setting config.sass to false.
|
9
|
+
|
10
|
+
* If pngout or pngout-darwin is available (run `which pngout pngout-darwin` to
|
11
|
+
find out), Montage will compress the generated sprites. Installing pngout
|
12
|
+
is strongly recommended; significant savings can be made on larger PNGs.
|
13
|
+
|
14
|
+
* The `montage` command accepts a '--force' option which will regenerate all
|
15
|
+
sprites even if they haven't been changed since the last run.
|
16
|
+
|
17
|
+
* Sprites will be regenerated if the file has been deleted.
|
18
|
+
|
19
|
+
v0.1.2 - 2010-04-06
|
20
|
+
-------------------
|
21
|
+
|
22
|
+
* Sprites will only be regenerated when their definition (in montage.yml) has
|
23
|
+
changed, or if the contents of the source files have changed.
|
24
|
+
|
25
|
+
* The `montage init` command now uses the highline gem to ask for the paths to
|
26
|
+
a project's source files, and the intended sprite output directory.
|
27
|
+
|
28
|
+
* Running `montage init` will copy some sample source files into the source
|
29
|
+
directory. This allows running `montage` immediately after creating the
|
30
|
+
project, to see how things work.
|
31
|
+
|
32
|
+
v0.1.1 - 2010-04-05
|
33
|
+
-------------------
|
34
|
+
|
35
|
+
* Small fix for Ruby 1.9.1, which doesn't define String#inject.
|
36
|
+
|
37
|
+
v0.1.0 - 2010-04-05
|
38
|
+
-------------------
|
39
|
+
|
40
|
+
* Initial release. Supports creation of sprites and not much else.
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009-2010 Anthony Williams
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
Montage
|
2
|
+
=======
|
3
|
+
|
4
|
+
_"[Even Rocky had a montage](http://www.youtube.com/watch?v=FIi0vFyqWAc)."_
|
5
|
+
|
6
|
+
**Source**
|
7
|
+
: [http://github.com/antw/montage](http://github.com/antw/montage)
|
8
|
+
|
9
|
+
**Author**
|
10
|
+
: Anthony Williams
|
11
|
+
|
12
|
+
**Copyright**
|
13
|
+
: 2009-2010
|
14
|
+
|
15
|
+
**License**
|
16
|
+
: MIT License
|
17
|
+
|
18
|
+
SYNOPSIS
|
19
|
+
--------
|
20
|
+
|
21
|
+
Popularised by Dave Shea in an [A List Apart](http://www.alistapart.com/articles/sprites), "sprite" images combine many smaller images into a single, larger image, with CSS then being used to divide the sprite back into it's constituent parts.
|
22
|
+
|
23
|
+
However, creating sprites burdens you with having to manually update them every time a minor change is required. Even more frustrating is the need to remember the precise background positions required when editing the CSS.
|
24
|
+
|
25
|
+
Montage is a library which, provided a simple configuration file, will automate this process, and if you're a SASS user, you're in for a treat: Montage generates mixins which make working with your sprites incredibly simple:
|
26
|
+
|
27
|
+
SASS Usage:
|
28
|
+
|
29
|
+
#navigation
|
30
|
+
a#home, a#products
|
31
|
+
+main-sprite("home")
|
32
|
+
a#products
|
33
|
+
+main-sprite-pos("products")
|
34
|
+
|
35
|
+
Generated CSS:
|
36
|
+
|
37
|
+
#navigation a#home, #navigation a#products {
|
38
|
+
background: url(/path/to/sprite.ext) 0 0 no-repeat; }
|
39
|
+
|
40
|
+
#navigation a#products {
|
41
|
+
background-position: 0 -40px; }
|
42
|
+
|
43
|
+
Montage has been split out from [Kin](http://github.com/antw/kin) -- a collection of various bits-and-bobs from my Merb projects.
|
44
|
+
|
45
|
+
Montage is pretty primitive in that it stacks each image in a single column. This is perfect when your source images are of a similar width (such as is the case with icons), but not so good when they vary significantly in size.
|
46
|
+
|
47
|
+
FEATURE LIST
|
48
|
+
------------
|
49
|
+
|
50
|
+
Coming soon.
|
51
|
+
|
52
|
+
USAGE
|
53
|
+
-----
|
54
|
+
|
55
|
+
Coming soon.
|
56
|
+
|
57
|
+
Ward specs are run against:
|
58
|
+
|
59
|
+
* Ruby (MRI) 1.8.6 p399,
|
60
|
+
* Ruby (MRI) 1.8.7 p249,
|
61
|
+
* Ruby (YARV) 1.9.1 p378,
|
62
|
+
|
63
|
+
Montage requires RMagick which presently rules out support for JRuby and Rubinius.
|
64
|
+
|
65
|
+
CONTRIBUTING
|
66
|
+
------------
|
67
|
+
|
68
|
+
* Fork the project, taking care not to get any in your eyes.
|
69
|
+
|
70
|
+
* Make your feature addition or bug fix.
|
71
|
+
|
72
|
+
* Add tests for it. This is especially important not only because it helps
|
73
|
+
ensure that I don't unintentionally break it in a future version, but also
|
74
|
+
since it appeases Phyllis --- the goddess of Cucumbers --- who has been
|
75
|
+
known to rain showers of fresh vegetables on those who don't write tests.
|
76
|
+
|
77
|
+
* Commit, but do not mess with the Rakefile, VERSION, or history. If you want
|
78
|
+
to have your own version, that is fine, but bump version in a commit by
|
79
|
+
itself so that I can ignore it when I pull.
|
80
|
+
|
81
|
+
* Send me a pull request. Bonus points for topic branches. But we all know
|
82
|
+
everything is made up and the points don't matter.
|
83
|
+
|
84
|
+
COPYRIGHT
|
85
|
+
---------
|
86
|
+
|
87
|
+
Montage © 2009-2010 by [Anthony Williams](mailto:hi@antw.me). Licensed under the MIT license. Please see the {file:LICENSE} for more information.
|
88
|
+
|
89
|
+
The sample sources in lib/montage/templates/sources are courtesy of Yusuke Kamiyamane: http://p.yusukekamiyamane.com
|
data/Rakefile
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
|
4
|
+
require File.expand_path('../lib/montage/version', __FILE__)
|
5
|
+
|
6
|
+
CLOBBER.include ['pkg', '*.gem', 'doc', 'coverage', 'measurements']
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'jeweler'
|
10
|
+
Jeweler::Tasks.new do |gem|
|
11
|
+
gem.name = 'montage'
|
12
|
+
gem.summary = 'Montage'
|
13
|
+
gem.homepage = 'http://github.com/antw/montage'
|
14
|
+
gem.description = 'Even Rocky had a montage.'
|
15
|
+
|
16
|
+
gem.author = 'Anthony Williams'
|
17
|
+
gem.email = 'hi@antw.me'
|
18
|
+
|
19
|
+
gem.platform = Gem::Platform::RUBY
|
20
|
+
gem.has_rdoc = false
|
21
|
+
|
22
|
+
# Dependencies.
|
23
|
+
gem.add_dependency 'activesupport', '>= 3.0.0.beta'
|
24
|
+
gem.add_dependency 'rmagick', '>= 2.12'
|
25
|
+
gem.add_dependency 'highline', '>= 1.5'
|
26
|
+
|
27
|
+
# Development dependencies.
|
28
|
+
gem.add_development_dependency 'rspec', '>= 1.3.0'
|
29
|
+
gem.add_development_dependency 'cucumber', '>= 0.6'
|
30
|
+
gem.add_development_dependency 'open4', '>= 1.0'
|
31
|
+
gem.add_development_dependency 'haml', '>= 3.0.0.beta.1'
|
32
|
+
gem.add_development_dependency 'yard', '>= 0.5'
|
33
|
+
end
|
34
|
+
|
35
|
+
Jeweler::GemcutterTasks.new
|
36
|
+
rescue LoadError
|
37
|
+
puts 'Jeweler (or a dependency) not available. Install it with: gem '\
|
38
|
+
'install jeweler'
|
39
|
+
end
|
40
|
+
|
41
|
+
FileList['tasks/**/*.rake'].each { |task| import task }
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.1
|
data/bin/montage
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
unless $:.include?(File.dirname(__FILE__) + '/../lib')
|
4
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rubygems' unless ENV['NORUBYGEMS']
|
8
|
+
|
9
|
+
require 'montage'
|
10
|
+
require 'montage/commands'
|
11
|
+
|
12
|
+
Montage::Commands.print_masthead
|
13
|
+
|
14
|
+
case ARGV[0]
|
15
|
+
when 'init'
|
16
|
+
require 'montage/commands/init'
|
17
|
+
Montage::Commands::Init.run(ARGV)
|
18
|
+
else
|
19
|
+
require 'montage/commands/generate'
|
20
|
+
Montage::Commands::Generate.run(ARGV)
|
21
|
+
end
|
22
|
+
|
data/lib/montage.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'digest/sha2'
|
2
|
+
require 'erb'
|
3
|
+
require 'pathname'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
# Gems.
|
7
|
+
require 'active_support/ordered_hash'
|
8
|
+
require 'rmagick'
|
9
|
+
|
10
|
+
# On with the library...
|
11
|
+
require 'montage/core_ext'
|
12
|
+
require 'montage/project'
|
13
|
+
require 'montage/sass_builder'
|
14
|
+
require 'montage/source'
|
15
|
+
require 'montage/sprite'
|
16
|
+
require 'montage/version'
|
17
|
+
|
18
|
+
module Montage
|
19
|
+
# Generic exception for all Montage exception classes.
|
20
|
+
MontageError = Class.new(StandardError)
|
21
|
+
|
22
|
+
# Raised when a project directory couldn't be found.
|
23
|
+
MissingProject = Class.new(MontageError)
|
24
|
+
|
25
|
+
# Raised when a creating a new project in an existing project directory.
|
26
|
+
ProjectExists = Class.new(MontageError)
|
27
|
+
|
28
|
+
# Raised when a sprite set expects a source image, but none could be found.
|
29
|
+
MissingSource = Class.new(MontageError)
|
30
|
+
|
31
|
+
# Raised when a sprite can't be saved due to incorrect permissions.
|
32
|
+
TargetNotWritable = Class.new(MontageError)
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'highline/import'
|
2
|
+
|
3
|
+
HighLine.use_color = ! ARGV.delete('--no-color') && ! ARGV.delete('--no-colour')
|
4
|
+
HighLine.use_color = false if !STDOUT.tty? && !ENV.has_key?("AUTOTEST")
|
5
|
+
|
6
|
+
module Kernel
|
7
|
+
def_delegators :$terminal, :color
|
8
|
+
end
|
9
|
+
|
10
|
+
module Montage
|
11
|
+
module Commands
|
12
|
+
BLANK = "\n".freeze
|
13
|
+
|
14
|
+
extend self
|
15
|
+
|
16
|
+
# Prints the Montage masthead, introducing the programme, and including
|
17
|
+
# the current version number.
|
18
|
+
def print_masthead
|
19
|
+
say BLANK
|
20
|
+
say "Montage v#{Montage::VERSION}"
|
21
|
+
say "=========#{'=' * Montage::VERSION.length}"
|
22
|
+
say BLANK
|
23
|
+
end
|
24
|
+
|
25
|
+
# Exits immediately, outputting a blank line first.
|
26
|
+
def exit(status)
|
27
|
+
say BLANK
|
28
|
+
Kernel.exit(status)
|
29
|
+
end
|
30
|
+
|
31
|
+
end # Commands
|
32
|
+
end # Montage
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module Montage
|
2
|
+
module Commands
|
3
|
+
# Generates sprites for a project.
|
4
|
+
class Generate
|
5
|
+
extend Commands
|
6
|
+
|
7
|
+
# Terminal reset code; removes any content on the current line and moves
|
8
|
+
# the cursor back to the beginning.
|
9
|
+
RESET = "\r\e[0K"
|
10
|
+
|
11
|
+
# Glyphs used when doing long-running processes.
|
12
|
+
GLYPHS = %w( ~ \\ | / )
|
13
|
+
|
14
|
+
# Given a project, generates sprites.
|
15
|
+
#
|
16
|
+
# @param [Array] argv
|
17
|
+
# The arguments given on the command line.
|
18
|
+
#
|
19
|
+
def self.run(argv)
|
20
|
+
new(Montage::Project.find(Dir.pwd), argv.include?('--force')).run!
|
21
|
+
|
22
|
+
rescue Montage::MissingProject
|
23
|
+
say color(<<-ERROR.compress_lines, :red)
|
24
|
+
Couldn't find a Montage project in the current directory. If
|
25
|
+
you want to create a new project here, run `montage init'.
|
26
|
+
ERROR
|
27
|
+
|
28
|
+
exit(1)
|
29
|
+
|
30
|
+
rescue Montage::MissingSource, Montage::TargetNotWritable => e
|
31
|
+
say Montage::Commands::BLANK
|
32
|
+
say color(e.message.compress_lines, :red)
|
33
|
+
|
34
|
+
exit(1)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Creates a new Generate instance.
|
38
|
+
#
|
39
|
+
# @param [Montage::Project] project
|
40
|
+
# The project whose sprites are to be generated.
|
41
|
+
# @param [Boolean] force
|
42
|
+
# Rengerate sprites, even if they haven't been changed.
|
43
|
+
#
|
44
|
+
def initialize(project, force)
|
45
|
+
@project, @force, @generated = project, force, []
|
46
|
+
end
|
47
|
+
|
48
|
+
# Runs the generator, saving the sprites and cache.
|
49
|
+
#
|
50
|
+
def run!
|
51
|
+
if generate_sprites!
|
52
|
+
optimise_with_pngout!
|
53
|
+
write_cache!
|
54
|
+
write_sass!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private # ==============================================================
|
59
|
+
|
60
|
+
# Returns the cached digests.
|
61
|
+
#
|
62
|
+
# @return [Hash]
|
63
|
+
#
|
64
|
+
def cache
|
65
|
+
@_sprite_caches ||= begin
|
66
|
+
cache_path = @project.paths.sprites + '.montage_cache'
|
67
|
+
cache_path.file? ? YAML.load_file(cache_path) || {} : {}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Step 1: Generates the sprites for the given project. Skips those which
|
72
|
+
# have not changed since they were last generated.
|
73
|
+
#
|
74
|
+
# @return [Boolean]
|
75
|
+
# Returns true if at least one sprite has been updated.
|
76
|
+
#
|
77
|
+
def generate_sprites!
|
78
|
+
unless @project.paths.sprites.directory?
|
79
|
+
@project.paths.sprites.mkpath
|
80
|
+
end
|
81
|
+
|
82
|
+
@project.sprites.each do |sprite|
|
83
|
+
digest = sprite.digest
|
84
|
+
|
85
|
+
|
86
|
+
if @force or cache[sprite.name] != digest or not sprite.path.file?
|
87
|
+
with_feedback %(Generating "#{sprite.name}"), 'Generating' do
|
88
|
+
sprite.write
|
89
|
+
cache[sprite.name] = digest
|
90
|
+
@generated << sprite
|
91
|
+
end
|
92
|
+
|
93
|
+
say color("Done", :green)
|
94
|
+
else
|
95
|
+
say %(- Generating "#{sprite.name}": ) +
|
96
|
+
color("Unchanged; ignoring", :yellow)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
say Montage::Commands::BLANK
|
101
|
+
@generated.any?
|
102
|
+
end
|
103
|
+
|
104
|
+
# Step 2: Optimise generated sprites with PNGOut.
|
105
|
+
#
|
106
|
+
def optimise_with_pngout!
|
107
|
+
return if @generated.empty?
|
108
|
+
|
109
|
+
# Try to find PNGOut.
|
110
|
+
pngout = `which pngout pngout-darwin`.split("\n").first
|
111
|
+
|
112
|
+
if pngout.nil?
|
113
|
+
say <<-MESSAGE.compress_lines
|
114
|
+
Skipping optimisation with PNGOut since Montage couldn't find
|
115
|
+
"pngout" or "pngout-darwin" anywhere.
|
116
|
+
MESSAGE
|
117
|
+
say Montage::Commands::BLANK
|
118
|
+
|
119
|
+
return
|
120
|
+
end
|
121
|
+
|
122
|
+
max_sprite_name_length = @generated.inject(0) do |max, sprite|
|
123
|
+
max > sprite.name.length ? max : sprite.name.length
|
124
|
+
end
|
125
|
+
|
126
|
+
@generated.each do |sprite|
|
127
|
+
original_size = sprite.path.size
|
128
|
+
|
129
|
+
with_feedback %(Optimising "#{sprite.name}"), 'Optimising' do
|
130
|
+
5.times do |i|
|
131
|
+
# Optimise until pngout reports that it can't compress further,
|
132
|
+
# or until we've tried five times.
|
133
|
+
out = `#{pngout} #{sprite.path} #{sprite.path} -s0 -k0 -y`
|
134
|
+
break if out =~ /Unable to compress further/
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
new_size = sprite.path.size
|
139
|
+
|
140
|
+
reduction = ('%.1fkb (%d' % [
|
141
|
+
(original_size.to_f - new_size) / 1024,
|
142
|
+
100 - (new_size.to_f / original_size) * 100 ]) + '%)'
|
143
|
+
|
144
|
+
say color("Done; saved #{reduction}", :green)
|
145
|
+
end
|
146
|
+
|
147
|
+
say Montage::Commands::BLANK
|
148
|
+
|
149
|
+
rescue Errno::ENOENT
|
150
|
+
say ("#{RESET}" + <<-MESSAGE.compress_lines)
|
151
|
+
Skipping optimisation with PNGOut since Montage is currently only in
|
152
|
+
bed with Linux and OS X. Sorry!
|
153
|
+
MESSAGE
|
154
|
+
say Montage::Commands::BLANK
|
155
|
+
exit(1)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Step 3: Writes the cached digests to the cache file.
|
159
|
+
#
|
160
|
+
def write_cache!
|
161
|
+
cache_path = @project.paths.sprites + '.montage_cache'
|
162
|
+
|
163
|
+
File.open(cache_path, 'w') do |cache_writer|
|
164
|
+
cache_writer.puts YAML.dump(cache)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Step 4: Writes the Sass file to disk.
|
169
|
+
#
|
170
|
+
def write_sass!
|
171
|
+
unless @project.paths.sass == false
|
172
|
+
say "- Generating Sass: "
|
173
|
+
Montage::SassBuilder.new(@project).write
|
174
|
+
say color("Done", :green)
|
175
|
+
say Montage::Commands::BLANK
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# --- Optimisation Output ----------------------------------------------
|
180
|
+
|
181
|
+
# Executes a block while providing live feedback to the user.
|
182
|
+
#
|
183
|
+
# @param [String] prefix
|
184
|
+
# The "prefix" of each notification; this is always shown at the
|
185
|
+
# beginning of each line.
|
186
|
+
# @param [String] verb
|
187
|
+
# What's happening?
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# with_notification('Generating image', 'Generating') { ... }
|
191
|
+
#
|
192
|
+
# # "- Generating image: Generating" # initially
|
193
|
+
# # "- Generating image: Still generating" # after 3 seconds
|
194
|
+
# # "- Generating image: STILL generating" # after 6 seconds
|
195
|
+
#
|
196
|
+
def with_feedback(prefix, verb = 'Generating', &work)
|
197
|
+
notifier = Thread.new do
|
198
|
+
prefix = "- #{prefix}: "
|
199
|
+
iteration = 0
|
200
|
+
|
201
|
+
while true do
|
202
|
+
case iteration
|
203
|
+
when 0 then message = color(verb, :blue)
|
204
|
+
when 30 then message = color("Still #{verb.downcase}", :blue)
|
205
|
+
when 60 then message = color("STILL #{verb.downcase}", :blue)
|
206
|
+
when 90 then message =
|
207
|
+
color("Gosh, this is taking a while...", :blue)
|
208
|
+
end
|
209
|
+
|
210
|
+
say "#{RESET}#{prefix}#{message} [#{GLYPHS[iteration % 4]}] "
|
211
|
+
|
212
|
+
iteration += 1
|
213
|
+
$stdout.flush
|
214
|
+
sleep(0.1)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
worker = Thread.new do
|
219
|
+
begin
|
220
|
+
work.call
|
221
|
+
ensure
|
222
|
+
notifier.kill
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
notifier.join
|
227
|
+
worker.join
|
228
|
+
|
229
|
+
say "#{RESET}#{prefix}"
|
230
|
+
end
|
231
|
+
|
232
|
+
end # Generate
|
233
|
+
end # Commands
|
234
|
+
end # Montage
|