Class: Rack::Bundle

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/bundle.rb

Defined Under Namespace

Classes: CSSBundle, DatabaseStore, FileSystemStore, JSBundle

Constant Summary collapse

SELECTORS =
Struct.new('Selector', :js, :css).new(
  'head script[src$=".js"]:not([src^="http"])',
  'head link[href$=".css"]:not([href^="http"])'
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app, options = {}) {|_self| ... } ⇒ Bundle

Returns a new instance of Bundle.

Yields:

  • (_self)

Yield Parameters:

  • _self (Rack::Bundle)

    the object that the method was called on

Raises:

  • (ArgumentError)


16
17
18
19
20
21
# File 'lib/rack/bundle.rb', line 16

def initialize app, options = {}
  @app, @public_dir = app, options[:public_dir]
  @storage = options[:storage] || FileSystemStore.new(@public_dir)
  yield self if block_given?      
  raise ArgumentError, ":public_dir needs to be a directory" unless ::File.directory?(@public_dir.to_s)
end

Instance Attribute Details

#documentObject

Returns the value of attribute document.



10
11
12
# File 'lib/rack/bundle.rb', line 10

def document
  @document
end

#public_dirObject

Returns the value of attribute public_dir.



10
11
12
# File 'lib/rack/bundle.rb', line 10

def public_dir
  @public_dir
end

#storageObject

Returns the value of attribute storage.



10
11
12
# File 'lib/rack/bundle.rb', line 10

def storage
  @storage
end

Instance Method Details

#call(env) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/rack/bundle.rb', line 23

def call env
  if match = %r(^/rack-bundle-(\w+)).match(env['PATH_INFO'])
    bundle = @storage.find_bundle_by_hash match[1]
    bundle ? respond_with(bundle) : not_found
  else
    status, headers, @response = @app.call(env)
    return [status, headers, @response] unless headers['Content-Type'] =~ /html/
    parse!
    replace_javascripts!
    replace_stylesheets!
    [status, headers, [@document.to_html]]
  end
end

#parse!Object



37
38
39
# File 'lib/rack/bundle.rb', line 37

def parse!
  @document = Nokogiri::HTML(@response.join)
end

#replace_javascripts!Object



41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/rack/bundle.rb', line 41

def replace_javascripts!
  return unless @document.css(SELECTORS.js).count > 1
  bundle = JSBundle.new *scripts
  @storage.add bundle unless @storage.has_bundle? bundle
  bundle_node = @document.create_element 'script',
    :type     => 'text/javascript',
    :src      => bundle_path(bundle),
    :charset  => 'utf-8'
  @document.css(SELECTORS.js).first.before(bundle_node)
  @document.css(SELECTORS.js).slice(1..-1).remove
  @document
end

#replace_stylesheets!Object



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/rack/bundle.rb', line 54

def replace_stylesheets!
  return unless local_css_nodes.count > 1
  styles = local_css_nodes.group_by { |node| node.attribute('media').value rescue nil }
  styles.each do |media, nodes|
    next unless nodes.count > 1
    stylesheets = stylesheet_contents_for nodes
    bundle = CSSBundle.new *stylesheets
    @storage.add bundle unless @storage.has_bundle? bundle
    node = @document.create_element 'link',
      :rel    => 'stylesheet',
      :type   => 'text/css',
      :href   => bundle_path(bundle),
      :media  => media
    nodes.first.before(node)
    nodes.map { |node| node.remove }
  end
  @document
end