mill 0.16 → 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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/Rakefile +1 -9
  4. data/TODO.md +4 -0
  5. data/bin/mill +1 -27
  6. data/lib/mill/command.rb +13 -0
  7. data/lib/mill/commands/build.rb +17 -0
  8. data/lib/mill/commands/check.rb +16 -0
  9. data/lib/mill/commands/diff.rb +18 -0
  10. data/lib/mill/commands/list.rb +20 -0
  11. data/lib/mill/commands/snapshot.rb +20 -0
  12. data/lib/mill/commands/tree.rb +17 -0
  13. data/lib/mill/commands/types.rb +18 -0
  14. data/lib/mill/commands/upload.rb +24 -0
  15. data/lib/mill/config.rb +27 -0
  16. data/lib/mill/resource.rb +74 -87
  17. data/lib/mill/resources/blob.rb +4 -0
  18. data/lib/mill/resources/feed.rb +5 -13
  19. data/lib/mill/resources/image.rb +10 -18
  20. data/lib/mill/resources/markdown.rb +20 -0
  21. data/lib/mill/resources/markup.rb +62 -0
  22. data/lib/mill/resources/page.rb +140 -0
  23. data/lib/mill/resources/redirect.rb +17 -16
  24. data/lib/mill/resources/robots.rb +3 -4
  25. data/lib/mill/resources/sitemap.rb +3 -5
  26. data/lib/mill/resources/stylesheet.rb +4 -4
  27. data/lib/mill/resources/textile.rb +27 -0
  28. data/lib/mill/resources.rb +89 -0
  29. data/lib/mill/site.rb +182 -283
  30. data/lib/mill.rb +27 -9
  31. data/mill.gemspec +19 -19
  32. data/test/content/c.md +4 -0
  33. data/test/content/d.md +4 -0
  34. data/test/main_test.rb +68 -0
  35. data/test/mill.yaml +8 -0
  36. metadata +118 -51
  37. data/Gemfile +0 -6
  38. data/TODO.txt +0 -61
  39. data/lib/mill/html_helpers.rb +0 -128
  40. data/lib/mill/navigator.rb +0 -61
  41. data/lib/mill/resources/dir.rb +0 -31
  42. data/lib/mill/resources/google_site_verification.rb +0 -30
  43. data/lib/mill/resources/text.rb +0 -218
  44. data/lib/mill/version.rb +0 -5
  45. data/test/test.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5accfe1e5067386b3de4898faceb6ea201c6bc30097da779c38ef343e0aad18c
4
- data.tar.gz: 5861a090880607573153929c75f0475fb258467676b2a4084514e8b368028bb6
3
+ metadata.gz: 72216a7795be9cfd8a2039e3eac35f73f4c129a30e951074c638d6c77088c869
4
+ data.tar.gz: aead637972f953d1d01aaee384554766361cfb4d9efa1ae95a6aaa2e2e5e6d11
5
5
  SHA512:
6
- metadata.gz: 1c1e0a63042509e67a028e2e50b2f61fa92560ee16bb77370ca1ca82d1f75ebbd7054b9ba8b2408aff32e83a44c3e5f9cc2600316e5dd22c8a47ef7d26cee932
7
- data.tar.gz: 7dc21c2b4181768be5150d1e51ef6ea9b16aba0a33c8536dd9609e72b458913e2fa79ee460d9c50c204dc6a0da733587bd4807005a16ca2acc4e5806b33d168d
6
+ metadata.gz: 34d154f5a9cfa6e0a10d4abc57c7d3d99e18e857b1457e5ab9fbf82b50d426f469ed8cd79dc8821cdcddcf9e7fc95920d868b2025a0a328fdab9624e7d83d115
7
+ data.tar.gz: 8c433c5295ad53229ac23473eddd21b12995f225beb542e9c4d64ecafbec63d215fa343630e3380b5b162b62fd63c29eeba9b58f0404cf281aa89c36ef666bd2
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 jslabovitz
3
+ Copyright (c) 2023 John S. Labovitz
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/Rakefile CHANGED
@@ -1,9 +1 @@
1
- require 'bundler/gem_tasks'
2
- Bundler.require
3
- require 'rake/testtask'
4
-
5
- Rake::TestTask.new do |t|
6
- t.test_files = FileList['test/*test.rb']
7
- end
8
-
9
- task :default => :test
1
+ require 'simple-rake-tasks'
data/TODO.md ADDED
@@ -0,0 +1,4 @@
1
+ # TODO
2
+
3
+ - make Resources use tree for lookup instead of dictionary
4
+ - keep simple array of resources for quick access/iterators
data/bin/mill CHANGED
@@ -2,30 +2,4 @@
2
2
 
3
3
  require 'mill'
4
4
 
5
- load Path.pwd / 'code' / 'site.rb'
6
-
7
- begin
8
- case (command = ARGV.shift)
9
- when nil, 'make'
10
- $site.make
11
- when 'clean'
12
- $site.clean
13
- when 'check'
14
- $site.check
15
- when 'list'
16
- $site.list
17
- when 'diff'
18
- $site.diff
19
- when 'snapshot'
20
- $site.snapshot
21
- when 'upload'
22
- $site.upload
23
- when 'show'
24
- puts $site.send(ARGV.shift)
25
- else
26
- raise "Unknown command: #{command.inspect}"
27
- end
28
- rescue Mill::Error => e
29
- warn e
30
- exit(1)
31
- end
5
+ Simple::CommandParser.run(ARGV)
@@ -0,0 +1,13 @@
1
+ module Mill
2
+
3
+ class Command < Simple::CommandParser::Command
4
+
5
+ attr_accessor :dir
6
+
7
+ def run(args)
8
+ @site = Mill::Site.load(@dir || '.')
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,17 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class Build < Command
6
+
7
+ def run(args)
8
+ super
9
+ @site.build
10
+ @site.save
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,16 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class Check < Command
6
+
7
+ def run(args)
8
+ super
9
+ @site.check
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,18 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class Diff < Command
6
+
7
+ def run(args)
8
+ super
9
+ @site.output_dir.chdir do
10
+ run_command(%w[git diff])
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,20 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class List < Command
6
+
7
+ def run(args)
8
+ super
9
+ @site.build
10
+ @site.resources.each do |resource|
11
+ resource.print
12
+ puts
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,20 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class Snapshot < Command
6
+
7
+ def run(args)
8
+ super
9
+ @site.output_dir.chdir do
10
+ run_command(%w[git init]) unless Path.new('.git').exist?
11
+ run_command(%w[git add .])
12
+ run_command(%w[git commit -a -m Update.])
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,17 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class Tree < Command
6
+
7
+ def run(args)
8
+ super
9
+ @site.build
10
+ @site.resources.print_tree
11
+ end
12
+
13
+ end
14
+
15
+ end
16
+
17
+ end
@@ -0,0 +1,18 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class Types < Command
6
+
7
+ def run(args)
8
+ super
9
+ @site.file_types.sort.each do |type, klass|
10
+ puts '%-40s %s' % [type, klass]
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,24 @@
1
+ module Mill
2
+
3
+ module Commands
4
+
5
+ class Upload < Command
6
+
7
+ def run(args)
8
+ super
9
+ raise "site_rsync not defined" unless @site.site_rsync
10
+ options = %w[
11
+ --progress
12
+ --verbose
13
+ --archive
14
+ --exclude=.git
15
+ --delete-after
16
+ ]
17
+ run_command('rsync', *options, @site.output_dir, @site.site_rsync, verbose: true)
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,27 @@
1
+ module Mill
2
+
3
+ ConfigFileName = 'mill.yaml'
4
+
5
+ BaseConfig = Simple::Configurator.define(
6
+ dir: { default: '.', converter: :path },
7
+ input_dir: { default: 'content', converter: :path },
8
+ output_dir: { default: 'public_html', converter: :path },
9
+ code_dir: { default: 'code', converter: :path },
10
+ site_uri: { default: 'http://localhost', converter: :uri },
11
+ site_rsync: nil,
12
+ site_title: nil,
13
+ site_email: nil,
14
+ site_twitter: { converter: :uri },
15
+ site_instagram: { converter: :uri },
16
+ site_postal: nil,
17
+ site_phone: nil,
18
+ site_control_date: { converter: :date },
19
+ html_version: { default: :html5, converter: :symbol },
20
+ make_error: true,
21
+ make_feed: true,
22
+ make_sitemap: true,
23
+ make_robots: true,
24
+ allow_robots: true,
25
+ )
26
+
27
+ end
data/lib/mill/resource.rb CHANGED
@@ -4,123 +4,105 @@ module Mill
4
4
 
5
5
  FileTypes = []
6
6
 
7
- attr_accessor :input_file
8
- attr_accessor :output_file
9
7
  attr_accessor :path
8
+ attr_accessor :uri
9
+ attr_accessor :primary
10
+ attr_accessor :input
10
11
  attr_accessor :date
11
- attr_accessor :public
12
- attr_accessor :content
12
+ attr_reader :output
13
13
  attr_accessor :site
14
14
  attr_accessor :node
15
15
 
16
- def initialize(input_file: nil,
17
- output_file: nil,
18
- date: nil,
19
- public: false,
20
- content: nil,
21
- site: nil)
22
- if input_file
23
- @input_file = Path.new(input_file)
24
- @date = input_file.mtime.to_datetime
25
- else
26
- @date = DateTime.now
27
- end
28
- if output_file
29
- @output_file = Path.new(output_file)
30
- @path = '/' + @output_file.relative_to(site.output_dir).to_s
31
- end
32
- self.date = date if date
33
- self.public = public
34
- @content = content
35
- @site = site
36
- end
37
-
38
- def date=(date)
39
- @date = case date
40
- when String, Time
41
- begin
42
- DateTime.parse(date.to_s)
43
- rescue ArgumentError => e
44
- raise Error, "Can't parse date: #{date.inspect}"
45
- end
46
- when Date, DateTime, nil
47
- date
48
- else
49
- raise Error, "Can't assign 'date' attribute: #{date.inspect}"
16
+ include SetParams
17
+ include Simple::Printer::Printable
18
+
19
+ def initialize(params={})
20
+ super({ primary: false }.merge(params))
21
+ unless defined?(@date)
22
+ @date = @input&.kind_of?(Path) ? @input.mtime.to_datetime : DateTime.now
50
23
  end
24
+ @uri = Addressable::URI.encode(@path, Addressable::URI)
51
25
  end
52
26
 
53
- def public=(public)
54
- @public = case public
55
- when 'false', FalseClass
56
- false
57
- when 'true', TrueClass
58
- true
59
- else
60
- raise Error, "Can't assign 'public' attribute: #{public.inspect}"
61
- end
27
+ def inspect
28
+ "<#{self.class}>"
62
29
  end
63
30
 
64
- def public?
65
- @public == true
31
+ def primary?
32
+ @primary
66
33
  end
67
34
 
68
- def text?
69
- kind_of?(Resource::Text) && public?
35
+ def root?
36
+ self == @site.root_resource
70
37
  end
71
38
 
72
- def redirect?
73
- kind_of?(Resource::Redirect)
39
+ def output_file
40
+ if @site && @path
41
+ @site.output_dir / Path.new(@path).relative_to('/')
42
+ else
43
+ nil
44
+ end
74
45
  end
75
46
 
76
- def inspect
77
- "<%p> input_file: %p, output_file: %p, path: %s, date: %s, public: %p, content: <%p>, parent: %p, siblings: %p, children: %p" % [
78
- self.class,
79
- @input_file ? @input_file.relative_to(@site.input_dir).to_s : nil,
80
- @output_file ? @output_file.relative_to(@site.output_dir).to_s : nil,
81
- @path,
82
- @date.to_s,
83
- @public,
84
- @content&.class,
85
- parent&.path,
86
- siblings.map(&:path),
87
- children.map(&:path),
47
+ def printable
48
+ [
49
+ :path,
50
+ { key: :input, value: input_description },
51
+ { key: :output_file, value: (o = output_file) ? o.relative_to(@site.output_dir).to_s : nil },
52
+ :date,
53
+ :primary?,
54
+ :class,
55
+ { label: 'Parent', value: parent&.path || '-' },
56
+ { label: 'Siblings', value: siblings&.map(&:path)&.join(', ') || '-' },
57
+ { label: 'Children', value: children&.map(&:path)&.join(', ') || '-' },
88
58
  ]
89
59
  end
90
60
 
61
+ def input_description
62
+ case @input
63
+ when Path
64
+ @input.relative_to(@site.input_dir).to_s
65
+ when String
66
+ (@input[0...100] + '...').inspect
67
+ when nil
68
+ '-'
69
+ else
70
+ "<#{@input.class}>"
71
+ end
72
+ end
73
+
91
74
  def parent
92
- @node.parent&.content
75
+ @node&.parent&.content
93
76
  end
94
77
 
95
78
  def siblings
96
- @node.siblings.map(&:content).compact
79
+ @node ? @node.siblings.map(&:content).compact : []
97
80
  end
98
81
 
99
- def children
100
- @node.children.map(&:content).compact
82
+ def previous_sibling
83
+ @node&.previous_sibling&.content
101
84
  end
102
85
 
103
- def uri
104
- raise Error, "#{@input_file}: No path defined for #{self.class}" unless @path
105
- Addressable::URI.encode(@path, Addressable::URI)
86
+ def next_sibling
87
+ @node&.next_sibling&.content
88
+ end
89
+
90
+ def children
91
+ @node ? @node.children.map(&:content).compact : []
106
92
  end
107
93
 
108
94
  def absolute_uri
109
- @site.site_uri + uri
95
+ @site.site_uri + @uri
110
96
  end
111
97
 
112
98
  def tag_uri
113
- @site.tag_uri + uri
99
+ @site.tag_uri + @uri
114
100
  end
115
101
 
116
102
  def change_frequency
117
103
  :weekly
118
104
  end
119
105
 
120
- def final_content
121
- @content
122
- end
123
-
124
106
  def load
125
107
  # implemented in subclass
126
108
  end
@@ -130,16 +112,21 @@ module Mill
130
112
  end
131
113
 
132
114
  def save
133
- @output_file.dirname.mkpath
134
- if (content = final_content)
135
- # ;;warn "#{path}: writing #{@input_file} to #{@output_file}"
136
- @output_file.write(content.to_s)
137
- @output_file.utime(@date.to_time, @date.to_time)
138
- elsif @input_file
139
- # ;;warn "#{path}: copying #{@input_file} to #{@output_file}"
140
- @input_file.copy(@output_file)
115
+ file = output_file
116
+ file.dirname.mkpath
117
+ if @output
118
+ # ;;warn "#{@path}: writing output to #{file}"
119
+ file.write(@output)
120
+ file.utime(@date.to_time, @date.to_time)
121
+ elsif @input.kind_of?(Path)
122
+ # ;;warn "#{@path}: copying #{@input} to #{file}"
123
+ @input.copy(file)
124
+ elsif @input
125
+ # ;;warn "#{@path}: writing input to #{file}"
126
+ file.write(@input)
127
+ file.utime(@date.to_time, @date.to_time)
141
128
  else
142
- raise Error, "Can't build resource without content or input file: #{path}"
129
+ raise Error, "#{@path}: Can't build resource without output or input file"
143
130
  end
144
131
  end
145
132
 
@@ -5,6 +5,8 @@ module Mill
5
5
  class Blob < Resource
6
6
 
7
7
  FileTypes = %w{
8
+ text/plain
9
+
8
10
  application/pdf
9
11
 
10
12
  application/zip
@@ -16,9 +18,11 @@ module Mill
16
18
  application/x-javascript
17
19
 
18
20
  font/otf
21
+ font/woff2
19
22
  application/font-sfnt
20
23
  application/x-font-opentype
21
24
  application/x-font-otf
25
+ application/font-woff
22
26
 
23
27
  application/mp4
24
28
  audio/mpeg
@@ -1,20 +1,16 @@
1
- # see http://www.sitemaps.org/protocol.php
2
-
3
1
  module Mill
4
2
 
5
3
  class Resource
6
4
 
7
5
  class Feed < Resource
8
6
 
9
- include HTMLHelpers
10
-
11
7
  def build
12
8
  resources = @site.feed_resources
13
- builder = Nokogiri::XML::Builder.new do |xml|
9
+ @output = Nokogiri::XML::Builder.new do |xml|
14
10
  xml.feed(xmlns: 'http://www.w3.org/2005/Atom') do
15
11
  xml.id(@site.tag_uri)
16
12
  xml.title(@site.site_title) if @site.site_title
17
- xml.link(rel: 'alternate', type: 'text/html', href: @site.home_resource.absolute_uri) if @site.home_resource
13
+ xml.link(rel: 'alternate', type: 'text/html', href: @site.root_resource.absolute_uri) if @site.root_resource
18
14
  xml.link(rel: 'self', type: 'application/atom+xml', href: absolute_uri)
19
15
  xml.author do
20
16
  xml.name(@site.feed_author_name) if @site.feed_author_name
@@ -35,15 +31,11 @@ module Mill
35
31
  end
36
32
  end
37
33
  end
38
- end
39
- @content = builder.doc
40
- super
34
+ end.doc
41
35
  end
42
36
 
43
- def link_html
44
- html_fragment do |html|
45
- html.link(href: uri, rel: 'alternate', type: 'application/atom+xml')
46
- end
37
+ def build_link(html)
38
+ html.link(href: uri, rel: 'alternate', type: 'application/atom+xml')
47
39
  end
48
40
 
49
41
  end
@@ -4,8 +4,6 @@ module Mill
4
4
 
5
5
  class Image < Resource
6
6
 
7
- include HTMLHelpers
8
-
9
7
  FileTypes = %w{
10
8
  image/gif
11
9
  image/jpeg
@@ -18,27 +16,21 @@ module Mill
18
16
  attr_accessor :width
19
17
  attr_accessor :height
20
18
 
21
- def inspect
22
- super + ", width: %p, height: %p" % [
23
- @width,
24
- @height,
19
+ def printable
20
+ super + [
21
+ :width,
22
+ :height,
25
23
  ]
26
24
  end
27
25
 
28
26
  def load
29
- info = ImageSize.path(@input_file.to_s)
30
- @width, @height = *info.size
31
- super
32
- end
33
-
34
- def img_html
35
- html_fragment do |html|
36
- html.img(
37
- src: uri,
38
- alt: @title,
39
- height: @height,
40
- width: @width)
27
+ raise Error, "Input must be file" unless @input.kind_of?(Path)
28
+ begin
29
+ info = ImageSize.path(@input.to_s)
30
+ rescue => e
31
+ raise Error, "Can't load image file #{@input.to_s.inspect}: #{e}"
41
32
  end
33
+ @width, @height = *info.size
42
34
  end
43
35
 
44
36
  end
@@ -0,0 +1,20 @@
1
+ module Mill
2
+
3
+ class Resource
4
+
5
+ class Markdown < Markup
6
+
7
+ FileTypes = %w{
8
+ text/markdown
9
+ text/x-web-markdown
10
+ }
11
+
12
+ def parse_text(text)
13
+ Kramdown::Document.new((text || '').strip).to_html
14
+ end
15
+
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,62 @@
1
+ module Mill
2
+
3
+ class Resource
4
+
5
+ class Markup < Resource
6
+
7
+ def printable
8
+ super + [
9
+ :header,
10
+ { label: 'Text', value: @text[0...100] + '...' },
11
+ ]
12
+ end
13
+
14
+ def load
15
+ @text = case @input
16
+ when Path
17
+ @input.read
18
+ when String
19
+ @input.dup
20
+ else
21
+ raise Error, "Unknown markup input: #{@input.class}"
22
+ end
23
+ @header = HashStruct.new
24
+ if @text.split(/\n/, 2).first =~ /^\w+:\s+/
25
+ fields = {}
26
+ lines, @text = @text.split(/\n\n/, 2)
27
+ lines.split(/\n/).each do |line|
28
+ if line.start_with?(/\s+/)
29
+ key = fields.keys.last
30
+ fields[key] += line
31
+ else
32
+ key, value = line.strip.split(/:\s*/, 2)
33
+ fields[key] = value
34
+ end
35
+ end
36
+ @header = HashStruct.new(fields)
37
+ end
38
+ end
39
+
40
+ def parse_text(text)
41
+ # implemented in subclass
42
+ end
43
+
44
+ def convert_class
45
+ @site.resource_class_for_type('text/html')
46
+ end
47
+
48
+ def convert
49
+ return nil if @header[:draft]
50
+ convert_class.new(
51
+ path: @path.sub(%r{\.\w+$}, '.html'),
52
+ input: parse_text(@text),
53
+ date: @date,
54
+ **@header,
55
+ )
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+
62
+ end