mill 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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