processing.rb 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. require 'sprockets/engines'
  2. require 'sprockets/mime'
  3. require 'sprockets/processor'
  4. require 'sprockets/utils'
  5. module Sprockets
  6. # `Processing` is an internal mixin whose public methods are exposed on
  7. # the `Environment` and `Index` classes.
  8. module Processing
  9. include Engines, Mime
  10. # Register a new mime type.
  11. def register_mime_type(mime_type, ext)
  12. # Overrides the global behavior to expire the index
  13. expire_index!
  14. @trail.append_extension(ext)
  15. super
  16. end
  17. # Returns an `Array` of format extension `String`s.
  18. #
  19. # format_extensions
  20. # # => ['.js', '.css']
  21. #
  22. def format_extensions
  23. @trail.extensions - @engines.keys
  24. end
  25. # Registers a new Engine `klass` for `ext`.
  26. def register_engine(ext, klass)
  27. # Overrides the global behavior to expire the index
  28. expire_index!
  29. add_engine_to_trail(ext, klass)
  30. super
  31. end
  32. # Deprecated alias for `preprocessors`.
  33. def processors(*args)
  34. preprocessors(*args)
  35. end
  36. # Returns an `Array` of `Processor` classes. If a `mime_type`
  37. # argument is supplied, the processors registered under that
  38. # extension will be returned.
  39. #
  40. # Preprocessors are ran before Postprocessors and Engine
  41. # processors.
  42. #
  43. # All `Processor`s must follow the `Tilt::Template` interface. It is
  44. # recommended to subclass `Tilt::Template`.
  45. def preprocessors(mime_type = nil)
  46. if mime_type
  47. @preprocessors[mime_type].dup
  48. else
  49. deep_copy_hash(@preprocessors)
  50. end
  51. end
  52. # Returns an `Array` of `Processor` classes. If a `mime_type`
  53. # argument is supplied, the processors registered under that
  54. # extension will be returned.
  55. #
  56. # Postprocessors are ran after Preprocessors and Engine processors.
  57. #
  58. # All `Processor`s must follow the `Tilt::Template` interface. It is
  59. # recommended to subclass `Tilt::Template`.
  60. def postprocessors(mime_type = nil)
  61. if mime_type
  62. @postprocessors[mime_type].dup
  63. else
  64. deep_copy_hash(@postprocessors)
  65. end
  66. end
  67. # Deprecated alias for `register_preprocessor`.
  68. def register_processor(*args, &block)
  69. register_preprocessor(*args, &block)
  70. end
  71. # Registers a new Preprocessor `klass` for `mime_type`.
  72. #
  73. # register_preprocessor 'text/css', Sprockets::DirectiveProcessor
  74. #
  75. # A block can be passed for to create a shorthand processor.
  76. #
  77. # register_preprocessor :my_processor do |context, data|
  78. # data.gsub(...)
  79. # end
  80. #
  81. def register_preprocessor(mime_type, klass, &block)
  82. expire_index!
  83. if block_given?
  84. name = klass.to_s
  85. klass = Class.new(Processor) do
  86. @name = name
  87. @processor = block
  88. end
  89. end
  90. @preprocessors[mime_type].push(klass)
  91. end
  92. # Registers a new Postprocessor `klass` for `mime_type`.
  93. #
  94. # register_postprocessor 'text/css', Sprockets::CharsetNormalizer
  95. #
  96. # A block can be passed for to create a shorthand processor.
  97. #
  98. # register_postprocessor :my_processor do |context, data|
  99. # data.gsub(...)
  100. # end
  101. #
  102. def register_postprocessor(mime_type, klass, &block)
  103. expire_index!
  104. if block_given?
  105. name = klass.to_s
  106. klass = Class.new(Processor) do
  107. @name = name
  108. @processor = block
  109. end
  110. end
  111. @postprocessors[mime_type].push(klass)
  112. end
  113. # Deprecated alias for `unregister_preprocessor`.
  114. def unregister_processor(*args)
  115. unregister_preprocessor(*args)
  116. end
  117. # Remove Preprocessor `klass` for `mime_type`.
  118. #
  119. # unregister_preprocessor 'text/css', Sprockets::DirectiveProcessor
  120. #
  121. def unregister_preprocessor(mime_type, klass)
  122. expire_index!
  123. if klass.is_a?(String) || klass.is_a?(Symbol)
  124. klass = @preprocessors[mime_type].detect { |cls|
  125. cls.respond_to?(:name) &&
  126. cls.name == "Sprockets::Processor (#{klass})"
  127. }
  128. end
  129. @preprocessors[mime_type].delete(klass)
  130. end
  131. # Remove Postprocessor `klass` for `mime_type`.
  132. #
  133. # unregister_postprocessor 'text/css', Sprockets::DirectiveProcessor
  134. #
  135. def unregister_postprocessor(mime_type, klass)
  136. expire_index!
  137. if klass.is_a?(String) || klass.is_a?(Symbol)
  138. klass = @postprocessors[mime_type].detect { |cls|
  139. cls.respond_to?(:name) &&
  140. cls.name == "Sprockets::Processor (#{klass})"
  141. }
  142. end
  143. @postprocessors[mime_type].delete(klass)
  144. end
  145. # Returns an `Array` of `Processor` classes. If a `mime_type`
  146. # argument is supplied, the processors registered under that
  147. # extension will be returned.
  148. #
  149. # Bundle Processors are ran on concatenated assets rather than
  150. # individual files.
  151. #
  152. # All `Processor`s must follow the `Tilt::Template` interface. It is
  153. # recommended to subclass `Tilt::Template`.
  154. def bundle_processors(mime_type = nil)
  155. if mime_type
  156. @bundle_processors[mime_type].dup
  157. else
  158. deep_copy_hash(@bundle_processors)
  159. end
  160. end
  161. # Registers a new Bundle Processor `klass` for `mime_type`.
  162. #
  163. # register_bundle_processor 'text/css', Sprockets::CharsetNormalizer
  164. #
  165. # A block can be passed for to create a shorthand processor.
  166. #
  167. # register_bundle_processor :my_processor do |context, data|
  168. # data.gsub(...)
  169. # end
  170. #
  171. def register_bundle_processor(mime_type, klass, &block)
  172. expire_index!
  173. if block_given?
  174. name = klass.to_s
  175. klass = Class.new(Processor) do
  176. @name = name
  177. @processor = block
  178. end
  179. end
  180. @bundle_processors[mime_type].push(klass)
  181. end
  182. # Remove Bundle Processor `klass` for `mime_type`.
  183. #
  184. # unregister_bundle_processor 'text/css', Sprockets::CharsetNormalizer
  185. #
  186. def unregister_bundle_processor(mime_type, klass)
  187. expire_index!
  188. if klass.is_a?(String) || klass.is_a?(Symbol)
  189. klass = @bundle_processors[mime_type].detect { |cls|
  190. cls.respond_to?(:name) &&
  191. cls.name == "Sprockets::Processor (#{klass})"
  192. }
  193. end
  194. @bundle_processors[mime_type].delete(klass)
  195. end
  196. # Return CSS compressor or nil if none is set
  197. def css_compressor
  198. bundle_processors('text/css').detect { |klass|
  199. klass.respond_to?(:name) &&
  200. klass.name == 'Sprockets::Processor (css_compressor)'
  201. }
  202. end
  203. # Assign a compressor to run on `text/css` assets.
  204. #
  205. # The compressor object must respond to `compress` or `compile`.
  206. def css_compressor=(compressor)
  207. expire_index!
  208. unregister_bundle_processor 'text/css', :css_compressor
  209. return unless compressor
  210. register_bundle_processor 'text/css', :css_compressor do |context, data|
  211. compressor.compress(data)
  212. end
  213. end
  214. # Return JS compressor or nil if none is set
  215. def js_compressor
  216. bundle_processors('application/javascript').detect { |klass|
  217. klass.respond_to?(:name) &&
  218. klass.name == 'Sprockets::Processor (js_compressor)'
  219. }
  220. end
  221. # Assign a compressor to run on `application/javascript` assets.
  222. #
  223. # The compressor object must respond to `compress` or `compile`.
  224. def js_compressor=(compressor)
  225. expire_index!
  226. unregister_bundle_processor 'application/javascript', :js_compressor
  227. return unless compressor
  228. register_bundle_processor 'application/javascript', :js_compressor do |context, data|
  229. compressor.compress(data)
  230. end
  231. end
  232. private
  233. def add_engine_to_trail(ext, klass)
  234. @trail.append_extension(ext.to_s)
  235. if klass.respond_to?(:default_mime_type) && klass.default_mime_type
  236. if format_ext = extension_for_mime_type(klass.default_mime_type)
  237. @trail.alias_extension(ext.to_s, format_ext)
  238. end
  239. end
  240. end
  241. end
  242. end