zine 0.2.0 → 0.3.0

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.
@@ -1,11 +1,23 @@
1
1
  <footer>
2
- <div class="contact">
2
+ <div class="column">
3
+ <h3>Contact me</h3>
3
4
  <p>Twitter:&nbsp;<a href="https://twitter.com/<%= page[:twitter_name] %>">@<%= page[:twitter_name] %></a></p>
4
5
  </div>
5
- <div class="contact">
6
- <p>&copy; 2017<span> <%= page[:site_author] %></span>
7
- </p>
6
+ <div class="column">
7
+ <h3>Me elsewhere</h3>
8
+ <ul>
9
+ <% for @link in page[:links_array] %>
10
+ <li><a href="<%= @link['uri'] %>"><%= @link['name'] %></a></li>
11
+ <% end %>
12
+ </ul>
8
13
  </div>
14
+ <div class="column">
15
+ <h3>The fine print</h3>
16
+ <ul>
17
+ <li>Built with <a href="https://github.com/mikekreuzer/zine">Zine</a></li>
18
+ <li>&copy; 2017<span> <%= page[:site_author] %></span></li>
19
+ </ul>
20
+ <div>
9
21
  </footer>
10
22
  </body>
11
23
  </html>
@@ -2,7 +2,7 @@
2
2
  <main>
3
3
  <section>
4
4
  <% for @post in data %>
5
- <h2><%= @post[:page][:title] %></h2>
5
+ <h2><a href="<%= @post[:uri] %>"><%= @post[:page][:title] %></a></h2>
6
6
  <p class="date"><%= @post[:page][:date_us] %></p>
7
7
  <%= @post[:html] %>
8
8
  <div class="tags">Tags:
@@ -13,6 +13,8 @@
13
13
  </ul>
14
14
  </div>
15
15
  <% end %>
16
+ <h2>Previously</h2>
17
+ <p><a href="/articles.html">Earlier posts...</a></p>
16
18
  </section>
17
19
  </main>
18
20
  <%= footer_partial %>
@@ -1,28 +1,41 @@
1
1
  ---
2
2
  directories:
3
- blog: blog
4
- build: build
5
- assets: assets
6
- posts: posts
7
- source: source
8
- styles: styles
9
- templates: templates
10
- templates:
11
- articles: articles
12
- default: default
13
- home: home
14
- new_post: new_post.erb
15
- post: post
16
- rss: rss
17
- tag: tag
18
- tag_index: tag_index
3
+ assets: assets
4
+ blog: blog
5
+ build: build
6
+ posts: posts
7
+ source: source
8
+ styles: styles
9
+ templates: templates
10
+ links:
11
+ -
12
+ name: GitHub
13
+ uri: https://github.com/mikekreuzer
14
+ -
15
+ name: Ripley
16
+ uri: https://mikekreuzer.github.io/Ripley/
19
17
  options:
20
- css_preprocessor: less
21
- github_name: mikekreuzer
22
- number_items_in_RSS: 7
23
- num_items_on_home: 7
24
- site_author: Mike Kreuzer
25
- site_description: The scribblings of a once and future code monkey
26
- site_name: Mike Kreuzer
27
- site_URL: https://mikekreuzer.com
28
- twitter_name: mikekreuzer
18
+ css_preprocessor: less
19
+ github_name: mikekreuzer
20
+ number_items_in_RSS: 7
21
+ num_items_on_home: 7
22
+ site_author: Mike Kreuzer
23
+ site_description: The scribblings of a once and future code monkey
24
+ site_name: Mike Kreuzer
25
+ site_URL: https://mikekreuzer.com
26
+ twitter_name: mikekreuzer
27
+ templates:
28
+ articles: articles
29
+ default: default
30
+ home: home
31
+ new_post: new_post.erb
32
+ post: post
33
+ rss: rss
34
+ tag: tag
35
+ tag_index: tag_index
36
+ upload:
37
+ credentials: /local/absolute/path/to/yaml/file/with/username/and/password
38
+ host: 127.0.0.1
39
+ method: none|sftp
40
+ path: /remote/absolute/path/to/html
41
+ verbose: true
data/lib/zine/style.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'sassc'
2
+
3
+ module Zine
4
+ # Render sass into CSS in the source directory, to be copied later
5
+ class Style
6
+ # Source & destination files
7
+ def initialize(directories)
8
+ @style_file = File.join directories['styles'], 'screen.scss'
9
+ @css_file = File.join directories['source'], 'screen.css'
10
+ end
11
+
12
+ # Write the CSS file
13
+ def process
14
+ sass = File.open(@style_file, 'r').read
15
+ css = SassC::Engine.new(sass, style: :compressed).render
16
+ File.write @css_file, css
17
+ end
18
+ end
19
+ end
data/lib/zine/tag.rb CHANGED
@@ -8,6 +8,7 @@ module Zine
8
8
  @posts_by_tag = sort_tags tags_by_post
9
9
  @templates = { tag: tag_templates, tag_index: tag_index_templates }
10
10
  @tag_dir = File.join @options['directories']['build'], 'tags'
11
+ FileUtils.remove_dir @tag_dir, force: true
11
12
  FileUtils.mkdir_p @tag_dir
12
13
  end
13
14
 
@@ -0,0 +1,161 @@
1
+ require 'net/ssh'
2
+ require 'net/sftp'
3
+ require 'rainbow'
4
+ require 'set'
5
+
6
+ module Zine
7
+ # Deploy changes to a remote host
8
+ # TODO: add GitHub deploys as well...
9
+ class Upload
10
+ # a folder in a path
11
+ Node = Struct.new(:name, :path_string)
12
+
13
+ def initialize(build_dir, options, delete_file_array, upload_file_array)
14
+ return unless options['method'] == 'sftp'
15
+
16
+ @build_dir = build_dir
17
+ @host = options['host']
18
+ @path = options['path']
19
+ @verbose = options['verbose']
20
+
21
+ cred_file = options['credentials']
22
+ @credentials = parse_yaml(File.open(cred_file, 'r'), cred_file)
23
+
24
+ @upload_file_array = Set.new(upload_file_array).to_a
25
+ @delete_file_array = Set.new(delete_file_array).to_a - @upload_file_array
26
+ end
27
+
28
+ def delete
29
+ Net::SFTP.start(@host, @credentials['username'],
30
+ password: @credentials['password']) do |sftp|
31
+ @delete_file_array.each do |rel_file_path|
32
+ sftp.remove(File.join(@path, rel_file_path)).wait
33
+ puts "Deleted #{rel_file_path}" if @verbose
34
+ end
35
+ end
36
+ end
37
+
38
+ def deploy
39
+ Net::SFTP.start(@host, @credentials['username'],
40
+ password: @credentials['password']) do |sftp|
41
+ deploy_directories sftp
42
+ deploy_files sftp
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def break_strings_into_arrays(paths_array)
49
+ paths_array.map do |dir|
50
+ dir.to_s.split File::SEPARATOR
51
+ end
52
+ end
53
+
54
+ # make directories
55
+ def deploy_directories(sftp)
56
+ node_array = make_sparse_node_array @upload_file_array
57
+ node_array.each do |level|
58
+ level.each do |node|
59
+ next if node.nil?
60
+ path_string = node.path_string
61
+ mkdir_p(sftp, path_string)
62
+ puts "mkdir_p #{path_string}" if @verbose
63
+ end
64
+ end
65
+ end
66
+
67
+ # upload files
68
+ def deploy_files(sftp)
69
+ @upload_file_array.each do |rel_file_path|
70
+ sftp.upload(File.join(@build_dir, rel_file_path),
71
+ File.join(@path, rel_file_path),
72
+ permissions: 0o644).wait # -rw-r--r--
73
+ puts "Uploaded #{rel_file_path}" if @verbose
74
+ end
75
+ end
76
+
77
+ def mkdir_p(sftp, path)
78
+ sftp.mkdir!(File.join(@path, path), permissions: 0o755) # drwxr-xr-x
79
+ rescue Net::SFTP::StatusException => error
80
+ raise if error.code != 4 && error.code != 11 # folder already exists
81
+ end
82
+
83
+ # make a sparse matrix as a directory tree, to make mkdir calls efficiently
84
+ def make_sparse_node_array(file_array)
85
+ paths_array = remove_filenames file_array # remove file names
86
+ paths_array = Set.new(paths_array).to_a # remove duplicates
87
+ paths_array = break_strings_into_arrays paths_array # to array of arrays
88
+ paths_array = strings_to_nodes paths_array # ...of nodes
89
+ level_array = transpose paths_array # arrayed by level
90
+ remove_duplicates level_array # make it sparse
91
+ end
92
+
93
+ def parse_yaml(text, cred_file)
94
+ YAML.safe_load text
95
+ rescue Psych::Exception
96
+ puts Rainbow("Could not parse YAML in: #{cred_file}").red
97
+ { 'username' => '', 'password' => '' }
98
+ end
99
+
100
+ # for each level, if a node has the same name & same path it's a duplicate
101
+ def remove_duplicates(level_array)
102
+ level_array.map do |level|
103
+ length = level.length
104
+ level_copy = level
105
+ level.each_with_index.map do |node, index|
106
+ next if node.nil?
107
+ if index.zero?
108
+ node
109
+ elsif !level_copy[0..(index - 1)]
110
+ .index { |item| same(item, node) }.nil? ||
111
+ !level_copy[(index + 1)..(length - 1)]
112
+ .index { |item| same(item, node) }.nil?
113
+ level_copy[index] = nil
114
+ nil
115
+ else
116
+ node
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ # array of file paths to array of directory paths
123
+ def remove_filenames(file_array)
124
+ file_array.map do |file|
125
+ path = File.dirname file
126
+ if path == '.'
127
+ nil
128
+ else
129
+ path
130
+ end
131
+ end
132
+ end
133
+
134
+ # equality for a node
135
+ def same(first, second)
136
+ return false if first.nil? || second.nil?
137
+ first.name == second.name && first.path_string == second.path_string
138
+ end
139
+
140
+ # convert directory names to nodes with knowledge of their parentage
141
+ def strings_to_nodes(paths_array)
142
+ paths_array.map do |path|
143
+ path_string_array = path
144
+ path.each_with_index.map do |elem, index|
145
+ Node.new(elem, path_string_array[0..index].join(File::SEPARATOR))
146
+ end
147
+ end
148
+ end
149
+
150
+ # flip it, to get directories by level in a path, rather than by path
151
+ def transpose(input)
152
+ result = []
153
+ max_size = input.max_by(&:size).size
154
+ max_size.times do |i|
155
+ result[i] = Array.new(input.first.size)
156
+ input.each_with_index { |r, j| result[i][j] = r[i] }
157
+ end
158
+ result
159
+ end
160
+ end
161
+ end
data/lib/zine/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Zine
2
- VERSION = '0.2.0'.freeze
2
+ VERSION = '0.3.0'.freeze
3
3
  end
@@ -0,0 +1,88 @@
1
+ require 'listen'
2
+ require 'pathname'
3
+
4
+ module Zine
5
+ # Watch files for changes
6
+ class Watcher
7
+ attr_reader :upload_array, :delete_array
8
+
9
+ def initialize(posts_and_headlines, build_directory, source_directory)
10
+ @posts_and_headlines = posts_and_headlines
11
+ @build_directory = File.join Dir.pwd, build_directory
12
+ @source_directory = File.join Dir.pwd, source_directory
13
+ @upload_array = []
14
+ @delete_array = []
15
+ end
16
+
17
+ # Build a delete list & an upload list for SSH from changes in build,
18
+ # & rebuild & reload on changes in source
19
+ def start
20
+ watch_build_dir
21
+ watch_source_dir
22
+ end
23
+
24
+ private
25
+
26
+ def on_build_change(path_string_array)
27
+ path_string_array.each do |str|
28
+ rel_path = rel_path_from_build_dir str
29
+ @upload_array << rel_path
30
+ end
31
+ end
32
+
33
+ def on_build_delete(path_string_array)
34
+ path_string_array.each do |str|
35
+ rel_path = rel_path_from_build_dir str
36
+ @delete_array << rel_path
37
+ # @upload_array.delete rel_path
38
+ end
39
+ end
40
+
41
+ def rel_path_from_build_dir(path)
42
+ full = Pathname(path)
43
+ full.relative_path_from(Pathname(@build_directory))
44
+ end
45
+
46
+ # rebuild the file, and the headline files & tags
47
+ # TODO: moves within the watched directory won't delete the old location
48
+ def on_source_change(path)
49
+ path.each do |file|
50
+ if !file.nil? && (file =~ /^.+\.md$/).nil?
51
+ @posts_and_headlines.preview_straight_copy file
52
+ else
53
+ @posts_and_headlines.preview_rebuild file
54
+ end
55
+ end
56
+ end
57
+
58
+ # delete build file from posts, then posts entry
59
+ # rebuild the headline files... and the tags...
60
+ def on_source_delete(path)
61
+ path.each do |file|
62
+ if !file.nil? && (file =~ /^.+\.md$/).nil?
63
+ @posts_and_headlines.preview_straight_delete file
64
+ else
65
+ @posts_and_headlines.preview_delete file
66
+ end
67
+ end
68
+ end
69
+
70
+ def watch_build_dir
71
+ listener = Listen.to(@build_directory) do |modified, added, removed|
72
+ on_build_change modified unless modified.empty?
73
+ on_build_change added unless added.empty?
74
+ on_build_delete removed unless removed.empty?
75
+ end
76
+ listener.start
77
+ end
78
+
79
+ def watch_source_dir
80
+ listener = Listen.to(@source_directory) do |modified, added, removed|
81
+ on_source_change modified unless modified.empty?
82
+ on_source_change added unless added.empty?
83
+ on_source_delete removed unless removed.empty?
84
+ end
85
+ listener.start
86
+ end
87
+ end
88
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Kreuzer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-09 00:00:00.000000000 Z
11
+ date: 2017-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,26 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: highline
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.7'
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.7.8
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '1.7'
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.7.8
69
89
  - !ruby/object:Gem::Dependency
70
90
  name: htmlcompressor
71
91
  requirement: !ruby/object:Gem::Requirement
@@ -73,6 +93,9 @@ dependencies:
73
93
  - - "~>"
74
94
  - !ruby/object:Gem::Version
75
95
  version: '0.3'
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 0.3.1
76
99
  type: :runtime
77
100
  prerelease: false
78
101
  version_requirements: !ruby/object:Gem::Requirement
@@ -80,6 +103,9 @@ dependencies:
80
103
  - - "~>"
81
104
  - !ruby/object:Gem::Version
82
105
  version: '0.3'
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: 0.3.1
83
109
  - !ruby/object:Gem::Dependency
84
110
  name: kramdown
85
111
  requirement: !ruby/object:Gem::Requirement
@@ -87,6 +113,9 @@ dependencies:
87
113
  - - "~>"
88
114
  - !ruby/object:Gem::Version
89
115
  version: '1.13'
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 1.13.2
90
119
  type: :runtime
91
120
  prerelease: false
92
121
  version_requirements: !ruby/object:Gem::Requirement
@@ -94,6 +123,49 @@ dependencies:
94
123
  - - "~>"
95
124
  - !ruby/object:Gem::Version
96
125
  version: '1.13'
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 1.13.2
129
+ - !ruby/object:Gem::Dependency
130
+ name: listen
131
+ requirement: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - "~>"
134
+ - !ruby/object:Gem::Version
135
+ version: '3.0'
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 3.1.5
139
+ type: :runtime
140
+ prerelease: false
141
+ version_requirements: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '3.0'
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: 3.1.5
149
+ - !ruby/object:Gem::Dependency
150
+ name: net-sftp
151
+ requirement: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - "~>"
154
+ - !ruby/object:Gem::Version
155
+ version: '2.1'
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: 2.1.2
159
+ type: :runtime
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - "~>"
164
+ - !ruby/object:Gem::Version
165
+ version: '2.1'
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: 2.1.2
97
169
  - !ruby/object:Gem::Dependency
98
170
  name: rainbow
99
171
  requirement: !ruby/object:Gem::Requirement
@@ -101,6 +173,9 @@ dependencies:
101
173
  - - "~>"
102
174
  - !ruby/object:Gem::Version
103
175
  version: '2.2'
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: 2.2.1
104
179
  type: :runtime
105
180
  prerelease: false
106
181
  version_requirements: !ruby/object:Gem::Requirement
@@ -108,6 +183,29 @@ dependencies:
108
183
  - - "~>"
109
184
  - !ruby/object:Gem::Version
110
185
  version: '2.2'
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: 2.2.1
189
+ - !ruby/object:Gem::Dependency
190
+ name: sassc
191
+ requirement: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - "~>"
194
+ - !ruby/object:Gem::Version
195
+ version: '1.11'
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: 1.11.2
199
+ type: :runtime
200
+ prerelease: false
201
+ version_requirements: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - "~>"
204
+ - !ruby/object:Gem::Version
205
+ version: '1.11'
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: 1.11.2
111
209
  - !ruby/object:Gem::Dependency
112
210
  name: thin
113
211
  requirement: !ruby/object:Gem::Requirement
@@ -129,6 +227,9 @@ dependencies:
129
227
  - - "~>"
130
228
  - !ruby/object:Gem::Version
131
229
  version: '0.19'
230
+ - - ">="
231
+ - !ruby/object:Gem::Version
232
+ version: 0.19.4
132
233
  type: :runtime
133
234
  prerelease: false
134
235
  version_requirements: !ruby/object:Gem::Requirement
@@ -136,6 +237,9 @@ dependencies:
136
237
  - - "~>"
137
238
  - !ruby/object:Gem::Version
138
239
  version: '0.19'
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: 0.19.4
139
243
  description: |-
140
244
  Yet another blog aware static site generator.
141
245
  These are the very early days of zine, expect breaking changes.
@@ -157,10 +261,16 @@ files:
157
261
  - lib/zine/data_page.rb
158
262
  - lib/zine/page.rb
159
263
  - lib/zine/post.rb
264
+ - lib/zine/posts_and_headlines.rb
160
265
  - lib/zine/server.rb
161
266
  - lib/zine/skeleton/source/about.md
267
+ - lib/zine/skeleton/source/assets/webicon-rss-m.png
268
+ - lib/zine/skeleton/source/assets/webicon-rss.svg
269
+ - lib/zine/skeleton/source/assets/webicon-twitter-m.png
270
+ - lib/zine/skeleton/source/assets/webicon-twitter.svg
162
271
  - lib/zine/skeleton/source/posts/2017-01-25-my-new-blog.md
163
272
  - lib/zine/skeleton/source/screen.css
273
+ - lib/zine/skeleton/source/styles/screen.scss
164
274
  - lib/zine/skeleton/source/templates/articles.erb
165
275
  - lib/zine/skeleton/source/templates/default.erb
166
276
  - lib/zine/skeleton/source/templates/footer_partial.erb
@@ -172,9 +282,12 @@ files:
172
282
  - lib/zine/skeleton/source/templates/tag.erb
173
283
  - lib/zine/skeleton/source/templates/tag_index.erb
174
284
  - lib/zine/skeleton/zine.yaml
285
+ - lib/zine/style.rb
175
286
  - lib/zine/tag.rb
176
287
  - lib/zine/templates.rb
288
+ - lib/zine/upload.rb
177
289
  - lib/zine/version.rb
290
+ - lib/zine/watcher.rb
178
291
  homepage: https://github.com/mikekreuzer/zine
179
292
  licenses:
180
293
  - MIT