spriteful 0.0.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/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2013 Lucas Mazza <lucastmazza@gmail.com>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,103 @@
1
+ # Spriteful
2
+
3
+ Spriteful is a command line sprite generator tool, meant to be used regardless of your programming language, application stack or Web framework.
4
+
5
+ ## Usage
6
+
7
+ Lets say that you have your images in `images/icons/` and you want to generate a sprite for them.
8
+
9
+ ```bash
10
+ spriteful images/icons
11
+ # create icons.png
12
+ # create icons.css
13
+ ```
14
+
15
+ Boom! Spriteful will generate a `icons.png` in your working directory and the respective CSS
16
+ for your sprite in the `icons.css` file.
17
+
18
+ If you want a bit more of control on where we should place the combined image and the CSS, you
19
+ can use the `s` (for `stylesheets`) and `d` ( for `destination`) flags and Spriteful will place
20
+ your `icons.png` in a specific directory and will save the CSS in the `icons.css` file instead
21
+ of copying it to your clipboard.
22
+
23
+ ```bash
24
+ spriteful images/icons -s stylesheets -d images
25
+ # create images/icons.png
26
+ # create stylesheets/icons.css
27
+ ```
28
+
29
+ ### The CSS
30
+
31
+ By default, Spriteful will generate a set of CSS classes based on the images of your sprite. In the
32
+ case of having a `new.png` image in our `icons` sprite, you can use it putting together the `icons`
33
+ and `new` class.
34
+
35
+ ```html
36
+ <a href='/new' class='icons new'>New thing</a>
37
+ ```
38
+
39
+ ### SCSS support
40
+
41
+ Spriteful can generate SCSS-ish code with the `-f` flag. This way the generated code will use
42
+ [Placeholder Selectors](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#placeholder_selectors_)
43
+ instead of generating a class for each image in your sprite.
44
+
45
+ ```bash
46
+ spriteful images/icons -f scss
47
+ # create icons.png
48
+ # copy icons.scss
49
+ ```
50
+
51
+ ```scss
52
+ // in your SCSS code...
53
+ .button {
54
+ @extend %icons-sprite-new;
55
+ }
56
+ ```
57
+
58
+ ### Multiple sprites
59
+
60
+ You can deal with multiple sprites in a single run. If `images/icons` has a set of images for one
61
+ sprite and `images/flags` another set you can generate both `icons.png` and `flags.png` with a single
62
+ execution.
63
+
64
+ ```bash
65
+ spriteful images/icons images/flags -s stylesheets -d images
66
+ # create images/icons.png
67
+ # create stylesheets/icons.css
68
+ # create images/flags.png
69
+ # create stylesheets/flags.css
70
+ ```
71
+
72
+ ### Spriteful and Rails
73
+
74
+ If you are working on a Ruby on Rails application Spriteful can provide some extra goodies for
75
+ you. If run you the `spriteful` command with the `--rails` flag, all sprites under `app/assets/images/sprites` will be generated with respective stylesheets at `app/assets/stylesheets/sprites`, using the proper `image_url` helper for the format of your choice.
76
+
77
+ So, given that you have the `icons` and `flags` directories with your images under `app/assets/images`, you might get a similar output when generating these two sprites.
78
+
79
+ ```bash
80
+ spriteful --rails
81
+ # create app/assets/images/sprites/flags.png
82
+ # create app/assets/stylesheets/sprites/flags.css.erb
83
+ # create app/assets/images/sprites/icons.png
84
+ # create app/assets/stylesheets/sprites/icons.css.erb
85
+ ```
86
+
87
+ ## Available options
88
+
89
+ * `--stylesheets` (`-s`) - Directory to save the generated stylesheet(s), instead of copying them to the clipboard.
90
+ * `--destination` (`-d`) - Directory to save the generated image(s).
91
+ * `--rails` (`-r`) - Forces rails specific settings, see [Spriteful and Rails](#spriteful-and-rails) for more info.
92
+ * `--format` (`-f`) - Format to generate the sprite(s) stylesheet(s). Either "css" or "scss".
93
+ * `--horizontal` - Changes the sprite orientation to horizontal, since all sprites are combined vertically by default.
94
+ * `--save` - Saves the provided arguments for later use.
95
+ * `--spacing` - Add some spacing between the images in the sprite.
96
+
97
+ You can add a `.spritefulrc` file with default options to your home directory or the current one that they will be picked up whenever you run the `spriteful` command.
98
+
99
+ ### Examples
100
+
101
+ This repository contains an `examples` folder with some very simple sprites and the output generated
102
+ by Spriteful. Feel free to take a look or try it on your own by cloning this repository and running
103
+ `spriteful` on it.
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ require 'shellwords'
3
+
4
+ require 'spriteful'
5
+ require 'spriteful/cli'
6
+
7
+ unless ARGV.include?('--help') || ARGV.include?('-h')
8
+ %w(~/.spritefulrc ./.spritefulrc).each do |rcfile|
9
+ path = File.expand_path(rcfile)
10
+ if File.exist?(path)
11
+ ARGV.unshift(*Shellwords.split(File.read(path)))
12
+ end
13
+ end
14
+ end
15
+
16
+ Spriteful::CLI.start
@@ -0,0 +1,9 @@
1
+ require 'thor/error'
2
+
3
+ require 'spriteful/image'
4
+ require 'spriteful/sprite'
5
+ require 'spriteful/stylesheet'
6
+
7
+ module Spriteful
8
+ class EmptySourceError < Thor::Error; end
9
+ end
@@ -0,0 +1,124 @@
1
+ require 'shellwords'
2
+ require 'thor/group'
3
+
4
+ module Spriteful
5
+ class CLI < Thor::Group
6
+ include Thor::Actions
7
+ desc 'Generates image sprites with corresponding stylesheets.'
8
+
9
+ argument :sources, type: :array, desc: 'Images to generate the sprites.', default: []
10
+
11
+ class_option :format, aliases: '-f', banner: 'FORMAT', type: :string, desc: 'Format to generate the sprite(s) stylesheet(s). Either "css" or "scss".', default: 'css'
12
+ class_option :stylesheets, aliases: '-s', banner: 'STYLESHEETS_DIR', type: :string, desc: 'Directory to save the generated stylesheet(s), instead of copying them to the clipboard.', default: Dir.pwd
13
+ class_option :destination, aliases: '-d', banner: 'DESTINATION_DIR', type: :string, desc: 'Destination directory to save the combined image(s).', default: Dir.pwd
14
+ class_option :root, aliases: '-r', banner: 'ROOT_DIR', type: :string, desc: 'Root folder from where your static files will be served.'
15
+
16
+ class_option :rails, type: :boolean, desc: 'Follow default conventions for a Rails application with the Asset Pipeline.'
17
+ class_option :horizontal, type: :boolean, desc: 'Change the sprite orientation to "horizontal".'
18
+ class_option :save, type: :boolean, desc: 'Save the supplied arguments to ".spritefulrc".'
19
+ class_option :spacing, type: :numeric, desc: 'Add spacing between the images in the sprite.'
20
+
21
+ # Public: Gets the CLI banner for the Thor help message.
22
+ #
23
+ # Returns a String.
24
+ def self.banner
25
+ 'spriteful sources [options]'
26
+ end
27
+
28
+ # Public: Initializes the CLI object and replaces the frozen
29
+ # 'options' object with an unfrozen one that we can mutate.
30
+ def initialize(*)
31
+ super
32
+ self.options = options.dup
33
+ end
34
+
35
+ # Public: executes the CLI processing of the sprite sources
36
+ # into combined images and stylesheets.
37
+ # Returns nothing.
38
+ def execute
39
+ prepare_options!
40
+ if sources.empty?
41
+ self.class.help(shell)
42
+ exit(1)
43
+ end
44
+
45
+ sources.uniq!
46
+ sources.each do |source|
47
+ create_sprite(source)
48
+ end
49
+
50
+ save_options
51
+ end
52
+
53
+ private
54
+ # Internal: create a sprite image and stylesheet from a given source.
55
+ #
56
+ # Returns nothing.
57
+ def create_sprite(source)
58
+ sprite = Spriteful::Sprite.new(File.expand_path(source), options.destination, sprite_options)
59
+ stylesheet = Spriteful::Stylesheet.new(sprite, File.expand_path(options.stylesheets), stylesheet_options)
60
+
61
+ sprite.combine!
62
+ create_file sprite.path, sprite.blob
63
+ create_file stylesheet.path, stylesheet.render
64
+ end
65
+
66
+ # Internal: Saves the existing options on 'ARGV' to the '.spritefulrc'
67
+ # file if the '--save' flag is present.
68
+ #
69
+ # Returns nothing.
70
+ def save_options
71
+ if options.save?
72
+ options.delete(:save)
73
+ parts = sources + options.map { |key, value| ["--#{key}", value.to_s] }.flatten
74
+ create_file '.spritefulrc', Shellwords.join(parts) + "\n", force: true
75
+ end
76
+ end
77
+
78
+ def stylesheet_options
79
+ {
80
+ root: options.root,
81
+ format: options.format,
82
+ rails: options.rails?
83
+ }
84
+ end
85
+
86
+ # Internal: Gets the set of options that are specific for the 'Sprite'
87
+ # class.
88
+ #
89
+ # Returns a Hash.
90
+ def sprite_options
91
+ {
92
+ horizontal: options.horizontal?,
93
+ spacing: options.spacing
94
+ }
95
+ end
96
+
97
+ # Internal: Change the `options` hash if necessary, based on the
98
+ # 'rails' flag.
99
+ #
100
+ # Returns nothing.
101
+ def prepare_options!
102
+ if options.rails?
103
+ sources.concat(detect_sources)
104
+ set_rails_defaults
105
+ end
106
+ end
107
+
108
+ # Internal: Detects possible source directories in Rails applications
109
+ # that are present inside the 'images/sprites' asset path.
110
+ #
111
+ # Returns an Array of directories.
112
+ def detect_sources
113
+ Dir['app/assets/images/sprites/*'].select { |dir| File.directory?(dir) }
114
+ end
115
+
116
+ # Internal: Sets Rails specific default options to the 'options' object.
117
+ #
118
+ # Returns nothing.
119
+ def set_rails_defaults
120
+ options['stylesheets'] = File.expand_path('app/assets/stylesheets/sprites')
121
+ options['destination'] = File.expand_path('app/assets/images/sprites')
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,43 @@
1
+ module Spriteful
2
+ # Internal: Data structure to represent the images that are part
3
+ # of a sprite.
4
+ class Image
5
+ # Public: returns the path where the Image lives.
6
+ attr_reader :path
7
+
8
+ # Public: returns the filename of the Image.
9
+ attr_reader :name
10
+
11
+ # Public: returns the Image width in pixels.
12
+ attr_reader :width
13
+
14
+ # Public: returns the Image height in pixels.
15
+ attr_reader :height
16
+
17
+ # Public: Gets/sets the top position of the image in a sprite.
18
+ attr_accessor :top
19
+
20
+ # Public: Gets/sets the left position of the image in a sprite.
21
+ attr_accessor :left
22
+
23
+ # Public: Gets the source 'ChunkyPNG::Image'.
24
+ attr_reader :source
25
+
26
+ # Public: Initializes an Image, extracting the image
27
+ # metadata such as width and path supplied by an 'ChunkyPNG::Image'
28
+ # object that was initialized from the real image blob.
29
+ #
30
+ # chunky_image - an 'ChunkyPNG::Image' object.
31
+ # path - the path where the image is present.
32
+ def initialize(chunky_image, path)
33
+ @source = chunky_image
34
+ @path = path
35
+ @name = File.basename(@path)
36
+ @width = chunky_image.width
37
+ @height = chunky_image.height
38
+
39
+ @top = 0
40
+ @left = 0
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,135 @@
1
+ require 'chunky_png'
2
+
3
+ module Spriteful
4
+ # Public: the 'Sprite' class is responsible for combining a directory
5
+ # of images into a single one, and providing the required information
6
+ # about the related images.
7
+ class Sprite
8
+ # Public: returns the path where the sprite will be saved.
9
+ attr_reader :path
10
+
11
+ # Public: Gets the name of the sprite.
12
+ attr_reader :name
13
+
14
+ # Public: Gets the filename of the sprite.
15
+ attr_reader :filename
16
+
17
+ # Public: Gets the the spacing between the images in the sprite.
18
+ attr_reader :spacing
19
+
20
+ # Public: Gets the the binary contents of the combined image.
21
+ attr_reader :blob
22
+
23
+ # Public: Gets the the width of the combined image.
24
+ attr_reader :width
25
+
26
+ # Public: Gets the the height of the combined image.
27
+ attr_reader :height
28
+
29
+ # Public: Gets the flag to check if the sprite is vertical or not.
30
+ attr_reader :vertical
31
+ alias :vertical? :vertical
32
+
33
+ # Public: Initialize a Sprite.
34
+ #
35
+ # source_dir - the source directory where the sprite images are located.
36
+ # destination - the destination directory where the sprite should be saved.
37
+ # options - additional Hash of options.
38
+ # :horizontal - flag to turn the sprite into the horizontal
39
+ # orientation.
40
+ # :spacing - spacing in pixels that should be placed between
41
+ # the images in the sprite. Defaults to 0.
42
+ def initialize(source_dir, destination, options = {})
43
+ source_pattern = File.join(source_dir, '*.png')
44
+ sources = Dir[source_pattern].sort
45
+
46
+ if sources.size == 0
47
+ raise EmptySourceError, "No image sources found at '#{source_dir}'."
48
+ end
49
+
50
+ @vertical = !options[:horizontal]
51
+ @spacing = options[:spacing] || 0
52
+
53
+ @name = File.basename(source_dir)
54
+ @filename = "#{name}.png"
55
+ @path = File.expand_path(File.join(destination, @filename))
56
+ sources = sources.map { |source| [source, ChunkyPNG::Image.from_file(source)] }
57
+ @images = initialize_images(Hash[sources])
58
+
59
+ @height, @width = detect_dimensions
60
+ end
61
+
62
+ # Public: combines the source images into a single one,
63
+ # storing the combined image into the sprite path.
64
+ #
65
+ # Returns nothing.
66
+ def combine!
67
+ combined = ChunkyPNG::Image.new(width, height, ChunkyPNG::Color::TRANSPARENT)
68
+ @images.each do |image|
69
+ combined.compose!(image.source, image.left.abs, image.top.abs)
70
+ end
71
+ @blob = combined.to_blob(:best_compression)
72
+ end
73
+
74
+ # Public: exposes the source images found in the 'source'
75
+ # directory.
76
+ #
77
+ # Yields an 'Image' object on each interation.
78
+ #
79
+ # Returns an 'Enumerator' if no block is given.
80
+ def each_image
81
+ return to_enum(__method__) unless block_given?
82
+ @images.each { |image| yield image }
83
+ end
84
+
85
+ alias :images :each_image
86
+
87
+ private
88
+ # Internal: detect the expected 'height' and 'width' of the
89
+ # combined image of this sprite. This should take in account
90
+ # the sprite orientation and the configured spacing.
91
+ #
92
+ # Returns an Array with the 'height' and 'width'.
93
+ def detect_dimensions
94
+ total_spacing = (@images.size - 1) * spacing
95
+
96
+ if vertical?
97
+ height = @images.map { |image| image.height }.inject(:+) + total_spacing
98
+ width = @images.map { |image| image.width }.max
99
+ else
100
+ height = @images.map { |image| image.height }.max
101
+ width = @images.map { |image| image.width }.inject(:+) + total_spacing
102
+ end
103
+
104
+ [height, width]
105
+ end
106
+
107
+ # Internal: Initializes a collection of 'Image' objects
108
+ # based on the 'source' images. The images will have
109
+ # the source images metadata and the required 'top' and
110
+ # 'left' coordinates that the image will be placed
111
+ # in the sprite.
112
+ #
113
+ # sources - a Hash of source paths and image objects.
114
+ #
115
+ # Returns an Array.
116
+ def initialize_images(sources)
117
+ sprite_position = 0
118
+ images = []
119
+ sources.each_with_index do |(path, chunky_image), index|
120
+ image = Image.new(chunky_image, path)
121
+ padding = index * spacing
122
+
123
+ if vertical?
124
+ image.top = sprite_position
125
+ sprite_position -= image.height + padding
126
+ else
127
+ image.left = sprite_position
128
+ sprite_position -= image.width + padding
129
+ end
130
+ images << image
131
+ end
132
+ images
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,109 @@
1
+ require 'pathname'
2
+ require 'erb'
3
+
4
+ module Spriteful
5
+ # Public: class responsible for putting together the CSS code
6
+ # to use a specific sprite.
7
+ class Stylesheet
8
+ # Public: returns the format used to render the Stylesheet.
9
+ attr_reader :format
10
+
11
+ # Public: returns the 'Sprite' of this Stylesheet.
12
+ attr_reader :sprite
13
+
14
+ # Public: returns the path where the Stylesheet should be stored.
15
+ attr_reader :path
16
+
17
+ # Public: Initialize a Stylesheet
18
+ #
19
+ # sprite - a 'Sprite' object to create the Stylesheet.
20
+ # destination - the directory where the Stylesheet will be created.
21
+ # options - additional Hash of options.
22
+ # :format - the Stylesheet format.
23
+ # :rails - A flag to generate Asset Pipeline compatible Stylesheets.
24
+ def initialize(sprite, destination, options = {})
25
+ @sprite = sprite
26
+ @destination = Pathname.new(destination)
27
+ @root = nil
28
+ if options[:root]
29
+ @root = Pathname.new(File.expand_path(options[:root]))
30
+ end
31
+ @format = options[:format]
32
+ @rails = options.fetch(:rails) { false }
33
+
34
+ @path = @destination.join(name)
35
+ end
36
+
37
+ # Public: renders the CSS code for this Stylesheet.
38
+ # An ERB template will be used to process the code, based
39
+ # on the stylesheet format.
40
+ #
41
+ # Returns the CSS code as a 'String'.
42
+ def render
43
+ source = File.expand_path("../stylesheets/template.#{format}.erb", __FILE__)
44
+ ERB.new(File.read(source), nil, '-').result(binding)
45
+ end
46
+
47
+ # Public: returns this Stylesheet name, based
48
+ # on the Sprite name and the current format.
49
+ #
50
+ # Returns a String.
51
+ def name
52
+ extension = rails? ? rails_extension : format
53
+ "#{sprite_name}.#{extension}"
54
+ end
55
+
56
+ protected
57
+
58
+ # Internal: returns the 'rails ' flag.
59
+ def rails?
60
+ @rails
61
+ end
62
+
63
+ # Internal: defines the file extension to be used with
64
+ # Rails applications, since we need to account for the ERB
65
+ # preprocessing of plain CSS files.
66
+ #
67
+ # Returns a String.
68
+ def rails_extension
69
+ case format
70
+ when 'css'
71
+ 'css.erb'
72
+ when 'scss'
73
+ 'scss'
74
+ end
75
+ end
76
+
77
+ def sprite_name
78
+ case format
79
+ when 'css'
80
+ sprite.name
81
+ when 'scss'
82
+ "_#{sprite.name}"
83
+ end
84
+ end
85
+
86
+ # Internal: sanitizes the 'name' of a given object to
87
+ # be used as a CSS selector class.
88
+ #
89
+ # Returns a 'String'.
90
+ def class_name_for(object)
91
+ object.name.split('.').first.downcase.tr('_', '-')
92
+ end
93
+
94
+ # Internal: computes a relative path between the sprite
95
+ # path and the stylesheet expected location.
96
+ #
97
+ # Returns a 'String'.
98
+ def image_url(sprite)
99
+ path = Pathname.new(sprite.path)
100
+ if @rails
101
+ "sprites/#{sprite.filename}"
102
+ elsif @root
103
+ "/#{path.relative_path_from(@root)}"
104
+ else
105
+ path.relative_path_from(@destination)
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,21 @@
1
+ /*
2
+ * This Stylesheet was generated by the 'spriteful' gem.
3
+ * Below there are several CSS classes to use the '<%= sprite.name %>'
4
+ * sprite on you HTML code, as in:
5
+ *
6
+ * <div class='<%= class_name_for(sprite) %> <%= class_name_for(sprite.images.first) %>'>Your markup here.</div>
7
+ */
8
+
9
+ .<%= class_name_for(sprite) %> {
10
+ <% if rails? -%>
11
+ background-image: url(<%%= image_url('<%= image_url(sprite) %>') %>);
12
+ <% else -%>
13
+ background-image: url(<%= image_url(sprite) %>);
14
+ <% end -%>
15
+ background-repeat: no-repeat;
16
+ }
17
+ <% sprite.each_image do |image| %>
18
+ .<%= class_name_for(sprite) %>.<%= class_name_for(image) %> {
19
+ background-position: <%= image.left %>px <%= image.top %>px;
20
+ }
21
+ <% end %>
@@ -0,0 +1,25 @@
1
+ // ============================================================================
2
+ // This Stylesheet was generated by the 'spriteful' gem.
3
+ // Below there are several [Placeholder Selectors]
4
+ // (http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#placeholder_selectors_)
5
+ // to use the '<%= sprite.name %>' sprite on your SCSS code, as in:
6
+ //
7
+ // .my-thing {
8
+ // @extend %<%= class_name_for(sprite) %>-sprite-<%= class_name_for(sprite.images.first) %>;
9
+ // // Your styles here.
10
+ // }
11
+
12
+ %<%= class_name_for(sprite) %>-sprite {
13
+ <%- if rails? -%>
14
+ background-image: image-url('<%= image_url(sprite) %>');
15
+ <%- else -%>
16
+ background-image: url(<%= image_url(sprite) %>);
17
+ <%- end -%>
18
+ background-repeat: no-repeat;
19
+ }
20
+ <% sprite.each_image do |image| %>
21
+ %<%= class_name_for(sprite) %>-sprite-<%= class_name_for(image) %> {
22
+ @extend %<%= class_name_for(sprite) %>-sprite;
23
+ background-position: <%= image.left %>px <%= image.top %>px;
24
+ }
25
+ <% end %>
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spriteful::Image do
4
+ let(:path) { 'path/to/image.png' }
5
+ let(:chunky_image) { double('ChunkyPNG Image', width: 10, height: 5) }
6
+ subject(:image) { Spriteful::Image.new(chunky_image, path) }
7
+
8
+ it { expect(image.name).to eq('image.png') }
9
+ it { expect(image.path).to eq('path/to/image.png') }
10
+ it { expect(image.width).to eq(10) }
11
+ it { expect(image.height).to eq(5) }
12
+ it { expect(image.source).to eq(chunky_image) }
13
+ end
@@ -0,0 +1,9 @@
1
+ require 'spriteful'
2
+
3
+ RSpec.configure do |config|
4
+ config.treat_symbols_as_metadata_keys_with_true_values = true
5
+ config.run_all_when_everything_filtered = true
6
+ config.filter_run :focus
7
+
8
+ config.order = 'random'
9
+ end
@@ -0,0 +1,95 @@
1
+ require 'fileutils'
2
+ require 'spec_helper'
3
+
4
+ describe Spriteful::Sprite do
5
+ let(:source) { File.expand_path('spec/fixtures/simple') }
6
+ let(:destination) { File.expand_path('tmp') }
7
+
8
+ before { FileUtils.rm(Dir["#{destination}/*.png"]) }
9
+
10
+ describe 'initialization' do
11
+ it 'raises an error if the source directory is empty' do
12
+ source = File.expand_path('spec/fixtures/missing')
13
+ expect {
14
+ Spriteful::Sprite.new(source, destination)
15
+ }.to raise_error(Spriteful::EmptySourceError)
16
+ end
17
+ end
18
+
19
+ describe '#width' do
20
+ it 'returns the whole sprite width' do
21
+ sprite = Spriteful::Sprite.new(source, destination)
22
+ expect(sprite.width).to be(10)
23
+ end
24
+
25
+ it 'accounts for the padding information' do
26
+ sprite = Spriteful::Sprite.new(source, destination, spacing: 10, horizontal: true)
27
+ expect(sprite.width).to be(30)
28
+ end
29
+ end
30
+
31
+ describe '#height' do
32
+ it 'returns the whole sprite height' do
33
+ sprite = Spriteful::Sprite.new(source, destination)
34
+ expect(sprite.height).to be(20)
35
+ end
36
+
37
+ it 'accounts for the spacing information' do
38
+ sprite = Spriteful::Sprite.new(source, destination, spacing: 10)
39
+ expect(sprite.height).to be(30)
40
+ end
41
+ end
42
+
43
+ describe '#path' do
44
+ it 'returns the path where the combined image will be saved' do
45
+ sprite = Spriteful::Sprite.new(source, destination)
46
+ expect(sprite.path).to eq(File.expand_path('tmp/simple.png'))
47
+ end
48
+ end
49
+
50
+ describe '#filename' do
51
+ it 'returns the filename of the sprite combined image' do
52
+ sprite = Spriteful::Sprite.new(source, destination)
53
+ expect(sprite.filename).to eq('simple.png')
54
+ end
55
+ end
56
+
57
+ describe '#combine!' do
58
+ it 'sets the sprite blob' do
59
+ sprite = Spriteful::Sprite.new(source, destination)
60
+ sprite.combine!
61
+ expect(sprite.blob).to be
62
+ end
63
+
64
+ it 'combine images vertically by default' do
65
+ sprite = Spriteful::Sprite.new(source, destination)
66
+ sprite.combine!
67
+ image = ChunkyPNG::Image.from_blob(sprite.blob)
68
+ expect(image.width).to be(10)
69
+ expect(image.height).to be(20)
70
+ end
71
+
72
+ it 'can combine images horizontally' do
73
+ sprite = Spriteful::Sprite.new(source, destination, horizontal: true)
74
+ sprite.combine!
75
+ image = ChunkyPNG::Image.from_blob(sprite.blob)
76
+ expect(image.width).to be(20)
77
+ expect(image.height).to be(10)
78
+ end
79
+ end
80
+
81
+ describe '#images' do
82
+ it 'yields an object for each image found in the source directory' do
83
+ sprite = Spriteful::Sprite.new(source, destination)
84
+ blue, red = sprite.images.to_a
85
+
86
+ expect(blue.name).to eq('blue.png')
87
+ expect(blue.top).to eq(0)
88
+ expect(blue.left).to eq(0)
89
+
90
+ expect(red.name).to eq('red.png')
91
+ expect(red.top).to eq(-10)
92
+ expect(red.left).to eq(0)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Spriteful::Stylesheet do
4
+ let(:source) { File.expand_path('spec/fixtures/simple') }
5
+ let(:destination) { File.expand_path('tmp') }
6
+ let(:sprite) { Spriteful::Sprite.new(source, destination) }
7
+
8
+ describe '#render' do
9
+ it 'renders the CSS for the given sprite' do
10
+ stylesheet = Spriteful::Stylesheet.new(sprite, destination, format: 'css')
11
+ output = stylesheet.render
12
+
13
+ expect(output).to match(/.simple \{/)
14
+ expect(output).to match(/.simple.blue \{/)
15
+ expect(output).to match(/.simple.red \{/)
16
+ end
17
+
18
+ it 'renders the SCSS format' do
19
+ sprite = Spriteful::Sprite.new(source, destination)
20
+ stylesheet = Spriteful::Stylesheet.new(sprite, destination, format: 'scss')
21
+ output = stylesheet.render
22
+
23
+ expect(output).to match(/%simple-sprite \{/)
24
+ expect(output).to match(/%simple-sprite-blue \{/)
25
+ expect(output).to match(/%simple-sprite-red \{/)
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spriteful
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Lucas Mazza
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.18.1
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: '2.0'
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.18.1
33
+ - - <
34
+ - !ruby/object:Gem::Version
35
+ version: '2.0'
36
+ - !ruby/object:Gem::Dependency
37
+ name: chunky_png
38
+ requirement: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.8
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ~>
50
+ - !ruby/object:Gem::Version
51
+ version: 1.2.8
52
+ - !ruby/object:Gem::Dependency
53
+ name: rspec
54
+ requirement: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ version: 2.14.0
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: 2.14.0
68
+ - !ruby/object:Gem::Dependency
69
+ name: bundler
70
+ requirement: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.3'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: '1.3'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rake
86
+ requirement: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ none: false
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ description: A sprite generation tool
101
+ email:
102
+ - lucastmazza@gmail.com
103
+ executables:
104
+ - spriteful
105
+ extensions: []
106
+ extra_rdoc_files: []
107
+ files:
108
+ - LICENSE
109
+ - README.md
110
+ - lib/spriteful/cli.rb
111
+ - lib/spriteful/image.rb
112
+ - lib/spriteful/sprite.rb
113
+ - lib/spriteful/stylesheet.rb
114
+ - lib/spriteful/stylesheets/template.css.erb
115
+ - lib/spriteful/stylesheets/template.scss.erb
116
+ - lib/spriteful.rb
117
+ - spec/fixtures/simple/blue.png
118
+ - spec/fixtures/simple/red.png
119
+ - spec/image_spec.rb
120
+ - spec/spec_helper.rb
121
+ - spec/sprite_spec.rb
122
+ - spec/stylesheet_spec.rb
123
+ - bin/spriteful
124
+ homepage: https://github.com/lucasmazza/spriteful
125
+ licenses:
126
+ - Apache 2.0
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project:
145
+ rubygems_version: 1.8.23
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: ''
149
+ test_files:
150
+ - spec/fixtures/simple/blue.png
151
+ - spec/fixtures/simple/red.png
152
+ - spec/image_spec.rb
153
+ - spec/spec_helper.rb
154
+ - spec/sprite_spec.rb
155
+ - spec/stylesheet_spec.rb