public
Rubygem
Description: Rails Plugin - a Ruby way to manage your stylesheets and javascripts. Don't put all your assets in your layout; define what you need where you need them.
Homepage: http://6brand.com
Clone URL: git://github.com/JackDanger/sweet_assets.git
studioda (author)
Fri Feb 15 08:23:15 -0800 2008
commit  e1232281357a247916d2848176c073e0baece93c
tree    0e018546ca00cca87521067382bc6ab45e986349
parent  2b569a2bfc503bb99e841ef3f106dfcb45014997
sweet_assets / lib / sweet_assets.rb
100644 158 lines (133 sloc) 5.424 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
require 'cgi'
require 'action_view/helpers/url_helper'
require 'action_view/helpers/tag_helper'
 
module SweetAssets
  PRIMARY_JAVASCRIPTS = [:prototype, :scriptaculous, :builder, :effects, :dragdrop, :controls, :slider, :sound, :application]
 
  class << self
 
    attr_accessor :use_primary_javascripts
 
    def included(base)
      base.class_eval do
        include AssignmentMethods
        include ClassMethods
        extend SweetAssetsShortcuts
        include AppendAssetsAfterRescue
        before_filter :initialize_assets_accessor
        before_filter :apply_default_styles
        before_filter :apply_default_scripts
        after_filter :apply_sweet_assets
      end
    end
  end
 
 
  module SweetAssetsShortcuts
    def style_like(*assets)
      options = assets.extract_options!
      before_filter Proc.new {|controller| controller.style_like *assets }, options
    end
 
    def script_like(*assets)
      options = assets.extract_options!
      before_filter Proc.new {|controller| controller.script_like *assets }, options
    end
  end
  
  module AssignmentMethods
    def style_like(*styles)
      styles.each do |style|
        style = style.to_s
        sweet_assets[:stylesheets][style.ends_with?('!') ? :bottom : :top] << style.gsub(/!$/, '')
      end
    end
    
    def script_like(*scripts)
      scripts.each do |script|
        script = script.to_s
        if 'defaults' == script
          SweetAssets.use_primary_javascripts = true
        else
          sweet_assets[:javascripts][script.ends_with?('!') ? :bottom : :top] << script.gsub(/!$/, '')
        end
      end
    end
    
    def sweet_assets
      self.is_a?(ActionView::Base) ?
        controller.instance_variable_get("@sweet_assets") :
        @sweet_assets
    end
  end
  
  module ClassMethods
    
    def method_missing_with_sweet_assets(method_name, *args, &block)
      
      if match = method_name.to_s.match(/^(style_like|script_like)_(\w+!?)$/)
        send match[1], match[2]
      else
        method_missing_without_sweet_assets(method_name, *args, &block)
      end
    end
    alias_method_chain :method_missing, :sweet_assets
    
    def initialize_assets_accessor
      @sweet_assets = { :javascripts => {:top => [], :bottom => []},
                        :stylesheets => {:top => [], :bottom => []} }
    end
    
    def apply_default_styles
      style_like :application
      style_like "#{controller_name}!"
    end
 
    def apply_default_scripts
      # we don't apply application.js by default because Rails already knows how to do that.
      script_like "#{controller_name}!"
    end
 
    def apply_sweet_assets
      return true unless @sweet_assets.any? {|asset_type, assets| assets.any? {|placement, files| !files.blank? } }
      generator = SweetAssetsGenerator.new(@sweet_assets, self)
      response.body.gsub! '<head>', "<head>\n#{generator.tags(:top)}\n" if response.body.respond_to?(:gsub!)
      response.body.gsub! '</head>', "\n#{generator.tags(:bottom)}\n</head>" if response.body.respond_to?(:gsub!)
      SweetAssets.use_primary_javascripts = false
      @sweet_assets = {}
    end
    
    class SweetAssetsGenerator
      
      include ActionView::Helpers::TagHelper
      include ActionView::Helpers::AssetTagHelper
 
      def initialize(assets, controller)
        @assets = assets
        @controller = controller
      end
      
      def tags(placement)
        javascript_tags(placement) + "\n" + stylesheet_tags(placement)
      end
 
      def stylesheet_tags(placement)
        files = @assets[:stylesheets][placement].dup
        files.uniq!
        files.map! {|file| file =~ /\.css$/ ? file : "#{file}.css" }
        files = files.select {|file| File.exists?("#{STYLESHEETS_DIR}/#{file}") } unless RAILS_ENV.eql?('test')
        return '' if files.blank?
        files << {:cache => "sweet_stylesheets_#{files.join(',')}" } if ActionController::Base.perform_caching
        stylesheet_link_tag *files
      end
 
      def javascript_tags(placement)
        files = @assets[:javascripts][placement].dup
        if SweetAssets.use_primary_javascripts
          files = SweetAssets::PRIMARY_JAVASCRIPTS + files
        end
        files.uniq!
        files.map! {|file| file =~ /\.js$/ ? file : "#{file}.js" }
        files = files.select {|file| File.exists?("#{JAVASCRIPTS_DIR}/#{file}") } unless RAILS_ENV.eql?('test')
        return '' if files.blank?
        files << {:cache => "sweet_javascripts_#{files.join(',')}" } if ActionController::Base.perform_caching
        javascript_include_tag *files
      end
    end
  end
 
  # we're going to wrap our rescue_action around the top-level rescue_action method chain
  # this ensures that we can apply the stylesheets even if the after filter was aborted due to an exception
  module AppendAssetsAfterRescue
    def self.included(base)
      base.class_eval do
        def initialize_with_append_sweet_assets_rescue_action(*args)
          initialize_without_append_sweet_assets_rescue_action(*args)
          self.class.send :alias_method_chain, :rescue_action, :append_sweet_assets unless respond_to?(:rescue_action_without_append_sweet_assets)
        end
        alias_method_chain :initialize, :append_sweet_assets_rescue_action
      end
    end
    
    def rescue_action_with_append_sweet_assets(*args)
      rescue_action_without_append_sweet_assets(*args)
      apply_sweet_assets
    end
  end
end