utopia 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 944c3e8fb35114656d9bf4f5628d6c4ecf569015
4
- data.tar.gz: b34c396bc981f396faee6d49ace329141d3c5d20
3
+ metadata.gz: 45aef2de7e3895af0d07047f106c870ddf6f52a9
4
+ data.tar.gz: c44105d12552392fc82e952e1084cc56f563e5cc
5
5
  SHA512:
6
- metadata.gz: 969bb2a0804488b5f72ea3b1d5652a5219cd1f865a6e3652dcb3bd0794f67de48b1d0ddaf8f2df4796ccc396b92b85d0205ed1e8c800528857b3edb28de22a42
7
- data.tar.gz: '022596c8e3262206412bd534e3c78fbeb127f310081381971e2567e51a42a7af91b6a64d60bb78226b940280fe0e274787c98352462081bcfc3c3edf76f2ac09'
6
+ metadata.gz: 84bcd1fde7888daeae19321e11eae4cddf9ad83968994e12f838f1972387b6aee51612a2ba642f449bbeecb0364b014983c75020f7be045bfac1bd25a7d2f9a0
7
+ data.tar.gz: 9da83f29130302129c6d4928bf621d9db153b3ae937b5dc428e9266ba32d6dac125562ff1500e9705884b2b9e6b3303a900ae43e8ca123a3dc862744fc6ef785
@@ -69,6 +69,7 @@ module Utopia
69
69
  # Copy git hooks:
70
70
  system("cp", "-r", File.join(Setup::Server::ROOT, 'git', 'hooks'), File.join(destination_root, '.git')) or fail "could not copy git hooks"
71
71
  # finally set everything in the .git directory to be group writable
72
+ # This failed for me and I had to do sudo chown http:http .git -R first.
72
73
  system("chmod", "-Rf", "g+w", File.join(destination_root, '.git')) or fail "could not update permissions of .git directory"
73
74
  end
74
75
  end
@@ -54,7 +54,8 @@ module Utopia
54
54
 
55
55
  # Named:
56
56
  if name = options[:name]
57
- ordered.select!{|link| link.name[name]}
57
+ # We use pattern === name, which matches either the whole string, or matches a regexp.
58
+ ordered.select!{|link| name === link.name}
58
59
  end
59
60
 
60
61
  if locale = options[:locale]
@@ -155,7 +156,7 @@ module Utopia
155
156
  end
156
157
 
157
158
  def indices(path, &block)
158
- Dir.entries(path).reject{|filename| !filename.match(INDEX_XNODE_FILTER)}
159
+ Dir.entries(path).select{|filename| filename.match(INDEX_XNODE_FILTER)}
159
160
  end
160
161
 
161
162
  def load_indices(name, path, metadata)
@@ -21,202 +21,12 @@
21
21
  require_relative 'middleware'
22
22
  require_relative 'localization'
23
23
 
24
- require 'time'
25
-
26
- require 'digest/sha1'
27
- require 'mime/types'
24
+ require_relative 'static/local_file'
25
+ require_relative 'static/mime_types'
28
26
 
29
27
  module Utopia
30
28
  # A middleware which serves static files from the specified root directory.
31
29
  class Static
32
- # Default mime-types which are common for files served over HTTP:
33
- MIME_TYPES = {
34
- :xiph => {
35
- "ogx" => "application/ogg",
36
- "ogv" => "video/ogg",
37
- "oga" => "audio/ogg",
38
- "ogg" => "audio/ogg",
39
- "spx" => "audio/ogg",
40
- "flac" => "audio/flac",
41
- "anx" => "application/annodex",
42
- "axa" => "audio/annodex",
43
- "xspf" => "application/xspf+xml",
44
- },
45
- :media => [
46
- :xiph, "mp3", "mp4", "wav", "aiff", ["aac", "audio/x-aac"], "mov", "avi", "wmv", "mpg"
47
- ],
48
- :text => [
49
- "html", "css", "js", ["map", "application/json"], "txt", "rtf", "xml", "pdf"
50
- ],
51
- :fonts => [
52
- "otf", ["eot", "application/vnd.ms-fontobject"], "ttf", "woff"
53
- ],
54
- :archive => [
55
- "zip", "tar", "tgz", "tar.gz", "tar.bz2", ["dmg", "application/x-apple-diskimage"],
56
- ["torrent", "application/x-bittorrent"]
57
- ],
58
- :images => [
59
- "png", "gif", "jpeg", "tiff", "svg"
60
- ],
61
- :default => [
62
- :media, :text, :archive, :images, :fonts
63
- ]
64
- }
65
-
66
- # A class to assist with loading mime-type metadata.
67
- class MimeTypeLoader
68
- def initialize(library)
69
- @extensions = {}
70
- @library = library
71
- end
72
-
73
- attr :extensions
74
-
75
- def self.extensions_for(types, library = MIME_TYPES)
76
- loader = self.new(library)
77
- loader.expand(types)
78
- return loader.extensions
79
- end
80
-
81
- def extract_extensions(mime_types)
82
- mime_types.select{|mime_type| !mime_type.obsolete?}.each do |mime_type|
83
- mime_type.extensions.each do |ext|
84
- @extensions["." + ext] = mime_type.content_type
85
- end
86
- end
87
- end
88
-
89
- class ExpansionError < ArgumentError
90
- end
91
-
92
- def expand(types)
93
- types.each do |type|
94
- current_count = @extensions.size
95
-
96
- begin
97
- case type
98
- when Symbol
99
- self.expand(MIME_TYPES[type])
100
- when Array
101
- @extensions["." + type[0]] = type[1]
102
- when String
103
- self.extract_extensions MIME::Types.of(type)
104
- when Regexp
105
- self.extract_extensions MIME::Types[type]
106
- when MIME::Type
107
- self.extract_extensions.call([type])
108
- end
109
- rescue
110
- raise ExpansionError.new("#{self.class.name}: Error while processing #{type.inspect}!")
111
- end
112
-
113
- if @extensions.size == current_count
114
- raise ExpansionError.new("#{self.class.name}: Could not find any mime type for #{type.inspect}")
115
- end
116
- end
117
- end
118
- end
119
-
120
- private
121
-
122
- # Represents a local file on disk which can be served directly, or passed upstream to sendfile.
123
- class LocalFile
124
- def initialize(root, path)
125
- @root = root
126
- @path = path
127
- @etag = Digest::SHA1.hexdigest("#{File.size(full_path)}#{mtime_date}")
128
-
129
- @range = nil
130
- end
131
-
132
- attr :root
133
- attr :path
134
- attr :etag
135
- attr :range
136
-
137
- # Fit in with Rack::Sendfile
138
- def to_path
139
- full_path
140
- end
141
-
142
- def full_path
143
- File.join(@root, @path.components)
144
- end
145
-
146
- def mtime_date
147
- File.mtime(full_path).httpdate
148
- end
149
-
150
- def bytesize
151
- File.size(full_path)
152
- end
153
-
154
- # This reflects whether calling each would yield anything.
155
- def empty?
156
- bytesize == 0
157
- end
158
-
159
- alias size bytesize
160
-
161
- def each
162
- File.open(full_path, "rb") do |file|
163
- file.seek(@range.begin)
164
- remaining = @range.end - @range.begin+1
165
-
166
- while remaining > 0
167
- break unless part = file.read([8192, remaining].min)
168
-
169
- remaining -= part.length
170
-
171
- yield part
172
- end
173
- end
174
- end
175
-
176
- def modified?(env)
177
- if modified_since = env['HTTP_IF_MODIFIED_SINCE']
178
- return false if File.mtime(full_path) <= Time.parse(modified_since)
179
- end
180
-
181
- if etags = env['HTTP_IF_NONE_MATCH']
182
- etags = etags.split(/\s*,\s*/)
183
- return false if etags.include?(etag) || etags.include?('*')
184
- end
185
-
186
- return true
187
- end
188
-
189
- CONTENT_LENGTH = Rack::CONTENT_LENGTH
190
- CONTENT_RANGE = 'Content-Range'.freeze
191
-
192
- def serve(env, response_headers)
193
- ranges = Rack::Utils.get_byte_ranges(env['HTTP_RANGE'], size)
194
- response = [200, response_headers, self]
195
-
196
- # puts "Requesting ranges: #{ranges.inspect} (#{size})"
197
-
198
- if ranges == nil or ranges.size != 1
199
- # No ranges, or multiple ranges (which we don't support).
200
- # TODO: Support multiple byte-ranges, for now just send entire file:
201
- response[0] = 200
202
- response[1][CONTENT_LENGTH] = size.to_s
203
- @range = 0...size
204
- else
205
- # Partial content:
206
- @range = ranges[0]
207
- partial_size = @range.count
208
-
209
- response[0] = 206
210
- response[1][CONTENT_LENGTH] = partial_size.to_s
211
- response[1][CONTENT_RANGE] = "bytes #{@range.min}-#{@range.max}/#{size}"
212
- end
213
-
214
- return response
215
- end
216
- end
217
-
218
- public
219
-
220
30
  DEFAULT_CACHE_CONTROL = 'public, max-age=3600'.freeze
221
31
 
222
32
  # @param root [String] The root directory to serve files from.
@@ -0,0 +1,123 @@
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'time'
22
+ require 'digest/sha1'
23
+
24
+ module Utopia
25
+ # A middleware which serves static files from the specified root directory.
26
+ class Static
27
+ # Represents a local file on disk which can be served directly, or passed upstream to sendfile.
28
+ class LocalFile
29
+ def initialize(root, path)
30
+ @root = root
31
+ @path = path
32
+ @etag = Digest::SHA1.hexdigest("#{File.size(full_path)}#{mtime_date}")
33
+
34
+ @range = nil
35
+ end
36
+
37
+ attr :root
38
+ attr :path
39
+ attr :etag
40
+ attr :range
41
+
42
+ # Fit in with Rack::Sendfile
43
+ def to_path
44
+ full_path
45
+ end
46
+
47
+ def full_path
48
+ File.join(@root, @path.components)
49
+ end
50
+
51
+ def mtime_date
52
+ File.mtime(full_path).httpdate
53
+ end
54
+
55
+ def bytesize
56
+ File.size(full_path)
57
+ end
58
+
59
+ # This reflects whether calling each would yield anything.
60
+ def empty?
61
+ bytesize == 0
62
+ end
63
+
64
+ alias size bytesize
65
+
66
+ def each
67
+ File.open(full_path, "rb") do |file|
68
+ file.seek(@range.begin)
69
+ remaining = @range.end - @range.begin+1
70
+
71
+ while remaining > 0
72
+ break unless part = file.read([8192, remaining].min)
73
+
74
+ remaining -= part.length
75
+
76
+ yield part
77
+ end
78
+ end
79
+ end
80
+
81
+ def modified?(env)
82
+ if modified_since = env['HTTP_IF_MODIFIED_SINCE']
83
+ return false if File.mtime(full_path) <= Time.parse(modified_since)
84
+ end
85
+
86
+ if etags = env['HTTP_IF_NONE_MATCH']
87
+ etags = etags.split(/\s*,\s*/)
88
+ return false if etags.include?(etag) || etags.include?('*')
89
+ end
90
+
91
+ return true
92
+ end
93
+
94
+ CONTENT_LENGTH = Rack::CONTENT_LENGTH
95
+ CONTENT_RANGE = 'Content-Range'.freeze
96
+
97
+ def serve(env, response_headers)
98
+ ranges = Rack::Utils.get_byte_ranges(env['HTTP_RANGE'], size)
99
+ response = [200, response_headers, self]
100
+
101
+ # puts "Requesting ranges: #{ranges.inspect} (#{size})"
102
+
103
+ if ranges == nil or ranges.size != 1
104
+ # No ranges, or multiple ranges (which we don't support).
105
+ # TODO: Support multiple byte-ranges, for now just send entire file:
106
+ response[0] = 200
107
+ response[1][CONTENT_LENGTH] = size.to_s
108
+ @range = 0...size
109
+ else
110
+ # Partial content:
111
+ @range = ranges[0]
112
+ partial_size = @range.count
113
+
114
+ response[0] = 206
115
+ response[1][CONTENT_LENGTH] = partial_size.to_s
116
+ response[1][CONTENT_RANGE] = "bytes #{@range.min}-#{@range.max}/#{size}"
117
+ end
118
+
119
+ return response
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,114 @@
1
+ # Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'mime/types'
22
+
23
+ module Utopia
24
+ # A middleware which serves static files from the specified root directory.
25
+ class Static
26
+ # Default mime-types which are common for files served over HTTP:
27
+ MIME_TYPES = {
28
+ :xiph => {
29
+ "ogx" => "application/ogg",
30
+ "ogv" => "video/ogg",
31
+ "oga" => "audio/ogg",
32
+ "ogg" => "audio/ogg",
33
+ "spx" => "audio/ogg",
34
+ "flac" => "audio/flac",
35
+ "anx" => "application/annodex",
36
+ "axa" => "audio/annodex",
37
+ "xspf" => "application/xspf+xml",
38
+ },
39
+ :media => [
40
+ :xiph, "mp3", "mp4", "wav", "aiff", ["aac", "audio/x-aac"], "mov", "avi", "wmv", "mpg"
41
+ ],
42
+ :text => [
43
+ "html", "css", "js", ["map", "application/json"], "txt", "rtf", "xml", "pdf"
44
+ ],
45
+ :fonts => [
46
+ "otf", ["eot", "application/vnd.ms-fontobject"], "ttf", "woff"
47
+ ],
48
+ :archive => [
49
+ "zip", "tar", "tgz", "tar.gz", "tar.bz2", ["dmg", "application/x-apple-diskimage"],
50
+ ["torrent", "application/x-bittorrent"]
51
+ ],
52
+ :images => [
53
+ "png", "gif", "jpeg", "tiff", "svg"
54
+ ],
55
+ :default => [
56
+ :media, :text, :archive, :images, :fonts
57
+ ]
58
+ }
59
+
60
+ # A class to assist with loading mime-type metadata.
61
+ class MimeTypeLoader
62
+ def initialize(library)
63
+ @extensions = {}
64
+ @library = library
65
+ end
66
+
67
+ attr :extensions
68
+
69
+ def self.extensions_for(types, library = MIME_TYPES)
70
+ loader = self.new(library)
71
+ loader.expand(types)
72
+ return loader.extensions
73
+ end
74
+
75
+ def extract_extensions(mime_types)
76
+ mime_types.select{|mime_type| !mime_type.obsolete?}.each do |mime_type|
77
+ mime_type.extensions.each do |ext|
78
+ @extensions["." + ext] = mime_type.content_type
79
+ end
80
+ end
81
+ end
82
+
83
+ class ExpansionError < ArgumentError
84
+ end
85
+
86
+ def expand(types)
87
+ types.each do |type|
88
+ current_count = @extensions.size
89
+
90
+ begin
91
+ case type
92
+ when Symbol
93
+ self.expand(MIME_TYPES[type])
94
+ when Array
95
+ @extensions["." + type[0]] = type[1]
96
+ when String
97
+ self.extract_extensions MIME::Types.of(type)
98
+ when Regexp
99
+ self.extract_extensions MIME::Types[type]
100
+ when MIME::Type
101
+ self.extract_extensions.call([type])
102
+ end
103
+ rescue
104
+ raise ExpansionError.new("#{self.class.name}: Error while processing #{type.inspect}!")
105
+ end
106
+
107
+ if @extensions.size == current_count
108
+ raise ExpansionError.new("#{self.class.name}: Could not find any mime type for #{type.inspect}")
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -19,5 +19,5 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  module Utopia
22
- VERSION = "2.0.0"
22
+ VERSION = "2.0.1"
23
23
  end
@@ -22,64 +22,80 @@
22
22
 
23
23
  require 'utopia/content/links'
24
24
 
25
- module Utopia::Content::LinksSpec
26
- describe Utopia::Content::Links do
27
- it "should give a list of links" do
28
- links = Utopia::Content::Links.index(File.expand_path("links", __dir__), Utopia::Path.create("/"))
29
-
30
- expect(links.size).to be == 3
31
-
32
- expect(links[0].kind).to be == :virtual
33
- expect(links[0].href).to be == nil
34
-
35
- expect(links[1].title).to be == "Welcome"
36
- expect(links[1].to_href).to be == '<a class="link" href="/welcome">Welcome</a>'
37
- expect(links[1].kind).to be == :file
38
- expect(links[1].href).to be == "/welcome"
39
- expect(links[1].name).to be == 'welcome'
40
-
41
- expect(links[2].title).to be == 'Foo Bar'
42
- expect(links[2].kind).to be == :directory
43
- expect(links[2].href).to be == "/foo/index"
44
- expect(links[2].name).to be == 'foo'
45
-
46
- expect(links[1]).to be_eql links[1]
47
- expect(links[0]).to_not be_eql links[1]
48
- end
25
+ RSpec.describe Utopia::Content::Links do
26
+ describe 'INDEX_XNODE_FILTER' do
27
+ subject{Utopia::Content::Links::INDEX_XNODE_FILTER}
49
28
 
50
- it "should filter links by name" do
51
- links = Utopia::Content::Links.index(File.expand_path("links", __dir__), Utopia::Path.create("/"), name: /foo/)
52
-
53
- expect(links.size).to be == 1
29
+ it "should match index" do
30
+ expect("index.xnode").to match(subject)
54
31
  end
55
32
 
56
- it "should select localized links" do
57
- root = File.expand_path("links", __dir__)
58
-
59
- # Select both test links
60
- links = Utopia::Content::Links.index(root, Utopia::Path.create("/foo"))
61
- expect(links.size).to be == 2
62
-
63
- links = Utopia::Content::Links.index(root, Utopia::Path.create("/foo"), locale: 'en')
64
- expect(links.size).to be == 1
33
+ it "should not match invalid index" do
34
+ expect("old-index.xnode").to_not match(subject)
65
35
  end
36
+ end
37
+
38
+ it "should not match partial strings" do
39
+ links = Utopia::Content::Links.index(File.expand_path("links", __dir__), Utopia::Path.create("/"), name: "come")
66
40
 
67
- it "should read correct link order for en" do
68
- root = File.expand_path("localized", __dir__)
69
-
70
- # Select both test links
71
- links = Utopia::Content::Links.index(root, Utopia::Path.create("/"), locale: 'en')
72
-
73
- expect(links.collect(&:title)).to be == ['One', 'Two', 'Three', 'Four', 'Five']
74
- end
41
+ expect(links).to be_empty
42
+ end
43
+
44
+ it "should give a list of links" do
45
+ links = Utopia::Content::Links.index(File.expand_path("links", __dir__), Utopia::Path.create("/"))
75
46
 
76
- it "should read correct link order for zh" do
77
- root = File.expand_path("localized", __dir__)
78
-
79
- # Select both test links
80
- links = Utopia::Content::Links.index(root, Utopia::Path.create("/"), locale: 'zh')
81
-
82
- expect(links.collect(&:title)).to be == ['One', 'Two', 'Three', '四']
83
- end
47
+ expect(links.size).to be == 3
48
+
49
+ expect(links[0].kind).to be == :virtual
50
+ expect(links[0].href).to be == nil
51
+
52
+ expect(links[1].title).to be == "Welcome"
53
+ expect(links[1].to_href).to be == '<a class="link" href="/welcome">Welcome</a>'
54
+ expect(links[1].kind).to be == :file
55
+ expect(links[1].href).to be == "/welcome"
56
+ expect(links[1].name).to be == 'welcome'
57
+
58
+ expect(links[2].title).to be == 'Foo Bar'
59
+ expect(links[2].kind).to be == :directory
60
+ expect(links[2].href).to be == "/foo/index"
61
+ expect(links[2].name).to be == 'foo'
62
+
63
+ expect(links[1]).to be_eql links[1]
64
+ expect(links[0]).to_not be_eql links[1]
65
+ end
66
+
67
+ it "should filter links by name" do
68
+ links = Utopia::Content::Links.index(File.expand_path("links", __dir__), Utopia::Path.create("/"), name: /foo/)
69
+
70
+ expect(links.size).to be == 1
71
+ end
72
+
73
+ it "should select localized links" do
74
+ root = File.expand_path("links", __dir__)
75
+
76
+ # Select both test links
77
+ links = Utopia::Content::Links.index(root, Utopia::Path.create("/foo"))
78
+ expect(links.size).to be == 2
79
+
80
+ links = Utopia::Content::Links.index(root, Utopia::Path.create("/foo"), locale: 'en')
81
+ expect(links.size).to be == 1
82
+ end
83
+
84
+ it "should read correct link order for en" do
85
+ root = File.expand_path("localized", __dir__)
86
+
87
+ # Select both test links
88
+ links = Utopia::Content::Links.index(root, Utopia::Path.create("/"), locale: 'en')
89
+
90
+ expect(links.collect(&:title)).to be == ['One', 'Two', 'Three', 'Four', 'Five']
91
+ end
92
+
93
+ it "should read correct link order for zh" do
94
+ root = File.expand_path("localized", __dir__)
95
+
96
+ # Select both test links
97
+ links = Utopia::Content::Links.index(root, Utopia::Path.create("/"), locale: 'zh')
98
+
99
+ expect(links.collect(&:title)).to be == ['One', 'Two', 'Three', '四']
84
100
  end
85
101
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: utopia
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-23 00:00:00.000000000 Z
11
+ date: 2017-03-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trenni
@@ -394,6 +394,8 @@ files:
394
394
  - lib/utopia/session/lazy_hash.rb
395
395
  - lib/utopia/setup.rb
396
396
  - lib/utopia/static.rb
397
+ - lib/utopia/static/local_file.rb
398
+ - lib/utopia/static/mime_types.rb
397
399
  - lib/utopia/version.rb
398
400
  - materials/utopia.png
399
401
  - materials/utopia.svg