spritely 0.3.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/spritely.rb +11 -34
- data/lib/spritely/collection.rb +12 -11
- data/lib/spritely/engine.rb +4 -0
- data/lib/spritely/generators/base.rb +0 -16
- data/lib/spritely/generators/chunky_png.rb +1 -4
- data/lib/spritely/image_set.rb +2 -2
- data/lib/spritely/sass_functions.rb +30 -29
- data/lib/spritely/sprite_map.rb +14 -31
- data/lib/spritely/sprockets/preprocessor.rb +65 -0
- data/lib/spritely/sprockets/transformer.rb +43 -0
- data/lib/spritely/version.rb +1 -1
- data/spec/fixtures/rails-app-changes/app/assets/stylesheets/sprites.css.scss +10 -18
- data/spec/fixtures/rails-app/app/assets/images/sprites/application.png.sprite +5 -0
- data/spec/fixtures/rails-app/app/assets/images/sprites/foo.png.sprite +1 -0
- data/spec/fixtures/rails-app/app/assets/stylesheets/sprites.css.scss +6 -14
- data/spec/fixtures/rails-app/app/assets/stylesheets/sprites_2.css.scss +4 -6
- data/spec/integration/precompilation_spec.rb +2 -14
- data/spec/spec_helper.rb +0 -4
- data/spec/spritely/collection_spec.rb +9 -8
- data/spec/spritely/generators/chunky_png_spec.rb +8 -13
- data/spec/spritely/image_set_spec.rb +2 -8
- data/spec/spritely/sass_functions_spec.rb +38 -37
- data/spec/spritely/sprite_map_spec.rb +16 -52
- data/spec/spritely/sprockets/preprocessor_spec.rb +33 -0
- data/spec/support/rails_app_helpers.rb +4 -5
- metadata +38 -49
- data/lib/generators/spritely/install_generator.rb +0 -17
- data/lib/spritely/adapters/sprockets_2.rb +0 -13
- data/lib/spritely/adapters/sprockets_3.rb +0 -11
- data/lib/spritely/cache.rb +0 -51
- data/lib/spritely/options.rb +0 -59
- data/lib/spritely/sprockets/manifest.rb +0 -20
- data/spec/generators/spritely/install_generator_spec.rb +0 -28
- data/spec/spritely/cache_spec.rb +0 -24
- data/spec/spritely/options_spec.rb +0 -29
- data/spec/spritely_spec.rb +0 -41
- data/spec/support/shared_examples.rb +0 -40
- data/spec/support/shared_examples/sprockets_2_sass_functions_helpers.rb +0 -13
- data/spec/support/shared_examples/sprockets_3_sass_functions_helpers.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1afa4634c2ebe161a2557ad31168f308f4fd4de
|
4
|
+
data.tar.gz: 176498f2a2579987e8c8ac4c12cc960e1ceba4b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95d85bb25e1761b8223f6fc2bc2aeb50a9e3c8f7cb91e15842b5f767d7b8545fe330dfdec6f39b9919107d82b83ccae1eee973863f15a47dbad28f74aae8d78a
|
7
|
+
data.tar.gz: 6709371eaedb1db506fa2ab023f197e978e477f0017a1100e3f2337663b64c86c32e39250109cd3b91fedfce315259dd060b14c045202051f6245fc3cf70ecc5
|
data/lib/spritely.rb
CHANGED
@@ -1,38 +1,15 @@
|
|
1
|
-
require '
|
2
|
-
require 'sprockets/rails/version'
|
3
|
-
require 'sprockets/railtie'
|
4
|
-
require 'sprockets/version'
|
1
|
+
require 'sprockets'
|
5
2
|
require 'spritely/sass_functions'
|
6
|
-
require 'spritely/sprockets/
|
7
|
-
require 'spritely/
|
8
|
-
require 'spritely/adapters/sprockets_3'
|
3
|
+
require 'spritely/sprockets/preprocessor'
|
4
|
+
require 'spritely/sprockets/transformer'
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
::Rails.application.assets || ::Sprockets::Railtie.build_environment(::Rails.application)
|
14
|
-
else
|
15
|
-
::Rails.application.assets
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.directory
|
20
|
-
::Rails.root.join(relative_folder_path)
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.relative_folder_path
|
24
|
-
Pathname.new(File.join('app', 'assets', 'images', 'sprites'))
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.sprockets_version
|
28
|
-
Gem::Version.new(::Sprockets::VERSION).segments.first
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.sprockets_rails_version
|
32
|
-
Gem::Version.new(::Sprockets::Rails::VERSION).segments.first
|
33
|
-
end
|
6
|
+
if defined?(::Rails::Engine)
|
7
|
+
require 'spritely/engine'
|
8
|
+
end
|
34
9
|
|
35
|
-
|
36
|
-
Adapters.const_get("Sprockets#{sprockets_version}").new
|
37
|
-
end
|
10
|
+
module Spritely
|
38
11
|
end
|
12
|
+
|
13
|
+
::Sprockets.register_mime_type 'text/sprite', extensions: ['.png.sprite']
|
14
|
+
::Sprockets.register_preprocessor 'text/sprite', Spritely::Sprockets::Preprocessor.new(comments: ["//", ["/*", "*/"]])
|
15
|
+
::Sprockets.register_transformer 'text/sprite', 'image/png', Spritely::Sprockets::Transformer
|
data/lib/spritely/collection.rb
CHANGED
@@ -21,6 +21,7 @@ module Spritely
|
|
21
21
|
def cache_key
|
22
22
|
files.collect { |file| Digest::MD5.file(file) }.join
|
23
23
|
end
|
24
|
+
alias_method :to_s, :cache_key
|
24
25
|
|
25
26
|
# Returns the width of the to-be-generated sprite image. When none of the
|
26
27
|
# images repeat, it is simply the max width of all images in the sprite.
|
@@ -29,17 +30,13 @@ module Spritely
|
|
29
30
|
# multiple is then multiplied by the minimum multiple that will result in a
|
30
31
|
# value greater than or equal to the max width of all images in the sprite.
|
31
32
|
def width
|
32
|
-
|
33
|
-
|
34
|
-
max_width = image_sets.collect(&:width).max
|
35
|
-
if image_sets.none?(&:repeated?)
|
36
|
-
@width = max_width
|
33
|
+
@width ||= if image_sets.none?(&:repeated?)
|
34
|
+
max_width
|
37
35
|
else
|
38
|
-
|
39
|
-
@width += lcm while @width < max_width
|
40
|
-
end
|
36
|
+
lcm = image_sets.select(&:repeated?).collect(&:width).reduce(:lcm)
|
41
37
|
|
42
|
-
|
38
|
+
lcm * (max_width / lcm.to_f).ceil
|
39
|
+
end
|
43
40
|
end
|
44
41
|
|
45
42
|
def height
|
@@ -58,11 +55,15 @@ module Spritely
|
|
58
55
|
private
|
59
56
|
|
60
57
|
def image_sets
|
61
|
-
@image_sets ||= files.collect { |file| ImageSet.new(file, options[File.basename(file, ".png")]) }
|
58
|
+
@image_sets ||= files.collect { |file| ImageSet.new(file, options[:images][File.basename(file, ".png")] || options[:global]) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def max_width
|
62
|
+
@max_width ||= image_sets.collect(&:width).max
|
62
63
|
end
|
63
64
|
|
64
65
|
def heights
|
65
|
-
image_sets.collect(&:outer_height)
|
66
|
+
@heights ||= image_sets.collect(&:outer_height)
|
66
67
|
end
|
67
68
|
end
|
68
69
|
end
|
@@ -1,25 +1,9 @@
|
|
1
1
|
module Spritely
|
2
2
|
module Generators
|
3
3
|
class Base < Struct.new(:sprite_map)
|
4
|
-
def self.create!(sprite_map)
|
5
|
-
new(sprite_map).tap do |generator|
|
6
|
-
generator.build!
|
7
|
-
generator.ensure_directory_exists!
|
8
|
-
generator.save!
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def ensure_directory_exists!
|
13
|
-
raise("'#{Spritely.relative_folder_path}' doesn't exist. Run `rails generate spritely:install`.") unless File.exist?(Spritely.directory)
|
14
|
-
end
|
15
|
-
|
16
4
|
def build!
|
17
5
|
raise NotImplementedError, "#{self.class} must implement #build!"
|
18
6
|
end
|
19
|
-
|
20
|
-
def save!
|
21
|
-
raise NotImplementedError, "#{self.class} must implement #save!"
|
22
|
-
end
|
23
7
|
end
|
24
8
|
end
|
25
9
|
end
|
@@ -9,11 +9,8 @@ module Spritely
|
|
9
9
|
png = ::ChunkyPNG::Image.from_blob(image.data)
|
10
10
|
canvas.replace!(png, image.left, image.top)
|
11
11
|
end
|
12
|
-
end
|
13
12
|
|
14
|
-
|
15
|
-
canvas.metadata['cache_key'] = sprite_map.cache_key
|
16
|
-
canvas.save(sprite_map.filename, :fast_rgba)
|
13
|
+
canvas.to_blob(:fast_rgba)
|
17
14
|
end
|
18
15
|
|
19
16
|
private
|
data/lib/spritely/image_set.rb
CHANGED
@@ -1,28 +1,17 @@
|
|
1
|
-
require '
|
1
|
+
require 'sass'
|
2
2
|
|
3
3
|
module Spritely
|
4
4
|
module SassFunctions
|
5
|
-
def
|
6
|
-
|
7
|
-
Spritely.sprockets_adapter.reset_cache!(sprockets_environment, sprite_map.filename)
|
8
|
-
sprockets_context.depend_on(Spritely.directory)
|
9
|
-
sprite_map.files.each do |file|
|
10
|
-
sprockets_context.depend_on(file)
|
11
|
-
sprockets_context.depend_on_asset(file)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
::Sass::Script::Functions.declare :spritely_map, [:glob], var_kwargs: true
|
5
|
+
def spritely_url(sprite_name)
|
6
|
+
sprockets_context.link_asset("sprites/#{sprite_name.value}.png")
|
17
7
|
|
18
|
-
|
19
|
-
asset_url(Sass::Script::String.new("sprites/#{sprite_map.name}.png"))
|
8
|
+
asset_url(Sass::Script::String.new("sprites/#{sprite_name.value}.png"))
|
20
9
|
end
|
21
10
|
|
22
|
-
::Sass::Script::Functions.declare :spritely_url, [:
|
11
|
+
::Sass::Script::Functions.declare :spritely_url, [:sprite_name]
|
23
12
|
|
24
|
-
def spritely_position(
|
25
|
-
image = find_image(
|
13
|
+
def spritely_position(sprite_name, image_name)
|
14
|
+
image = find_image(sprite_name, image_name)
|
26
15
|
|
27
16
|
x = Sass::Script::Number.new(-image.left, image.left == 0 ? [] : ['px'])
|
28
17
|
y = Sass::Script::Number.new(-image.top, image.top == 0 ? [] : ['px'])
|
@@ -30,35 +19,47 @@ module Spritely
|
|
30
19
|
Sass::Script::List.new([x, y], :space)
|
31
20
|
end
|
32
21
|
|
33
|
-
::Sass::Script::Functions.declare :spritely_position, [:
|
22
|
+
::Sass::Script::Functions.declare :spritely_position, [:sprite_name, :image_name]
|
34
23
|
|
35
|
-
def spritely_background(
|
36
|
-
Sass::Script::List.new([spritely_url(
|
24
|
+
def spritely_background(sprite_name, image_name)
|
25
|
+
Sass::Script::List.new([spritely_url(sprite_name), spritely_position(sprite_name, image_name)], :space)
|
37
26
|
end
|
38
27
|
|
39
|
-
::Sass::Script::Functions.declare :spritely_background, [:
|
28
|
+
::Sass::Script::Functions.declare :spritely_background, [:sprite_name, :image_name]
|
40
29
|
|
41
|
-
def spritely_width(
|
42
|
-
image = find_image(
|
30
|
+
def spritely_width(sprite_name, image_name)
|
31
|
+
image = find_image(sprite_name, image_name)
|
43
32
|
|
44
33
|
Sass::Script::Number.new(image.width, ['px'])
|
45
34
|
end
|
46
35
|
|
47
|
-
::Sass::Script::Functions.declare :spritely_width, [:
|
36
|
+
::Sass::Script::Functions.declare :spritely_width, [:sprite_name, :image_name]
|
48
37
|
|
49
|
-
def spritely_height(
|
50
|
-
image = find_image(
|
38
|
+
def spritely_height(sprite_name, image_name)
|
39
|
+
image = find_image(sprite_name, image_name)
|
51
40
|
|
52
41
|
Sass::Script::Number.new(image.height, ['px'])
|
53
42
|
end
|
54
43
|
|
55
|
-
::Sass::Script::Functions.declare :spritely_height, [:
|
44
|
+
::Sass::Script::Functions.declare :spritely_height, [:sprite_name, :image_name]
|
56
45
|
|
57
46
|
private
|
58
47
|
|
59
|
-
def find_image(
|
48
|
+
def find_image(sprite_name, image_name)
|
49
|
+
sprockets_context.link_asset("sprites/#{sprite_name.value}.png")
|
50
|
+
|
51
|
+
sprite_map = sprite_maps.fetch(sprite_name.value) do |name|
|
52
|
+
asset = sprockets_environment.find_asset("sprites/#{name}.png.sprite") || raise(Sass::SyntaxError, "No sprite map '#{name}' found.")
|
53
|
+
|
54
|
+
sprite_maps[name] = SpriteMap.new(name, sprockets_environment, asset.metadata[:sprite_directives])
|
55
|
+
end
|
56
|
+
|
60
57
|
sprite_map.find(image_name.value) || raise(Sass::SyntaxError, "No image '#{image_name.value}' found in sprite map '#{sprite_map.name}'.")
|
61
58
|
end
|
59
|
+
|
60
|
+
def sprite_maps
|
61
|
+
@sprite_maps ||= {}
|
62
|
+
end
|
62
63
|
end
|
63
64
|
end
|
64
65
|
|
data/lib/spritely/sprite_map.rb
CHANGED
@@ -1,58 +1,41 @@
|
|
1
1
|
require 'forwardable'
|
2
|
-
require '
|
3
|
-
require 'spritely/cache'
|
2
|
+
require 'digest/md5'
|
4
3
|
require 'spritely/collection'
|
5
4
|
require 'spritely/generators/chunky_png'
|
6
5
|
|
7
6
|
module Spritely
|
8
|
-
class SpriteMap
|
7
|
+
class SpriteMap
|
9
8
|
extend Forwardable
|
10
9
|
|
11
10
|
def_delegators :collection, :find, :width, :height, :images
|
12
11
|
|
13
|
-
attr_reader :glob, :options
|
12
|
+
attr_reader :name, :glob, :environment, :options
|
14
13
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
def initialize(name, environment, options)
|
15
|
+
@name = name
|
16
|
+
@glob = [name, "*.png"].join("/")
|
17
|
+
@environment = environment
|
18
|
+
@options = options
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
23
|
-
@options = Options.new(options)
|
21
|
+
def inspect
|
22
|
+
"#<Spritely::SpriteMap name=#{name} options=#{options}>"
|
24
23
|
end
|
25
24
|
|
26
25
|
def cache_key
|
27
|
-
@cache_key ||=
|
28
|
-
end
|
29
|
-
|
30
|
-
def inspect
|
31
|
-
"#<Spritely::SpriteMap name=#{name} options=#{options}>"
|
26
|
+
@cache_key ||= Digest::MD5.hexdigest([options, collection].join)
|
32
27
|
end
|
33
28
|
|
34
29
|
def collection
|
35
30
|
@collection ||= Collection.create(files, options)
|
36
31
|
end
|
37
32
|
|
38
|
-
def
|
39
|
-
Generators::ChunkyPng.
|
40
|
-
end
|
41
|
-
|
42
|
-
def name
|
43
|
-
glob.split('/')[0..-2].join('-')
|
44
|
-
end
|
45
|
-
|
46
|
-
def filename
|
47
|
-
Spritely.directory.join("#{name}.png")
|
48
|
-
end
|
49
|
-
|
50
|
-
def needs_generation?
|
51
|
-
!File.exist?(filename) || Cache.busted?(filename, cache_key)
|
33
|
+
def save!
|
34
|
+
Generators::ChunkyPng.new(self).build!
|
52
35
|
end
|
53
36
|
|
54
37
|
def files
|
55
|
-
|
38
|
+
environment.paths.flat_map { |path| Dir.glob(File.join(path, glob)) }.sort
|
56
39
|
end
|
57
40
|
end
|
58
41
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'sprockets/directive_processor'
|
2
|
+
|
3
|
+
module Spritely
|
4
|
+
module Sprockets
|
5
|
+
# Converts Sprockets directives from this:
|
6
|
+
#
|
7
|
+
# //= repeat arrow true
|
8
|
+
# //= spacing arrow 10
|
9
|
+
# //= position another-image right
|
10
|
+
# //= spacing 5
|
11
|
+
#
|
12
|
+
# To this:
|
13
|
+
#
|
14
|
+
# {
|
15
|
+
# global: { spacing: 5 },
|
16
|
+
# images: {
|
17
|
+
# 'arrow' => { repeat: 'true', spacing: '10' },
|
18
|
+
# 'another-image' => { position: 'right', spacing: '5' }
|
19
|
+
# }
|
20
|
+
# }
|
21
|
+
class Preprocessor < ::Sprockets::DirectiveProcessor
|
22
|
+
GLOBAL_DIRECTIVES = %w(position spacing).freeze
|
23
|
+
IMAGE_DIRECTIVES = %w(repeat position spacing).freeze
|
24
|
+
|
25
|
+
def _call(input)
|
26
|
+
@sprite_directives = { global: {}, images: {} }
|
27
|
+
|
28
|
+
super.tap do
|
29
|
+
merge_global_options!
|
30
|
+
|
31
|
+
input[:metadata][:sprite_directives] = @sprite_directives
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
(GLOBAL_DIRECTIVES + IMAGE_DIRECTIVES).uniq.each do |directive|
|
36
|
+
define_method("process_#{directive}_directive") do |image_or_value, value_or_nil = nil|
|
37
|
+
if value_or_nil
|
38
|
+
process_image_option(directive, image_or_value, value_or_nil)
|
39
|
+
else
|
40
|
+
process_global_option(directive, image_or_value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def process_image_option(directive, image, value)
|
48
|
+
@sprite_directives[:images][image] ||= {}
|
49
|
+
@sprite_directives[:images][image][directive.to_sym] = value
|
50
|
+
end
|
51
|
+
|
52
|
+
def process_global_option(directive, value)
|
53
|
+
raise ArgumentError, "'#{directive}' is not a valid global option" unless GLOBAL_DIRECTIVES.include?(directive)
|
54
|
+
|
55
|
+
@sprite_directives[:global][directive.to_sym] = value
|
56
|
+
end
|
57
|
+
|
58
|
+
def merge_global_options!
|
59
|
+
@sprite_directives[:images].each do |image, options|
|
60
|
+
options.merge!(@sprite_directives[:global]) { |key, left, right| left }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spritely/version'
|
2
|
+
require 'spritely/sprite_map'
|
3
|
+
|
4
|
+
module Spritely
|
5
|
+
module Sprockets
|
6
|
+
class Transformer < Struct.new(:input)
|
7
|
+
def self.call(input)
|
8
|
+
new(input).call
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.cache_key
|
12
|
+
@cache_key ||= "#{name}:#{Spritely::VERSION}".freeze
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
data = cache.fetch([self.class.cache_key, input[:name], sprite_map.cache_key]) do
|
17
|
+
sprite_map.files.each do |file|
|
18
|
+
context.depend_on(File.dirname(file))
|
19
|
+
context.link_asset(file)
|
20
|
+
end
|
21
|
+
|
22
|
+
sprite_map.save!
|
23
|
+
end
|
24
|
+
|
25
|
+
context.metadata.merge(data: data)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def context
|
31
|
+
@context ||= input[:environment].context_class.new(input)
|
32
|
+
end
|
33
|
+
|
34
|
+
def cache
|
35
|
+
@cache ||= input[:cache]
|
36
|
+
end
|
37
|
+
|
38
|
+
def sprite_map
|
39
|
+
@sprite_map ||= SpriteMap.new(input[:name].remove("sprites/"), input[:environment], input[:metadata][:sprite_directives])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|