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/lib/pith/project.rb CHANGED
@@ -19,17 +19,16 @@ module Pith
19
19
  Pathname.glob(input_dir + "**/*").map do |input_file|
20
20
  next if input_file.directory?
21
21
  path = input_file.relative_path_from(input_dir)
22
- input(path)
22
+ input_cache[path]
23
23
  end.compact
24
24
  end
25
25
 
26
26
  def input(path)
27
- @input_cache ||= Hash.new do |h, path|
28
- h[path] = Input.new(self, path)
27
+ path = Pathname(path)
28
+ inputs.each do |input|
29
+ return input if input.path == path || input.output_path == path
29
30
  end
30
- input = @input_cache[path]
31
- raise %{can't locate "#{path}"} unless input.full_path.file?
32
- input
31
+ raise ReferenceError, "Can't find #{path.inspect}"
33
32
  end
34
33
 
35
34
  def build
@@ -62,7 +61,15 @@ module Pith
62
61
  eval(config_file.read, binding, config_file)
63
62
  end
64
63
  end
65
-
64
+
65
+ def input_cache
66
+ @input_cache ||= Hash.new do |h, path|
67
+ h[path] = Input.new(self, path)
68
+ end
69
+ end
70
+
66
71
  end
67
72
 
73
+ class ReferenceError < StandardError; end
74
+
68
75
  end
data/lib/pith/project.rb~ CHANGED
@@ -17,34 +17,59 @@ module Pith
17
17
 
18
18
  def inputs
19
19
  Pathname.glob(input_dir + "**/*").map do |input_file|
20
- unless input_file.directory?
21
- path = input_file.relative_path_from(input_dir)
22
- Input.new(self, path)
23
- end
20
+ next if input_file.directory?
21
+ path = input_file.relative_path_from(input_dir)
22
+ input_cache[path]
24
23
  end.compact
25
24
  end
26
25
 
27
- def input(name)
28
- input_dir + name
26
+ def input(path)
27
+ path = Pathname(path)
28
+ inputs.each do |input|
29
+ return input if input.path == path || input.output_path == path
30
+ end
31
+ raise ReferenceError, "Can't find #{path.inspect}"
29
32
  end
30
33
 
31
34
  def build
35
+ load_config
32
36
  inputs.each do |input|
33
37
  input.build
34
38
  end
35
39
  end
36
-
37
- def serve
38
- require "pith/server"
39
- Pith::Server.run(self)
40
- end
41
40
 
42
41
  def logger
43
42
  @logger ||= Logger.new(nil)
44
43
  end
45
44
 
46
45
  attr_writer :logger
46
+
47
+ def helpers(&block)
48
+ helper_module.module_eval(&block)
49
+ end
50
+
51
+ def helper_module
52
+ @helper_module ||= Module.new
53
+ end
54
+
55
+ private
47
56
 
57
+ def load_config
58
+ config_file = input_dir + "_pith/config.rb"
59
+ project = self
60
+ if config_file.exist?
61
+ eval(config_file.read, binding, config_file)
62
+ end
63
+ end
64
+
65
+ def input_cache
66
+ @input_cache ||= Hash.new do |h, path|
67
+ h[path] = Input.new(self, path)
68
+ end
69
+ end
70
+
48
71
  end
49
72
 
73
+ class ReferenceError < StandardError; end
74
+
50
75
  end
@@ -8,15 +8,14 @@ module Pith
8
8
 
9
9
  include Tilt::CompileSite
10
10
 
11
- def self.can_render?(extension)
12
- Tilt.registered?(extension)
13
- end
14
-
15
11
  def initialize(project)
12
+ @project = project
16
13
  @input_stack = []
17
14
  @rendered_inputs = Set.new
18
15
  self.extend(project.helper_module)
19
16
  end
17
+
18
+ attr_reader :project
20
19
 
21
20
  def initial_input
22
21
  @input_stack.first
@@ -29,21 +28,25 @@ module Pith
29
28
  def render(input, locals = {}, &block)
30
29
  @rendered_inputs << input
31
30
  with_input(input) do
32
- Tilt.new(input.full_path).render(self, locals, &block)
31
+ result = input.render(self, locals, &block)
32
+ layout_ref = current_input.meta["layout"]
33
+ result = render_ref(layout_ref) { result } if layout_ref
34
+ result
33
35
  end
34
36
  end
35
37
 
36
38
  attr_reader :rendered_inputs
37
39
 
38
- def include(name, locals = {}, &block)
39
- included_input = current_input.relative_input(name)
40
+ def include(template_ref, locals = {}, &block)
40
41
  content_block = if block_given?
41
42
  content = capture_haml(&block)
42
43
  proc { content }
43
44
  end
44
- render(included_input, locals, &content_block)
45
+ render_ref(template_ref, locals, &content_block)
45
46
  end
46
47
 
48
+ alias :inside :include
49
+
47
50
  def content_for
48
51
  @content_for_hash ||= Hash.new { "" }
49
52
  end
@@ -52,16 +55,29 @@ module Pith
52
55
  initial_input.meta || {}
53
56
  end
54
57
 
55
- def href(name)
56
- target_path = current_input.relative_path(name)
57
- target_path.relative_path_from(initial_input.path.parent)
58
+ def href(target_ref)
59
+ relative_path_to(resolve_path(target_ref))
58
60
  end
59
61
 
60
- def link(target, label)
61
- %{<a href="#{href(target)}">#{label}</a>}
62
+ def link(target_ref, label = nil)
63
+ target_path = resolve_path(target_ref)
64
+ label ||= begin
65
+ project.input(target_path).title
66
+ rescue Pith::ReferenceError
67
+ "???"
68
+ end
69
+ %{<a href="#{relative_path_to(target_path)}">#{label}</a>}
62
70
  end
63
71
 
64
72
  private
73
+
74
+ def relative_path_to(target_path)
75
+ target_path.relative_path_from(initial_input.path.parent)
76
+ end
77
+
78
+ def resolve_path(ref)
79
+ current_input.resolve_path(ref)
80
+ end
65
81
 
66
82
  def with_input(input)
67
83
  @input_stack.push(input)
@@ -71,6 +87,11 @@ module Pith
71
87
  @input_stack.pop
72
88
  end
73
89
  end
90
+
91
+ def render_ref(template_ref, locals = {}, &block)
92
+ template = project.input(resolve_path(template_ref))
93
+ render(template, locals, &block)
94
+ end
74
95
 
75
96
  end
76
97
 
@@ -1,3 +1,4 @@
1
+ require "set"
1
2
  require "pathname"
2
3
  require "tilt"
3
4
 
@@ -7,10 +8,19 @@ module Pith
7
8
 
8
9
  include Tilt::CompileSite
9
10
 
10
- def initialize(input)
11
- @input_stack = [input]
11
+ def self.can_render?(extension)
12
+ Tilt.registered?(extension)
12
13
  end
13
14
 
15
+ def initialize(project)
16
+ @project = project
17
+ @input_stack = []
18
+ @rendered_inputs = Set.new
19
+ self.extend(project.helper_module)
20
+ end
21
+
22
+ attr_reader :project
23
+
14
24
  def initial_input
15
25
  @input_stack.first
16
26
  end
@@ -19,19 +29,28 @@ module Pith
19
29
  @input_stack.last
20
30
  end
21
31
 
22
- def include(name, locals = {}, &block)
23
- including_input = current_input
24
- included_input = including_input.relative_input(name)
25
- with_input(included_input) do
26
- content_block = if block_given?
27
- content = with_input(including_input) do
28
- capture_haml(&block)
29
- end
30
- proc { content }
32
+ def render_input(input, locals = {}, &block)
33
+ @rendered_inputs << input
34
+ with_input(input) do
35
+ rendered = Tilt.new(input.file).render(self, locals, &block)
36
+ layout_ref = current_input.meta["layout"]
37
+ if layout_ref
38
+ render_ref(layout_ref) { rendered }
39
+ else
40
+ rendered
31
41
  end
32
- current_input.render(self, locals, &content_block)
33
42
  end
34
43
  end
44
+
45
+ attr_reader :rendered_inputs
46
+
47
+ def include(template_ref, locals = {}, &block)
48
+ content_block = if block_given?
49
+ content = capture_haml(&block)
50
+ proc { content }
51
+ end
52
+ render_ref(template_ref, locals, &content_block)
53
+ end
35
54
 
36
55
  def content_for
37
56
  @content_for_hash ||= Hash.new { "" }
@@ -41,16 +60,29 @@ module Pith
41
60
  initial_input.meta || {}
42
61
  end
43
62
 
44
- def href(name)
45
- target_path = current_input.relative_path(name)
46
- target_path.relative_path_from(initial_input.path.parent)
63
+ def href(target_ref)
64
+ relative_path_to(resolve_path(target_ref))
47
65
  end
48
66
 
49
- def link(target, label)
50
- %{<a href="#{href(target)}">#{label}</a>}
67
+ def link(target_ref, label = nil)
68
+ target_path = resolve_path(target_ref)
69
+ label ||= begin
70
+ project.input(target_path).title
71
+ rescue Pith::ReferenceError
72
+ "???"
73
+ end
74
+ %{<a href="#{relative_path_to(target_path)}">#{label}</a>}
51
75
  end
52
76
 
53
77
  private
78
+
79
+ def relative_path_to(target_path)
80
+ target_path.relative_path_from(initial_input.path.parent)
81
+ end
82
+
83
+ def resolve_path(ref)
84
+ current_input.resolve_path(ref)
85
+ end
54
86
 
55
87
  def with_input(input)
56
88
  @input_stack.push(input)
@@ -60,6 +92,11 @@ module Pith
60
92
  @input_stack.pop
61
93
  end
62
94
  end
95
+
96
+ def render_ref(template_ref, locals = {}, &block)
97
+ template = project.input(resolve_path(template_ref))
98
+ render_input(template, locals, &block)
99
+ end
63
100
 
64
101
  end
65
102
 
data/lib/pith/server.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require "rack"
2
2
  require "adsf/rack"
3
- require "logger"
4
3
 
5
4
  module Pith
6
5
 
data/lib/pith/server.rb~ CHANGED
@@ -1,31 +1,27 @@
1
1
  require "rack"
2
2
  require "adsf/rack"
3
- require "logger"
4
3
 
5
4
  module Pith
6
5
 
7
6
  module Server
8
7
 
9
- class << self
10
-
11
- def new(project)
12
- Rack::Builder.new do
13
- use Rack::CommonLogger, project.logger
14
- use Rack::ShowExceptions
15
- use Rack::Lint
16
- use Pith::Server::AutoBuild, project
17
- use Adsf::Rack::IndexFileFinder, :root => project.output_dir
18
- run Rack::File.new(project.output_dir)
19
- end
20
- end
21
-
22
- def run(project)
23
- app = new(project)
24
- Rack::Handler.get("thin").run(app, :Port => 4321)
8
+ def new(project)
9
+ Rack::Builder.new do
10
+ use Rack::CommonLogger, project.logger
11
+ use Rack::ShowExceptions
12
+ use Rack::Lint
13
+ use Pith::Server::AutoBuild, project
14
+ use Adsf::Rack::IndexFileFinder, :root => project.output_dir
15
+ run Rack::File.new(project.output_dir)
25
16
  end
17
+ end
26
18
 
19
+ def run(project, options = {})
20
+ Rack::Handler.get("thin").run(new(project), options)
27
21
  end
28
22
 
23
+ extend self
24
+
29
25
  class AutoBuild
30
26
 
31
27
  def initialize(app, project)
data/lib/pith/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pith
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.3".freeze
3
3
  end
data/lib/pith/version.rb~ CHANGED
@@ -1,3 +1,3 @@
1
1
  module Pith
2
- VERSION = "0.0.2a".freeze
2
+ VERSION = "0.0.2".freeze
3
3
  end
data/lib/pith.rb~ CHANGED
@@ -1,2 +1 @@
1
- require 'pith/console_logger'
2
1
  require 'pith/project'
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <link href='stylesheets/app.css' rel='stylesheet' type='text/css' />
5
+ </head>
6
+ <body>
7
+ <ol class='tabs'>
8
+ <li><a href="index.html">Introduction</a></li>
9
+ </ol>
10
+ <div class='box'>
11
+ <p>This is my site. Do you like it?</p>
12
+ </div>
13
+ </body>
14
+ </html>
@@ -0,0 +1,38 @@
1
+ .sidebar {
2
+ width: 19%;
3
+ float: right; }
4
+
5
+ .main {
6
+ width: 79%; }
7
+
8
+ .box {
9
+ -moz-border-radius: 0.5em;
10
+ -webkit-border-radius: 0.5em;
11
+ border: 2px solid grey;
12
+ padding: 0.5em; }
13
+ .box .heading {
14
+ font-size: 120%;
15
+ border-bottom: 1px solid #aaaaaa;
16
+ font-weight: bold;
17
+ margin-bottom: 0.5em; }
18
+
19
+ ol.tabs {
20
+ position: relative;
21
+ padding: 0;
22
+ margin: 0 0 -2px 1em;
23
+ list-style-type: none; }
24
+ ol.tabs li {
25
+ display: inline-block;
26
+ border: 2px solid grey;
27
+ -moz-border-radius-topleft: 0.5em;
28
+ -webkit-border-top-left-radius: 0.5em;
29
+ -moz-border-radius-topright: 0.5em;
30
+ -webkit-border-top-right-radius: 0.5em;
31
+ background: #cccccc;
32
+ padding: 0.5em; }
33
+ ol.tabs li.current {
34
+ border-bottom: 2px solid white;
35
+ background: white; }
36
+ ol.tabs li a {
37
+ color: inherit;
38
+ text-decoration: none; }
@@ -1,8 +1,7 @@
1
- = include "_layouts/standard.haml" do
1
+ = inside "_layouts/standard.haml" do
2
2
 
3
3
  %ol.tabs
4
4
  %li= link "index.html", "Introduction"
5
5
 
6
6
  .box
7
7
  %p This is my site. Do you like it?
8
-
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require "pith/input/abstract"
3
+ require "pith/project"
4
+
5
+ describe Pith::Input::Abstract do
6
+
7
+ before do
8
+ $input_dir.mkpath
9
+ @project = Pith::Project.new(:input_dir => $input_dir)
10
+ @input_file = $input_dir + "some_page.html.haml"
11
+ @input_file.touch
12
+ end
13
+
14
+ describe "#title" do
15
+
16
+ it "is based on last component of filename" do
17
+ @project.input("some_page.html").title.should == "Some page"
18
+ end
19
+
20
+ it "can be over-ridden in metadata" do
21
+ @input_file.open("w") do |i|
22
+ i.puts "-# ---"
23
+ i.puts "-# title: Blah blah"
24
+ i.puts "-# ..."
25
+ end
26
+ @project.input("some_page.html").title.should == "Blah blah"
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require "pith/input/abstract"
3
+ require "pith/project"
4
+
5
+ describe Pith::Input::Abstract do
6
+
7
+ before do
8
+ $input_dir.mkpath
9
+ @project = Pith::Project.new(:input_dir => $input_dir)
10
+ @input_file = $input_dir + "some_page.html.haml"
11
+ @input_file.touch
12
+ end
13
+
14
+ describe "#title" do
15
+
16
+ it "is based on last component of filename" do
17
+ @project.input("some_page.html").title.should == "Some page"
18
+ end
19
+
20
+ it "can be over-ridden in metadata" do
21
+ @input_file.open("w") do |i|
22
+ i.puts "-# ---"
23
+ i.puts "-# title: Blah blah"
24
+ i.puts "-# ..."
25
+ end
26
+ @project.input("some_page.html").title.should == "Blah blah"
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -9,7 +9,7 @@ describe Pith::Metadata do
9
9
  Pith::Metadata.extract_from(StringIO.new(@input))
10
10
  end
11
11
 
12
- describe "with input containing no YAML metadata" do
12
+ describe "when input contains no YAML metadata" do
13
13
 
14
14
  before do
15
15
  @input = "%p Blah blah"
@@ -21,7 +21,7 @@ describe Pith::Metadata do
21
21
 
22
22
  end
23
23
 
24
- describe "with input containing YAML metadata" do
24
+ describe "when input contains YAML metadata" do
25
25
 
26
26
  before do
27
27
  @input = <<-HAML.gsub(/^ +/, '')
@@ -13,14 +13,14 @@ describe Pith::Project do
13
13
  describe "(with a non-template input path)" do
14
14
 
15
15
  before do
16
- @input_path = $input_dir + "input.txt"
17
- @input_path.touch
16
+ @input_file = $input_dir + "input.txt"
17
+ @input_file.touch
18
18
  end
19
19
 
20
20
  it "constructs an Verbatim object" do
21
21
  @input = @project.input("input.txt")
22
22
  @input.should be_kind_of(Pith::Input::Verbatim)
23
- @input.full_path.should == @input_path
23
+ @input.file.should == @input_file
24
24
  end
25
25
 
26
26
  it "returns the same Input output every time" do
@@ -34,14 +34,27 @@ describe Pith::Project do
34
34
  describe "(with a template input path)" do
35
35
 
36
36
  before do
37
- @input_path = $input_dir + "input.haml"
38
- @input_path.touch
37
+ @input_file = $input_dir + "input.html.haml"
38
+ @input_file.touch
39
39
  end
40
40
 
41
41
  it "constructs an Template object" do
42
- @input = @project.input("input.haml")
42
+ @input = @project.input("input.html.haml")
43
43
  @input.should be_kind_of(Pith::Input::Template)
44
- @input.full_path.should == @input_path
44
+ @input.file.should == @input_file
45
+ end
46
+
47
+ end
48
+
49
+ describe "(with a template ouput path)" do
50
+
51
+ before do
52
+ @input_file = $input_dir + "input.html.haml"
53
+ @input_file.touch
54
+ end
55
+
56
+ it "can also be used to locate the Template" do
57
+ @project.input("input.html").should == @project.input("input.html.haml")
45
58
  end
46
59
 
47
60
  end
@@ -51,7 +64,7 @@ describe Pith::Project do
51
64
  it "complains" do
52
65
  lambda do
53
66
  @project.input("bogus.path")
54
- end.should raise_error
67
+ end.should raise_error(Pith::ReferenceError)
55
68
  end
56
69
 
57
70
  end
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'pith/project'
3
+
4
+ describe Pith::Project do
5
+
6
+ before do
7
+ $input_dir.mkpath
8
+ @project = Pith::Project.new(:input_dir => $input_dir)
9
+ end
10
+
11
+ describe "#input" do
12
+
13
+ describe "(with a non-template input path)" do
14
+
15
+ before do
16
+ @input_file = $input_dir + "input.txt"
17
+ @input_file.touch
18
+ end
19
+
20
+ it "constructs an Verbatim object" do
21
+ @input = @project.input("input.txt")
22
+ @input.should be_kind_of(Pith::Input::Verbatim)
23
+ @input.file.should == @input_file
24
+ end
25
+
26
+ it "returns the same Input output every time" do
27
+ first_time = @project.input("input.txt")
28
+ second_time = @project.input("input.txt")
29
+ second_time.should equal(first_time)
30
+ end
31
+
32
+ end
33
+
34
+ describe "(with a template input path)" do
35
+
36
+ before do
37
+ @input_file = $input_dir + "input.html.haml"
38
+ @input_file.touch
39
+ end
40
+
41
+ it "constructs an Template object" do
42
+ @input = @project.input("input.html.haml")
43
+ @input.should be_kind_of(Pith::Input::Template)
44
+ @input.file.should == @input_file
45
+ end
46
+
47
+ end
48
+
49
+ describe "(with a template ouput path)" do
50
+
51
+ before do
52
+ @input_file = $input_dir + "input.html.haml"
53
+ @input_file.touch
54
+ end
55
+
56
+ it "can also be used to locate the Template" do
57
+ @project.input("input.html").should == @project.input("input.html.haml")
58
+ end
59
+
60
+ end
61
+
62
+ describe "(with an invalid input path)" do
63
+
64
+ it "complains" do
65
+ lambda do
66
+ @project.input("bogus.path")
67
+ end.should raise_error(Pith::ReferenceError)
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+ end