benoit 0.1.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.
Files changed (164) hide show
  1. data/.gitignore +4 -0
  2. data/.gitmodules +3 -0
  3. data/.rspec +1 -0
  4. data/.rspec-turnip +1 -0
  5. data/.ruby-version +1 -0
  6. data/Assetfile +44 -0
  7. data/Gemfile +5 -0
  8. data/Gemfile.lock +110 -0
  9. data/Rakefile +9 -0
  10. data/benoit.gemspec +50 -0
  11. data/bin/benoit +121 -0
  12. data/bin/bundle-development +1 -0
  13. data/bin/bundle-sandbox +1 -0
  14. data/lib/benoit.rb +36 -0
  15. data/lib/benoit/cadenza.rb +11 -0
  16. data/lib/benoit/cadenza/output_filters.rb +21 -0
  17. data/lib/benoit/cleaner.rb +10 -0
  18. data/lib/benoit/compiler_error.rb +49 -0
  19. data/lib/benoit/configuration.rb +24 -0
  20. data/lib/benoit/current_site.rb +12 -0
  21. data/lib/benoit/file_wrapper_extensions.rb +13 -0
  22. data/lib/benoit/filters.rb +15 -0
  23. data/lib/benoit/filters/base_filter.rb +44 -0
  24. data/lib/benoit/filters/blacklist_filter.rb +18 -0
  25. data/lib/benoit/filters/cadenza_filter.rb +75 -0
  26. data/lib/benoit/filters/content_page_filter.rb +45 -0
  27. data/lib/benoit/filters/markdown_filter.rb +19 -0
  28. data/lib/benoit/filters/metadata_cleaner.rb +30 -0
  29. data/lib/benoit/filters/move_to_root_filter.rb +22 -0
  30. data/lib/benoit/filters/pagination_filter.rb +23 -0
  31. data/lib/benoit/filters/pass_thru_filter.rb +22 -0
  32. data/lib/benoit/filters/sass_filter.rb +74 -0
  33. data/lib/benoit/filters/set_metadata_filter.rb +15 -0
  34. data/lib/benoit/logger.rb +69 -0
  35. data/lib/benoit/page.rb +88 -0
  36. data/lib/benoit/page_metadata.rb +8 -0
  37. data/lib/benoit/page_metadata/container.rb +74 -0
  38. data/lib/benoit/page_metadata/json_converter.rb +28 -0
  39. data/lib/benoit/page_metadata/parser.rb +38 -0
  40. data/lib/benoit/page_metadata/store.rb +75 -0
  41. data/lib/benoit/pipeline.rb +1 -0
  42. data/lib/benoit/pipeline/dsl_extensions.rb +8 -0
  43. data/lib/benoit/pipeline/pagination_matcher.rb +53 -0
  44. data/lib/benoit/pipeline_project.rb +81 -0
  45. data/lib/benoit/site_context.rb +123 -0
  46. data/lib/benoit/utils/finds_layouts_for_template.rb +77 -0
  47. data/lib/benoit/utils/normalizes_path_to_template.rb +43 -0
  48. data/lib/benoit/utils/paginated_list.rb +102 -0
  49. data/lib/benoit/version.rb +3 -0
  50. data/lib/build_notifiers/file_built_notifier.rb +20 -0
  51. data/lib/build_notifiers/progress_notifier.rb +57 -0
  52. data/lib/cli.rb +39 -0
  53. data/spec/.rbenv-gemsets +1 -0
  54. data/spec/Gemfile +9 -0
  55. data/spec/Gemfile.lock +57 -0
  56. data/spec/bin/autospec +16 -0
  57. data/spec/bin/cucumber +16 -0
  58. data/spec/bin/htmldiff +16 -0
  59. data/spec/bin/ldiff +16 -0
  60. data/spec/bin/rspec +16 -0
  61. data/spec/features/build_command.feature +46 -0
  62. data/spec/features/frontmatter_metadata.feature +99 -0
  63. data/spec/features/javascript_files.feature +35 -0
  64. data/spec/features/output_filters.feature +20 -0
  65. data/spec/features/page_layouts.feature +72 -0
  66. data/spec/features/pagination.feature +58 -0
  67. data/spec/features/sass_files.feature +30 -0
  68. data/spec/features/version.feature +5 -0
  69. data/spec/lib/filters/base_filter_spec.rb +141 -0
  70. data/spec/lib/filters/markdown_filter_spec.rb +65 -0
  71. data/spec/lib/filters/sass_filter_spec.rb +73 -0
  72. data/spec/lib/metadata_json_converter_spec.rb +65 -0
  73. data/spec/lib/metadata_store_spec.rb +148 -0
  74. data/spec/lib/page_spec.rb +19 -0
  75. data/spec/lib/site_context_spec.rb +106 -0
  76. data/spec/spec_helper.rb +16 -0
  77. data/spec/steps/output_file_steps.rb +45 -0
  78. data/spec/steps/run_steps.rb +71 -0
  79. data/spec/steps/staticly_steps.rb +194 -0
  80. data/spec/support/aruba/rspec.rb +66 -0
  81. data/spec/support/files/img.png +0 -0
  82. data/spec/support/files/input.css.scss +7 -0
  83. data/spec/support/files/input.scss +7 -0
  84. data/spec/support/spec_helpers/file_helpers.rb +8 -0
  85. data/spec/support/spec_helpers/memory_file_wrapper.rb +43 -0
  86. data/spec/support/spec_helpers/memory_manifest.rb +19 -0
  87. data/spec/turnip_helper.rb +19 -0
  88. data/vendor/frontmatter/frontmatter.gemspec +24 -0
  89. data/vendor/frontmatter/lib/frontmatter.rb +92 -0
  90. data/vendor/frontmatter/lib/frontmatter/version.rb +3 -0
  91. data/vendor/rake-pipeline/.gitignore +18 -0
  92. data/vendor/rake-pipeline/.rspec +1 -0
  93. data/vendor/rake-pipeline/.travis.yml +12 -0
  94. data/vendor/rake-pipeline/.yardopts +2 -0
  95. data/vendor/rake-pipeline/GETTING_STARTED.md +268 -0
  96. data/vendor/rake-pipeline/Gemfile +14 -0
  97. data/vendor/rake-pipeline/LICENSE +20 -0
  98. data/vendor/rake-pipeline/README.markdown +11 -0
  99. data/vendor/rake-pipeline/README.yard +178 -0
  100. data/vendor/rake-pipeline/Rakefile +21 -0
  101. data/vendor/rake-pipeline/bin/rakep +4 -0
  102. data/vendor/rake-pipeline/examples/copying_files.md +12 -0
  103. data/vendor/rake-pipeline/examples/minifying_files.md +37 -0
  104. data/vendor/rake-pipeline/examples/modifying_pipelines.md +67 -0
  105. data/vendor/rake-pipeline/examples/multiple_pipelines.md +77 -0
  106. data/vendor/rake-pipeline/lib/generators/rake/pipeline/install/install_generator.rb +70 -0
  107. data/vendor/rake-pipeline/lib/rake-pipeline.rb +509 -0
  108. data/vendor/rake-pipeline/lib/rake-pipeline/cli.rb +57 -0
  109. data/vendor/rake-pipeline/lib/rake-pipeline/dsl.rb +9 -0
  110. data/vendor/rake-pipeline/lib/rake-pipeline/dsl/pipeline_dsl.rb +246 -0
  111. data/vendor/rake-pipeline/lib/rake-pipeline/dsl/project_dsl.rb +108 -0
  112. data/vendor/rake-pipeline/lib/rake-pipeline/dynamic_file_task.rb +194 -0
  113. data/vendor/rake-pipeline/lib/rake-pipeline/error.rb +17 -0
  114. data/vendor/rake-pipeline/lib/rake-pipeline/file_wrapper.rb +195 -0
  115. data/vendor/rake-pipeline/lib/rake-pipeline/filter.rb +267 -0
  116. data/vendor/rake-pipeline/lib/rake-pipeline/filters.rb +4 -0
  117. data/vendor/rake-pipeline/lib/rake-pipeline/filters/concat_filter.rb +63 -0
  118. data/vendor/rake-pipeline/lib/rake-pipeline/filters/gsub_filter.rb +56 -0
  119. data/vendor/rake-pipeline/lib/rake-pipeline/filters/ordering_concat_filter.rb +38 -0
  120. data/vendor/rake-pipeline/lib/rake-pipeline/filters/pipeline_finalizing_filter.rb +21 -0
  121. data/vendor/rake-pipeline/lib/rake-pipeline/graph.rb +178 -0
  122. data/vendor/rake-pipeline/lib/rake-pipeline/manifest.rb +82 -0
  123. data/vendor/rake-pipeline/lib/rake-pipeline/manifest_entry.rb +34 -0
  124. data/vendor/rake-pipeline/lib/rake-pipeline/matcher.rb +141 -0
  125. data/vendor/rake-pipeline/lib/rake-pipeline/middleware.rb +73 -0
  126. data/vendor/rake-pipeline/lib/rake-pipeline/precompile.rake +8 -0
  127. data/vendor/rake-pipeline/lib/rake-pipeline/project.rb +338 -0
  128. data/vendor/rake-pipeline/lib/rake-pipeline/rails_plugin.rb +10 -0
  129. data/vendor/rake-pipeline/lib/rake-pipeline/railtie.rb +34 -0
  130. data/vendor/rake-pipeline/lib/rake-pipeline/reject_matcher.rb +29 -0
  131. data/vendor/rake-pipeline/lib/rake-pipeline/server.rb +15 -0
  132. data/vendor/rake-pipeline/lib/rake-pipeline/sorted_pipeline.rb +19 -0
  133. data/vendor/rake-pipeline/lib/rake-pipeline/version.rb +6 -0
  134. data/vendor/rake-pipeline/rails/init.rb +2 -0
  135. data/vendor/rake-pipeline/rake-pipeline.gemspec +24 -0
  136. data/vendor/rake-pipeline/spec/cli_spec.rb +73 -0
  137. data/vendor/rake-pipeline/spec/concat_filter_spec.rb +37 -0
  138. data/vendor/rake-pipeline/spec/dsl/pipeline_dsl_spec.rb +165 -0
  139. data/vendor/rake-pipeline/spec/dsl/project_dsl_spec.rb +41 -0
  140. data/vendor/rake-pipeline/spec/dynamic_file_task_spec.rb +119 -0
  141. data/vendor/rake-pipeline/spec/encoding_spec.rb +106 -0
  142. data/vendor/rake-pipeline/spec/file_wrapper_spec.rb +132 -0
  143. data/vendor/rake-pipeline/spec/filter_spec.rb +367 -0
  144. data/vendor/rake-pipeline/spec/graph_spec.rb +56 -0
  145. data/vendor/rake-pipeline/spec/gsub_filter_spec.rb +87 -0
  146. data/vendor/rake-pipeline/spec/manifest_entry_spec.rb +46 -0
  147. data/vendor/rake-pipeline/spec/manifest_spec.rb +67 -0
  148. data/vendor/rake-pipeline/spec/matcher_spec.rb +141 -0
  149. data/vendor/rake-pipeline/spec/middleware_spec.rb +199 -0
  150. data/vendor/rake-pipeline/spec/ordering_concat_filter_spec.rb +42 -0
  151. data/vendor/rake-pipeline/spec/pipeline_spec.rb +232 -0
  152. data/vendor/rake-pipeline/spec/project_spec.rb +295 -0
  153. data/vendor/rake-pipeline/spec/rake_acceptance_spec.rb +720 -0
  154. data/vendor/rake-pipeline/spec/rake_tasks_spec.rb +21 -0
  155. data/vendor/rake-pipeline/spec/reject_matcher_spec.rb +31 -0
  156. data/vendor/rake-pipeline/spec/sorted_pipeline_spec.rb +27 -0
  157. data/vendor/rake-pipeline/spec/spec_helper.rb +38 -0
  158. data/vendor/rake-pipeline/spec/support/spec_helpers/file_utils.rb +35 -0
  159. data/vendor/rake-pipeline/spec/support/spec_helpers/filters.rb +37 -0
  160. data/vendor/rake-pipeline/spec/support/spec_helpers/input_helpers.rb +23 -0
  161. data/vendor/rake-pipeline/spec/support/spec_helpers/memory_file_wrapper.rb +35 -0
  162. data/vendor/rake-pipeline/spec/support/spec_helpers/memory_manifest.rb +19 -0
  163. data/vendor/rake-pipeline/tools/perfs +101 -0
  164. metadata +497 -0
@@ -0,0 +1,49 @@
1
+ #
2
+ # CompilerError.rb
3
+ # Benoit
4
+ #
5
+ # Created by Joseph Fiorini on 11/5/12.
6
+ # Copyright 2012 densitypop. All rights reserved.
7
+ #
8
+
9
+ class StandardError
10
+ def to_json
11
+ { message: "Benoit has encountered an internal error. Please contact @benoitapp on Twitter to resolve this problem.", type: "error" }.to_json
12
+ end
13
+ end
14
+
15
+ module Benoit
16
+ class CompilerError < StandardError
17
+ attr_accessor :line, :message
18
+ attr_reader :output, :env, :file_path, :original_error
19
+
20
+ def initialize(line, file_path, original_error)
21
+ @line = line
22
+ @file_path = file_path
23
+ @output = output
24
+ @env = env
25
+ @original_error = original_error
26
+ end
27
+
28
+ def to_json
29
+ { line_no: @line, message: @message, path: @file_path, original_error: @original_error, type: "error" }.to_json
30
+ end
31
+
32
+ end
33
+
34
+ class FileMissingError < CompilerError
35
+ attr_accessor :missing_file
36
+
37
+ def initialize(missing_file, line, file_path, original_error)
38
+ @missing_file = missing_file
39
+ super line, file_path, original_error
40
+ end
41
+
42
+ def message
43
+ <<-EOS
44
+ You included a file named #{missing_file.inspect} in #{file_path.inspect}. I could not find a file with that name. Maybe you forgot to specify a folder?
45
+ EOS
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module Benoit
2
+ module Configuration
3
+
4
+ class Config
5
+
6
+ attr_accessor :output_mode, :cache_path, :output_path, :site_path
7
+ attr_writer :clean_before_build
8
+
9
+ def clean_before_build?
10
+ @clean_before_build
11
+ end
12
+
13
+ end
14
+
15
+ def configure(&block)
16
+ block.call(config)
17
+ end
18
+
19
+ def config
20
+ @config ||= Config.new
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ require 'delegate'
2
+
3
+ module Benoit
4
+ class CurrentSite < SimpleDelegator
5
+ def self.load
6
+ context_hash = PageMetadata::SiteContextConverter.export
7
+ new(Benoit::SiteContext.from_hash(context_hash))
8
+ end
9
+ end
10
+ end
11
+
12
+
@@ -0,0 +1,13 @@
1
+ module Benoit
2
+ module FileWrapperExtensions
3
+
4
+ def final_output=(output)
5
+ @final_output = output
6
+ end
7
+
8
+ def final_output
9
+ @final_output
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module Benoit
2
+ module Filters
3
+ require_relative './filters/base_filter'
4
+ require_relative './filters/sass_filter'
5
+ require_relative './filters/cadenza_filter'
6
+ require_relative './filters/pass_thru_filter'
7
+ require_relative './filters/blacklist_filter'
8
+ require_relative './filters/markdown_filter'
9
+ require_relative './filters/metadata_cleaner'
10
+ require_relative './filters/pagination_filter'
11
+ require_relative './filters/content_page_filter'
12
+ require_relative './filters/move_to_root_filter'
13
+ end
14
+ end
15
+
@@ -0,0 +1,44 @@
1
+ module Benoit
2
+ module Filters
3
+ class BaseFilter < Rake::Pipeline::Filter
4
+
5
+ class << self
6
+ attr_reader :builder, :output_name_generator
7
+
8
+ def build_output(&block)
9
+ @builder = block
10
+ end
11
+
12
+ def output_name(&block)
13
+ @output_name_generator = block
14
+ end
15
+ end
16
+
17
+ attr_accessor :current_site
18
+
19
+ def output_name_generator
20
+ self.class.output_name_generator ||
21
+ @output_name_generator
22
+ end
23
+
24
+ def builder
25
+ self.class.builder
26
+ end
27
+
28
+ def generate_output(inputs, output)
29
+ inputs.each do |input|
30
+ page = current_site[input.path]
31
+ content = build_output(page, input) if builder
32
+ output.write(content || page["content"])
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def build_output(page, input)
39
+ builder.(page, input)
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ module Benoit::Filters
2
+ class BlacklistFilter < Rake::Pipeline::Filter
3
+ attr_accessor :whitelist
4
+
5
+ def initialize(options={}, &block)
6
+ @whitelist = options.delete(:allow)
7
+ super &block
8
+ end
9
+
10
+ def generate_rake_tasks
11
+ @rake_tasks = []
12
+ end
13
+
14
+ def output_files
15
+ []
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,75 @@
1
+ require 'cadenza'
2
+
3
+ class Benoit::Filters::CadenzaFilter < Rake::Pipeline::Filter
4
+ attr_reader :options
5
+ attr_accessor :current_site
6
+
7
+ include Benoit
8
+
9
+ def initialize
10
+ super
11
+ @page_layouts = {}
12
+ end
13
+
14
+ def generate_output(inputs, output)
15
+
16
+ site_context = current_site.to_context
17
+
18
+ inputs.each do |input|
19
+ load_paths = [input.root, Dir.pwd, "#{Dir.pwd}/_layouts"]
20
+
21
+ Benoit::Cadenza.load_output_filters!
22
+
23
+ load_paths.each do |load_path|
24
+ ::Cadenza::BaseContext.add_load_path load_path
25
+ end
26
+
27
+ page = current_site[input.path].to_hash
28
+
29
+ # Leave the original page for paginated pages blank
30
+ # otherwise we will get an "iteration reached an end" error
31
+ # from trying to iterate past the end of the enumerator
32
+ if input.path !~ /\d+.html/ && page.keys.any? { |key| key =~ /\w+_per_page/ }
33
+ output.write("")
34
+ next
35
+ end
36
+
37
+ context_hash = {
38
+ "site" => site_context,
39
+ "page" => page
40
+ }
41
+
42
+ begin
43
+ compiled = ::Cadenza.render_template input.path, context_hash
44
+ rescue ::Cadenza::TemplateNotFoundError => ex
45
+ error = Benoit::FileMissingError.new(ex.message, nil, input.path, ex)
46
+ raise error
47
+ rescue ::Cadenza::FilterNotDefinedError => ex
48
+ missing_filter = ex.message.scan(/undefined filter '([\w\-_]*)'/).flatten.first
49
+ error = Benoit::CompilerError.new(nil, input.path, ex)
50
+ error.message = "You used a filter named #{missing_filter.inspect}, but I could not find it. Maybe it's misspelled?"
51
+ raise error
52
+ rescue ::Cadenza::Error => ex
53
+ end
54
+
55
+ output.write compiled
56
+ end
57
+ end
58
+
59
+
60
+ def page_layouts_for_input(input)
61
+ @page_layouts[input.path] ||=
62
+ FindsLayoutsForTemplate(input.path, root: input.root, load_paths: ["_layouts"])
63
+ end
64
+
65
+ def additional_dependencies(input=nil)
66
+ if input
67
+ Dir["**/*.markdown"].map do |f|
68
+ f.gsub input.root, ""
69
+ end
70
+ else
71
+ []
72
+ end
73
+ end
74
+
75
+ end
@@ -0,0 +1,45 @@
1
+ module Benoit::Filters
2
+
3
+ class ContentPageFilter < Rake::Pipeline::Filter
4
+
5
+ attr_accessor :current_site
6
+
7
+ def initialize
8
+ super
9
+ @page_layouts = {}
10
+ end
11
+
12
+ def generate_output(inputs, output)
13
+ inputs.each do |input|
14
+
15
+ layout = page_layouts_for_input(input).first
16
+
17
+ template =
18
+ if layout
19
+ # TODO: Only use this for files that don't extend already but have specified a layout, if the file extends, then just replace the extends line with the normalized layout
20
+ "{% extends '#{layout}' %}\n\n"
21
+ end.to_s
22
+
23
+ template << input.read
24
+
25
+ output.write(template)
26
+
27
+ end
28
+ end
29
+
30
+ def page_layouts_for_input(input)
31
+ @page_layouts[input.path] ||=
32
+ FindsLayoutsForTemplate(input, root: input.root, load_paths: ["_layouts"])
33
+ end
34
+
35
+ def additional_dependencies(input=nil)
36
+ if input
37
+ output = current_site.paths_map[input.path]
38
+ page_layouts_for_input(input)
39
+ else
40
+ []
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ require 'redcarpet'
2
+
3
+ module Benoit::Filters
4
+ class MarkdownFilter < BaseFilter
5
+
6
+ output_name do |path|
7
+ path.sub(/\.(md|mdown|mkdown|markdown)$/, '.html')
8
+ end
9
+
10
+ build_output do |page|
11
+
12
+ markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, fenced_code_blocks: true)
13
+ rendered = markdown.render(page["content"])
14
+
15
+ page["content"] = rendered
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ module Benoit::Filters
2
+ class MetadataCleaner < Rake::Pipeline::Filter
3
+
4
+ include Benoit
5
+
6
+ attr_accessor :current_site
7
+
8
+ def generate_output(inputs, output)
9
+ inputs.each do |input|
10
+ metadata = current_site[input.path]
11
+ if metadata and metadata.key?("content")
12
+ output.write metadata["content"]
13
+ else
14
+ output.write input.read
15
+ end
16
+ end
17
+ end
18
+
19
+
20
+ def super_pipeline(descendent=self.pipeline)
21
+ if descendent.respond_to? :pipeline
22
+ super_pipeline(descendent.pipeline)
23
+ else
24
+ descendent
25
+ end
26
+ end
27
+
28
+
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ class Benoit::Filters::MoveToRootFilter < Rake::Pipeline::Filter
2
+
3
+ def initialize
4
+ block = proc { |input|
5
+ components = input.split('/')
6
+ if components.length == 1 # Already at root
7
+ components.first
8
+ elsif components.first.start_with? '_'
9
+ components.shift
10
+ end
11
+ components.join('/')
12
+ }
13
+ super &block
14
+ end
15
+
16
+ def generate_output(inputs, output)
17
+ inputs.each do |input|
18
+ output.write input.read
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,23 @@
1
+ class Pathname
2
+ def append_basename(str, suffix=nil)
3
+ ext = suffix || extname
4
+ dirname.join(basename(ext).to_s + str + ext.to_s)
5
+ end
6
+ end
7
+
8
+ module Benoit
9
+ module Filters
10
+ class PaginationFilter < MetadataCleaner
11
+
12
+ def initialize
13
+ @output_name_generator = ->(_,input){
14
+ pages_for_input = pipeline.per_page_counts[input]
15
+ (1..pages_for_input).to_a.map do |page|
16
+ Pathname.new(input.path).append_basename(page.to_s).to_path
17
+ end
18
+ }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ #
2
+ # pass_thru_filter.rb
3
+ # Benoit
4
+ #
5
+ # Created by Joseph Fiorini on 10/3/12.
6
+ # Copyright 2012 densitypop. All rights reserved.
7
+ #
8
+
9
+
10
+ module Benoit::Filters
11
+ class PassThruFilter < Rake::Pipeline::Filter
12
+
13
+ processes_binary_files
14
+
15
+ def generate_output(inputs, output)
16
+ inputs.each do |input|
17
+ output.write input.read
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,74 @@
1
+ #
2
+ # sass_filter.rb
3
+ # Benoit
4
+ #
5
+ # Created by Joseph Fiorini on 10/6/12.
6
+ # Copyright 2012 densitypop. All rights reserved.
7
+ #
8
+
9
+ require 'compass'
10
+ require 'sass'
11
+
12
+ class Benoit::Filters::SassFilter < Rake::Pipeline::Filter
13
+ attr_reader :options, :additional_load_paths
14
+
15
+ def initialize(options={})
16
+ load_paths = options.delete(:additional_load_paths) || []
17
+
18
+ # TODO: Handle files that don't end in .scss
19
+ block ||= proc { |input| input.sub(/\.(?:css\.)?(scss|sass)$/, '.css') }
20
+ super(&block)
21
+ Compass.add_project_configuration
22
+ Compass.configuration.project_path ||= Dir.pwd
23
+ @additional_load_paths = Compass.configuration.sass_load_paths
24
+ @additional_load_paths += load_paths.map do |f|
25
+ File.expand_path(f)
26
+ end
27
+
28
+
29
+ @options = options
30
+ @options[:load_paths] ||= []
31
+ @options[:load_paths].concat(additional_load_paths)
32
+
33
+ end
34
+
35
+ def generate_output(inputs, output)
36
+ inputs.each do |input|
37
+ begin
38
+ sass_options = sass_options_for_file(input).merge(filename: input.path)
39
+ sass_engine = Sass::Engine.for_file(input.fullpath, sass_options)
40
+ output.write sass_engine.render
41
+ rescue Sass::SyntaxError => ex
42
+ path = ex.sass_filename.gsub(input.root + "/", "")
43
+ missing_files = ex.message.scan(/File to import not found or unreadable: ([\w\-]*)\./).flatten
44
+ if missing_files.empty?
45
+ error = Benoit::CompilerError.new(nil, path, ex)
46
+ error.line = ex.sass_line
47
+ else
48
+ error = Benoit::FileMissingError.new(missing_files.first, ex.sass_line, path, ex)
49
+ end
50
+ raise error
51
+ rescue StandardError => ex
52
+ raise Benoit::CompilerError.new(nil, path, ex)
53
+ end
54
+ end
55
+ end
56
+
57
+ def additional_dependencies(input=nil)
58
+ Dir.glob("**/*.scss")
59
+ end
60
+
61
+
62
+ private
63
+
64
+ def sass_options_for_file(file)
65
+ added_opts = {
66
+ :syntax => file.path.match(/\.sass$/) ? :sass : :scss,
67
+ :trace => true,
68
+ :cache => false,
69
+ :cache_location => nil
70
+ }
71
+
72
+ added_opts.merge(@options)
73
+ end
74
+ end