pith 0.0.2 → 0.0.3

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 (44) hide show
  1. data/README.markdown +10 -3
  2. data/Rakefile +13 -3
  3. data/cucumber.yml +1 -6
  4. data/features/helpers.feature~ +23 -0
  5. data/features/ignorance.feature +12 -1
  6. data/features/ignorance.feature~ +12 -1
  7. data/features/incremental_rebuild.feature~ +24 -0
  8. data/features/layouts.feature +22 -2
  9. data/features/layouts.feature~ +20 -0
  10. data/features/metadata.feature +1 -1
  11. data/features/{linking.feature → relative_linking.feature} +32 -2
  12. data/features/relative_linking.feature~ +109 -0
  13. data/features/step_definitions/build_steps.rb +20 -16
  14. data/features/step_definitions/build_steps.rb~ +32 -11
  15. data/features/support/env.rb +6 -6
  16. data/features/support/env.rb~ +36 -4
  17. data/features/support/rspec_matchers.rb~ +5 -0
  18. data/lib/pith/input/abstract.rb +120 -0
  19. data/lib/pith/input/abstract.rb~ +120 -0
  20. data/lib/pith/input/template.rb +56 -0
  21. data/lib/pith/input/template.rb~ +46 -0
  22. data/lib/pith/input/verbatim.rb +31 -0
  23. data/lib/pith/input/verbatim.rb~ +31 -0
  24. data/lib/pith/input.rb +5 -176
  25. data/lib/pith/input.rb~ +10 -85
  26. data/lib/pith/project.rb +14 -7
  27. data/lib/pith/project.rb~ +36 -11
  28. data/lib/pith/render_context.rb +34 -13
  29. data/lib/pith/render_context.rb~ +54 -17
  30. data/lib/pith/server.rb +0 -1
  31. data/lib/pith/server.rb~ +13 -17
  32. data/lib/pith/version.rb +1 -1
  33. data/lib/pith/version.rb~ +1 -1
  34. data/lib/pith.rb~ +0 -1
  35. data/sample/_out/index.html +14 -0
  36. data/sample/_out/stylesheets/app.css +38 -0
  37. data/sample/index.html.haml +1 -2
  38. data/spec/pith/input/abstract_spec.rb +31 -0
  39. data/spec/pith/input/abstract_spec.rb~ +31 -0
  40. data/spec/pith/metadata_spec.rb +2 -2
  41. data/spec/pith/project_spec.rb +21 -8
  42. data/spec/pith/project_spec.rb~ +74 -0
  43. data/spec/spec_helper.rb~ +27 -0
  44. metadata +76 -6
data/README.markdown CHANGED
@@ -5,11 +5,13 @@ Pith is a static web-site generator, written in Ruby.
5
5
 
6
6
  Using Pith, you can:
7
7
 
8
- * __Express yourself succintly__ using [Haml][haml], [Sass][sass], ERb, Markdown and Textile.
8
+ * __Express yourself succintly__ using Markdown or Textile.
9
9
 
10
- * __Encapsulate common markup__ in "partial" templates.
10
+ * __Layout your pages__ written in ERb, [Haml][haml], or Liquid.
11
11
 
12
- * __Separate content and layout__ using "layout" templates.
12
+ * __Style things up using__ [Sass][sass].
13
+
14
+ * __Encapsulate common markup__ in "layout" and "partial" templates.
13
15
 
14
16
  * __Easily link pages and resources__ using relative links.
15
17
 
@@ -17,6 +19,11 @@ Using Pith, you can:
17
19
 
18
20
  * __Define custom helper-methods__ to increase expressiveness.
19
21
 
22
+ Why Pith?
23
+ ---------
24
+
25
+ Why another static web-site generator, when there are other good options out there? Pith's main differentiating factor is that structure of the output slavishly mirrors the structure of the input; there are no magic input directories for layouts, or dynamic content, or anything else.
26
+
20
27
  Install it
21
28
  ----------
22
29
 
data/Rakefile CHANGED
@@ -10,7 +10,17 @@ task :default => :cucumber
10
10
 
11
11
  require 'cucumber/rake/task'
12
12
 
13
- Cucumber::Rake::Task.new(:cucumber) do |t|
14
- t.fork = true
15
- t.profile = 'default'
13
+ namespace :cucumber do
14
+
15
+ [:wip, :default].each do |profile|
16
+
17
+ Cucumber::Rake::Task.new(profile) do |t|
18
+ t.fork = true
19
+ t.profile = profile
20
+ end
21
+
22
+ end
23
+
16
24
  end
25
+
26
+ task :cucumber => ["cucumber:wip", "cucumber:default"]
data/cucumber.yml CHANGED
@@ -1,7 +1,2 @@
1
- <%
2
- rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
3
- rerun_opts = rerun.to_s.strip.empty? ? "--format progress features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}"
4
- std_opts = "#{rerun_opts} --format rerun --out rerun.txt --strict --tags ~@wip --require features/support --require features/step_definitions"
5
- %>
6
- default: <%= std_opts %>
1
+ default: --tags ~@wip features
7
2
  wip: --tags @wip:3 --wip features
@@ -0,0 +1,23 @@
1
+ Feature: helper methods
2
+
3
+ I want to extend Pith with helper methods
4
+ So that I can use them in templates
5
+
6
+ Scenario: call a helper from a template
7
+
8
+ Given input file "_pith/config.rb" contains
9
+ """
10
+ project.helpers do
11
+
12
+ def greet(subject = "mate")
13
+ "Hello, #{subject}"
14
+ end
15
+
16
+ end
17
+ """
18
+
19
+ And input file "index.html.haml" contains "= greet('World')"
20
+
21
+ When I build the site
22
+
23
+ Then output file "index.html" should contain "Hello, World"
@@ -14,7 +14,7 @@ Scenario: a layout template at the input root
14
14
 
15
15
  Then output file "_layout" should not exist
16
16
 
17
- Scenario: a partial in a subdirectory
17
+ Scenario: a partial in an ignored subdirectory
18
18
 
19
19
  Given input file "_partials/foo.html.haml" contains
20
20
  """
@@ -24,3 +24,14 @@ Scenario: a partial in a subdirectory
24
24
  When I build the site
25
25
 
26
26
  Then output file "_partials/foo.html" should not exist
27
+
28
+ Scenario: an ignored partial in a subdirectory
29
+
30
+ Given input file "partials/_foo.html.haml" contains
31
+ """
32
+ Blah de blah
33
+ """
34
+
35
+ When I build the site
36
+
37
+ Then output file "partials/_foo.html" should not exist
@@ -14,7 +14,7 @@ Scenario: a layout template at the input root
14
14
 
15
15
  Then output file "_layout" should not exist
16
16
 
17
- Scenario: a partial in a subdirectory
17
+ Scenario: a partial in an ignored subdirectory
18
18
 
19
19
  Given input file "_partials/foo.html.haml" contains
20
20
  """
@@ -24,3 +24,14 @@ Scenario: a partial in a subdirectory
24
24
  When I build the site
25
25
 
26
26
  Then output file "_partials/foo.html" should not exist
27
+
28
+ Scenario: an ignored partial in a subdirectory
29
+
30
+ Given input file "partials/_foo.html.haml" contains
31
+ """
32
+ Blah de blah
33
+ """
34
+
35
+ When I build the site
36
+
37
+ Then output file "partials/_foo.html" should not exist
@@ -0,0 +1,24 @@
1
+ Feature: incremental rebuilding
2
+
3
+ I want to rebuild just the outputs whose inputs have changed
4
+ So that that I can bring the project up-to-date efficiently
5
+
6
+ Scenario: alter an input, and the output changes
7
+
8
+ Given input file "page.html.haml" contains "Old content"
9
+ And the site is up-to-date
10
+
11
+ When I change input file "page.html.haml" to contain "New content"
12
+ And I rebuild the site
13
+
14
+ Then output file "page.html" should be re-generated
15
+ And output file "page.html" should contain "New content"
16
+
17
+ Scenario: don't alter an input, and the output is untouched
18
+
19
+ Given input file "page.html.haml" contains "Content"
20
+ And the site is up-to-date
21
+
22
+ When I rebuild the site
23
+
24
+ Then output file "page.html" should not be re-generated
@@ -7,7 +7,7 @@ Scenario: Haml template with a layout
7
7
 
8
8
  Given input file "index.html.haml" contains
9
9
  """
10
- = include "layouts/_simple.haml" do
10
+ = inside "layouts/_simple.haml" do
11
11
  blah blah
12
12
  """
13
13
  And input file "layouts/_simple.haml" contains
@@ -25,7 +25,7 @@ Scenario: instance variable assigned within the layed-out block
25
25
 
26
26
  Given input file "index.html.haml" contains
27
27
  """
28
- = include "layouts/_with_header.haml" do
28
+ = inside "layouts/_with_header.haml" do
29
29
  - @title = "XXX"
30
30
  %p blah blah
31
31
  """
@@ -41,3 +41,23 @@ Scenario: instance variable assigned within the layed-out block
41
41
  <h1>XXX</h1>
42
42
  <p>blah blah</p>
43
43
  """
44
+
45
+ Scenario: Layout specified in meta-data
46
+
47
+ Given input file "index.html.haml" contains
48
+ """
49
+ -# ---
50
+ -# layout: layouts/_simple.haml
51
+ -#...
52
+ blah blah
53
+ """
54
+ And input file "layouts/_simple.haml" contains
55
+ """
56
+ %p= yield
57
+ """
58
+
59
+ When I build the site
60
+ Then output file "index.html" should contain
61
+ """
62
+ <p>blah blah</p>
63
+ """
@@ -41,3 +41,23 @@ Scenario: instance variable assigned within the layed-out block
41
41
  <h1>XXX</h1>
42
42
  <p>blah blah</p>
43
43
  """
44
+
45
+ Scenario: Layout specified in meta-data
46
+
47
+ Given input file "index.html.haml" contains
48
+ """
49
+ -# ---
50
+ -# layout: layouts/_simple.haml
51
+ -#...
52
+ blah blah
53
+ """
54
+ And input file "layouts/_simple.haml" contains
55
+ """
56
+ %p= yield
57
+ """
58
+
59
+ When I build the site
60
+ Then output file "index.html" should contain
61
+ """
62
+ <p>blah blah</p>
63
+ """
@@ -3,7 +3,7 @@ Feature: metadata
3
3
  I want extract metadata from page source
4
4
  So that I can use it elsewhere
5
5
 
6
- Scenario: link from one top-level page to another
6
+ Scenario: use meta-data from YAML comment
7
7
 
8
8
  Given input file "page.html.haml" contains
9
9
  """
@@ -1,6 +1,7 @@
1
1
  Feature: linking between files
2
2
 
3
- I want to be able to link pages easily
3
+ I want to be able to generate relative reference to other pages
4
+ So that the generated site is re-locateable
4
5
 
5
6
  Scenario: link from one top-level page to another
6
7
 
@@ -8,7 +9,8 @@ Scenario: link from one top-level page to another
8
9
  """
9
10
  = link("page.html", "Page")
10
11
  """
11
-
12
+ And input file "page.html" exists
13
+
12
14
  When I build the site
13
15
  Then output file "index.html" should contain
14
16
  """
@@ -21,6 +23,7 @@ Scenario: link from a sub-directory to a root-level page
21
23
  """
22
24
  = link("/help.html", "Help")
23
25
  """
26
+ And input file "help.html" exists
24
27
 
25
28
  When I build the site
26
29
  Then output file "subdir/page.html" should contain
@@ -34,6 +37,7 @@ Scenario: link to an image
34
37
  """
35
38
  %img{:src => href("/logo.png")}
36
39
  """
40
+ And input file "logo.png" exists
37
41
 
38
42
  When I build the site
39
43
  Then output file "subdir/page.html" should contain
@@ -54,6 +58,8 @@ Scenario: links within a layout block
54
58
  = yield
55
59
  """
56
60
 
61
+ And input file "subdir/other.html" exists
62
+
57
63
  When I build the site
58
64
  Then output file "subdir/page.html" should contain
59
65
  """
@@ -72,8 +78,32 @@ Scenario: links included from a partial
72
78
  %link{ :href=>href("/stylesheets/app.css"), :rel=>"stylesheet", :type=>"text/css" }
73
79
  """
74
80
 
81
+ And input file "stylesheets/app.css" exists
82
+
75
83
  When I build the site
76
84
  Then output file "subdir/page.html" should contain
77
85
  """
78
86
  <link href='../stylesheets/app.css' rel='stylesheet' type='text/css' />
79
87
  """
88
+
89
+ Scenario: use "title" meta-data attribute in link
90
+
91
+ Given input file "index.html.haml" contains
92
+ """
93
+ = link("page.html")
94
+ """
95
+
96
+ And input file "page.html.haml" contains
97
+ """
98
+ -# ---
99
+ -# title: "Title from meta-data"
100
+ -# ...
101
+ Target content
102
+ """
103
+
104
+ When I build the site
105
+
106
+ Then output file "index.html" should contain
107
+ """
108
+ <a href="page.html">Title from meta-data</a>
109
+ """
@@ -0,0 +1,109 @@
1
+ Feature: linking between files
2
+
3
+ I want to be able to generate relative reference to other pages
4
+ So that the generated site is re-locateable
5
+
6
+ Scenario: link from one top-level page to another
7
+
8
+ Given input file "index.html.haml" contains
9
+ """
10
+ = link("page.html", "Page")
11
+ """
12
+ And input file "page.html" exists
13
+
14
+ When I build the site
15
+ Then output file "index.html" should contain
16
+ """
17
+ <a href="page.html">Page</a>
18
+ """
19
+
20
+ Scenario: link from a sub-directory to a root-level page
21
+
22
+ Given input file "subdir/page.html.haml" contains
23
+ """
24
+ = link("/help.html", "Help")
25
+ """
26
+ And input file "help.html" exists
27
+
28
+ When I build the site
29
+ Then output file "subdir/page.html" should contain
30
+ """
31
+ <a href="../help.html">Help</a>
32
+ """
33
+
34
+ Scenario: link to an image
35
+
36
+ Given input file "subdir/page.html.haml" contains
37
+ """
38
+ %img{:src => href("/logo.png")}
39
+ """
40
+ And input file "logo.png" exists
41
+
42
+ When I build the site
43
+ Then output file "subdir/page.html" should contain
44
+ """
45
+ <img src='../logo.png' />
46
+ """
47
+
48
+ Scenario: links within a layout block
49
+
50
+ Given input file "subdir/page.html.haml" contains
51
+ """
52
+ = include "/common/_layout.haml" do
53
+ = link "other.html", "Other page"
54
+ """
55
+
56
+ And input file "common/_layout.haml" contains
57
+ """
58
+ = yield
59
+ """
60
+
61
+ And input file "subdir/other.html" exists
62
+
63
+ When I build the site
64
+ Then output file "subdir/page.html" should contain
65
+ """
66
+ <a href="other.html">Other page</a>
67
+ """
68
+
69
+ Scenario: links included from a partial
70
+
71
+ Given input file "subdir/page.html.haml" contains
72
+ """
73
+ = include "/common/_partial.haml"
74
+ """
75
+
76
+ And input file "common/_partial.haml" contains
77
+ """
78
+ %link{ :href=>href("/stylesheets/app.css"), :rel=>"stylesheet", :type=>"text/css" }
79
+ """
80
+
81
+ And input file "stylesheets/app.css" exists
82
+
83
+ When I build the site
84
+ Then output file "subdir/page.html" should contain
85
+ """
86
+ <link href='../stylesheets/app.css' rel='stylesheet' type='text/css' />
87
+ """
88
+
89
+ Scenario: use "title" meta-data attribute in link
90
+
91
+ Given input file "index.html.haml" contains
92
+ """
93
+ = link("page.html")
94
+ """
95
+
96
+ And input file "page.html.haml" contains
97
+ """
98
+ -# ---
99
+ -# title: "Title from meta-data"
100
+ -# ...
101
+ Target content
102
+ """
103
+
104
+ When I build the site
105
+
106
+ Then output file "index.html" should contain
107
+ """
108
+ <a href="page.html">Title from meta-data</a>
109
+ """
@@ -1,17 +1,21 @@
1
- Given /^input file "([^\"]*)" contains "([^\"]*)"$/ do |file_name, content|
2
- @inputs.write(file_name, content, :mtime => (Time.now - 5))
1
+ Given /^input file "([^\"]*)" contains "([^\"]*)"$/ do |path, content|
2
+ @inputs.write(path, content, :mtime => (Time.now - 5))
3
3
  end
4
4
 
5
- Given /^input file "([^\"]*)" contains$/ do |file_name, content|
6
- @inputs.write(file_name, content, :mtime => (Time.now - 5))
5
+ Given /^input file "([^\"]*)" contains$/ do |path, content|
6
+ @inputs.write(path, content, :mtime => (Time.now - 5))
7
+ end
8
+
9
+ Given /^input file "([^\"]*)" exists$/ do |path|
10
+ Given %{input file "#{path}" contains "something"}
7
11
  end
8
12
 
9
13
  Given "the site is up-to-date" do
10
14
  When "I build the site"
11
15
  end
12
16
 
13
- When /^I change input file "([^\"]*)" to contain "([^\"]*)"$/ do |file_name, content|
14
- @inputs[file_name] = content
17
+ When /^I change input file "([^\"]*)" to contain "([^\"]*)"$/ do |path, content|
18
+ @inputs[path] = content
15
19
  end
16
20
 
17
21
  When /^I (?:re)?build the site$/ do
@@ -25,22 +29,22 @@ class String
25
29
  end
26
30
  end
27
31
 
28
- Then /^output file "([^\"]*)" should contain "([^\"]*)"$/ do |file_name, content|
29
- @outputs[file_name].clean.should == content.clean
32
+ Then /^output file "([^\"]*)" should contain "([^\"]*)"$/ do |path, content|
33
+ @outputs[path].clean.should == content.clean
30
34
  end
31
35
 
32
- Then /^output file "([^\"]*)" should contain$/ do |file_name, content|
33
- @outputs[file_name].clean.should == content.clean
36
+ Then /^output file "([^\"]*)" should contain$/ do |path, content|
37
+ @outputs[path].clean.should == content.clean
34
38
  end
35
39
 
36
- Then /^output file "([^\"]*)" should not exist$/ do |file_name|
37
- @outputs[file_name].should == nil
40
+ Then /^output file "([^\"]*)" should not exist$/ do |path|
41
+ @outputs[path].should == nil
38
42
  end
39
43
 
40
- Then /^output file "([^"]*)" should be re\-generated$/ do |file_name|
41
- @project.logger.messages.should contain(/--> +#{file_name}/)
44
+ Then /^output file "([^"]*)" should be re\-generated$/ do |path|
45
+ @project.logger.messages.should contain(/--> +#{path}/)
42
46
  end
43
47
 
44
- Then /^output file "([^"]*)" should not be re\-generated$/ do |file_name|
45
- @project.logger.messages.should_not contain(/--> +#{file_name}/)
48
+ Then /^output file "([^"]*)" should not be re\-generated$/ do |path|
49
+ @project.logger.messages.should_not contain(/--> +#{path}/)
46
50
  end
@@ -1,12 +1,25 @@
1
- Given /^input file "([^\"]*)" contains "([^\"]*)"$/ do |file_name, content|
2
- @inputs[file_name] = content
1
+ Given /^input file "([^\"]*)" contains "([^\"]*)"$/ do |path, content|
2
+ @inputs.write(path, content, :mtime => (Time.now - 5))
3
3
  end
4
4
 
5
- Given /^input file "([^\"]*)" contains$/ do |file_name, content|
6
- @inputs[file_name] = content
5
+ Given /^input file "([^\"]*)" contains$/ do |path, content|
6
+ @inputs.write(path, content, :mtime => (Time.now - 5))
7
7
  end
8
8
 
9
- When /^I build the site$/ do
9
+ Given /^input file "([^\"]*)" exists$/ do |path|
10
+ Given %{input file "#{path}" contains "something"}
11
+ end
12
+
13
+ Given "the site is up-to-date" do
14
+ When "I build the site"
15
+ end
16
+
17
+ When /^I change input file "([^\"]*)" to contain "([^\"]*)"$/ do |path, content|
18
+ @inputs[path] = content
19
+ end
20
+
21
+ When /^I (?:re)?build the site$/ do
22
+ @project.logger.clear
10
23
  @project.build
11
24
  end
12
25
 
@@ -16,14 +29,22 @@ class String
16
29
  end
17
30
  end
18
31
 
19
- Then /^output file "([^\"]*)" should contain "([^\"]*)"$/ do |file_name, content|
20
- @outputs[file_name].clean.should == content.clean
32
+ Then /^output file "([^\"]*)" should contain "([^\"]*)"$/ do |path, content|
33
+ @outputs[path].clean.should == content.clean
34
+ end
35
+
36
+ Then /^output file "([^\"]*)" should contain$/ do |path, content|
37
+ @outputs[path].clean.should == content.clean
38
+ end
39
+
40
+ Then /^output file "([^\"]*)" should not exist$/ do |path|
41
+ @outputs[path].should == nil
21
42
  end
22
43
 
23
- Then /^output file "([^\"]*)" should contain$/ do |file_name, content|
24
- @outputs[file_name].clean.should == content.clean
44
+ Then /^output file "([^"]*)" should be re\-generated$/ do |path|
45
+ @project.logger.messages.should contain(/--> +#{path}/)
25
46
  end
26
47
 
27
- Then /^output file "([^\"]*)" should not exist$/ do |file_name|
28
- @outputs[file_name].should == nil
48
+ Then /^output file "([^"]*)" should not be re\-generated$/ do |path|
49
+ @project.logger.messages.should_not contain(/--> +#{path}/)
29
50
  end
@@ -6,17 +6,17 @@ class DirHash
6
6
  @dir = Pathname(dir)
7
7
  end
8
8
 
9
- def [](file_name)
10
- file_path = @dir + file_name
9
+ def [](file)
10
+ file_path = @dir + file
11
11
  file_path.read if file_path.exist?
12
12
  end
13
13
 
14
- def []=(file_name, content)
15
- write(file_name, content)
14
+ def []=(file, content)
15
+ write(file, content)
16
16
  end
17
17
 
18
- def write(file_name, content, options = {})
19
- file_path = @dir + file_name
18
+ def write(file, content, options = {})
19
+ file_path = @dir + file
20
20
  file_path.parent.mkpath
21
21
  file_path.open("w") do |io|
22
22
  io << content
@@ -6,19 +6,50 @@ class DirHash
6
6
  @dir = Pathname(dir)
7
7
  end
8
8
 
9
- def [](file_name)
10
- file_path = @dir + file_name
9
+ def [](file)
10
+ file_path = @dir + file
11
11
  file_path.read if file_path.exist?
12
12
  end
13
13
 
14
- def []=(file_name, content)
15
- file_path = @dir + file_name
14
+ def []=(file, content)
15
+ write(file, content)
16
+ end
17
+
18
+ def write(file, content, options = {})
19
+ file_path = @dir + file
16
20
  file_path.parent.mkpath
17
21
  file_path.open("w") do |io|
18
22
  io << content
19
23
  end
24
+ if options[:mtime]
25
+ timestamp = options[:mtime]
26
+ file_path.utime(timestamp, timestamp)
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ class InternalLogger
33
+
34
+ def initialize
35
+ @messages = []
36
+ end
37
+
38
+ attr_reader :messages
39
+
40
+ def clear
41
+ @messages.clear
20
42
  end
21
43
 
44
+ def info(message, &block)
45
+ message ||= block.call
46
+ write(message)
47
+ end
48
+
49
+ def write(message)
50
+ @messages << message
51
+ end
52
+
22
53
  end
23
54
 
24
55
  $project_dir = Pathname(__FILE__).expand_path.parent.parent.parent
@@ -38,6 +69,7 @@ Before do
38
69
  dir.mkpath
39
70
  end
40
71
  @project = Pith::Project.new(:input_dir => $input_dir, :output_dir => $output_dir)
72
+ @project.logger = InternalLogger.new
41
73
  @inputs = DirHash.new($input_dir)
42
74
  @outputs = DirHash.new($output_dir)
43
75
  end
@@ -0,0 +1,5 @@
1
+ Spec::Matchers.define :contain do |expected|
2
+ match do |actual|
3
+ actual.any? { |x| expected === x }
4
+ end
5
+ end