Class: Slinky::Manifest

Inherits:
Object
  • Object
show all
Defined in:
lib/slinky/manifest.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir, config, options = {}) ⇒ Manifest

Returns a new instance of Manifest.



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/slinky/manifest.rb', line 29

def initialize dir, config, options = {}
  @dir = dir
  @build_to = if d = options[:build_to]
                File.expand_path(d)
              else
                dir
              end
  @manifest_dir = ManifestDir.new dir, self, @build_to, self
  @devel = (options[:devel].nil?) ? true : options[:devel]
  @config = config
  @no_minify = options[:no_minify] || config.dont_minify
end

Instance Attribute Details

#dirObject

Returns the value of attribute dir.



27
28
29
# File 'lib/slinky/manifest.rb', line 27

def dir
  @dir
end

#manifest_dirObject

Returns the value of attribute manifest_dir.



27
28
29
# File 'lib/slinky/manifest.rb', line 27

def manifest_dir
  @manifest_dir
end

Instance Method Details

#add_all_by_path(paths) ⇒ Object

Adds a file to the manifest, updating the dependency graph



58
59
60
61
62
63
# File 'lib/slinky/manifest.rb', line 58

def add_all_by_path paths
  manifest_update paths do |path|
    md = find_by_path(File.dirname(path)).first
    mf = md.add_file(File.basename(path))
  end
end

#buildObject



200
201
202
203
204
205
206
# File 'lib/slinky/manifest.rb', line 200

def build
  @manifest_dir.build
  unless @devel
    compress_scripts
    compress_styles
  end
end

#build_dependency_graph[ManifestFile, ManifestFile]

Builds the directed graph representing the dependencies of all files in the manifest that contain a slinky_require declaration. The graph is represented as a list of pairs (required, by), each of which describes an edge.

Returns:



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/slinky/manifest.rb', line 152

def build_dependency_graph
  graph = []
  files(false).each{|mf|
    mf.directives[:slinky_require].each{|rf|
      required = mf.parent.find_by_path(rf, true)
      if required.size > 0
        required.each{|x|
          graph << [x, mf]
        }
      else
        error = "Could not find file #{rf} required by #{mf.source}"
        $stderr.puts error.foreground(:red)
        raise FileNotFoundError.new(error)
      end
    } if mf.directives[:slinky_require]
  }
  @dependency_graph = graph
end

#compress(ext, output, compressor) ⇒ Object



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/slinky/manifest.rb', line 100

def compress ext, output, compressor
  scripts = dependency_list.reject{|x| x.output_path.extname != ext}

  if scripts.size > 0
    s = scripts.collect{|s|
      f = File.open(s.build_to.to_s, 'rb'){|f| f.read}
      (block_given?) ? (yield s, f) : f
    }.join("\n")

    File.open(output, "w+"){|f|
      unless @no_minify
        f.write(compressor.compress(s))
      else
        f.write(s)
      end
    }
    scripts.collect{|s| FileUtils.rm(s.build_to)}
  end
end

#compress_scriptsObject



120
121
122
123
# File 'lib/slinky/manifest.rb', line 120

def compress_scripts
  compressor = YUI::JavaScriptCompressor.new(:munge => false)
  compress(".js", "#{@build_to}/scripts.js", compressor)
end

#compress_stylesObject



125
126
127
128
129
130
131
132
133
134
# File 'lib/slinky/manifest.rb', line 125

def compress_styles
  compressor = YUI::CssCompressor.new()

  compress(".css", "#{@build_to}/styles.css", compressor){|s, css|
    css.gsub(CSS_URL_MATCHER){|url|
      p = s.relative_output_path.dirname.to_s + "/#{$1}"
      "url('/#{p}')"
    }
  }
end

#dependency_listObject

Builds a list of files in topological order, so that when required in this order all dependencies are met. See en.wikipedia.org/wiki/Topological_sorting for more information.



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/slinky/manifest.rb', line 175

def dependency_list
  build_dependency_graph unless @dependency_graph
  graph = @dependency_graph.clone
  # will contain sorted elements
  l = []
  # start nodes, those with no incoming edges
  s = files(false).reject{|mf| mf.directives[:slinky_require]}
  while s.size > 0
    n = s.delete s.first
    l << n
    files(false).each{|m|
      e = graph.find{|e| e[0] == n && e[1] == m}
      next unless e
      graph.delete e
      s << m unless graph.any?{|e| e[1] == m}
    }
  end
  if graph != []
    problems = graph.collect{|e| e.collect{|x| x.source}.join(" -> ")}
    $stderr.puts "Dependencies #{problems.join(", ")} could not be satisfied".foreground(:red)
    raise DependencyError
  end
  l
end

#files(include_ignores = true) ⇒ ManifestFile

Returns a list of all files contained in this manifest

Returns:



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/slinky/manifest.rb', line 45

def files include_ignores = true
  unless @files
    @files = []
    files_rec @manifest_dir
  end
  if include_ignores
    @files
  else
    @files.reject{|f| @config.ignore.any?{|p| f.in_tree? p}}
  end
end

#find_by_path(path, allow_multiple = false) ⇒ Object

Finds the file at the given path in the manifest if one exists, otherwise nil.

Parameters:

  • String

    path the path of the file relative to the manifest

Returns:

  • ManifestFile the manifest file at that path if one exists



86
87
88
# File 'lib/slinky/manifest.rb', line 86

def find_by_path path, allow_multiple = false
  @manifest_dir.find_by_path path, allow_multiple
end

#md5Object

Returns a md5 encompassing the current state of the manifest. Any change to the manifest should produce a different hash. This can be used to determine if the manifest has changed.



211
212
213
214
215
216
217
218
# File 'lib/slinky/manifest.rb', line 211

def md5
  if @md5
    @md5
  else
    @md5 = Digest::MD5.hexdigest(files.map{|f| [f.source, f.md5]}
                                  .sort.flatten.join(":"))
  end
end

#remove_all_by_path(paths) ⇒ Object

Removes a file from the manifest



71
72
73
74
75
76
77
78
# File 'lib/slinky/manifest.rb', line 71

def remove_all_by_path paths
  manifest_update paths do |path|
    mf = find_by_path(path).first()
    if mf
      mf.parent.remove_file(mf)
    end
  end
end

#scripts_stringObject



90
91
92
93
94
95
96
97
98
# File 'lib/slinky/manifest.rb', line 90

def scripts_string
  if @devel
    dependency_list.reject{|x| x.output_path.extname != ".js" }.collect{|d|
      %Q\<script type="text/javascript" src="/#{d.relative_output_path}"></script>\
    }.join("\n")
  else
    %Q\<script type="text/javascript" src="/scripts.js?#{rand(999999999)}"></script>\
  end
end

#styles_stringObject



136
137
138
139
140
141
142
143
144
# File 'lib/slinky/manifest.rb', line 136

def styles_string
  if @devel
    dependency_list.reject{|x| x.output_path.extname != ".css"}.collect{|d|
      %Q\<link rel="stylesheet" href="/#{d.relative_output_path}" />\
    }.join("\n")
  else
    %Q\<link rel="stylesheet" href="/styles.css?#{rand(999999999)}" />\
  end
end

#update_all_by_path(paths) ⇒ Object

Notifies of an update to a file in the manifest



66
67
68
# File 'lib/slinky/manifest.rb', line 66

def update_all_by_path paths
  manifest_update paths
end