mill 0.1 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +0 -2
- data/TODO.txt +48 -25
- data/bin/mill +19 -0
- data/lib/mill.rb +7 -316
- data/lib/mill/error.rb +7 -0
- data/lib/mill/html_helpers.rb +57 -67
- data/lib/mill/navigator.rb +26 -50
- data/lib/mill/resource.rb +78 -59
- data/lib/mill/resources/dir.rb +31 -0
- data/lib/mill/resources/feed.rb +13 -22
- data/lib/mill/resources/google_site_verification.rb +24 -0
- data/lib/mill/resources/image.rb +12 -5
- data/lib/mill/resources/other.rb +29 -0
- data/lib/mill/resources/redirect.rb +7 -13
- data/lib/mill/resources/robots.rb +6 -9
- data/lib/mill/resources/sitemap.rb +3 -7
- data/lib/mill/resources/stylesheet.rb +27 -0
- data/lib/mill/resources/text.rb +139 -59
- data/lib/mill/site.rb +304 -0
- data/lib/mill/version.rb +2 -2
- data/mill.gemspec +1 -3
- data/test/Gemfile +7 -0
- data/test/Rakefile +7 -0
- data/test/content/a.md +3 -0
- data/test/content/b/index.md +3 -0
- data/test/content/index.md +3 -0
- metadata +24 -37
- data/lib/mill/file_types.rb +0 -30
- data/lib/mill/resources/generic.rb +0 -15
- data/lib/mill/tasks.rake +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1f8000209c86dddb14cc2a494f51ac7e6de3b88612c17e82347921d99c279f51
|
4
|
+
data.tar.gz: a3e076dc13fce8f7002b056639792114e876f70ab69266df761c5ae576b2eda6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e939321da85e85ba819a6f32808e8d027eedca5e9200087f2560fbaefd8bc0f4cef5459622a91a93ce51d1597fb040730f0abfc7fb0a09c074af31606c59a030
|
7
|
+
data.tar.gz: 4897e121dc46248eaef16b998c60a76ba2a1e1c0a7d590e733986e66f9622af2001c2f0015d7f230cadefadbdcdbff301b4a1c2a495266781f930fd0cbf21429
|
data/Gemfile
CHANGED
data/TODO.txt
CHANGED
@@ -1,38 +1,61 @@
|
|
1
|
-
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
- initialize site by setting ivars directly, not by passing params to super's initialize()
|
2
|
+
|
3
|
+
- create alternate sites (beta, final, etc.) by subclassing site, and changing @output or @location
|
4
|
+
|
5
|
+
- rework resource URI usage
|
6
|
+
- 'uri' attribute should be canonical
|
7
|
+
- 'output_file' should be derived from @site.output_dir + uri
|
8
|
+
- URIs should be fully qualified
|
9
|
+
- start with '/'
|
10
|
+
- have extension according to file type
|
11
|
+
- referencing URIs should follow server rules (e.g., / -> /index.html)
|
12
|
+
- #shorten_uris should only apply to writing final files
|
13
|
+
|
14
|
+
- combine @input_file & @content?
|
15
|
+
- if @content.kind_of?(Path): copy
|
16
|
+
- else: write as string
|
17
|
+
|
18
|
+
- rename Resource #load to #import
|
19
|
+
- uses path argument instead of @input_file
|
20
|
+
- sets @content to path
|
21
|
+
- sets @date to mtime of path
|
22
|
+
- subclasses should:
|
23
|
+
- call super
|
24
|
+
- subclasses may:
|
25
|
+
- assigned @content
|
26
|
+
- change URI
|
27
|
+
|
28
|
+
- rename Resource #build to #process
|
29
|
+
|
30
|
+
- formalize widget creation & access
|
31
|
+
- any object that responds to #to_html
|
32
|
+
- doesn't have to be specific class (e.g., Mill::Widget)
|
33
|
+
- object that is used across site
|
34
|
+
- possibly with different states or parameters (eg, navigation)
|
35
|
+
- built from current html_fragment use
|
36
|
+
- eg:
|
37
|
+
- navigation
|
38
|
+
- buy buttons
|
39
|
+
- Google Analytics bug
|
40
|
+
- link to resource (<a ...>)
|
41
|
+
- sidebars
|
42
|
+
- strings (existing String extensions)
|
43
|
+
|
44
|
+
- create bin/mill tool to replace Rake
|
5
45
|
|
6
46
|
- split Resource#date into Resource#published & Resource#updated
|
7
47
|
+ add <published> element to feed
|
8
48
|
+ #published should be stated date (e.g., from header)
|
9
49
|
+ #updated should be mtime of source file
|
10
50
|
|
11
|
-
- refactor MIME type usage
|
12
|
-
+ allow specified type as regexp or glob (use File.fnmatch?)
|
13
|
-
+ convert to MIME::Type object(s)
|
14
|
-
|
15
51
|
- make Navigator into more generic Collection
|
16
52
|
+ include Enumerable
|
17
53
|
|
18
54
|
- make Resource::External for external links?
|
19
55
|
+ add on import of HTML (by examining href/src/etc attributes)
|
20
56
|
|
21
|
-
-
|
22
|
-
|
23
|
-
|
24
|
-
+ A #convert_uris method should convert all references to proper type.
|
25
|
-
|
26
|
-
- Compress/minify Javascript, CSS, and HTML
|
27
|
-
+ https://remino.net/rails-html-css-js-gzip-compression/
|
28
|
-
+ http://sass-lang.com/documentation/file.SASS_REFERENCE.html#_16
|
29
|
-
+ JS: https://github.com/lautis/uglifier
|
30
|
-
+ HTML: https://github.com/paolochiodi/htmlcompressor
|
31
|
-
+ CSS: https://github.com/matthiassiegel/cssminify
|
32
|
-
|
33
|
-
- Write compressed versions along with non-compressed
|
34
|
-
+ Modify SimpleServer to use compressed versions if asked by client
|
35
|
-
|
36
|
-
- Add MailChimp signup form generator to HTMLHelpers.
|
57
|
+
- save compressed versions of files
|
58
|
+
- write compressed versions along with non-compressed
|
59
|
+
- serve compressed versions if asked by client
|
37
60
|
|
38
|
-
-
|
61
|
+
- add MailChimp signup form generator to HTMLHelpers
|
data/bin/mill
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'mill'
|
4
|
+
|
5
|
+
load Path.pwd / 'code' / 'site.rb'
|
6
|
+
|
7
|
+
begin
|
8
|
+
case ARGV.shift
|
9
|
+
when nil, 'make'
|
10
|
+
$site.make
|
11
|
+
when 'list'
|
12
|
+
$site.list
|
13
|
+
else
|
14
|
+
raise "Unknown command: #{command}"
|
15
|
+
end
|
16
|
+
rescue Mill::Error => e
|
17
|
+
warn e
|
18
|
+
exit(1)
|
19
|
+
end
|
data/lib/mill.rb
CHANGED
@@ -7,330 +7,21 @@ require 'path'
|
|
7
7
|
require 'pp'
|
8
8
|
require 'RedCloth'
|
9
9
|
require 'rubypants'
|
10
|
-
require '
|
10
|
+
require 'sass'
|
11
11
|
require 'time'
|
12
|
-
require 'tidy_ffi'
|
13
|
-
require 'term/ansicolor'
|
14
12
|
|
15
|
-
require 'mill/
|
13
|
+
require 'mill/error'
|
16
14
|
require 'mill/html_helpers'
|
17
15
|
require 'mill/navigator'
|
18
16
|
require 'mill/resource'
|
19
17
|
require 'mill/resources/feed'
|
20
|
-
require 'mill/resources/
|
18
|
+
require 'mill/resources/google_site_verification'
|
21
19
|
require 'mill/resources/image'
|
20
|
+
require 'mill/resources/other'
|
22
21
|
require 'mill/resources/redirect'
|
23
22
|
require 'mill/resources/robots'
|
24
23
|
require 'mill/resources/sitemap'
|
24
|
+
require 'mill/resources/stylesheet'
|
25
25
|
require 'mill/resources/text'
|
26
|
-
require 'mill/
|
27
|
-
|
28
|
-
class Mill
|
29
|
-
|
30
|
-
attr_accessor :input_dir
|
31
|
-
attr_accessor :output_dir
|
32
|
-
attr_accessor :site_title
|
33
|
-
attr_accessor :site_uri
|
34
|
-
attr_accessor :site_email
|
35
|
-
attr_accessor :site_control_date
|
36
|
-
attr_accessor :feed_resource
|
37
|
-
attr_accessor :sitemap_resource
|
38
|
-
attr_accessor :robots_resource
|
39
|
-
attr_accessor :ssh_location
|
40
|
-
attr_accessor :beta_ssh_location
|
41
|
-
attr_accessor :resources
|
42
|
-
attr_accessor :shorten_uris
|
43
|
-
attr_accessor :navigator
|
44
|
-
attr_accessor :navigator_items
|
45
|
-
attr_accessor :resource_classes
|
46
|
-
attr_accessor :schema_types
|
47
|
-
attr_accessor :redirects
|
48
|
-
attr_accessor :input_file_type_order
|
49
|
-
attr_accessor :link_elem_attrs
|
50
|
-
|
51
|
-
DefaultResourceClasses = [
|
52
|
-
Resource::Text,
|
53
|
-
Resource::Image,
|
54
|
-
Resource::Generic,
|
55
|
-
]
|
56
|
-
|
57
|
-
SchemasDir = Path.new(__FILE__).dirname / 'mill' / 'schemas'
|
58
|
-
|
59
|
-
DefaultSchemaTypes = {
|
60
|
-
feed: SchemasDir / 'atom.xsd',
|
61
|
-
sitemap: SchemasDir / 'sitemap.xsd',
|
62
|
-
}
|
63
|
-
|
64
|
-
def initialize(params={})
|
65
|
-
@resource_classes = {}
|
66
|
-
@resources = []
|
67
|
-
@resources_by_uri = {}
|
68
|
-
@schema_types = {}
|
69
|
-
@schemas = {}
|
70
|
-
@shorten_uris = true
|
71
|
-
@input_file_type_order = [:generic, :image, :text]
|
72
|
-
@link_elem_attrs = %w{
|
73
|
-
img/@src
|
74
|
-
script/@src
|
75
|
-
a/@href
|
76
|
-
link/@href
|
77
|
-
stylesheet/@href
|
78
|
-
}
|
79
|
-
params.each { |k, v| send("#{k}=", v) }
|
80
|
-
end
|
81
|
-
|
82
|
-
def input_dir=(path)
|
83
|
-
@input_dir = Path.new(path).expand_path
|
84
|
-
end
|
85
|
-
|
86
|
-
def output_dir=(path)
|
87
|
-
@output_dir = Path.new(path).expand_path
|
88
|
-
end
|
89
|
-
|
90
|
-
def site_uri=(uri)
|
91
|
-
@site_uri = Addressable::URI.parse(uri)
|
92
|
-
end
|
93
|
-
|
94
|
-
def site_control_date=(date)
|
95
|
-
begin
|
96
|
-
@site_control_date = Date.parse(date)
|
97
|
-
rescue ArgumentError => e
|
98
|
-
raise "bad control date #{date.inspect}: #{e}"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def file_type(file)
|
103
|
-
if file.directory? || file.basename.to_s[0] == '.'
|
104
|
-
return :ignore
|
105
|
-
else
|
106
|
-
MIME::Types.of(file.to_s).each do |mime_type|
|
107
|
-
if (type = @file_types[mime_type.content_type])
|
108
|
-
return type
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
nil
|
113
|
-
end
|
114
|
-
|
115
|
-
def add_resource(resource)
|
116
|
-
resource.mill = self
|
117
|
-
begin
|
118
|
-
# ;;warn "loading #{resource.class.type} resource #{resource.uri} as #{resource.class}"
|
119
|
-
resource.load
|
120
|
-
rescue => e
|
121
|
-
warn "Failed to load resource #{resource.uri} (#{resource.class}): #{e}"
|
122
|
-
raise
|
123
|
-
end
|
124
|
-
@resources << resource
|
125
|
-
end
|
126
|
-
|
127
|
-
def update_resource(resource)
|
128
|
-
@resources_by_uri[resource.uri] = resource
|
129
|
-
end
|
130
|
-
|
131
|
-
def find_resource(uri)
|
132
|
-
uri = Addressable::URI.parse(uri.to_s) unless uri.kind_of?(Addressable::URI)
|
133
|
-
resource = @resources_by_uri[uri]
|
134
|
-
if resource.nil? && @shorten_uris
|
135
|
-
uri.path = uri.path.sub(%r{\.html$}, '')
|
136
|
-
resource = @resources_by_uri[uri]
|
137
|
-
end
|
138
|
-
resource
|
139
|
-
end
|
140
|
-
|
141
|
-
def home_resource
|
142
|
-
find_resource('/') or raise "Can't find home"
|
143
|
-
end
|
144
|
-
|
145
|
-
def schema_for_type(type)
|
146
|
-
@schemas[type]
|
147
|
-
end
|
148
|
-
|
149
|
-
def tag_uri
|
150
|
-
"tag:#{@site_uri.host.downcase},#{@site_control_date}:"
|
151
|
-
end
|
152
|
-
|
153
|
-
def feed_generator
|
154
|
-
[
|
155
|
-
'Mill',
|
156
|
-
{
|
157
|
-
uri: Addressable::URI.parse('http://github.com/jslabovitz/mill'),
|
158
|
-
version: Mill::VERSION,
|
159
|
-
}
|
160
|
-
]
|
161
|
-
end
|
162
|
-
|
163
|
-
def feed_author_name
|
164
|
-
@site_title
|
165
|
-
end
|
166
|
-
|
167
|
-
def feed_author_uri
|
168
|
-
@site_uri
|
169
|
-
end
|
170
|
-
|
171
|
-
def feed_author_email
|
172
|
-
@site_email
|
173
|
-
end
|
174
|
-
|
175
|
-
def public_resources
|
176
|
-
@resources.select(&:public)
|
177
|
-
end
|
178
|
-
|
179
|
-
def clean
|
180
|
-
@output_dir.rmtree if @output_dir.exist?
|
181
|
-
@output_dir.mkpath
|
182
|
-
end
|
183
|
-
|
184
|
-
def load
|
185
|
-
warn "loading resources..."
|
186
|
-
build_file_types
|
187
|
-
build_resource_classes
|
188
|
-
build_schemas
|
189
|
-
load_files
|
190
|
-
load_others
|
191
|
-
end
|
192
|
-
|
193
|
-
def load_others
|
194
|
-
make_redirects
|
195
|
-
make_feed
|
196
|
-
make_sitemap
|
197
|
-
make_robots
|
198
|
-
make_navigator
|
199
|
-
end
|
200
|
-
|
201
|
-
def build
|
202
|
-
warn "building #{@resources.length} resources..."
|
203
|
-
@resources.each do |resource|
|
204
|
-
begin
|
205
|
-
resource.build
|
206
|
-
rescue => e
|
207
|
-
warn "Failed to build resource #{resource.uri}: #{e}"
|
208
|
-
raise
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def publish(mode=:final)
|
214
|
-
location = case mode
|
215
|
-
when :final
|
216
|
-
@ssh_location
|
217
|
-
when :beta
|
218
|
-
@beta_ssh_location
|
219
|
-
else
|
220
|
-
raise "Unknown publish mode: #{mode.inspect}"
|
221
|
-
end
|
222
|
-
raise "Must specify SSH location" unless location
|
223
|
-
system('rsync',
|
224
|
-
# '--dry-run',
|
225
|
-
'--archive',
|
226
|
-
'--delete-after',
|
227
|
-
'--progress',
|
228
|
-
# '--verbose',
|
229
|
-
@output_dir.to_s + '/',
|
230
|
-
location,
|
231
|
-
)
|
232
|
-
end
|
233
|
-
|
234
|
-
def server
|
235
|
-
SimpleServer.run!(
|
236
|
-
root: @output_dir,
|
237
|
-
multihosting: false,
|
238
|
-
)
|
239
|
-
end
|
240
|
-
|
241
|
-
private
|
242
|
-
|
243
|
-
def load_files
|
244
|
-
input_files_by_type.each do |type, input_files|
|
245
|
-
input_files.each do |input_file|
|
246
|
-
resource_class = @resource_classes[type] or raise "No resource class for #{input_file}"
|
247
|
-
resource = resource_class.new(
|
248
|
-
input_file: input_file,
|
249
|
-
output_file: @output_dir / input_file.relative_to(@input_dir))
|
250
|
-
add_resource(resource)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
def input_files_by_type
|
256
|
-
hash = {}
|
257
|
-
raise "Input path not found: #{@input_dir}" unless @input_dir.exist?
|
258
|
-
@input_dir.find do |input_file|
|
259
|
-
input_file = @input_dir / input_file
|
260
|
-
type = file_type(input_file) or raise "Can't determine file type of #{input_file}"
|
261
|
-
unless type == :ignore
|
262
|
-
hash[type] ||= []
|
263
|
-
hash[type] << input_file
|
264
|
-
end
|
265
|
-
end
|
266
|
-
hash.sort_by { |t, f| input_file_type_order.index(t) || input_file_type_order.length }
|
267
|
-
end
|
268
|
-
|
269
|
-
def make_feed
|
270
|
-
@feed_resource = Resource::Feed.new(
|
271
|
-
output_file: @output_dir / 'feed.xml')
|
272
|
-
add_resource(@feed_resource)
|
273
|
-
end
|
274
|
-
|
275
|
-
def make_sitemap
|
276
|
-
@sitemap_resource = Resource::Sitemap.new(
|
277
|
-
output_file: @output_dir / 'sitemap.xml')
|
278
|
-
add_resource(@sitemap_resource)
|
279
|
-
end
|
280
|
-
|
281
|
-
def make_robots
|
282
|
-
@robots_resource = Resource::Robots.new(
|
283
|
-
output_file: @output_dir / 'robots.txt')
|
284
|
-
add_resource(@robots_resource)
|
285
|
-
end
|
286
|
-
|
287
|
-
def make_navigator
|
288
|
-
if @navigator_items
|
289
|
-
@navigator = Navigator.new
|
290
|
-
@navigator.items = @navigator_items.map do |uri, title|
|
291
|
-
uri = Addressable::URI.parse(uri)
|
292
|
-
if title.nil? && uri.relative?
|
293
|
-
resource = find_resource(uri) or raise "Can't find navigation resource for URI #{uri}"
|
294
|
-
title = resource.title
|
295
|
-
end
|
296
|
-
Navigator::Item.new(uri: uri, title: title)
|
297
|
-
end
|
298
|
-
end
|
299
|
-
end
|
300
|
-
|
301
|
-
def make_redirects
|
302
|
-
return unless @redirects
|
303
|
-
@redirects.each do |from, to|
|
304
|
-
output_file = @output_dir / Path.new(from).relative_to('/')
|
305
|
-
resource = Resource::Redirect.new(
|
306
|
-
output_file: output_file,
|
307
|
-
redirect_uri: to)
|
308
|
-
add_resource(resource)
|
309
|
-
end
|
310
|
-
end
|
311
|
-
|
312
|
-
def build_schemas
|
313
|
-
DefaultSchemaTypes.merge(@schema_types).each do |type, file|
|
314
|
-
;;warn "loading schema #{type} from #{file}"
|
315
|
-
@schemas[type] = Nokogiri::XML::Schema(file.open) { |c| c.strict.nonet }
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
def build_file_types
|
320
|
-
@file_types = {}
|
321
|
-
FileTypes.each do |type, mime_types|
|
322
|
-
mime_types.each do |mime_type|
|
323
|
-
MIME::Types[mime_type].each do |t|
|
324
|
-
@file_types[t.content_type] = type
|
325
|
-
end
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
def build_resource_classes
|
331
|
-
@resource_classes = Hash[
|
332
|
-
(DefaultResourceClasses + @resource_classes).map { |rc| [rc.type, rc] }
|
333
|
-
]
|
334
|
-
end
|
335
|
-
|
336
|
-
end
|
26
|
+
require 'mill/site'
|
27
|
+
require 'mill/version'
|