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 CHANGED
@@ -1 +1 @@
1
- 0.2.3
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
@@ -2,27 +2,23 @@ module Plato
2
2
  class Manifest
3
3
  include Enumerable
4
4
 
5
- attr_reader :contents, :codec
6
-
7
- def initialize(contents = nil, opts = {})
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.is_a? Hash
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, codec = nil)
24
- repo = Repo.new(path, codec || self.codec)
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(new_codec = nil)
35
+ def map
40
36
  new_contents =
41
- if block_given?
42
- @contents.inject({}) do |hash, (path, data)|
43
- new_path_data = yield(path, data)
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, new_codec || self.codec)
42
+ self.class.new(new_contents)
51
43
  end
52
44
 
53
45
  def each(&block)
@@ -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
- attr_reader :root, :codec
32
+ class NotFound < StandardError; end
7
33
 
8
- CODEC_MAP = {}
34
+ attr_reader :root
9
35
 
10
- def initialize(root, codec = nil)
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 load(path)
44
+ def get(path)
20
45
  path = expanded_path(path)
21
- if File.exist? path
22
- @codec.read(path)
23
- else
24
- raise Filestore::NotFound
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 save(path, data)
29
- path = expanded_path(path)
30
- FileUtils.mkdir_p(File.dirname(path))
31
- @codec.write(path, data)
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
- def generate!
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
- DETECT_EXT = /(?:(.*)\/)?([^\/]+)\.([^.]+)\Z/
31
- def detect_zip_path(path)
32
- path = "#{path}.zip" if !File.exist? path and File.exist? "#{path}.zip"
33
-
34
- if File.exist? path and !File.directory? path and path.match(DETECT_EXT)
35
- dir, base, ext = path.match(DETECT_EXT).values_at(1,2,3)
36
-
37
- [dir, "#{base}.#{ext}!", base].compact.join("/")
38
- else
39
- path
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
- return @templates if @templates
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
- content_manifests = @content.keys.map do |c|
81
- Manifest.new(File.join(content_path, c), :hash)
54
+ content_repos = @content.keys.map do |c|
55
+ Repo.new(File.join(content_path, c))
82
56
  end
83
57
 
84
- content_manifests.each do |manifest|
85
- manifest.each do |path, content_data|
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(content_data)
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 template_resources
98
- templates unless @templates
99
- @template_resources
73
+ def resources
74
+ @resources ||= Manifest.new(Repo.new(resources_path))
100
75
  end
101
76
 
102
- def resources
103
- @resources ||= Manifest.new(resources_path, :refs)
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(:string) do |path, template|
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.3"
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: 17
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 3
10
- version: 0.2.3
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