mill 0.11 → 0.18
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.
- checksums.yaml +4 -4
- data/.gitignore +11 -1
- data/LICENSE +1 -1
- data/Rakefile +1 -2
- data/TODO.md +4 -0
- data/bin/mill +1 -27
- data/lib/mill/command.rb +13 -0
- data/lib/mill/commands/build.rb +17 -0
- data/lib/mill/commands/check.rb +16 -0
- data/lib/mill/commands/diff.rb +18 -0
- data/lib/mill/commands/list.rb +20 -0
- data/lib/mill/commands/snapshot.rb +20 -0
- data/lib/mill/commands/tree.rb +17 -0
- data/lib/mill/commands/types.rb +18 -0
- data/lib/mill/commands/upload.rb +24 -0
- data/lib/mill/config.rb +27 -0
- data/lib/mill/resource.rb +81 -81
- data/lib/mill/resources/blob.rb +4 -0
- data/lib/mill/resources/feed.rb +5 -13
- data/lib/mill/resources/image.rb +10 -18
- data/lib/mill/resources/markdown.rb +20 -0
- data/lib/mill/resources/markup.rb +62 -0
- data/lib/mill/resources/page.rb +140 -0
- data/lib/mill/resources/redirect.rb +17 -16
- data/lib/mill/resources/robots.rb +3 -4
- data/lib/mill/resources/sitemap.rb +3 -5
- data/lib/mill/resources/stylesheet.rb +4 -4
- data/lib/mill/resources/textile.rb +27 -0
- data/lib/mill/resources.rb +89 -0
- data/lib/mill/site.rb +181 -251
- data/lib/mill.rb +28 -8
- data/mill.gemspec +22 -17
- data/test/content/a.md +3 -0
- data/test/content/b/ba.md +3 -0
- data/test/content/b/bb.md +3 -0
- data/test/content/b/index.md +3 -0
- data/test/content/c.md +4 -0
- data/test/content/d.md +4 -0
- data/test/content/index.md +3 -0
- data/test/main_test.rb +68 -0
- data/test/mill.yaml +8 -0
- metadata +189 -40
- data/TODO.txt +0 -61
- data/lib/mill/html_helpers.rb +0 -122
- data/lib/mill/navigator.rb +0 -61
- data/lib/mill/resources/dir.rb +0 -31
- data/lib/mill/resources/google_site_verification.rb +0 -30
- data/lib/mill/resources/text.rb +0 -207
- data/lib/mill/version.rb +0 -5
data/lib/mill/navigator.rb
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
module Mill
|
|
2
|
-
|
|
3
|
-
class Navigator
|
|
4
|
-
|
|
5
|
-
class Item
|
|
6
|
-
|
|
7
|
-
attr_accessor :uri
|
|
8
|
-
attr_accessor :title
|
|
9
|
-
|
|
10
|
-
def initialize(uri:, title: nil)
|
|
11
|
-
@uri = Addressable::URI.parse(uri)
|
|
12
|
-
@title = title
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def initialize(items: [], site: nil)
|
|
18
|
-
@items = Hash[
|
|
19
|
-
items.map do |uri, title|
|
|
20
|
-
item = Item.new(uri: uri, title: title)
|
|
21
|
-
[item.uri, item]
|
|
22
|
-
end
|
|
23
|
-
]
|
|
24
|
-
@site = site
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def items
|
|
28
|
-
@items.values
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def first_item
|
|
32
|
-
@items.values.first
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def last_item
|
|
36
|
-
@items.values.last
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
def previous_item(uri)
|
|
40
|
-
if (item = @items[uri])
|
|
41
|
-
i = @items.values.index(item)
|
|
42
|
-
if i > 0
|
|
43
|
-
return @items.values[i - 1]
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
nil
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def next_item(uri)
|
|
50
|
-
if (item = @items[uri])
|
|
51
|
-
i = @items.values.index(item)
|
|
52
|
-
if i < @items.length - 1
|
|
53
|
-
return @items.values[i + 1]
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
nil
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
end
|
data/lib/mill/resources/dir.rb
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
module Mill
|
|
2
|
-
|
|
3
|
-
class Resource
|
|
4
|
-
|
|
5
|
-
class Index < Text
|
|
6
|
-
|
|
7
|
-
include HTMLHelpers
|
|
8
|
-
|
|
9
|
-
attr_accessor :pages
|
|
10
|
-
|
|
11
|
-
def initialize(pages:, **args)
|
|
12
|
-
@pages = pages
|
|
13
|
-
super(**args)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def load
|
|
17
|
-
super
|
|
18
|
-
@content = html_fragment do |html|
|
|
19
|
-
html.dl do
|
|
20
|
-
@pages.each do |page|
|
|
21
|
-
html.dt(page.title)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
module Mill
|
|
2
|
-
|
|
3
|
-
class Resource
|
|
4
|
-
|
|
5
|
-
class GoogleSiteVerification < Resource
|
|
6
|
-
|
|
7
|
-
attr_accessor :key
|
|
8
|
-
|
|
9
|
-
def initialize(key:, **args)
|
|
10
|
-
@key = key
|
|
11
|
-
@public = false
|
|
12
|
-
super(**args)
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def inspect
|
|
16
|
-
super + ", key: %p" % [
|
|
17
|
-
@key,
|
|
18
|
-
]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def load
|
|
22
|
-
@content = "google-site-verification: #{@key}.html\n"
|
|
23
|
-
super
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
end
|
data/lib/mill/resources/text.rb
DELETED
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
module Mill
|
|
2
|
-
|
|
3
|
-
class Resource
|
|
4
|
-
|
|
5
|
-
class Text < Resource
|
|
6
|
-
|
|
7
|
-
include HTMLHelpers
|
|
8
|
-
|
|
9
|
-
FileTypes = %w{
|
|
10
|
-
text/plain
|
|
11
|
-
text/html
|
|
12
|
-
text/markdown
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
attr_accessor :title
|
|
16
|
-
attr_accessor :summary
|
|
17
|
-
attr_accessor :author
|
|
18
|
-
|
|
19
|
-
def initialize(title: nil, summary: nil, author: nil, public: true, **args)
|
|
20
|
-
@title = title
|
|
21
|
-
@summary = summary
|
|
22
|
-
@author = author
|
|
23
|
-
super(public: public, **args)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def inspect
|
|
27
|
-
super + ", title: %p, summary: %p, author: %p" % [
|
|
28
|
-
@title,
|
|
29
|
-
@summary,
|
|
30
|
-
@author,
|
|
31
|
-
]
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def load
|
|
35
|
-
super
|
|
36
|
-
if @input_file
|
|
37
|
-
@content = @input_file.read
|
|
38
|
-
mode = case @input_file.extname.downcase
|
|
39
|
-
when '.md', '.mdown', '.markdown'
|
|
40
|
-
:markdown
|
|
41
|
-
when '.textile'
|
|
42
|
-
:textile
|
|
43
|
-
when '.txt'
|
|
44
|
-
:pre
|
|
45
|
-
when '.htm', '.html'
|
|
46
|
-
:html
|
|
47
|
-
else
|
|
48
|
-
raise "Unknown text type: #{@input_file}"
|
|
49
|
-
end
|
|
50
|
-
if mode != :html
|
|
51
|
-
parse_text_header
|
|
52
|
-
@content = (@content || '').to_html(mode: mode, multiline: true)
|
|
53
|
-
@output_file = @output_file.replace_extension('.html')
|
|
54
|
-
end
|
|
55
|
-
begin
|
|
56
|
-
@content = parse_html(@content)
|
|
57
|
-
rescue Error => e
|
|
58
|
-
raise e, "#{@input_file}: #{e}"
|
|
59
|
-
end
|
|
60
|
-
parse_html_header
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def parse_html_header
|
|
65
|
-
unless @title
|
|
66
|
-
if (title_elem = @content.at_xpath('/html/head/title'))
|
|
67
|
-
@title = title_elem.text
|
|
68
|
-
else
|
|
69
|
-
@title = uri.to_s
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
@content.xpath('/html/head/meta[@name]').each do |meta|
|
|
73
|
-
send("#{meta['name']}=", meta['content'])
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
def parse_text_header
|
|
78
|
-
if @content.split(/\n/, 2).first =~ /^\w+:\s+/
|
|
79
|
-
header, @content = @content.split(/\n\n/, 2)
|
|
80
|
-
header.split(/\n/).map do |line|
|
|
81
|
-
key, value = line.strip.split(/:\s+/, 2)
|
|
82
|
-
key = key.gsub('-', '_').downcase.to_sym
|
|
83
|
-
send("#{key}=", value)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def final_content
|
|
89
|
-
html_document(@site.html_version) do |doc|
|
|
90
|
-
doc.html(lang: 'en') do |html|
|
|
91
|
-
html.parent << head
|
|
92
|
-
html.parent << body
|
|
93
|
-
end
|
|
94
|
-
end.to_html
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def head(&block)
|
|
98
|
-
html_fragment do |html|
|
|
99
|
-
html.head do
|
|
100
|
-
head = content_head
|
|
101
|
-
if (title = @title || (head && head.at_xpath('title')))
|
|
102
|
-
html.title { html << title.to_html }
|
|
103
|
-
end
|
|
104
|
-
yield(html) if block_given?
|
|
105
|
-
if head
|
|
106
|
-
head.children.reject { |e| e.text? || e.name == 'title' }.each do |e|
|
|
107
|
-
html << e.to_html
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def body(&block)
|
|
115
|
-
html_fragment do |html|
|
|
116
|
-
html.body do
|
|
117
|
-
if (elem = content_body)
|
|
118
|
-
html << elem.children.to_html
|
|
119
|
-
end
|
|
120
|
-
yield(html) if block_given?
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def content_head
|
|
126
|
-
@content && @content.at_xpath('/html/head')
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
def content_body
|
|
130
|
-
@content && @content.at_xpath('/html/body')
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
def add_external_link_targets(rel='noopener')
|
|
134
|
-
@content.xpath('//a').each do |a|
|
|
135
|
-
if a['href'] && a['href'] =~ /^\w+:/
|
|
136
|
-
a['target'] = '_blank'
|
|
137
|
-
a['rel'] = rel
|
|
138
|
-
end
|
|
139
|
-
end
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def remove_comments
|
|
143
|
-
@content.xpath('//comment()').each do |comment|
|
|
144
|
-
comment.remove
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
def add_image_sizes
|
|
149
|
-
@content.xpath('//img').each do |img|
|
|
150
|
-
# skip elements that already have width/height defined
|
|
151
|
-
next if img[:width] || img[:height]
|
|
152
|
-
img_link = Addressable::URI.parse(img['src'])
|
|
153
|
-
raise Error, "No link in <img> element: #{img.to_s}" if img_link.nil? || img_link.empty?
|
|
154
|
-
next if img_link.host
|
|
155
|
-
img_uri = uri + img_link
|
|
156
|
-
img_resource = @site.find_resource(img_uri) or raise Error, "Can't find image for #{img_uri}"
|
|
157
|
-
img[:width], img[:height] = img_resource.width, img_resource.height
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def shorten_links
|
|
162
|
-
find_link_elements(@content).each do |attribute|
|
|
163
|
-
elem = attribute.parent
|
|
164
|
-
link_uri = Addressable::URI.parse(attribute.value) or raise Error, "Can't parse #{attribute.value.inspect} from #{xpath.inspect}"
|
|
165
|
-
link_uri = uri + link_uri
|
|
166
|
-
if link_uri.relative?
|
|
167
|
-
self_uri = uri.normalize
|
|
168
|
-
self_uri.scheme = 'http'
|
|
169
|
-
link_uri.scheme = 'http'
|
|
170
|
-
attribute.value = self_uri.route_to(link_uri)
|
|
171
|
-
# ;;warn "[#{uri}] shortened link #{elem.name}/@#{attribute.name}: #{link_uri} => #{attribute.value}"
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def summary
|
|
177
|
-
@summary || ((p = feed_content.at_xpath('//p')) && p.children)
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def feed_content
|
|
181
|
-
if (body = content_body)
|
|
182
|
-
# If we have a main element (<div class="main"> or <main>), use that.
|
|
183
|
-
# Otherwise, use the body, but delete header/footer/nav divs or elements.
|
|
184
|
-
if (main = body.at_xpath('//div[@id="main"]')) || (main = body.at_xpath('//main'))
|
|
185
|
-
main.children
|
|
186
|
-
elsif (article = body.at_xpath('//article'))
|
|
187
|
-
article.children
|
|
188
|
-
else
|
|
189
|
-
body_elem = body.clone
|
|
190
|
-
%w{header nav masthead footer}.each do |name|
|
|
191
|
-
if (elem = body_elem.at_xpath("//div[@id=\"#{name}\"]")) || (elem = body_elem.at_xpath("//#{name}"))
|
|
192
|
-
elem.remove
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
body_elem.children
|
|
196
|
-
end
|
|
197
|
-
else
|
|
198
|
-
warn "Warning: Resource #{uri} (#{self.class}) has no content"
|
|
199
|
-
nil
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
end
|