html_mockup 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/mockup CHANGED
File without changes
@@ -6,29 +6,32 @@ require 'fileutils'
6
6
  include FileUtils
7
7
 
8
8
  require File.dirname(__FILE__) + "/template"
9
+ require File.dirname(__FILE__) + "/project"
9
10
  require File.dirname(__FILE__) + "/w3c_validator"
10
11
 
11
12
  module HtmlMockup
12
13
  class Cli < Thor
13
14
  desc "serve [directory]","Serve directory as HTML, defaults to current directory"
14
15
  method_options :port => :string, # Defaults to 9000
15
- :partial_path => :string, # Defaults to [directory]/../partials
16
- :validate => :boolean, # Automatically validate all HTML responses @ the w3c
16
+ :html_path => :string, # The document root, defaults to "[directory]/html"
17
+ :partial_path => :string, # Defaults to [directory]/partials
17
18
  :handler => :string # The handler to use (defaults to mongrel)
18
- def serve(path=".")
19
- require File.dirname(__FILE__) + '/server'
19
+ def serve(path=".")
20
+ # Load the project, it should take care of all the paths
21
+ @project = initialize_project(path, options)
20
22
 
21
- @path,@partial_path = template_paths(path,options["partial_path"])
23
+ server = @project.server
22
24
 
23
- server_options = {}
24
- server_options[:Port] = options["port"] || "9000"
25
-
26
- server = Server.new(@path,@partial_path,options,server_options)
27
-
28
- puts "Running HtmlMockup with #{server.handler.inspect} on port #{server_options[:Port]}"
29
- puts " Taking partials from #{@partial_path} (#{HtmlMockup::Template.partial_files(@partial_path).size} found)"
25
+ puts "Running HtmlMockup with #{server.handler.inspect} on port #{server.port}"
26
+ puts banner(@project)
30
27
 
31
- server.run
28
+ server.run!
29
+ end
30
+
31
+ desc "release [directory]", "Create a release for the project"
32
+ def release(path=".")
33
+ project = initialize_project(path, options)
34
+ project.release.run!
32
35
  end
33
36
 
34
37
  desc "validate [directory/file]", "Validates the file or all HTML in directory"
@@ -84,72 +87,35 @@ module HtmlMockup
84
87
  end
85
88
  end
86
89
 
87
- desc "convert [directory]","Inject all partials, into all HTML files within directory"
88
- method_options :partial_path => :string, # Defaults to [directory]/../partials
89
- :filter => :string # What files should be converted defaults to **/*.html
90
- def convert(path=".")
91
- path,partial_path = template_paths(path,options["partial_path"])
92
- filter = options["filter"] || "**/*.html"
93
- puts "Converting #{filter} in #{path}"
94
- puts " Taking partials from #{partial_path} (#{HtmlMockup::Template.partial_files(partial_path).size} found)"
95
-
96
- if path.directory?
97
- Dir.glob("#{path}/#{filter}").each do |file|
98
- puts " Converting file: " + file
99
- HtmlMockup::Template.open(file, :partial_path => partial_path).save
100
- end
101
- else
102
- HtmlMockup::Template.open(path, :partial_path => partial_path).save
103
- end
104
-
105
- end
106
-
107
90
  desc "extract [source_path] [target_path]", "Extract a fully relative html mockup into target_path. It will expand all absolute href's, src's and action's into relative links if they are absolute"
108
- method_options :partial_path => :string, # Defaults to [directory]/../partials
91
+ method_options :partial_path => :string, # Defaults to [directory]/partials
109
92
  :filter => :string # What files should be converted defaults to **/*.html
110
- def extract(source_path=".",target_path="../out")
111
- require 'hpricot'
112
- source_path,target_path = Pathname.new(source_path),Pathname.new(target_path)
113
- source_path,partial_path = template_paths(source_path,options["partial_path"])
114
- filter = options["filter"] || "**/*.html"
115
- raise "Target #{target_path} already exists, please choose a new directory to extract into" if target_path.exist?
116
-
117
- mkdir_p(target_path)
118
- target_path = target_path.realpath
119
-
120
- # Copy source to target first, we'll overwrite the templates later on.
121
- cp_r(source_path.children,target_path)
122
-
123
- Dir.chdir(source_path) do
124
- Dir.glob(filter).each do |file_name|
125
- source = HtmlMockup::Template.open(file_name, :partial_path => partial_path).render
126
- cur_dir = Pathname.new(file_name).dirname
127
- up_to_root = File.join([".."] * (file_name.split("/").size - 1))
128
- doc = Hpricot(source)
129
- %w{src href action}.each do |attribute|
130
- (doc/"*[@#{attribute}]").each do |tag|
131
- next unless tag[attribute] =~ /\A\//
132
- if true_file = resolve_path(cur_dir + up_to_root + tag[attribute].sub(/\A\//,""))
133
- tag[attribute] = true_file.relative_path_from(cur_dir).to_s
134
- else
135
- puts "Could not resolve link #{tag[attribute]} in #{file_name}"
136
- end
137
- end
138
- end
139
-
140
- File.open(target_path + file_name,"w"){|f| f.write(doc.to_original_html) }
141
- end
142
- end
93
+ def extract(source_path=".", target_path="../out")
94
+ project = initialize_project(source_path)
95
+ extractor = HtmlMockup::Extractor.new(project, target_path)
96
+ puts "Extracting mockup"
97
+ puts banner(project)
98
+ extractor.run!
143
99
  end
144
100
 
145
101
  protected
146
102
 
147
- def template_paths(path,partial_path=nil)
148
- path = Pathname.new(path)
149
- partial_path = partial_path && Pathname.new(partial_path) || (path + "../partials/").realpath
150
- [path,partial_path]
103
+ def banner(project)
104
+ puts " Html: \"#{project.html_path}\""
105
+ puts " Partials: \"#{project.partial_path}\" (#{HtmlMockup::Template.partial_files(project.partial_path).size} found)"
151
106
  end
152
107
 
108
+ # TODO: handle options
109
+ def initialize_project(path, options={})
110
+
111
+ if((Pathname.new(path) + "../partials").exist?)
112
+ puts "[ERROR]: Don't use the \"html\" path, use the project base path instead"
113
+ exit(1)
114
+ end
115
+
116
+ Project.new(path)
117
+ end
118
+
153
119
  def w3cvalidate(file)
154
120
  validator = W3CValidator.new(File.read(file))
155
121
  validator.validate!
@@ -160,19 +126,6 @@ module HtmlMockup
160
126
  validator.valid
161
127
  end
162
128
 
163
- def resolve_path(path)
164
- path = Pathname.new(path) unless path.kind_of?(Pathname)
165
- # Append index.html/index.htm/index.rhtml if it's a diretory
166
- if path.directory?
167
- search_files = %w{.html .htm}.map!{|p| path + "index#{p}" }
168
- # If it ends with a slash or does not contain a . and it's not a directory
169
- # try to add .html/.htm/.rhtml to see if that exists.
170
- elsif (path.to_s =~ /\/$/) || (path.to_s =~ /^[^.]+$/)
171
- search_files = [path.to_s + ".html", path.to_s + ".htm"].map!{|p| Pathname.new(p) }
172
- else
173
- search_files = [path]
174
- end
175
- search_files.find{|p| p.exist? }
176
- end
129
+
177
130
  end
178
131
  end
@@ -0,0 +1,100 @@
1
+ require 'hpricot'
2
+
3
+ module HtmlMockup
4
+ class Extractor
5
+
6
+ attr_reader :project, :target_path
7
+
8
+ def initialize(project, target_path)
9
+ @project = project
10
+ @target_path = Pathname.new(target_path)
11
+ end
12
+
13
+ def run!
14
+ target_path = self.target_path
15
+ source_path, partial_path = self.project.html_path, self.project.partial_path
16
+
17
+
18
+ filter = "**/*.html"
19
+ raise ArgumentError, "Target #{target_path} already exists, please choose a new directory to extract into" if target_path.exist?
20
+
21
+ mkdir_p(target_path)
22
+ target_path = target_path.realpath
23
+
24
+ # Copy source to target first, we'll overwrite the templates later on.
25
+ cp_r(source_path.children, target_path)
26
+
27
+ Dir.chdir(source_path) do
28
+ Dir.glob(filter).each do |file_name|
29
+ source = HtmlMockup::Template.open(file_name, :partial_path => partial_path).render
30
+ cur_dir = Pathname.new(file_name).dirname
31
+ up_to_root = File.join([".."] * (file_name.split("/").size - 1))
32
+ doc = Hpricot(source)
33
+ %w{src href action}.each do |attribute|
34
+ (doc/"*[@#{attribute}]").each do |tag|
35
+ converted_url = convert_relative_url_to_absolute_url(tag[attribute], cur_dir, up_to_root)
36
+
37
+ case converted_url
38
+ when String
39
+ tag[attribute] = converted_url
40
+ when nil
41
+ puts "Could not resolve link #{tag[attribute]} in #{file_name}"
42
+ end
43
+ end
44
+ end
45
+
46
+ File.open(target_path + file_name,"w"){|f| f.write(doc.to_original_html) }
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ protected
53
+
54
+ # @return [false, nil, String] False if it can't be converted, nil if it can't be resolved and the converted string if it can be resolved.
55
+ def convert_relative_url_to_absolute_url(url, cur_dir, up_to_root)
56
+ # Skip if the url doesn't start with a / (but not with //)
57
+ return false unless url =~ /\A\/[^\/]/
58
+
59
+ # Strip off anchors
60
+ anchor = nil
61
+ url.gsub!(/(#.+)\Z/) do |r|
62
+ anchor = r
63
+ ""
64
+ end
65
+
66
+ # Strip off query strings
67
+ query = nil
68
+ url.gsub!(/(\?.+)\Z/) do |r|
69
+ query = r
70
+ ""
71
+ end
72
+
73
+ if true_file = resolve_path(cur_dir + up_to_root + url.sub(/\A\//,""))
74
+ url = true_file.relative_path_from(cur_dir).to_s
75
+ url += query if query
76
+ url += anchor if anchor
77
+ url
78
+ else
79
+ nil
80
+ end
81
+
82
+ end
83
+
84
+ def resolve_path(path)
85
+ path = Pathname.new(path) unless path.kind_of?(Pathname)
86
+ # Append index.html/index.htm/index.rhtml if it's a diretory
87
+ if path.directory?
88
+ search_files = %w{.html .htm}.map!{|p| path + "index#{p}" }
89
+ # If it ends with a slash or does not contain a . and it's not a directory
90
+ # try to add .html/.htm to see if that exists.
91
+ elsif (path.to_s =~ /\/$/) || (path.to_s =~ /^[^.]+$/)
92
+ search_files = [path.to_s + ".html", path.to_s + ".htm"].map!{|p| Pathname.new(p) }
93
+ else
94
+ search_files = [path]
95
+ end
96
+ search_files.find{|p| p.exist? }
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,63 @@
1
+ module HtmlMockup
2
+ # Loader for mockupfile
3
+ class Mockupfile
4
+
5
+ # This is the context for the mockupfile evaluation. It should be empty except for the
6
+ # #mockup method.
7
+ class Context
8
+
9
+ def initialize(mockupfile)
10
+ @_mockupfile = mockupfile
11
+ end
12
+
13
+ def mockup
14
+ @_mockupfile
15
+ end
16
+
17
+ def binding
18
+ ::Kernel.binding
19
+ end
20
+
21
+ end
22
+
23
+ # @attr :path [Pathname] The path of the Mockupfile for this project
24
+ attr_accessor :path, :project
25
+
26
+ def initialize(project)
27
+ @project = project
28
+ @path = Pathname.new(project.path + "Mockupfile")
29
+ end
30
+
31
+ # Actually load the mockupfile
32
+ def load
33
+ if File.exist?(@path) && !self.loaded?
34
+ @source = File.read(@path)
35
+ context = Context.new(self)
36
+ eval @source, context.binding
37
+ @loaded = true
38
+ end
39
+ end
40
+
41
+ # Wether or not the Mockupfile has been loaded
42
+ def loaded?
43
+ @loaded
44
+ end
45
+
46
+ def release
47
+ if block_given?
48
+ yield(self.project.release)
49
+ end
50
+ self.project.release
51
+ end
52
+
53
+ def serve
54
+ if block_given?
55
+ yield(self.project.server)
56
+ end
57
+ self.project.server
58
+ end
59
+
60
+ alias :server :serve
61
+
62
+ end
63
+ end
@@ -0,0 +1,54 @@
1
+ require File.dirname(__FILE__) + "/release"
2
+ require File.dirname(__FILE__) + "/server"
3
+ require File.dirname(__FILE__) + "/mockupfile"
4
+
5
+ module HtmlMockup
6
+ # Loader for mockupfile
7
+ class Project
8
+
9
+ # @attr :path [Pathname] The project path
10
+ # @attr :html_path [Pathname] The path of the HTML mockup
11
+ # @attr :partial_path [Pathname] The path for the partials for this mockup
12
+ # @attr :mockupfile [Mockupfile] The Mockupfile for this project
13
+ attr_accessor :path, :html_path, :partial_path, :mockupfile
14
+
15
+ def initialize(path, options={})
16
+ @path = Pathname.new(path)
17
+
18
+ options = {
19
+ :html_path => @path + "html",
20
+ :partial_path => @path + "partials"
21
+ }.update(options)
22
+
23
+ html_path, partial_path = mockup_paths(options[:html_path], options[:partial_path])
24
+ @mockupfile = Mockupfile.new(self)
25
+ @mockupfile.load
26
+ end
27
+
28
+ def server
29
+ @server ||= Server.new(self.html_path, self.partial_path)
30
+ end
31
+
32
+ def release
33
+ @release ||= Release.new(self)
34
+ end
35
+
36
+ def html_path=(p)
37
+ @html_path = Pathname.new(p).realpath
38
+ end
39
+
40
+ def partial_path=(p)
41
+ @partial_path = Pathname.new(p).realpath
42
+ end
43
+
44
+ protected
45
+
46
+ def mockup_paths(html_path, partial_path = nil)
47
+ html_path = Pathname.new(html_path)
48
+ partial_path = partial_path && Pathname.new(partial_path) || (html_path + "../partials/")
49
+ [html_path, partial_path]
50
+ end
51
+
52
+
53
+ end
54
+ end
@@ -14,16 +14,18 @@ module HtmlMockup
14
14
  def call(env)
15
15
  path = env["PATH_INFO"]
16
16
 
17
- # Append index.html/index.htm/index.rhtml if it's a diretory
17
+ # TODO: Combine with Extractor#resolve_path
18
+
19
+ # Append index.html/index.htm if it's a diretory
18
20
  if File.directory?(File.join(@docroot,path))
19
- search_files = %w{.html .htm .rhtml}.map!{|p| File.join(@docroot,path,"index#{p}")}
20
- # If it's already a .html/.htm/.rhtml file, render that file
21
- elsif (path =~ /\.r?html?$/)
21
+ search_files = %w{.html .htm}.map!{|p| File.join(@docroot,path,"index#{p}")}
22
+ # If it's already a .html/.htm file, render that file
23
+ elsif (path =~ /\.html?$/)
22
24
  search_files = [File.join(@docroot,path)]
23
25
  # If it ends with a slash or does not contain a . and it's not a directory
24
- # try to add .html/.htm/.rhtml to see if that exists.
26
+ # try to add .html/.htm to see if that exists.
25
27
  elsif (path =~ /\/$/) || (path =~ /^[^.]+$/)
26
- search_files = [path + ".html", path + ".htm", path + ".rhtml"].map!{|p| File.join(@docroot,p) }
28
+ search_files = [path + ".html", path + ".htm"].map!{|p| File.join(@docroot,p) }
27
29
  # Otherwise don't render anything at all.
28
30
  else
29
31
  search_files = []
@@ -0,0 +1,21 @@
1
+ module HtmlMockup
2
+ module Rack
3
+ # Listens to the "sleep" parameter and sleeps the amount of seconds specified by the parameter. There is however a maximum of 5 seconds.
4
+ class Sleep
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ r = Rack::Request.new(env)
12
+ if r.params["sleep"]
13
+ sleeptime = [r.params["sleep"].to_i, 5].min
14
+ sleep sleeptime
15
+ end
16
+ @app.call(env)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ require 'fileutils'
2
+
3
+ # Finalizes the release into a directory in target_path
4
+ #
5
+ # The directory name will have the format PREFIX-VERSION
6
+ #
7
+ module HtmlMockup::Release::Finalizers
8
+ class Dir < Base
9
+
10
+ # @option options :prefix Prefix to put before the version (default = "html")
11
+ def call(release, options = {})
12
+ name = [(options[:prefix] || "html"), release.scm.version].join("-")
13
+
14
+ release.log(self, "Finalizing release to #{release.target_path + name}")
15
+
16
+ if File.exist?(release.target_path + name)
17
+ release.log(self, "Removing existing target #{release.target_path + name}")
18
+ FileUtils.rm_rf(release.target_path + name)
19
+ end
20
+
21
+ FileUtils.cp_r release.build_path, release.target_path + name
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ module HtmlMockup::Release::Finalizers
2
+ class Zip < Base
3
+ end
4
+ end
@@ -0,0 +1,11 @@
1
+ module HtmlMockup::Release::Finalizers
2
+ class Base
3
+ def call(release, options = {})
4
+ raise ArgumentError, "Implement in subclass"
5
+ end
6
+ end
7
+ end
8
+
9
+ require File.dirname(__FILE__) + "/finalizers/zip"
10
+ require File.dirname(__FILE__) + "/finalizers/dir"
11
+
@@ -0,0 +1,98 @@
1
+ require 'tilt'
2
+ module HtmlMockup
3
+
4
+ # Inject VERSION / DATE (i.e. in TOC)
5
+ # r.inject({"VERSION" => release.version, "DATE" => release.date}, :into => %w{_doc/toc.html})
6
+
7
+ # Inject CHANGELOG
8
+ # r.inject({"CHANGELOG" => {:file => "", :filter => BlueCloth}}, :into => %w{_doc/changelog.html})
9
+
10
+ class Release::Injector
11
+
12
+ # @example Simple variable injection (replaces [VARIABLE] into all .css files)
13
+ # {"[VARIABLE]" => "replacement"}, :into => %w{**/*.css}
14
+ #
15
+ # @example Regex variable injection (replaces all matches into test.js files)
16
+ # {/\/\*\s*\[BANNER\]\s*\*\// => "replacement"}, :into => %w{javacripts/test.js}
17
+ #
18
+ # @example Simple variable injection with filtering (replaces [VARIABLE] with :content run through the markdown processor into all .html files)
19
+ # {"[VARIABLE]" => {:content => "# header one", :processor => "md"}, :into => %w{**/*.html}
20
+ #
21
+ # @example Full file injection (replaces all matches of [CHANGELOG] with the contents of "CHANGELOG.md" into _doc/changelog.html)
22
+ #
23
+ # {"CHANGELOG" => {:file => "CHANGELOG.md"}}, :into => %w{_doc/changelog.html}
24
+ #
25
+ # @example Full file injection with filtering (replaces all matches of [CHANGELOG] with the contents of "CHANGELOG" which ran through Markdown compresser into _doc/changelog.html)
26
+ #
27
+ # {"CHANGELOG" => {:file => "CHANGELOG", :processor => "md"}}, :into => %w{_doc/changelog.html}
28
+ #
29
+ # Processors are based on Tilt (https://github.com/rtomayko/tilt).
30
+ # Currently supported/tested processors are:
31
+ #
32
+ # * 'md' for Markdown (bluecloth)
33
+ #
34
+ # Injection files are relative to the :source_path
35
+ #
36
+ # @param [Hash] variables Variables to inject. See example for more info
37
+ # @option options [Array] :into An array of file globs relative to the build_path
38
+ def initialize(variables, options)
39
+ @variables = variables
40
+ @into = options[:into]
41
+ end
42
+
43
+ def call(release)
44
+ files = release.get_files(@into)
45
+
46
+ files.each do |f|
47
+ c = File.read(f)
48
+ injected_vars = []
49
+ @variables.each do |variable, injection|
50
+ if c.gsub!(variable, get_content(injection, release))
51
+ injected_vars << variable
52
+ end
53
+ end
54
+ release.log(self, "Injected variables #{injected_vars.inspect} into #{f}") if injected_vars.size > 0
55
+ File.open(f,"w") { |fh| fh.write c }
56
+ end
57
+
58
+ end
59
+
60
+ def get_content(injection, release)
61
+ case injection
62
+ when String
63
+ injection
64
+ when Hash
65
+ get_complex_injection(injection, release)
66
+ else
67
+ if injection.respond_to?(:to_s)
68
+ injection.to_s
69
+ else
70
+ raise ArgumentError, "Woah, what's this? #{injection.inspect}"
71
+ end
72
+ end
73
+ end
74
+
75
+ def get_complex_injection(injection, release)
76
+
77
+ if injection[:file]
78
+ content = File.read(release.source_path + injection[:file])
79
+ else
80
+ content = injection[:content]
81
+ end
82
+
83
+ raise ArgumentError, "No :content or :file specified" if !content
84
+
85
+ if injection[:processor]
86
+ if tmpl = Tilt[injection[:processor]]
87
+ (tmpl.new{ content }).render
88
+ else
89
+ raise ArgumentError, "Unknown processor #{injection[:processor]}"
90
+ end
91
+ else
92
+ content
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+ end
@@ -0,0 +1,54 @@
1
+ require 'fileutils'
2
+ module HtmlMockup::Release::Processors
3
+ class Requirejs < Base
4
+
5
+ # @option options [Hash] :build_files An a hash of files to build (as key) and the target directory in the release to put it as value, each one will be built in a separate directory. (default is {"javascripts/site.build.js" => "javascripts"})
6
+ # @option options [String] :node The system path for node (defaults to "node" in path)
7
+ # @option options [String] :rjs The system path to the requirejs optimizer (r.js) (defaults to "../vendor/requirejs/r.js" (relative to source_path))
8
+ def call(release, options={})
9
+ options = {
10
+ :build_files => {"javascripts/site.build.js" => "javascripts"},
11
+ :rjs => release.source_path + "../vendor/requirejs/r.js",
12
+ :node => "node"
13
+ }.update(options)
14
+
15
+ begin
16
+ `#{options[:node]} -v`
17
+ rescue Errno::ENOENT
18
+ raise RuntimeError, "Could not find node in #{node.inspect}"
19
+ end
20
+
21
+ if !File.exist?(options[:rjs])
22
+ raise RuntimeError, "Could not find r.js optimizer at #{options[:rjs].inspect}"
23
+ end
24
+
25
+ options[:build_files].each do |build_file, target|
26
+ build_file = release.build_path + build_file
27
+ target = release.build_path + target
28
+ release.log(self, "Optimizing #{build_file}")
29
+
30
+ # Hack to create tempfile in build
31
+ t = Tempfile.new("requirejs", release.build_path)
32
+ tmp_build_dir = t.path
33
+ t.close
34
+ t.unlink
35
+
36
+ # Run r.js optimizer
37
+ output = `#{options[:node]} #{options[:rjs]} -o #{build_file} dir=#{tmp_build_dir}`
38
+
39
+ # Check if r.js succeeded
40
+ unless $?.success?
41
+ raise RuntimeError, "Asset compilation with node failed.\nr.js output:\n #{output}"
42
+ end
43
+
44
+ if File.exist?(target)
45
+ release.log(self, "Removing target #{target}")
46
+ FileUtils.rm_rf(target)
47
+ end
48
+
49
+ # Move the tmp_build_dir to target
50
+ FileUtils.mv(tmp_build_dir, target)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,38 @@
1
+ # Use the sass gem
2
+ require 'sass'
3
+
4
+ module HtmlMockup::Release::Processors
5
+ class Sass < Base
6
+ # @param [Hash] options Options as described below, all other options will be passed to Sass.compile_file.
7
+ #
8
+ # @option options [Array] :match An array of shell globs, defaults to ["stylesheets/**/*.scss"]
9
+ # @option options [Array] :skip An array of regexps which will be skipped, defaults to [/_.*\.scss\Z/], Attention! Skipped files will be deleted as well!
10
+ def call(release, options={})
11
+ options = {
12
+ :match => ["stylesheets/**/*.scss"],
13
+ :skip => [/_.*\.scss\Z/],
14
+ :style => :expanded
15
+ }.update(options)
16
+
17
+ match = options.delete(:match)
18
+ skip = options.delete(:skip)
19
+
20
+ # Sassify SCSS files
21
+ files = release.get_files(match)
22
+ files.each do |f|
23
+ if !skip.detect{|r| r.match(f) }
24
+ release.log(self, "Processing: #{f}")
25
+ # Compile SCSS
26
+ ::Sass.compile_file(f, f.gsub(/\.scss$/, ".css"), options)
27
+ end
28
+ end
29
+
30
+ # Cleanup
31
+ files.each do |f|
32
+ # Remove source file
33
+ File.unlink(f)
34
+ end
35
+
36
+ end
37
+ end
38
+ end