mill 0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8f1e09004e5ec42eaa48258220004b0821601096
4
+ data.tar.gz: 6e92566945ca1b4549feeb5496aafd3c964b067d
5
+ SHA512:
6
+ metadata.gz: f6b982c3c4fc9e81b47b50a303a15ccfb0cf4c3409a25b6e47e1aff213b3c08ec973329b069dd10693186c45d5df1824e173839ca1a251c48c7d44a597a6884b
7
+ data.tar.gz: 992d9f6ba951a49e12122e0a75fb09f2cd8932878dc1f9975decc590514874ea83587a7b211ea8d64de1f520d4af3ee3dff488f55cd84e28983f2adfa28b16b7
@@ -0,0 +1,37 @@
1
+ *.gem
2
+ *.rbc
3
+ .DS_Store
4
+ /.config
5
+ /coverage/
6
+ /InstalledFiles
7
+ /pkg/
8
+ /spec/reports/
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /test/site
12
+ /test/resources
13
+ /tmp/
14
+
15
+ ## Specific to RubyMotion:
16
+ .dat*
17
+ .repl_history
18
+ build/
19
+
20
+ ## Documentation cache and generated files:
21
+ /.yardoc/
22
+ /_yardoc/
23
+ /doc/
24
+ /rdoc/
25
+
26
+ ## Environment normalisation:
27
+ /.bundle/
28
+ /lib/bundler/man/
29
+
30
+ # for a library or gem, you might want to ignore these files since the code is
31
+ # intended to run in multiple environments; otherwise, check them in:
32
+ Gemfile.lock
33
+ # .ruby-version
34
+ # .ruby-gemset
35
+
36
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
37
+ .rvmrc
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'simple-server', git: 'https://github.com/jslabovitz/simple-server.git'
4
+
5
+ # Specify your gem's dependencies in mill.gemspec
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 jslabovitz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ mill
2
+ ====
3
+
4
+ A simple but useful static site generator, in Ruby.
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,38 @@
1
+ - resolve confusion between content-generation in #load vs. #final_content
2
+ + who does what?
3
+ + replacement/modification of HTML elements (image sizing, etc.) only happens in #load
4
+ + maybe #final_content should have option to fully qualify URIs, etc., to handle feed content
5
+
6
+ - split Resource#date into Resource#published & Resource#updated
7
+ + add <published> element to feed
8
+ + #published should be stated date (e.g., from header)
9
+ + #updated should be mtime of source file
10
+
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
+ - make Navigator into more generic Collection
16
+ + include Enumerable
17
+
18
+ - make Resource::External for external links?
19
+ + add on import of HTML (by examining href/src/etc attributes)
20
+
21
+ - Rationalize resource URI usage:
22
+ + #shorten_uris should only apply to writing final files.
23
+ + In original content/etc., URIs should be more flexible.
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.
37
+
38
+ - Add Google Analytics bug generator to HTMLHelpers and Mill setup.
@@ -0,0 +1,336 @@
1
+ require 'addressable'
2
+ require 'image_size'
3
+ require 'kramdown'
4
+ require 'mime/types'
5
+ require 'nokogiri'
6
+ require 'path'
7
+ require 'pp'
8
+ require 'RedCloth'
9
+ require 'rubypants'
10
+ require 'simple-server'
11
+ require 'time'
12
+ require 'tidy_ffi'
13
+ require 'term/ansicolor'
14
+
15
+ require 'mill/file_types'
16
+ require 'mill/html_helpers'
17
+ require 'mill/navigator'
18
+ require 'mill/resource'
19
+ require 'mill/resources/feed'
20
+ require 'mill/resources/generic'
21
+ require 'mill/resources/image'
22
+ require 'mill/resources/redirect'
23
+ require 'mill/resources/robots'
24
+ require 'mill/resources/sitemap'
25
+ require 'mill/resources/text'
26
+ require 'mill/version'
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