plato 0.2.3 → 0.2.4
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.
- data/VERSION +1 -1
- data/lib/plato/headers_codec.rb +78 -0
- data/lib/plato/manifest.rb +13 -21
- data/lib/plato/rendering.rb +0 -10
- data/lib/plato/repo.rb +56 -151
- data/lib/plato/site.rb +67 -56
- data/lib/plato.rb +2 -1
- data/plato.gemspec +2 -1
- metadata +4 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.4
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Plato
|
2
|
+
module HeadersCodec
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def deflate(hash)
|
6
|
+
hash = stringify_keys(hash)
|
7
|
+
body = hash.delete('body')
|
8
|
+
|
9
|
+
[].tap do |buffer|
|
10
|
+
buffer << hash.map do |key, value|
|
11
|
+
"#{header_for(key)}: #{Sanitize.header(value)}"
|
12
|
+
end.join("\n")
|
13
|
+
|
14
|
+
buffer << "\n\n" << Sanitize.body(body) if body
|
15
|
+
buffer << "\n" unless buffer.last =~ /\n\Z/
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def inflate(string)
|
20
|
+
{}.tap do |result|
|
21
|
+
headers, body = string.split(/\n\n/, 2)
|
22
|
+
|
23
|
+
headers.split("\n").each do |line|
|
24
|
+
header, val = line.split(/:\s*/, 2)
|
25
|
+
|
26
|
+
result.update hash_key_for(header) => deserialize_value(val)
|
27
|
+
end
|
28
|
+
|
29
|
+
result['body'] = body.chomp if body
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def stringify_keys(hash)
|
36
|
+
hash.inject({}) {|h, (k, v)| h.update k.to_s => v }
|
37
|
+
end
|
38
|
+
|
39
|
+
def header_for(attr)
|
40
|
+
attr.to_s.gsub('_', ' ').gsub(/\b([a-z])/) {|m| m.capitalize }
|
41
|
+
end
|
42
|
+
|
43
|
+
def hash_key_for(header)
|
44
|
+
header.gsub(/\s+/, '_').downcase.to_s
|
45
|
+
end
|
46
|
+
|
47
|
+
def deserialize_value(val)
|
48
|
+
YAML.load(val) rescue val
|
49
|
+
end
|
50
|
+
|
51
|
+
module Sanitize
|
52
|
+
extend self
|
53
|
+
|
54
|
+
def header(header_val)
|
55
|
+
header_val.gsub(/(\r|\n)/) {|m| {"\r" => '\r', "\n" => '\n'}[m] }
|
56
|
+
end
|
57
|
+
|
58
|
+
def path_elem(elem)
|
59
|
+
elem.to_s.gsub(/\s+/, '_').gsub(/[^a-zA-Z0-9_-]/,'')
|
60
|
+
end
|
61
|
+
|
62
|
+
def body(body)
|
63
|
+
body # do we really need to do anything here?
|
64
|
+
end
|
65
|
+
|
66
|
+
def method_missing(method, value)
|
67
|
+
warn "Warning: not sanitizing #{method}."
|
68
|
+
value.to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def warn(warning)
|
74
|
+
$stderr.puts warning
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/plato/manifest.rb
CHANGED
@@ -2,27 +2,23 @@ module Plato
|
|
2
2
|
class Manifest
|
3
3
|
include Enumerable
|
4
4
|
|
5
|
-
attr_reader :contents
|
6
|
-
|
7
|
-
|
8
|
-
opts = { :codec => opts } unless opts.is_a? Hash
|
9
|
-
@codec = opts[:codec]
|
5
|
+
attr_reader :contents
|
6
|
+
alias to_h contents
|
7
|
+
alias to_hash contents
|
10
8
|
|
9
|
+
def initialize(contents = nil)
|
11
10
|
@contents =
|
12
11
|
if contents.nil?
|
13
12
|
{}
|
14
|
-
elsif contents.
|
15
|
-
contents
|
16
|
-
elsif contents.is_a? String
|
17
|
-
Repo.new(contents, @codec).all &opts[:filter]
|
13
|
+
elsif contents.respond_to? :to_hash
|
14
|
+
contents.to_hash
|
18
15
|
else
|
19
16
|
raise ArgumentError, "invalid contents"
|
20
17
|
end
|
21
18
|
end
|
22
19
|
|
23
|
-
def save_to(path
|
24
|
-
|
25
|
-
@contents.map {|path, hash| repo.save(path, hash); path }
|
20
|
+
def save_to(path)
|
21
|
+
Repo.new(path).set_all(contents)
|
26
22
|
end
|
27
23
|
|
28
24
|
def [](key)
|
@@ -36,18 +32,14 @@ module Plato
|
|
36
32
|
|
37
33
|
# if given a block, block should return a hash of the new path and
|
38
34
|
# new data, or nil if the file should be skipped
|
39
|
-
def map
|
35
|
+
def map
|
40
36
|
new_contents =
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
new_path_data ? hash.update(new_path_data) : hash
|
45
|
-
end
|
46
|
-
else
|
47
|
-
@contents.dup
|
37
|
+
@contents.inject({}) do |hash, (path, data)|
|
38
|
+
new_path_data = yield(path, data)
|
39
|
+
new_path_data ? hash.update(new_path_data) : hash
|
48
40
|
end
|
49
41
|
|
50
|
-
self.class.new(new_contents
|
42
|
+
self.class.new(new_contents)
|
51
43
|
end
|
52
44
|
|
53
45
|
def each(&block)
|
data/lib/plato/rendering.rb
CHANGED
@@ -74,14 +74,4 @@ module Plato
|
|
74
74
|
%{<script #{attribute_pairs(opts)}></script>}
|
75
75
|
end
|
76
76
|
end
|
77
|
-
|
78
|
-
class RubyTiltTemplate < Tilt::Template
|
79
|
-
def prepare; end
|
80
|
-
|
81
|
-
def precompiled_template(locals)
|
82
|
-
data
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
::Tilt.register('rb', RubyTiltTemplate)
|
87
77
|
end
|
data/lib/plato/repo.rb
CHANGED
@@ -2,33 +2,76 @@ require 'yaml'
|
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
4
|
module Plato
|
5
|
+
class FileObject
|
6
|
+
attr_reader :path, :data
|
7
|
+
|
8
|
+
def initialize(opts = {})
|
9
|
+
@path = opts[:path]
|
10
|
+
@data = opts[:data]
|
11
|
+
end
|
12
|
+
|
13
|
+
def data
|
14
|
+
@data ||= (File.read(@path) if @path)
|
15
|
+
end
|
16
|
+
alias read data
|
17
|
+
|
18
|
+
def write_to(to_path)
|
19
|
+
if @data
|
20
|
+
FileUtils.mkdir_p(File.dirname(to_path))
|
21
|
+
File.open(to_path, 'w') {|f| f.write(@data) }
|
22
|
+
elsif @path
|
23
|
+
FileUtils.mkdir_p(File.dirname(to_path))
|
24
|
+
FileUtils.cp(@path, to_path)
|
25
|
+
else
|
26
|
+
raise "cannot write out empty file object"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
5
31
|
class Repo
|
6
|
-
|
32
|
+
class NotFound < StandardError; end
|
7
33
|
|
8
|
-
|
34
|
+
attr_reader :root
|
9
35
|
|
10
|
-
def initialize(root
|
36
|
+
def initialize(root)
|
11
37
|
unless root == File.expand_path(root)
|
12
38
|
raise ArgumentError, "root is not an absolute path"
|
13
39
|
end
|
14
40
|
|
15
|
-
@codec = CODEC_MAP[codec] || StringCodec
|
16
41
|
@root = root.sub(/\/+\Z/, '') #remove trailing slash(es)
|
17
42
|
end
|
18
43
|
|
19
|
-
def
|
44
|
+
def get(path)
|
20
45
|
path = expanded_path(path)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
46
|
+
raise NotFound unless File.exist? path
|
47
|
+
|
48
|
+
FileObject.new(:path => path)
|
49
|
+
end
|
50
|
+
|
51
|
+
def set(path, data)
|
52
|
+
fo = data.respond_to?(:write_to) ?
|
53
|
+
data : FileObject.new(:data => data)
|
54
|
+
|
55
|
+
fo.write_to(expanded_path(path))
|
56
|
+
end
|
57
|
+
|
58
|
+
def all
|
59
|
+
paths = Dir[File.join(root, '**/*')].select {|e| File.file? e }
|
60
|
+
|
61
|
+
paths.inject({}) do |hash, path|
|
62
|
+
relative = relative_path(path)
|
63
|
+
hash.update relative => get(relative)
|
25
64
|
end
|
26
65
|
end
|
66
|
+
alias to_h all
|
67
|
+
alias to_hash all
|
27
68
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
69
|
+
def each(&block)
|
70
|
+
all.each(&block)
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_all(hash)
|
74
|
+
hash.each {|path, data| set(path, data) }
|
32
75
|
end
|
33
76
|
|
34
77
|
def destroy(path)
|
@@ -45,18 +88,6 @@ module Plato
|
|
45
88
|
end
|
46
89
|
end
|
47
90
|
|
48
|
-
def all
|
49
|
-
paths = Dir[File.join(root, '**/*')].select {|e| File.file? e }
|
50
|
-
|
51
|
-
if block_given?
|
52
|
-
paths = paths.select {|p| yield relative_path(p) }
|
53
|
-
end
|
54
|
-
|
55
|
-
paths.inject({}) do |hash, path|
|
56
|
-
hash.update relative_path(path) => load(path)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
91
|
private
|
61
92
|
|
62
93
|
def expanded_path(path)
|
@@ -68,131 +99,5 @@ module Plato
|
|
68
99
|
raise ArgumentError, "path must subpath of root" if relative == path
|
69
100
|
end
|
70
101
|
end
|
71
|
-
|
72
|
-
module RefCodec
|
73
|
-
extend self
|
74
|
-
|
75
|
-
def write(path, ref)
|
76
|
-
FileUtils.cp(ref, path)
|
77
|
-
end
|
78
|
-
|
79
|
-
def read(ref)
|
80
|
-
ref
|
81
|
-
end
|
82
|
-
end
|
83
|
-
CODEC_MAP[:refs] = RefCodec
|
84
|
-
|
85
|
-
module StringCodec
|
86
|
-
extend self
|
87
|
-
|
88
|
-
def write(path, data)
|
89
|
-
File.open(path, 'w') {|f| f.write data }
|
90
|
-
end
|
91
|
-
|
92
|
-
def read(path)
|
93
|
-
File.read(path)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
CODEC_MAP[:string] = StringCodec
|
97
|
-
|
98
|
-
module TemplateCodec
|
99
|
-
extend self
|
100
|
-
|
101
|
-
def read(path)
|
102
|
-
if template_class = Tilt[path]
|
103
|
-
template_class.new(path)
|
104
|
-
else
|
105
|
-
path
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
def write(path, data)
|
110
|
-
raise "Templates cannot be directly written"
|
111
|
-
end
|
112
|
-
end
|
113
|
-
CODEC_MAP[:template] = TemplateCodec
|
114
|
-
|
115
|
-
module HashCodec
|
116
|
-
extend StringCodec
|
117
|
-
extend self
|
118
|
-
|
119
|
-
def write(path, hash)
|
120
|
-
hash = stringify_keys(hash)
|
121
|
-
body = hash.delete('body')
|
122
|
-
|
123
|
-
data = [].tap do |buffer|
|
124
|
-
buffer << hash.map do |key, value|
|
125
|
-
"#{header_for(key)}: #{Sanitize.header(value)}"
|
126
|
-
end.join("\n")
|
127
|
-
|
128
|
-
buffer << "\n\n" << Sanitize.body(body) if body
|
129
|
-
buffer << "\n" unless buffer.last =~ /\n\Z/
|
130
|
-
end.join
|
131
|
-
|
132
|
-
super(path, data)
|
133
|
-
end
|
134
|
-
|
135
|
-
def read(path)
|
136
|
-
string = super
|
137
|
-
|
138
|
-
{}.tap do |result|
|
139
|
-
headers, body = string.split(/\n\n/, 2)
|
140
|
-
|
141
|
-
headers.split("\n").each do |line|
|
142
|
-
header, val = line.split(/:\s*/, 2)
|
143
|
-
|
144
|
-
result.update hash_key_for(header) => deserialize_value(val)
|
145
|
-
end
|
146
|
-
|
147
|
-
result['body'] = body.chomp if body
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
private
|
152
|
-
|
153
|
-
def stringify_keys(hash)
|
154
|
-
hash.inject({}) {|h, (k, v)| h.update k.to_s => v }
|
155
|
-
end
|
156
|
-
|
157
|
-
def header_for(attr)
|
158
|
-
attr.to_s.gsub('_', ' ').gsub(/\b([a-z])/) {|m| m.capitalize }
|
159
|
-
end
|
160
|
-
|
161
|
-
def hash_key_for(header)
|
162
|
-
header.gsub(/\s+/, '_').downcase.to_s
|
163
|
-
end
|
164
|
-
|
165
|
-
def deserialize_value(val)
|
166
|
-
YAML.load(val) rescue val
|
167
|
-
end
|
168
|
-
end
|
169
|
-
CODEC_MAP[:hash] = HashCodec
|
170
|
-
|
171
|
-
module Sanitize
|
172
|
-
extend self
|
173
|
-
|
174
|
-
def header(header_val)
|
175
|
-
header_val.gsub(/(\r|\n)/) {|m| {"\r" => '\r', "\n" => '\n'}[m] }
|
176
|
-
end
|
177
|
-
|
178
|
-
def path_elem(elem)
|
179
|
-
elem.to_s.gsub(/\s+/, '_').gsub(/[^a-zA-Z0-9_-]/,'')
|
180
|
-
end
|
181
|
-
|
182
|
-
def body(body)
|
183
|
-
body # do we really need to do anything here?
|
184
|
-
end
|
185
|
-
|
186
|
-
def method_missing(method, value)
|
187
|
-
warn "Warning: not sanitizing #{method}."
|
188
|
-
value.to_s
|
189
|
-
end
|
190
|
-
|
191
|
-
private
|
192
|
-
|
193
|
-
def warn(warning)
|
194
|
-
$stderr.puts warning
|
195
|
-
end
|
196
|
-
end
|
197
102
|
end
|
198
103
|
end
|
data/lib/plato/site.rb
CHANGED
@@ -14,29 +14,21 @@ module Plato
|
|
14
14
|
@config_path = File.join(@template_path, 'config.rb')
|
15
15
|
@content_path = File.join(@root)
|
16
16
|
@resources_path = File.join(@root, "resources")
|
17
|
-
end
|
18
17
|
|
19
|
-
|
20
|
-
RenderContext.load_view_helpers(File.join(template_path, 'view_helpers.rb'))
|
21
|
-
[ resources.save_to(cache_path),
|
22
|
-
template_resources.save_to(cache_path),
|
23
|
-
rendered_templates.save_to(cache_path),
|
24
|
-
rendered_content.save_to(cache_path)
|
25
|
-
].each do |ps|
|
26
|
-
puts ps.map{|s| " » #{File.join(cache_path,s)}" }
|
27
|
-
end
|
18
|
+
RenderContext.load_view_helpers(File.join(@template_path, 'view_helpers.rb'))
|
28
19
|
end
|
29
20
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
21
|
+
def generate!
|
22
|
+
[ ["resources", resources],
|
23
|
+
["template resources", template_resources],
|
24
|
+
["rendered templates", rendered_templates],
|
25
|
+
["rendered content", rendered_content]
|
26
|
+
].each do |(name, manifest)|
|
27
|
+
puts "## #{name}:"
|
28
|
+
manifest.save_to(cache_path)
|
29
|
+
manifest.to_h.keys.map{|p| File.join cache_path, p }.each do |path|
|
30
|
+
puts " #{path}"
|
31
|
+
end
|
40
32
|
end
|
41
33
|
end
|
42
34
|
|
@@ -45,46 +37,30 @@ module Plato
|
|
45
37
|
end
|
46
38
|
|
47
39
|
def templates
|
48
|
-
|
49
|
-
|
50
|
-
manifest = Manifest.new template_path, {
|
51
|
-
:codec => :template,
|
52
|
-
:filter => lambda {|p| p !~ /\A(config\.rb|view_helpers\.rb)/ }
|
53
|
-
}
|
54
|
-
|
55
|
-
path_parser = PathTemplate.new(":name*.:format.:engine")
|
56
|
-
sass_parser = PathTemplate.new(":name*.sass")
|
57
|
-
|
58
|
-
@template_resources = Manifest.new({}, :refs)
|
59
|
-
@templates = manifest.map do |path, template|
|
60
|
-
if template.is_a? String
|
61
|
-
# could not find a template engine, assume we're a raw resource
|
62
|
-
@template_resources[path] = template
|
63
|
-
nil
|
64
|
-
else
|
65
|
-
if match = path_parser.parse(path)
|
66
|
-
name, format = match.values_at("name", "format")
|
67
|
-
{ "#{name}.#{format}" => Template.new(template, format) }
|
68
|
-
else name = sass_parser.parse(path).values_at("name")
|
69
|
-
{ "#{name}.css" => Template.new(template, 'css') }
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
40
|
+
initialize_templates! unless @templates
|
41
|
+
@templates
|
73
42
|
end
|
74
43
|
|
44
|
+
def template_resources
|
45
|
+
initialize_templates! unless @templates
|
46
|
+
@template_resources
|
47
|
+
end
|
48
|
+
|
75
49
|
def content
|
76
50
|
return @content if @content
|
77
51
|
|
78
52
|
@content = config["content_categories"]
|
79
53
|
categories = @content.values
|
80
|
-
|
81
|
-
|
54
|
+
content_repos = @content.keys.map do |c|
|
55
|
+
Repo.new(File.join(content_path, c))
|
82
56
|
end
|
83
57
|
|
84
|
-
|
85
|
-
|
58
|
+
content_repos.each do |repo|
|
59
|
+
repo.each do |path, file|
|
86
60
|
if category = categories.find {|c| c.match path }
|
87
|
-
data = category.match(path).merge(
|
61
|
+
data = category.match(path).merge(
|
62
|
+
HeadersCodec.inflate(file.read)
|
63
|
+
)
|
88
64
|
|
89
65
|
category.documents << Document.new(category, data)
|
90
66
|
end
|
@@ -94,16 +70,51 @@ module Plato
|
|
94
70
|
@content
|
95
71
|
end
|
96
72
|
|
97
|
-
def
|
98
|
-
|
99
|
-
@template_resources
|
73
|
+
def resources
|
74
|
+
@resources ||= Manifest.new(Repo.new(resources_path))
|
100
75
|
end
|
101
76
|
|
102
|
-
|
103
|
-
|
77
|
+
DETECT_EXT = /(?:(.*)\/)?([^\/]+)\.([^.]+)\Z/
|
78
|
+
def detect_zip_path(path)
|
79
|
+
path = "#{path}.zip" if !File.exist? path and File.exist? "#{path}.zip"
|
80
|
+
|
81
|
+
if File.exist? path and !File.directory? path and path.match(DETECT_EXT)
|
82
|
+
dir, base, ext = path.match(DETECT_EXT).values_at(1,2,3)
|
83
|
+
|
84
|
+
[dir, "#{base}.#{ext}!", base].compact.join("/")
|
85
|
+
else
|
86
|
+
path
|
87
|
+
end
|
104
88
|
end
|
105
89
|
|
90
|
+
def initialize_templates!
|
91
|
+
path_parser = PathTemplate.new(":name*.:format.:engine")
|
92
|
+
sass_parser = PathTemplate.new(":name*.sass")
|
93
|
+
|
94
|
+
@template_resources = Manifest.new
|
95
|
+
@templates = {}
|
96
|
+
|
97
|
+
Repo.new(template_path).each do |path, file|
|
98
|
+
next if path =~ /\A(config\.rb|view_helpers\.rb)/
|
99
|
+
|
100
|
+
if tilt_class = Tilt[path]
|
101
|
+
tilt = tilt_class.new(File.join(template_path, path))
|
106
102
|
|
103
|
+
if match = path_parser.parse(path)
|
104
|
+
name, format = match.values_at("name", "format")
|
105
|
+
@templates["#{name}.#{format}"] = Template.new(tilt, format)
|
106
|
+
|
107
|
+
else name = sass_parser.parse(path).values_at("name")
|
108
|
+
@templates["#{name}.css"] = Template.new(tilt, 'css')
|
109
|
+
end
|
110
|
+
else
|
111
|
+
# could not find a template engine, assume we're a raw resource
|
112
|
+
@template_resources[path] = file
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
107
118
|
# helpers
|
108
119
|
|
109
120
|
Template = Struct.new(:renderer, :format)
|
@@ -117,7 +128,7 @@ module Plato
|
|
117
128
|
end
|
118
129
|
|
119
130
|
def rendered_templates
|
120
|
-
templates.map
|
131
|
+
Manifest.new(templates).map do |path, template|
|
121
132
|
if path !~ /\A_/
|
122
133
|
{ path => render(template, template.format, nil) }
|
123
134
|
end
|
data/lib/plato.rb
CHANGED
@@ -4,9 +4,10 @@ require 'ruby_archive'
|
|
4
4
|
module Plato
|
5
5
|
require 'plato/config'
|
6
6
|
require 'plato/document'
|
7
|
+
require 'plato/headers_codec'
|
7
8
|
require 'plato/manifest'
|
8
9
|
require 'plato/path_template'
|
9
|
-
require 'plato/repo'
|
10
10
|
require 'plato/rendering'
|
11
|
+
require 'plato/repo'
|
11
12
|
require 'plato/site'
|
12
13
|
end
|
data/plato.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{plato}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Matt Freels"]
|
@@ -23,6 +23,7 @@ Gem::Specification.new do |s|
|
|
23
23
|
"lib/plato.rb",
|
24
24
|
"lib/plato/config.rb",
|
25
25
|
"lib/plato/document.rb",
|
26
|
+
"lib/plato/headers_codec.rb",
|
26
27
|
"lib/plato/manifest.rb",
|
27
28
|
"lib/plato/path_template.rb",
|
28
29
|
"lib/plato/rendering.rb",
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plato
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 4
|
10
|
+
version: 0.2.4
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matt Freels
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- lib/plato.rb
|
98
98
|
- lib/plato/config.rb
|
99
99
|
- lib/plato/document.rb
|
100
|
+
- lib/plato/headers_codec.rb
|
100
101
|
- lib/plato/manifest.rb
|
101
102
|
- lib/plato/path_template.rb
|
102
103
|
- lib/plato/rendering.rb
|