active_assets 0.1.0 → 0.2.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/.gitignore +4 -0
  2. data/README.md +168 -0
  3. data/Rakefile +6 -0
  4. data/active_assets.gemspec +11 -6
  5. data/config.ru +2 -0
  6. data/lib/active_assets.rb +1 -0
  7. data/lib/active_assets/active_expansions/railtie.rb +10 -9
  8. data/lib/active_assets/active_sprites.rb +13 -0
  9. data/lib/active_assets/active_sprites/railtie.rb +29 -0
  10. data/lib/active_assets/active_sprites/runner.rb +101 -0
  11. data/lib/active_assets/active_sprites/sprite.rb +89 -0
  12. data/lib/active_assets/active_sprites/sprite_piece.rb +63 -0
  13. data/lib/active_assets/active_sprites/sprite_stylesheet.rb +24 -0
  14. data/lib/active_assets/active_sprites/sprites.rb +51 -0
  15. data/lib/active_assets/railtie.rb +2 -0
  16. data/lib/rails/active_assets.rb +4 -5
  17. data/lib/rails/active_expansions.rb +11 -0
  18. data/lib/rails/active_sprites.rb +11 -0
  19. data/lib/tasks/{cache.rake → active_expansions/cache.rake} +0 -0
  20. data/lib/tasks/active_sprites/sprites.rake +4 -0
  21. data/script/console +1 -0
  22. data/script/server +1 -0
  23. data/script/test_server +1 -0
  24. data/test/active_assets/active_expansions/asset_test.rb +18 -1
  25. data/test/active_assets/active_expansions/expansions_test.rb +16 -2
  26. data/test/active_assets/active_sprites/runner_test.rb +43 -0
  27. data/test/active_assets/active_sprites/sprite_piece_test.rb +65 -0
  28. data/test/active_assets/active_sprites/sprite_test.rb +53 -0
  29. data/test/active_assets/active_sprites/sprites_test.rb +35 -0
  30. data/test/fixtures/rails_root/config/application.rb +1 -0
  31. data/test/fixtures/rails_root/config/environment.rb +2 -0
  32. data/test/fixtures/rails_root/config/sprites.rb +14 -0
  33. data/test/fixtures/rails_root/public/images/sprite_images/sprite3/1.gif +0 -0
  34. data/test/fixtures/rails_root/public/images/sprite_images/sprite3/2.gif +0 -0
  35. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Argentina.gif +0 -0
  36. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Australia.gif +0 -0
  37. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Austria.gif +0 -0
  38. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Belgium.gif +0 -0
  39. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Brazil.gif +0 -0
  40. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Cameroon.gif +0 -0
  41. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Canada.gif +0 -0
  42. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Chile.gif +0 -0
  43. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/China.gif +0 -0
  44. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Denmark.gif +0 -0
  45. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Finland.gif +0 -0
  46. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/France.gif +0 -0
  47. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Germany.gif +0 -0
  48. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Greece.gif +0 -0
  49. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Hong Kong.gif +0 -0
  50. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Hungary.gif +0 -0
  51. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Iceland.gif +0 -0
  52. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/India.gif +0 -0
  53. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Indonesia.gif +0 -0
  54. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Ireland.gif +0 -0
  55. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Israel.gif +0 -0
  56. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Italy.gif +0 -0
  57. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Japan.gif +0 -0
  58. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Malaysia.gif +0 -0
  59. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Mexico.gif +0 -0
  60. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/New Zealand.gif +0 -0
  61. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Norway.gif +0 -0
  62. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Pakistan.gif +0 -0
  63. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Palestine.gif +0 -0
  64. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Peru.gif +0 -0
  65. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Poland.gif +0 -0
  66. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Portugal.gif +0 -0
  67. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Puerto Rico.gif +0 -0
  68. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Romania.gif +0 -0
  69. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Russia.gif +0 -0
  70. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Saudi Arabia.gif +0 -0
  71. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Singapore.gif +0 -0
  72. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/South Africa.gif +0 -0
  73. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/South Korea.gif +0 -0
  74. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Spain.gif +0 -0
  75. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Sweden.gif +0 -0
  76. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Switzerland.gif +0 -0
  77. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Thailand.gif +0 -0
  78. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/The Netherlands.gif +0 -0
  79. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Turkey.gif +0 -0
  80. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/UK.gif +0 -0
  81. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/USA.gif +0 -0
  82. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Ukraine.gif +0 -0
  83. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Uruguay.gif +0 -0
  84. data/test/fixtures/rails_root/public/images/sprite_images/sprite4/Venezuela.gif +0 -0
  85. data/test/fixtures/sinatra_root/active_assets_test_app.rb +12 -0
  86. data/test/fixtures/sinatra_root/views/layout.erb +7 -0
  87. data/test/fixtures/sinatra_root/views/sprite.erb +3 -0
  88. data/test/helper.rb +50 -0
  89. data/test/support/rails_helper.rb +10 -1
  90. data/vendor/bin/ng +0 -0
  91. data/vendor/bin/ng.exe +0 -0
  92. data/vendor/jruby-complete-1.5.6.jar +0 -0
  93. metadata +230 -21
data/.gitignore CHANGED
@@ -1,9 +1,13 @@
1
+ .DS_Store
1
2
  .rvmrc
2
3
  pkg/*
3
4
  *.gem
4
5
  .bundle
5
6
  Gemfile.lock
7
+ doc
6
8
 
7
9
  test/fixtures/rails_root/log
8
10
  test/fixtures/rails_root/public/stylesheets/cache
9
11
  test/fixtures/rails_root/public/javascripts/cache
12
+ test/fixtures/rails_root/public/stylesheets/sprites
13
+ test/fixtures/rails_root/public/images/sprites
data/README.md ADDED
@@ -0,0 +1,168 @@
1
+ Active Assets
2
+ =============
3
+
4
+ A Railtie that provides a full asset management system, including support for development and deployment. This includes building sprites, concatenating javascript and css via expansion definitions. Active Assets includes two libraries, Active Expansions and Active Sprites.
5
+
6
+ gem install active_assets
7
+
8
+ Gemfile
9
+ -------
10
+
11
+ gem 'active_assets', '~>0.2.0.rc'
12
+
13
+ In your rails app
14
+ -----------------
15
+ ### application.rb
16
+
17
+ ...
18
+ require 'rails/all'
19
+ require 'active_assets/railtie'
20
+ ...
21
+
22
+ ## The dsls
23
+ ### Introduction to Active Expansions
24
+
25
+ ActiveExpansions allow you to register Rails javascript and stylesheet expansions via a simple dsl. Addionally, the assets in the expansion are concatenated when appropriate and the expansion delivers the concatenated (or 'cached') assets' path in the appropriate environments. Also, files can be specified as deploy only or only for a specific environment. For example, you may wish to include jQuery or Prototype src files in development and use minified libraries from cdn sources in production. This is supported.
26
+
27
+ * Below demonstration shows several variations on how to declare expansions. Note that these declaration are redundant to demonstrate how to accomplish the same thing in different ways.
28
+ * Alternatively you can also register your assets in multiple files. Simply omit `config/asets.rb` and add as many .rb files as you like inside a directory `config/assets`
29
+ * Note the `register` is optional `Rails.application.expansions do` will work the same way
30
+
31
+ #### config/assets.rb
32
+
33
+ Rails.application.expansions.register do
34
+ expansion :global, :type => :js do
35
+ `vendor/jquery`
36
+ `application`
37
+ end
38
+
39
+ expansion :global, :type => :css do
40
+ `vendor/reset`
41
+ `application`
42
+ end
43
+
44
+ expansion :global do
45
+ `vendor/jquery.js`
46
+ `application.js`
47
+ `vendor/reset.css`
48
+ `application.css`
49
+ end
50
+
51
+ js do
52
+ expansion :global do
53
+ `vendor/jquery`
54
+ `application`
55
+ end
56
+ end
57
+
58
+ css do
59
+ expansion :global do
60
+ `vendor/reset`
61
+ `application`
62
+ end
63
+ end
64
+
65
+ expansion :global do
66
+ js do
67
+ `vendor/jquery`
68
+ `application`
69
+ end
70
+
71
+ css do
72
+ `vendor/reset`
73
+ `application`
74
+ end
75
+ end
76
+ end
77
+
78
+ #### config/assets/js.rb (suggestion only)
79
+ Rails.application.expansions.js do
80
+ expansion :global do
81
+ `vendor/jquery`
82
+ `application`
83
+ end
84
+ end
85
+
86
+ #### config/assets/css.rb (suggestion only)
87
+ Rails.application.expansions.css do
88
+ expansion :global do
89
+ `vendor/reset`
90
+ `application`
91
+ end
92
+ end
93
+
94
+ ### Introduction to Active Sprites
95
+
96
+ ActiveSprites allows you to generate sprites within your Rails apps with `rake sprites`! All you need is rmagick (in development) and you are on your way. Store the images that make up your sprites in your rails project, use the dsl below to tell ActiveSprites which images to include in your sprites, the css selector the corresponds to each image in the sprite, the location to write the sprite, and the location to write the stylesheet.
97
+
98
+ #### config/sprites.rb
99
+ Rails.application.sprites do
100
+ sprite 'sprites/world_flags.png' => 'sprites/world_flags.css'
101
+ _"sprite_images/world_flags/Argentina.gif" => ".flags.argentina"
102
+ _"sprites_images/world_flags/Australia.gif" => ".flags.australia"
103
+ ...
104
+ end
105
+ end
106
+
107
+ #### To generate
108
+ rake sprites
109
+
110
+ or
111
+
112
+ Rails.application.sprites.generate!
113
+
114
+ ### More on Active Expansions
115
+ You can specify certain assets only be used in a deployment setting or only be used in a production setting. The example below illustrates how to include a library in development and the same library from a cdn in production. The net result will be that the library will not get cached (concatenated) along with all of the other files because it is specified for use only in development and test. Hence, the cache file will only be comprised of the other assets in the expansion. Similarly, the cdn resort will not get cached either but instead will be used directly. The resulting expansion in production will include two paths, the cdn url to jquery and the path the cache file, in this case, public/{javascript,stylesheets}/cache/global.{js,css}.
116
+
117
+ Rails.application.expansions.register do
118
+ expansion :global do
119
+ js do
120
+ asset 'vendor/jquery', :group => [:development, :test]
121
+ asset 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js', :group => :deploy, :cache => false
122
+ `application`
123
+ end
124
+
125
+ css do
126
+ asset 'vendor/reset', :group => [:development, :test]
127
+ asset 'http://ajax.googleapis.com/ajax/libs/yui/2.8.1/build/reset-fonts/reset-fonts.css', :group => :deploy, :cache => false
128
+ `application`
129
+ end
130
+ end
131
+ end
132
+
133
+ back-tick and `a` are aliases for `asset`
134
+
135
+ #### ActiveExpansions configuration and deployment
136
+ By default, ActiveExpansions will not cache your assets even if `ActionController.perform_caching` is enabled. This is because if you are not serving assets from the same server as where your application resides, then you most likely want to cache your assets at deploy time (on the front-end servers). To cache assets manually,
137
+
138
+ Rails.application.expansions.javascripts.cache!
139
+ Rails.application.expansions.stylesheets.cache!
140
+
141
+ To enable your application to cache assets when the application is initialized, i.e. boot time, follow this example,
142
+
143
+ ##### config/environments/production.rb
144
+
145
+ ...
146
+ config.active_expansions.precache_assets = true
147
+ ...
148
+
149
+ ### More on Active Sprites
150
+
151
+ It is possible to add all of the world flags! Haha, see the following example,
152
+
153
+ Rails.application.sprites do
154
+ sprite :world_flags
155
+ Dir[Rails.root.join('public/images/sprite_images/world_flags/*.{png,gif,jpg}')].each do |path|
156
+ image_path = path[%r{^.*/public/images/(.*)$}, 1]
157
+ klass_name = ".flag.#{File.basename(image_path, File.extname(image_path)).split(' ').join('_')}"
158
+
159
+ sp image_path => klass_name
160
+ end
161
+ end
162
+ end
163
+
164
+ `_` and `sp` are aliases for `sprite_piece`
165
+
166
+ Also, you will notice that I gave a symbol for the sprite instead of a mapping. This will assume that you wish to store your sprite at `path/to/your/public/images/sprites/world_flags.png` and you wish to store your stylesheet at `path/to/your/public/stylesheets/sprites/world_flags.css`.
167
+
168
+ Copyright © Sam Woodard 2011. Release under the MIT License.
data/Rakefile CHANGED
@@ -9,4 +9,10 @@ Rake::TestTask.new(:test) do |t|
9
9
  t.verbose = true
10
10
  end
11
11
 
12
+ task :environment do
13
+ load 'test/fixtures/rails_root/config/environment.rb'
14
+ end
15
+
16
+ Dir['lib/tasks/**/*.rake'].each {|f| load f}
17
+
12
18
  task :default => :test
@@ -1,22 +1,27 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  Gem::Specification.new do |s|
3
3
  s.name = "active_assets"
4
- s.version = '0.1.0'
4
+ s.version = '0.2.0.rc'
5
5
  s.platform = Gem::Platform::RUBY
6
6
  s.authors = ["Sam Woodard"]
7
7
  s.email = ["sam@wildfireapp.com"]
8
- s.homepage = ""
8
+ s.homepage = "http://github.com/shwoodard/active_assets"
9
9
  s.summary = %q{A Railtie that provides a full asset management system, including support for development and deployment.}
10
- s.description = %q{A Railtie that provides a full asset management system, including support for development and deployment. Currently it is designed to manage javascripts and stylesheets but will handle image sprites in the future.}
10
+ s.description = %q{A Railtie that provides a full asset management system, including support for development and deployment. It is comprised of two libraries, ActiveSprites and ActiveExpansions. ActiveSprites generates sprites and their corresponding stylesheet from dsl definition. ActiveExpansions manages javascript and css, including concatenation support for deployment, using Rails expansions plus a dsl.}
11
11
 
12
- s.rubyforge_project = "rails-assets"
12
+ s.rubyforge_project = "activeassets"
13
13
 
14
14
  s.files = `git ls-files`.split("\n")
15
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
17
  s.require_paths = ["lib"]
18
18
 
19
- s.add_development_dependency "rails", "3.0.3"
19
+ s.add_runtime_dependency 'rmagick'
20
+
21
+ s.add_development_dependency "sinatra", "~>1.1.2"
22
+ s.add_development_dependency "thin", "~>1.2.7"
23
+ s.add_development_dependency "rails", "~>3.0.3"
20
24
  s.add_development_dependency "test-unit", "> 2.0"
21
- s.add_development_dependency "ZenTest"
25
+ s.add_development_dependency "capybara", "~>0.4.1.1"
26
+ s.add_development_dependency "ZenTest", "~>4.4.2"
22
27
  end
data/config.ru ADDED
@@ -0,0 +1,2 @@
1
+ require 'active_assets_test_app'
2
+ run ActiveAssetsTestApp
data/lib/active_assets.rb CHANGED
@@ -4,4 +4,5 @@ module ActiveAssets
4
4
  extend ActiveSupport::Autoload
5
5
 
6
6
  autoload :ActiveExpansions
7
+ autoload :ActiveSprites
7
8
  end
@@ -1,37 +1,38 @@
1
1
  require "rails"
2
- require "rails/active_assets"
2
+ require "rails/active_expansions"
3
3
  require 'active_support/ordered_options'
4
4
 
5
5
  module ActiveAssets
6
6
  module ActiveExpansions
7
7
  class Railtie < Rails::Railtie
8
8
  rake_tasks do
9
- Dir[File.expand_path("../../../tasks/*.rake", __FILE__)].each {|f| load f}
9
+ Dir[File.expand_path("../../../tasks/active_expansions/*.rake", __FILE__)].each {|f| load f}
10
10
  end
11
11
 
12
12
  config.active_expansions = ActiveSupport::OrderedOptions.new
13
13
 
14
- initializer :active_assets_extend_application do
15
- Rails.application.extend(Rails::ActiveAssets)
14
+ initializer 'active_expansion-extend-application' do
15
+ Rails.application.extend(Rails::ActiveExpansions)
16
16
  end
17
17
 
18
- initializer :load_active_assets do
18
+ initializer 'active_expansions-load-definitons' do
19
19
  load_active_assets(Rails.root)
20
20
  Rails.application.railties.engines.each {|e| load_active_assets(e.root) }
21
21
  end
22
22
 
23
- initializer :register_active_assets_expansions do
24
- Rails.application.expansions.javascripts.register! and Rails.application.expansions.stylesheets.register!
23
+ initializer 'active_expansions-register' do
24
+ Rails.application.expansions.javascripts.register!
25
+ Rails.application.expansions.stylesheets.register!
25
26
  end
26
27
 
27
- initializer :set_active_expansion_configs do
28
+ initializer 'active_expansions-set-configs' do
28
29
  options = config.active_expansions
29
30
  ActiveSupport.on_load(:active_expansions) do
30
31
  options.each { |k,v| send("#{k}=", v) }
31
32
  end
32
33
  end
33
34
 
34
- initializer :cache_active_assets do
35
+ initializer 'active_expansions-cache' do
35
36
  if Expansions.precache_assets
36
37
  Rails.application.expansions.javascripts.cache! and Rails.application.expansions.stylesheets.cache!
37
38
  end
@@ -0,0 +1,13 @@
1
+ require 'active_support'
2
+
3
+ module ActiveAssets
4
+ module ActiveSprites
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :SpritePiece
8
+ autoload :Sprite
9
+ autoload :Sprites
10
+ autoload :SpriteStylesheet
11
+ autoload :Runner
12
+ end
13
+ end
@@ -0,0 +1,29 @@
1
+ require 'rails'
2
+ require 'rails/active_sprites'
3
+ require 'active_assets/active_sprites'
4
+
5
+ module ActiveAssets
6
+ module ActiveSprites
7
+ class Railtie < Rails::Railtie
8
+ rake_tasks do
9
+ Dir[File.expand_path("../../../tasks/active_sprites/*.rake", __FILE__)].each {|f| load f}
10
+ end
11
+
12
+ initializer 'active_sprites-extend-application' do
13
+ Rails.application.extend(Rails::ActiveSprites)
14
+ end
15
+
16
+ initializer 'active_sprites-load-definitons' do
17
+ Rails.application.config.paths.config.paths.each {|config_path| load_sprite_definition(config_path) }
18
+ Rails.application.railties.engines.map(&:config).map(&:paths).map(&:config).map(&:paths).each do |config_path|
19
+ load_sprite_definition(config_path)
20
+ end
21
+ end
22
+
23
+ private
24
+ def load_sprite_definition(config_path)
25
+ load File.join(config_path, 'sprites.rb') if File.exists?(File.join(config_path, 'sprites.rb'))
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,101 @@
1
+ require 'rack/mount'
2
+ require 'action_view'
3
+ require 'rmagick'
4
+ require 'fileutils'
5
+
6
+ module ActiveAssets
7
+ module ActiveSprites
8
+ class Runner
9
+ class AssetContext < ActionView::Base
10
+ end
11
+ SpriteDetails = Struct.new(:sprite_path, :x, :y, :width, :height)
12
+
13
+ include Magick
14
+
15
+ DEFAULT_SPRITE = Image.new(0,0).freeze
16
+
17
+ def initialize(sprites)
18
+ @controller = ActionController::Base.new
19
+ @context = AssetContext.new(Rails.application.config.action_controller, {}, @controller)
20
+
21
+ @sprites = if ENV['SPRITE']
22
+ sprites.select do |name, sprite|
23
+ ENV['SPRITE'].split(',').map(&:compact).each do |sp|
24
+ # were going to be very forgiving
25
+ name == sp ||
26
+ name == sp.to_sym ||
27
+ name == ::Rack::Mount::Utils.normalize_path(sp)
28
+ end
29
+ end
30
+ else
31
+ sprites.values
32
+ end
33
+ end
34
+
35
+ def generate!(debug = ENV['DEBUG'])
36
+ @sprites.each do |sprite|
37
+ next if sprite.sprite_pieces.empty?
38
+ sprite_path = sanitize_asset_path(context.image_path(sprite.path))
39
+ p "Sprite Path: #{sprite_path}" if debug
40
+ sprite_stylesheet_path = sanitize_asset_path(context.stylesheet_path(sprite.stylesheet_path))
41
+ p "Sprite Stylesheet Path: #{sprite_stylesheet_path}" if debug
42
+
43
+ orientation = sprite.orientation.to_s
44
+ sprite_pieces = sprite.sprite_pieces
45
+
46
+ begin
47
+ sprite_piece_paths = sprite_pieces.map do |sp|
48
+ File.join(Rails.application.config.paths.public.to_a.first, sanitize_asset_path(context.image_path(sp.path)))
49
+ end
50
+ image_list = ImageList.new(*sprite_piece_paths)
51
+
52
+ offset = 0
53
+
54
+ image_list.each_with_index do |image, i|
55
+ sprite_pieces[i].details = SpriteDetails.new(
56
+ sprite_path,
57
+ orientation == Sprite::Orientation::VERTICAL ? 0 : "#{-offset}px",
58
+ orientation == Sprite::Orientation::VERTICAL ? "#{-offset}px" : 0,
59
+ "#{image.columns}px",
60
+ "#{image.rows}px"
61
+ )
62
+ offset += orientation == Sprite::Orientation::VERTICAL ? image.rows : image.columns
63
+ end
64
+
65
+ @sprite = image_list.montage do
66
+ self.tile = orientation == Sprite::Orientation::VERTICAL ? "1x#{sprite_pieces.size}" : "#{sprite_pieces.size}x1"
67
+ self.geometry = "+0+0"
68
+ self.background_color = 'transparent'
69
+ end
70
+
71
+ stylesheet = SpriteStylesheet.new(sprite_path, sprite_pieces)
72
+ stylesheet.write File.join(Rails.application.config.paths.public.to_a.first, sprite_stylesheet_path)
73
+ write File.join(Rails.application.config.paths.public.to_a.first, sprite_path)
74
+ ensure
75
+ finish
76
+ end
77
+ end
78
+ end
79
+
80
+ private
81
+ def context
82
+ @context
83
+ end
84
+
85
+ def write(path)
86
+ FileUtils.mkdir_p(File.dirname(path))
87
+ @sprite.write("png:#{path}")
88
+ end
89
+
90
+ def finish
91
+ @sprite.destroy! unless @sprite == DEFAULT_SPRITE
92
+ @sprite = DEFAULT_SPRITE
93
+ end
94
+
95
+ def sanitize_asset_path(path)
96
+ path.split('?').first
97
+ end
98
+
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,89 @@
1
+ module ActiveAssets
2
+ module ActiveSprites
3
+ class Sprite
4
+ module Orientation
5
+ VERTICAL = 'vertical'
6
+ HORIZONTAL = 'horizontal'
7
+ end
8
+ REQUIRED_PROPS = [:path, :stylesheet_path, :orientation]
9
+
10
+ class ValidationError < StandardError
11
+ attr_reader :sprite, :missing_fields
12
+ def initialize(sprite, missing_fields, msg = nil)
13
+ @sprite, @missing_fields = sprite, missing_fields
14
+ super(msg || "Your sprite#{", #{sprite.name}," if sprite.name} is invalid. It is missing the following fields: #{missing_fields.join(', ')}")
15
+ end
16
+ end
17
+
18
+ class OrientationInvalid < ValidationError
19
+ def initialize(sprite, orientation)
20
+ super(sprite, [:orientation], "The sprite orientation, #{orientation}, is invalid")
21
+ end
22
+ end
23
+
24
+ attr_reader :path, :stylesheet_path, :name, :orientation
25
+
26
+ def initialize
27
+ # Ordered Hash?
28
+ @sprite_pieces = ActiveSupport::OrderedHash.new do |sprite_pieces, path|
29
+ raise SpritePiece::ValidationError.new(nil, [:path]) if path.blank?
30
+ sprite_pieces[path] = SpritePiece.new
31
+ end
32
+ end
33
+
34
+ def has_sprite_piece_with_path?(path)
35
+ @sprite_pieces.has_key?(path)
36
+ end
37
+
38
+ def [](path)
39
+ return nil unless @sprite_pieces.has_key?(path)
40
+ @sprite_pieces[path]
41
+ end
42
+
43
+ def sprite_pieces
44
+ @sprite_pieces.values
45
+ end
46
+
47
+ def configure(sprite_path, stylesheet_path, options = {}, &blk)
48
+ @path ||= sprite_path
49
+ @name = options.delete(:as) || sprite_path
50
+ @stylesheet_path = stylesheet_path
51
+ @orientation = options[:orientation] || :vertical
52
+ valid!
53
+ instance_eval(&blk) if block_given?
54
+ self
55
+ end
56
+
57
+ def sprite_piece(options, &blk)
58
+ path, css_selector = options.find {|k, v| k.is_a?(String)}
59
+ options.delete(path)
60
+ mapping = SpritePiece::Mapping.new(path, css_selector)
61
+ @sprite_pieces[path].configure(mapping, options, &blk)
62
+ end
63
+ alias_method :sp, :sprite_piece
64
+ alias_method :_, :sprite_piece
65
+
66
+ def validation_error
67
+ missing_fields = REQUIRED_PROPS.reject {|prop| send(prop).present?}
68
+ return OrientationInvalid.new(self, orientation) if orientation && ![:vertical, :horizontal].include?(orientation.to_sym)
69
+ return if missing_fields.empty?
70
+ ValidationError.new(self, missing_fields)
71
+ end
72
+
73
+ def valid?
74
+ !validation_error
75
+ end
76
+
77
+ def valid!
78
+ e = validation_error
79
+ raise e if e
80
+ end
81
+
82
+ private
83
+
84
+ def orientation=(orientation)
85
+ @orientation = orientation
86
+ end
87
+ end
88
+ end
89
+ end