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
@@ -0,0 +1,120 @@
1
+ require "pathname"
2
+ require "pith/metadata"
3
+
4
+ module Pith
5
+ module Input
6
+
7
+ class Abstract
8
+
9
+ def initialize(project, path)
10
+ @project = project
11
+ @path = path
12
+ end
13
+
14
+ attr_reader :project, :path
15
+
16
+ # Public: Get the file-system location of this input.
17
+ #
18
+ # Returns a fully-qualified Pathname.
19
+ #
20
+ def file
21
+ project.input_dir + path
22
+ end
23
+
24
+ def output_file
25
+ project.output_dir + output_path
26
+ end
27
+
28
+ # Public: Get YAML metadata declared in the header of of a template.
29
+ #
30
+ # The first line of the template must end with "---". Any preceding characters
31
+ # are considered to be a comment prefix, and are stripped from the following
32
+ # lines. The metadata block ends when the comment block ends, or a line ending
33
+ # with "..." is encountered.
34
+ #
35
+ # Examples
36
+ #
37
+ # Given input starting with:
38
+ #
39
+ # -# ---
40
+ # -# published: 2008-09-15
41
+ # -# ...
42
+ #
43
+ # input.meta
44
+ # #=> { "published" => "2008-09-15" }
45
+ #
46
+ # Returns a Hash.
47
+ #
48
+ def meta
49
+ if @metadata.nil?
50
+ file.open do |io|
51
+ @metadata = Pith::Metadata.extract_from(io).freeze
52
+ end
53
+ end
54
+ @metadata
55
+ end
56
+
57
+ # Public: Get page title.
58
+ #
59
+ # The default title is based on the input file-name, sans-extension, capitalised,
60
+ # but can be overridden by providing a "title" in the metadata block.
61
+ #
62
+ # Examples
63
+ #
64
+ # input.path.to_s
65
+ # #=> "some_page.html.haml"
66
+ # input.title
67
+ # #=> "Some page"
68
+ #
69
+ def title
70
+ meta["title"] || default_title
71
+ end
72
+
73
+ # Public: Generate a corresponding output file.
74
+ #
75
+ def build
76
+ return false if ignorable? || uptodate?
77
+ logger.info("%-36s%-14s%s" % [path, "--(#{type})-->", output_path])
78
+ generate_output
79
+ end
80
+
81
+ # Public: Resolve a reference relative to this input.
82
+ #
83
+ # ref - a String referencing another asset
84
+ #
85
+ # A ref starting with "/" is resolved relative to the project root;
86
+ # anything else is resolved relative to this input.
87
+ #
88
+ # Returns a fully-qualified Pathname of the asset.
89
+ #
90
+ def resolve_path(ref)
91
+ ref = ref.to_str
92
+ if ref[0,1] == "/"
93
+ Pathname(ref[1..-1])
94
+ else
95
+ path.parent + ref
96
+ end
97
+ end
98
+
99
+ # Consider whether this input can be ignored.
100
+ #
101
+ # Returns true if it can.
102
+ #
103
+ def ignorable?
104
+ path.to_s.split("/").any? { |component| component.to_s[0,1] == "_" }
105
+ end
106
+
107
+ protected
108
+
109
+ def default_title
110
+ path.to_s.sub(/\..*/, '').tr('_-', ' ').capitalize
111
+ end
112
+
113
+ def logger
114
+ project.logger
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,120 @@
1
+ require "pathname"
2
+ require "pith/metadata"
3
+
4
+ module Pith
5
+ module Input
6
+
7
+ class Abstract
8
+
9
+ def initialize(project, path)
10
+ @project = project
11
+ @path = path
12
+ end
13
+
14
+ attr_reader :project, :path
15
+
16
+ # Public: Get the file-system location of this input.
17
+ #
18
+ # Returns a fully-qualified Pathname.
19
+ #
20
+ def file
21
+ project.input_dir + path
22
+ end
23
+
24
+ def output_file
25
+ project.output_dir + output_path
26
+ end
27
+
28
+ # Public: Get YAML metadata declared in the header of of a template.
29
+ #
30
+ # The first line of the template must end with "---". Any preceding characters
31
+ # are considered to be a comment prefix, and are stripped from the following
32
+ # lines. The metadata block ends when the comment block ends, or a line ending
33
+ # with "..." is encountered.
34
+ #
35
+ # Examples
36
+ #
37
+ # Given input starting with:
38
+ #
39
+ # -# ---
40
+ # -# published: 2008-09-15
41
+ # -# ...
42
+ #
43
+ # input.meta
44
+ # #=> { "published" => "2008-09-15" }
45
+ #
46
+ # Returns a Hash.
47
+ #
48
+ def meta
49
+ if @metadata.nil?
50
+ file.open do |io|
51
+ @metadata = Pith::Metadata.extract_from(io).freeze
52
+ end
53
+ end
54
+ @metadata
55
+ end
56
+
57
+ # Public: Get page title.
58
+ #
59
+ # The default title is based on the input file-name, sans-extension, capitalised,
60
+ # but can be overridden by providing a "title" in the metadata block.
61
+ #
62
+ # Examples
63
+ #
64
+ # input.path.to_s
65
+ # #=> "some_page.html.haml"
66
+ # input.title
67
+ # #=> "Some page"
68
+ #
69
+ def title
70
+ meta["title"] || default_title
71
+ end
72
+
73
+ # Public: Generate a corresponding output file.
74
+ #
75
+ def build
76
+ return false if ignorable? || uptodate?
77
+ logger.info("%-36s%-14s%s" % [path, "--(#{type})-->", output_path])
78
+ generate_output
79
+ end
80
+
81
+ # Public: Resolve a reference relative to this input.
82
+ #
83
+ # ref - a String referencing another asset
84
+ #
85
+ # A ref starting with "/" is resolved relative to the project root;
86
+ # anything else is resolved relative to this input.
87
+ #
88
+ # Returns a fully-qualified Pathname of the asset.
89
+ #
90
+ def resolve_path(ref)
91
+ ref = ref.to_str
92
+ if ref[0,1] == "/"
93
+ Pathname(ref[1..-1])
94
+ else
95
+ path.parent + ref
96
+ end
97
+ end
98
+
99
+ # Consider whether this input can be ignored.
100
+ #
101
+ # Returns true if it can.
102
+ #
103
+ def ignorable?
104
+ path.to_s.split("/").any? { |component| component.to_s[0,1] == "_" }
105
+ end
106
+
107
+ protected
108
+
109
+ def default_title
110
+ path.to_s.sub(/\..*/, '').tr('_-', ' ').capitalize
111
+ end
112
+
113
+ def logger
114
+ project.logger
115
+ end
116
+
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,56 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "pith/input/abstract"
4
+ require "pith/render_context"
5
+ require "tilt"
6
+
7
+ module Pith
8
+ module Input
9
+
10
+ class Template < Abstract
11
+
12
+ class UnrecognisedType < StandardError; end
13
+
14
+ def initialize(project, path)
15
+ super(project, path)
16
+ path.to_s =~ /^(.*)\.(.*)$/
17
+ @output_path = Pathname($1)
18
+ @type = $2
19
+ raise(UnrecognisedType, @type) unless Tilt.registered?(@type)
20
+ end
21
+
22
+ attr_reader :output_path, :type
23
+
24
+ def uptodate?
25
+ all_input_files && FileUtils.uptodate?(output_file, all_input_files)
26
+ end
27
+
28
+ # Generate output for this template
29
+ #
30
+ def generate_output
31
+ output_file.parent.mkpath
32
+ render_context = RenderContext.new(project)
33
+ output_file.open("w") do |out|
34
+ out.puts(render_context.render(self))
35
+ end
36
+ remember_dependencies(render_context.rendered_inputs)
37
+ end
38
+
39
+ # Render this input using Tilt
40
+ #
41
+ def render(context, locals = {}, &block)
42
+ Tilt.new(file).render(context, locals, &block)
43
+ end
44
+
45
+ private
46
+
47
+ def remember_dependencies(rendered_inputs)
48
+ @all_input_files = rendered_inputs.map { |input| input.file }
49
+ end
50
+
51
+ attr_accessor :all_input_files
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,46 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+ require "pith/input/abstract"
4
+ require "pith/render_context"
5
+
6
+ module Pith
7
+ module Input
8
+
9
+ class Template < Abstract
10
+
11
+ def initialize(project, path)
12
+ super(project, path)
13
+ path.to_s =~ /^(.*)\.(.*)$/
14
+ @output_path = Pathname($1)
15
+ @type = $2
16
+ end
17
+
18
+ attr_reader :output_path, :type
19
+
20
+ def uptodate?
21
+ all_input_files && FileUtils.uptodate?(output_file, all_input_files)
22
+ end
23
+
24
+ # Render this input using Tilt
25
+ #
26
+ def generate_output
27
+ output_file.parent.mkpath
28
+ render_context = RenderContext.new(project)
29
+ output_file.open("w") do |out|
30
+ out.puts(render_context.render_input(self))
31
+ end
32
+ remember_dependencies(render_context.rendered_inputs)
33
+ end
34
+
35
+ private
36
+
37
+ def remember_dependencies(rendered_inputs)
38
+ @all_input_files = rendered_inputs.map { |input| input.file }
39
+ end
40
+
41
+ attr_accessor :all_input_files
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ require "fileutils"
2
+ require "pith/input/abstract"
3
+
4
+ module Pith
5
+ module Input
6
+
7
+ class Verbatim < Abstract
8
+
9
+ def output_path
10
+ path
11
+ end
12
+
13
+ def type
14
+ "copy"
15
+ end
16
+
17
+ def uptodate?
18
+ FileUtils.uptodate?(output_file, [file])
19
+ end
20
+
21
+ # Copy this input verbatim into the output directory
22
+ #
23
+ def generate_output
24
+ output_file.parent.mkpath
25
+ FileUtils.copy(file, output_file)
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require "fileutils"
2
+ require "pith/input/abstract"
3
+
4
+ module Pith
5
+ module Input
6
+
7
+ class Verbatim < Abstract
8
+
9
+ def output_path
10
+ path
11
+ end
12
+
13
+ def type
14
+ "copy"
15
+ end
16
+
17
+ def uptodate?
18
+ FileUtils.uptodate?(output_file, [file])
19
+ end
20
+
21
+ # Copy this input verbatim into the output directory
22
+ #
23
+ def generate_output
24
+ output_file.parent.mkpath
25
+ FileUtils.copy(file, output_file)
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+ end
data/lib/pith/input.rb CHANGED
@@ -1,6 +1,5 @@
1
- require "pith/render_context"
2
- require "pith/metadata"
3
- require "fileutils"
1
+ require "pith/input/template"
2
+ require "pith/input/verbatim"
4
3
 
5
4
  module Pith
6
5
  module Input
@@ -8,182 +7,12 @@ module Pith
8
7
  class << self
9
8
 
10
9
  def new(project, path)
11
- if path.to_s =~ /^(.*)\.(.*)$/ && RenderContext.can_render?($2)
12
- Template.new(project, path)
13
- else
14
- Verbatim.new(project, path)
15
- end
10
+ Template.new(project, path)
11
+ rescue Template::UnrecognisedType
12
+ Verbatim.new(project, path)
16
13
  end
17
14
 
18
15
  end
19
16
 
20
- class Abstract
21
-
22
- def initialize(project, path)
23
- @project = project
24
- @path = path
25
- end
26
-
27
- attr_reader :project, :path
28
-
29
- # Public: Get the file-system location of this input.
30
- #
31
- # Returns a fully-qualified Pathname.
32
- #
33
- def full_path
34
- project.input_dir + path
35
- end
36
-
37
- # Public: Get YAML metadata declared in the header of of a template.
38
- #
39
- # The first line of the template must end with "---". Any preceding characters
40
- # are considered to be a comment prefix, and are stripped from the following
41
- # lines. The metadata block ends when the comment block ends, or a line ending
42
- # with "..." is encountered.
43
- #
44
- # Examples
45
- #
46
- # Given input starting with:
47
- #
48
- # -# ---
49
- # -# published: 2008-09-15
50
- # -# ...
51
- #
52
- # input.meta
53
- # #=> { "published" => "2008-09-15" }
54
- #
55
- # Returns a Hash.
56
- #
57
- def meta
58
- if @metadata.nil?
59
- full_path.open do |io|
60
- @metadata = Pith::Metadata.extract_from(io).freeze
61
- end
62
- end
63
- @metadata
64
- end
65
-
66
- # Public: Generate a corresponding output file.
67
- #
68
- # Returns the output Pathname.
69
- # Returns nil if no output was generated.
70
- #
71
- def build
72
- generate_output unless ignorable? || uptodate?
73
- end
74
-
75
- # Public: Resolve a reference relative to this input.
76
- #
77
- # href - a String referencing another asset
78
- #
79
- # An href starting with "/" is resolved relative to the project root;
80
- # anything else is resolved relative to this input.
81
- #
82
- # Returns a fully-qualified Pathname of the asset.
83
- #
84
- def relative_path(href)
85
- href = href.to_str
86
- if href[0,1] == "/"
87
- Pathname(href[1..-1])
88
- else
89
- path.parent + href
90
- end
91
- end
92
-
93
- # Resolve a reference relative to this input.
94
- #
95
- # href - a String referencing another asset
96
- #
97
- # Returns the referenced Input.
98
- #
99
- def relative_input(href)
100
- project.input(relative_path(href))
101
- end
102
-
103
- # Consider whether this input can be ignored.
104
- #
105
- # Returns true if it can.
106
- #
107
- def ignorable?
108
- path.to_s.split("/").any? { |component| component.to_s[0,1] == "_" }
109
- end
110
-
111
- protected
112
-
113
- def logger
114
- project.logger
115
- end
116
-
117
- def trace(strategy, output_path = nil)
118
- output_path ||= "X"
119
- logger.info("%-36s%-14s%s" % [path, "--(#{strategy})-->", output_path])
120
- end
121
-
122
- end
123
-
124
- class Template < Abstract
125
-
126
- def initialize(project, path)
127
- super(project, path)
128
- path.to_s =~ /^(.*)\.(.*)$/
129
- @output_path = $1
130
- @type = $2
131
- end
132
-
133
- attr_reader :output_path, :type
134
-
135
- def full_output_path
136
- project.output_dir + output_path
137
- end
138
-
139
- def uptodate?
140
- return false if all_input_paths.nil?
141
- FileUtils.uptodate?(full_output_path, all_input_paths)
142
- end
143
-
144
- # Render this input using Tilt
145
- #
146
- def generate_output
147
- trace(type, output_path)
148
- full_output_path.parent.mkpath
149
- render_context = RenderContext.new(project)
150
- full_output_path.open("w") do |out|
151
- out.puts(render_context.render(self))
152
- end
153
- remember_dependencies(render_context.rendered_inputs)
154
- end
155
-
156
- private
157
-
158
- def remember_dependencies(rendered_inputs)
159
- @all_input_paths = rendered_inputs.map { |input| input.full_path }
160
- end
161
-
162
- def all_input_paths
163
- @all_input_paths
164
- end
165
-
166
- end
167
-
168
- class Verbatim < Abstract
169
-
170
- def full_output_path
171
- project.output_dir + path
172
- end
173
-
174
- def uptodate?
175
- FileUtils.uptodate?(full_output_path, [full_path])
176
- end
177
-
178
- # Copy this input verbatim into the output directory
179
- #
180
- def generate_output
181
- trace("copy", path)
182
- full_output_path.parent.mkpath
183
- FileUtils.copy(full_path, full_output_path)
184
- end
185
-
186
- end
187
-
188
17
  end
189
18
  end
data/lib/pith/input.rb~ CHANGED
@@ -1,95 +1,20 @@
1
- require "tilt"
2
- require "pith/output_context"
3
- require "pith/metadata"
1
+ require "pith/input/template"
2
+ require "pith/input/verbatim"
4
3
 
5
4
  module Pith
6
-
7
- class Input
8
-
9
- def initialize(project, path)
10
- @project = project
11
- @path = path
12
- end
13
-
14
- attr_reader :project, :path
15
-
16
- def build
17
- ignore || evaluate_as_tilt_template || copy_verbatim
18
- end
19
-
20
- def relative_input(name)
21
- resolved_path = relative_path(name)
22
- input = project.inputs.find do |input|
23
- input.path == resolved_path
24
- end
25
- raise %{can't locate "#{resolved_path}"} if input.nil?
26
- input
27
- end
28
-
29
- def relative_path(name)
30
- name = name.to_str
31
- if name[0,1] == "/"
32
- Pathname(name[1..-1])
33
- else
34
- path.parent + name
35
- end
36
- end
37
-
38
- def render(context, locals = {}, &block)
39
- Tilt.new(full_path).render(context, locals, &block)
40
- end
5
+ module Input
41
6
 
42
- def meta
43
- if @metadata.nil?
44
- full_path.open do |io|
45
- @metadata = Pith::Metadata.extract_from(io).freeze
46
- end
47
- end
48
- @metadata
49
- end
50
-
51
- private
52
-
53
- def logger
54
- project.logger
55
- end
7
+ class << self
56
8
 
57
- def trace(strategy, output_path = nil)
58
- output_path ||= "X"
59
- logger.info("%-36s%-14s%s" % [path, "--(#{strategy})-->", output_path])
60
- end
61
-
62
- def full_path
63
- project.input_dir + path
64
- end
65
-
66
- def ignore
67
- path.to_s.split("/").any? { |component| component.to_s[0,1] == "_" }
68
- end
69
- alias :ignorable? :ignore
70
-
71
- def evaluate_as_tilt_template
72
- if path.to_s =~ /^(.*)\.(.*)$/ && Tilt.registered?($2)
73
- output_path = Pathname($1); ext = $2
74
- trace(ext, output_path)
75
- output_file = project.output_dir + output_path
76
- output_file.parent.mkpath
77
- output_file.open("w") do |out|
78
- output = render(RenderContext.new(self))
79
- out.puts(output)
9
+ def new(project, path)
10
+ if path.to_s =~ /^(.*)\.(.*)$/ && RenderContext.can_render?($2)
11
+ Template.new(project, path)
12
+ else
13
+ Verbatim.new(project, path)
80
14
  end
81
- output_file
82
15
  end
83
- end
84
16
 
85
- def copy_verbatim
86
- trace("copy", path)
87
- output_path = project.output_dir + path
88
- output_path.parent.mkpath
89
- FileUtils.copy(full_path, output_path)
90
- output_path
91
17
  end
92
18
 
93
19
  end
94
-
95
- end
20
+ end