pith 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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