benoit 0.2.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +1 -2
  3. data/.rspec +1 -1
  4. data/Assetfile +19 -4
  5. data/Gemfile.lock +29 -5
  6. data/Guardfile +28 -0
  7. data/Rakefile +2 -0
  8. data/benoit.gemspec +5 -0
  9. data/bin/benoit +25 -7
  10. data/lib/benoit/cadenza.rb +2 -0
  11. data/lib/benoit/cadenza/blocks.rb +18 -0
  12. data/lib/benoit/compiler_error.rb +5 -1
  13. data/lib/benoit/filters/base_filter.rb +4 -5
  14. data/lib/benoit/filters/cadenza_filter.rb +19 -16
  15. data/lib/benoit/filters/markdown_filter.rb +36 -4
  16. data/lib/benoit/logger.rb +2 -2
  17. data/lib/benoit/pipeline_project.rb +23 -23
  18. data/lib/benoit/server.rb +47 -0
  19. data/lib/benoit/server/remote.rb +29 -0
  20. data/lib/benoit/utils/finds_layouts_for_template.rb +28 -30
  21. data/lib/benoit/version.rb +1 -1
  22. data/spec/features/build_command.feature +1 -1
  23. data/spec/features/frontmatter_metadata.feature +3 -21
  24. data/spec/features/javascript_files.feature +1 -0
  25. data/spec/features/markdown_files.feature +41 -0
  26. data/spec/features/output_filters.feature +2 -7
  27. data/spec/features/page_layouts.feature +4 -28
  28. data/spec/features/pagination.feature +1 -0
  29. data/spec/lib/filters/base_filter_spec.rb +4 -33
  30. data/spec/lib/filters/markdown_filter_spec.rb +31 -8
  31. data/spec/lib/filters/sass_filter_spec.rb +2 -2
  32. data/spec/lib/site_context_spec.rb +2 -2
  33. data/spec/steps/staticly_steps.rb +1 -1
  34. data/spec/support/spec_helpers/memory_file_wrapper.rb +2 -6
  35. data/vendor/rake-pipeline/GETTING_STARTED.md +11 -11
  36. data/vendor/rake-pipeline/bin/rakep +1 -1
  37. data/vendor/rake-pipeline/lib/rake-pipeline.rb +2 -49
  38. data/vendor/rake-pipeline/lib/rake-pipeline/cli.rb +0 -1
  39. data/vendor/rake-pipeline/lib/rake-pipeline/file_wrapper.rb +2 -9
  40. data/vendor/rake-pipeline/lib/rake-pipeline/filter.rb +1 -19
  41. data/vendor/rake-pipeline/lib/rake-pipeline/manifest.rb +4 -0
  42. data/vendor/rake-pipeline/lib/rake-pipeline/middleware.rb +1 -2
  43. data/vendor/rake-pipeline/lib/rake-pipeline/project.rb +3 -2
  44. data/vendor/rake-pipeline/rake-pipeline.gemspec +1 -1
  45. data/vendor/rake-pipeline/spec/cli_spec.rb +0 -2
  46. data/vendor/rake-pipeline/spec/concat_filter_spec.rb +4 -4
  47. data/vendor/rake-pipeline/spec/filter_spec.rb +0 -35
  48. data/vendor/rake-pipeline/spec/gsub_filter_spec.rb +5 -5
  49. data/vendor/rake-pipeline/spec/ordering_concat_filter_spec.rb +4 -4
  50. data/vendor/rake-pipeline/spec/rake_acceptance_spec.rb +18 -0
  51. data/vendor/rake-pipeline/spec/support/spec_helpers/filters.rb +1 -1
  52. data/vendor/rake-pipeline/spec/support/spec_helpers/memory_file_wrapper.rb +2 -6
  53. metadata +77 -2
@@ -16,7 +16,7 @@ module Benoit
16
16
  message = <<-EOM
17
17
  Benoit encountered an error.
18
18
 
19
- #{ex.message}
19
+ #{ex}
20
20
  #{sub_message}
21
21
 
22
22
  #{ENV.map { |k,v| "#{k}=#{v}" }.join("\n")}
@@ -33,7 +33,7 @@ module Benoit
33
33
  if Benoit.config.output_mode == :app
34
34
  $stderr.puts({ line_no: nil, message: ex.message, path: __FILE__ }.to_json)
35
35
  else
36
- $stderr.puts ex.message
36
+ $stderr.puts ex.to_s
37
37
  $stderr.puts ex.backtrace
38
38
  end
39
39
  end
@@ -24,36 +24,36 @@ module Benoit
24
24
  if Benoit.config.clean_before_build?
25
25
  Benoit::Cleaner.run
26
26
  end
27
- project.pipelines.each do |pipeline|
28
- pipeline.register_invocation_hook :after_task, BuildNotifiers::FileBuiltNotifier
29
- pipeline.register_invocation_hook :before_filter, BuildNotifiers::ProgressNotifier
30
- pipeline.register_invocation_hook :filters_ready, ->(pipeline){
31
- require 'ostruct'
32
- paths_map = {}
33
- pipeline.output_files.each do |output|
34
- input = output.original_inputs.first
27
+ # project.pipelines.each do |pipeline|
28
+ # pipeline.register_invocation_hook :after_task, BuildNotifiers::FileBuiltNotifier
29
+ # pipeline.register_invocation_hook :before_filter, BuildNotifiers::ProgressNotifier
30
+ # pipeline.register_invocation_hook :filters_ready, ->(pipeline){
31
+ # require 'ostruct'
32
+ # paths_map = {}
33
+ # # pipeline.output_files.each do |output|
34
+ # # input = output.original_inputs.first
35
35
 
36
- wrapper = OpenStruct.new(path: output.path, read: input.read, fullpath: input.fullpath)
36
+ # # wrapper = OpenStruct.new(path: output.path, read: input.read, fullpath: input.fullpath)
37
37
 
38
- paths_map[input.path] = output.path
38
+ # # paths_map[input.path] = output.path
39
39
 
40
- PageMetadata::Store.current[wrapper]
40
+ # # PageMetadata::Store.current[wrapper]
41
41
 
42
- end
42
+ # # end
43
43
 
44
- current_site = CurrentSite.load
44
+ # current_site = CurrentSite.load
45
45
 
46
- current_site.paths_map = paths_map
46
+ # current_site.paths_map = paths_map
47
47
 
48
- # Load ALL filters (including filters within filters)
49
- filters = recursively_load_filters_from_pipeline(pipeline)
50
- filters.each do |filter|
51
- if filter.respond_to? :current_site=
52
- filter.current_site = current_site
53
- end
54
- end
55
- }
56
- end
48
+ # # Load ALL filters (including filters within filters)
49
+ # filters = recursively_load_filters_from_pipeline(pipeline)
50
+ # filters.each do |filter|
51
+ # if filter.respond_to? :current_site=
52
+ # filter.current_site = current_site
53
+ # end
54
+ # end
55
+ # }
56
+ # end
57
57
  project.invoke
58
58
  end
59
59
 
@@ -0,0 +1,47 @@
1
+ require 'rake-pipeline/middleware'
2
+ require 'rack/server'
3
+
4
+
5
+ module Benoit
6
+ class Server < Rack::Server
7
+
8
+ require_relative 'server/remote'
9
+
10
+ DEFAULT_APP = proc { [404, { "Content-Type" => "text/plain" }, ["not found"]] }
11
+
12
+ def initialize(project, options={})
13
+ @project = project
14
+ super options
15
+ end
16
+
17
+ def app
18
+ project = @project.project
19
+ Rack::Builder.new do
20
+ use Rack::ShowExceptions
21
+ use CustomExceptionHandler
22
+ map "/_remote" do
23
+ run Benoit::Server::Remote.new(project)
24
+ end
25
+ run Rake::Pipeline::Middleware.new DEFAULT_APP, project
26
+ end.to_app
27
+ end
28
+
29
+ end
30
+
31
+ class CustomExceptionHandler
32
+
33
+ def initialize(app)
34
+ @app = app
35
+ end
36
+
37
+ def call(env)
38
+ @app.call(env)
39
+ rescue StandardError => ex
40
+ Benoit::Cleaner.run
41
+ Logger.error "#{ex.message} (#{ex.class.name})"
42
+ Logger.error ex.backtrace.join("\n")
43
+ raise ex
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,29 @@
1
+ module Benoit
2
+ class Server
3
+ class Remote
4
+
5
+ def initialize(project)
6
+ @project = project
7
+ end
8
+
9
+ def call(env)
10
+ code = 200
11
+
12
+ case env['PATH_INFO']
13
+ when '/clean'
14
+ Benoit::Cleaner.run
15
+ body = "cleaned"
16
+ when '/build'
17
+ @project.invoke
18
+ body = "built"
19
+ end
20
+
21
+ code = 200 if body
22
+ body || (body, code = ["not found", 404])
23
+
24
+ [code, {"Content-Type" => "application/json"}, {response: body}.to_json]
25
+ end
26
+
27
+ end
28
+ end
29
+ end
@@ -16,33 +16,32 @@ module Benoit::Utils
16
16
  class FindsLayoutsForTemplate
17
17
 
18
18
 
19
- FrontMatterLookupStrategy = ->(input) {
20
- input =
21
- if input.respond_to? :final_output and input.final_output
22
- input.final_output
23
- else
24
- input
25
- end
26
- metadata = Benoit::PageMetadata::Store.current[input]
27
- return unless metadata
28
- metadata["layout"] || metadata["template"]
29
- }
30
-
31
- CadenzaInheritanceLookupStrategy = ->(input) {
32
- extends_pattern = /\{% extends "([\.\w_-]+)" %\}/
33
- return unless File.exist?(input.path)
34
- match_data = File.read(input.path).match(extends_pattern)
35
- return unless match_data
36
- match_data.captures[0]
37
- }
38
-
39
19
  attr_reader :root, :template_path, :load_paths, :input
40
20
 
21
+ def self.first_layout(content, options={})
22
+ FindsLayoutsForTemplate.new(content, options).lookup_layout
23
+ end
24
+
41
25
  def initialize(input, options)
42
- @load_paths = options.delete(:load_paths) || [""]
43
- @root = options.delete(:root)
44
- @template_path = input
26
+ if input.respond_to? :path
45
27
  @input = input
28
+ @template_path = input
29
+ else
30
+ @content = input
31
+ end
32
+ @load_paths = options.delete(:load_paths) || [""]
33
+ @root = options.delete(:root)
34
+ end
35
+
36
+ def match_extends_line(content)
37
+ extends_pattern = /\{% extends "([\.\w-]+)" %\}/
38
+ match_data = content.match(extends_pattern)
39
+ return unless match_data
40
+ match_data.captures[0]
41
+ end
42
+
43
+ def lookup_layout
44
+ match_extends_line(@content)
46
45
  end
47
46
 
48
47
  def lookup_layouts
@@ -53,24 +52,23 @@ module Benoit::Utils
53
52
 
54
53
  def recursively_lookup_layouts_for_file(input, template_list=[])
55
54
 
56
- parent_template = call_strategy_for_file input, root
55
+ parent_template = match_file input, root
57
56
 
58
57
  if parent_template
59
58
  normalized_path = NormalizesPathToTemplate(parent_template, load_paths)
60
59
  template_list << normalized_path
61
- input = Rake::Pipeline::FileWrapper.new(Dir.pwd, normalized_path)
62
60
  # TODO: Not a fan of Dir.pwd here, but it will always work. Is there a better way to get the correct input root?
61
+ input = Rake::Pipeline::FileWrapper.new(Dir.pwd, normalized_path)
63
62
  recursively_lookup_layouts_for_file(input, template_list)
64
63
  end
65
64
 
66
65
  template_list
67
66
  end
68
67
 
69
- def call_strategy_for_file(input, root)
70
- strategies = [FrontMatterLookupStrategy]
71
- strategies.inject(nil) do |parent_template,strategy|
72
- strategy.call(input) || parent_template
73
- end
68
+ def match_file(input, root)
69
+ return unless File.exist?(input.path)
70
+ content = File.read(input.path)
71
+ match_extends_line(content)
74
72
  end
75
73
 
76
74
  end
@@ -1,3 +1,3 @@
1
1
  module Benoit
2
- VERSION = "0.2.2"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -7,7 +7,7 @@ Feature: benoit build
7
7
  When I build the site
8
8
  Then a directory named "_build" should exist
9
9
 
10
- Scenario: Defaults cache path to "~/.benoit/tmpcache/{site}"
10
+ Scenario: Defaults cache path to "/tmp/.benoit/tmpcache/{site}"
11
11
  When I build the site
12
12
  Then a cache directory should exist for that site
13
13
 
@@ -1,5 +1,6 @@
1
1
  Feature: Site Context
2
2
 
3
+ @backlog
3
4
  Scenario: Groups posts by type
4
5
  Given a site named "subpages"
5
6
  And a file named "index.html" with content:
@@ -29,6 +30,7 @@ Feature: Site Context
29
30
  Scenario: Group arbitrary page types by type
30
31
 
31
32
 
33
+ @backlog
32
34
  Scenario: Loads content from markdown files
33
35
  Given a site named "test"
34
36
  And a file named "index.html" with content:
@@ -53,6 +55,7 @@ Feature: Site Context
53
55
  This is the content
54
56
  """
55
57
 
58
+ @backlog
56
59
  Scenario: Parses field named 'date' as a date object for reliable sorting
57
60
  Given a site
58
61
  And a file containing metadata:
@@ -76,24 +79,3 @@ Feature: Site Context
76
79
  2012-12-12
77
80
  2022-04-13
78
81
  """
79
-
80
- Scenario: Metadata contains rendered Markdown
81
- Given a site
82
- And a file with an extension of ".markdown" with content:
83
- """
84
- ---
85
- type: post
86
- ---
87
-
88
- [a link](http://www.example.com)
89
- """
90
- And a file named "index.html" with content:
91
- """
92
- {% for post in site.posts %}{{ post.content }}
93
- {% endfor %}
94
- """
95
- When I build the site
96
- Then the output file "index.html" should have content:
97
- """
98
- <a href="http://www.example.com">a link</a>
99
- """
@@ -3,6 +3,7 @@ Feature: Javascript Files
3
3
  Background:
4
4
  Given a site
5
5
 
6
+ @backlog
6
7
  Scenario: Concatenates multiple scripts
7
8
  Given a file named "js/a.js" with content:
8
9
  """
@@ -0,0 +1,41 @@
1
+ Feature: Markdown Files
2
+
3
+ Benoit converts Markdown files to HTML (Markdown files are those that end in ".markdown", ".md", ".mkdown" or ".mdown"). It uses the RedCarpet engine for rendering Markdown. Currently, there is no way to configure Markdown settings ([want this? Let me know!][feedback])
4
+
5
+ If you use a layout for your site, you can use the regular {% extends ... %} tag and {% block ... %} tags just like you do in HTML files. If you need to use more template features than just the layouts, then you will need to use HTML rather than Markdown.
6
+
7
+ Scenario: Converts Markdown to HTML
8
+ Given a file named "cadenza.markdown" with content:
9
+ """
10
+ [blah](http://www.google.com)
11
+ """
12
+ When I build the site
13
+ Then the output file "cadenza.html" should only have content:
14
+ """
15
+ <p><a href="http://www.google.com">blah</a></p>
16
+
17
+ """
18
+
19
+ Scenario: Properly wraps Markdown files in specified layout
20
+ Given a file named "cadenza.markdown" with content:
21
+ """
22
+ {% extends "_layout.html" %}
23
+ {% block content %}
24
+ [this is my content](http://www.google.com)
25
+ {% endblock %}
26
+ """
27
+ And a file named "_layouts/_layout.html" with content:
28
+ """
29
+ <section id="main">
30
+ {% block content %}{% endblock %}
31
+ </section>
32
+ """
33
+ When I run `benoit build`
34
+ Then the output file "cadenza.html" should have content:
35
+ """
36
+ <section id="main">
37
+
38
+ <a href="http://www.google.com">this is my content</a>
39
+
40
+ </section>
41
+ """
@@ -4,14 +4,9 @@ Feature: format_like Output Filter
4
4
  Given a site
5
5
 
6
6
  Scenario: Formats simple dates according to passed example
7
- Given a file containing metadata:
7
+ Given a file with an extension of ".html" with content:
8
8
  """
9
- date: 2012-12-23
10
- type: post
11
- """
12
- And that file has content:
13
- """
14
- {{page.date|format_like:"March 23, 2012"}}
9
+ {{"2012-12-23"|format_like:"March 23, 2012"}}
15
10
  """
16
11
  When I build the site
17
12
  Then the output file should have content:
@@ -25,36 +25,12 @@ Feature: Page Layouts
25
25
  </section>
26
26
  """
27
27
 
28
- Scenario: Reads layout from metadata in .html files
29
- Given a file with an extension of ".html" containing metadata:
30
- """
31
- layout: _layout
32
- """
33
- And that file has content:
34
- """
35
- {% block content %}CONTENT{% endblock %}
36
- """
37
- And a layout named "_layout" with content:
38
- """
39
- !!!
40
- {% block content %}{% endblock %}
41
- !!!
42
- """
43
- When I build the site
44
- Then the output file should have content:
45
- """
46
- !!!
47
- CONTENT
48
- !!!
49
- """
50
-
28
+ @backlog
51
29
  Scenario: Doesn't require layouts prefixed with underscore
52
- Given a file with an extension of ".html" containing metadata:
53
- """
54
- layout: layout
55
- """
56
- And that file has content:
30
+ Given a file with an extension of ".html" with content:
57
31
  """
32
+ {% extends "layout.html" %}
33
+
58
34
  {% block content %}CONTENT{% endblock %}
59
35
  """
60
36
  And a layout named "_layout" with content:
@@ -1,3 +1,4 @@
1
+ @backlog
1
2
  Feature: Content Pagination
2
3
 
3
4
  Background:
@@ -14,11 +14,11 @@ describe Benoit::Filters::BaseFilter do
14
14
  let(:html_input) { "<html><head></head><body><h1>TESTING</h1></body></html>" }
15
15
 
16
16
  def input_file(name, content)
17
- MemoryFileWrapper.new("/path/to/input", name, "UTF-8", Set.new([]), content)
17
+ MemoryFileWrapper.new("/path/to/input", name, "UTF-8", content)
18
18
  end
19
19
 
20
20
  def output_file(name)
21
- MemoryFileWrapper.new("/path/to/output", name, "UTF-8", Set.new([]))
21
+ MemoryFileWrapper.new("/path/to/output", name, "UTF-8")
22
22
  end
23
23
 
24
24
  def setup_filter(filter, input_filename='index.html')
@@ -28,25 +28,14 @@ describe Benoit::Filters::BaseFilter do
28
28
  filter.input_files = [input_file(input_filename, html_input)]
29
29
  filter.output_root= "/path/to/output"
30
30
  filter.rake_application = Rake::Application.new
31
- filter.current_site = {}
32
31
  filter
33
32
  end
34
33
 
35
- def setup_final_outputs(filter)
36
- filter.input_files.each_with_index do |input,i|
37
- output = filter.output_files[i]
38
- filter.current_site.merge!(input.path => { "content" => input.read })
39
- filter.current_site.merge!(output.path => { "content" => input.read })
40
- end
41
- end
42
-
43
34
  it "generates output directly from the input" do
44
35
  filter = setup_filter basic_filter.new
45
36
 
46
37
  expect(filter.output_files).to eq([output_file("index.html")])
47
38
 
48
- setup_final_outputs(filter)
49
-
50
39
  tasks = filter.generate_rake_tasks
51
40
  tasks.each(&:invoke)
52
41
 
@@ -74,7 +63,7 @@ describe Benoit::Filters::BaseFilter do
74
63
 
75
64
  let(:path_writer) do
76
65
  Class.new(described_class) do
77
- build_output do |page,input|
66
+ build_output do |input|
78
67
  input.path
79
68
  end
80
69
  end
@@ -83,8 +72,6 @@ describe Benoit::Filters::BaseFilter do
83
72
  it "gets output from calling builder" do
84
73
  filter = setup_filter builder_filter.new
85
74
 
86
- setup_final_outputs(filter)
87
-
88
75
  tasks = filter.generate_rake_tasks
89
76
  tasks.each(&:invoke)
90
77
 
@@ -92,26 +79,10 @@ describe Benoit::Filters::BaseFilter do
92
79
  expect(file.body).to eq("blah")
93
80
  end
94
81
 
95
- it "passes page object to builder" do
96
- filter = setup_filter page_filter.new
97
-
98
- setup_final_outputs(filter)
99
-
100
- page = filter.current_site[filter.output_files.first.path]
101
-
102
- tasks = filter.generate_rake_tasks
103
- tasks.each(&:invoke)
104
-
105
- file = MemoryFileWrapper.files["/path/to/output/index.html"]
106
- expect(file.body).to eq(page["content"])
107
- end
108
-
109
- it "passes input to builder when needed" do
82
+ it "passes input to builder" do
110
83
  filter = setup_filter path_writer.new
111
84
  input = filter.input_files.first
112
85
 
113
- setup_final_outputs(filter)
114
-
115
86
  tasks = filter.generate_rake_tasks
116
87
  tasks.each(&:invoke)
117
88