pagemaster 2.0.2 → 2.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f6cdf1de48e215acc4bc5333aaa696a5f780f60fee31215692c0a1f056086db5
4
- data.tar.gz: 77311ef8a70474d8d9fdf0af0a6a03a2c78c8e4102bc77e3af4c58c6bf8954c3
3
+ metadata.gz: 15e3d4691cda14a252ecc20253c4ce5a9cb99092208503df0b9f2c412b7ec4c5
4
+ data.tar.gz: 26ae449fe19081b43d10af962ca275734bcdb9fa2ad8d232ee9a6be14f409fef
5
5
  SHA512:
6
- metadata.gz: 68c63dc08c8246dea2a055e0c97e4be920d7547e3fbee31cae6fe25cf2086f5f50264eef2d76375b660e0a60625e64755dbcc7b7ceb27df31d7b05650b29f9ac
7
- data.tar.gz: 3506b331595c280a8f3a3fafedf14c7c6b9d98b0c13e611b7b7cf2ee22e653bfc41264fa5420e1826a72c7df9c6c1c15eb94e1eeafb5f2993c6d781f4034297d
6
+ metadata.gz: 02cc23dae3ef3d00cf0498f68040f9953207af6134bc880ccd71be63adca6181a7e01359b6a13a722e085cc63125c5c087f76d6046cb624ae5b9eabeeccfbe29
7
+ data.tar.gz: 2815b7482d9901f5eb105285190d20c46faa5f1f5ca3a8c795ea1821c3a1f657421c2321f9b69f98fb47d67534f1db59677fd808650b483526968ea463cd8a35
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
6
+ gem 'jekyll', require: false
7
+ gem 'simplecov', require: false
data/lib/pagemaster.rb CHANGED
@@ -1,90 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ # stdlib
1
4
  require 'csv'
2
- require 'yaml'
5
+ require 'fileutils'
3
6
  require 'json'
4
-
5
- include FileUtils
6
-
7
- # Jekyll comand to generate markdown collection pages from CSV/YML/JSON records
8
- class Pagemaster < Jekyll::Command
9
- class << self
10
- def init_with_program(prog)
11
- prog.command(:pagemaster) do |c|
12
- c.syntax 'pagemaster [options] [args]'
13
- c.description 'Generate md pages from collection data.'
14
- c.option :no_perma, '--no-permalink', 'Skips adding hard-coded permalink.'
15
- c.option :force, '--force', 'Erases pre-existing collection before regenerating.'
16
- c.action { |args, options| execute(args, options) }
17
- end
18
- end
19
-
20
- def execute(args, opts = {})
21
- config = YAML.load_file('_config.yml')
22
- abort 'Cannot find collections in config' unless config.key?('collections')
23
- args.each do |name|
24
- abort "Cannot find #{name} in collection config" unless config['collections'].key? name
25
- meta = {
26
- id_key: config['collections'][name].fetch('id_key'),
27
- layout: config['collections'][name].fetch('layout'),
28
- source: config['collections'][name].fetch('source'),
29
- ext: config.fetch('permalink', '') == 'pretty' ? '/' : '.html'
30
- }
31
- data = ingest(meta)
32
- generate_pages(name, meta, data, opts)
33
- end
34
- end
35
-
36
- def ingest(meta)
37
- src = "_data/#{meta[:source]}"
38
- puts "Processing #{src}...."
39
- data = case File.extname(src)
40
- when '.csv'
41
- CSV.read(src, headers: true).map(&:to_hash)
42
- when '.json'
43
- JSON.parse(File.read(src).encode('UTF-8'))
44
- when '.yml'
45
- YAML.load_file(src)
46
- else
47
- raise 'Collection source must have a valid extension (.csv, .yml, or .json)'
48
- end
49
- detect_duplicates(meta, data)
50
- data
51
- rescue StandardError
52
- raise "Cannot load #{src}. check for typos and rebuild."
53
- end
54
-
55
- def detect_duplicates(meta, data)
56
- ids = data.map { |d| d[meta[:data]] }
57
- duplicates = ids.detect { |i| ids.count(i) > 1 } || []
58
- raise "Your collection duplicate ids: \n#{duplicates}" unless duplicates.empty?
59
- end
60
-
61
- def generate_pages(name, meta, data, opts)
62
- dir = "_#{name}"
63
- perma = opts.fetch(:no_perma, meta[:ext])
64
-
65
- if opts.fetch(:force, false)
66
- FileUtils.rm_rf(dir)
67
- puts "Overwriting #{dir} directory with --force."
68
- end
69
-
70
- mkdir_p(dir)
71
- data.each do |item|
72
- pagename = slug(item.fetch(meta[:id_key]))
73
- pagepath = "#{dir}/#{pagename}.md"
74
- item['permalink'] = "/#{name}/#{pagename}#{perma}" if perma
75
- item['layout'] = meta[:layout]
76
- if File.exist?(pagepath)
77
- puts "#{pagename}.md already exits. Skipping."
78
- else
79
- File.open(pagepath, 'w') { |f| f.write("#{item.to_yaml}---") }
80
- end
81
- end
82
- rescue StandardError
83
- raise 'Pagemaster exited for some reason, most likely a missing or invalid id_key.'
84
- end
85
-
86
- def slug(str)
87
- str.downcase.tr(' ', '_').gsub(/[^:\w-]/, '')
88
- end
89
- end
90
- end
7
+ require 'jekyll'
8
+
9
+ # 3rd party
10
+ require 'rainbow'
11
+ require 'safe_yaml'
12
+
13
+ # relative
14
+ require 'pagemaster/collection'
15
+ require 'pagemaster/command'
16
+ require 'pagemaster/error'
17
+ require 'pagemaster/site'
18
+ require 'pagemaster/version'
19
+
20
+ #
21
+ #
22
+ module Pagemaster; end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pagemaster
4
+ #
5
+ #
6
+ class Collection
7
+ attr_reader :source, :id_key, :layout, :data, :dir
8
+
9
+ #
10
+ #
11
+ def initialize(name, config)
12
+ @name = name
13
+ @config = config
14
+ @source = fetch 'source'
15
+ @id_key = fetch 'id_key'
16
+ end
17
+
18
+ #
19
+ #
20
+ def fetch(key)
21
+ raise Error::InvalidCollection unless @config.key? key
22
+
23
+ @config.dig key
24
+ end
25
+
26
+ #
27
+ #
28
+ def ingest_source
29
+ file = "_data/#{@source}"
30
+ raise Error::InvalidSource, "Cannot find source file #{file}" unless File.exist? file
31
+
32
+ case File.extname file
33
+ when '.csv'
34
+ CSV.read(file, headers: true).map(&:to_hash)
35
+ when '.json'
36
+ JSON.parse(File.read(file).encode('UTF-8'))
37
+ when /\.ya?ml/
38
+ YAML.load_file file
39
+ else
40
+ raise Error::InvalidSource, "Collection source #{file} must have a valid extension (.csv, .yml, or .json)"
41
+ end
42
+ rescue StandardError
43
+ raise Error::InvalidSource, "Cannot load #{file}. check for typos and rebuild."
44
+ end
45
+
46
+ #
47
+ #
48
+ def validate_data
49
+ ids = @data.map { |d| d.dig @id_key }
50
+ raise Error::InvalidCollection, "One or more items in collection '#{@name}' is missing required id for the id_key '#{@id_key}'" unless ids.all?
51
+
52
+ duplicates = ids.detect { |i| ids.count(i) > 1 } || []
53
+ raise Error::InvalidCollection, "The collection '#{@name}' has the follwing duplicate ids for id_key #{@id_key}: \n#{duplicates}" unless duplicates.empty?
54
+ end
55
+
56
+ #
57
+ #
58
+ def overwrite_pages
59
+ return unless @dir
60
+
61
+ FileUtils.rm_rf @dir
62
+ puts Rainbow("Overwriting #{@dir} directory with --force.").cyan
63
+ end
64
+
65
+ #
66
+ #
67
+ def generate_pages(opts, collections_dir, source_dir)
68
+ @opts = opts
69
+ @dir = File.join [source_dir, collections_dir, "_#{@name}"].compact
70
+
71
+ overwrite_pages if @opts.fetch :force, false
72
+ FileUtils.mkdir_p @dir
73
+ @data = ingest_source
74
+ validate_data
75
+
76
+ @data.map do |d|
77
+ path = "#{@dir}/#{slug d[@id_key]}.md"
78
+ d['layout'] = @config['layout'] if @config.key? 'layout'
79
+ if File.exist? path
80
+ puts Rainbow("#{path} already exits. Skipping.").cyan
81
+ else
82
+ File.open(path, 'w') { |f| f.write("#{d.to_yaml}---") }
83
+ end
84
+ path
85
+ end
86
+ end
87
+
88
+ #
89
+ #
90
+ def slug(str)
91
+ str.downcase.tr(' ', '_').gsub(/[^:\w-]/, '')
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pagemaster
4
+ #
5
+ #
6
+ class Command < Jekyll::Command
7
+ def self.init_with_program(prog)
8
+ prog.command(:pagemaster) do |c|
9
+ c.syntax 'pagemaster [options] [args]'
10
+ c.description 'Generate md pages from collection data.'
11
+ c.option :force, '--force', 'Erases pre-existing collection before regenerating.'
12
+ c.action do |args, options|
13
+ site = Pagemaster::Site.new args, options
14
+ site.generate_pages
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pagemaster
4
+ module Error
5
+ #
6
+ #
7
+ class RainbowError < StandardError
8
+ def initialize(msg = '')
9
+ super(Rainbow(msg).magenta)
10
+ end
11
+ end
12
+
13
+ #
14
+ #
15
+ class InvalidConfig < RainbowError; end
16
+
17
+ #
18
+ #
19
+ class MissingArgs < RainbowError; end
20
+
21
+ #
22
+ #
23
+ class InvalidCollection < RainbowError; end
24
+
25
+ #
26
+ #
27
+ class InvalidArgument < RainbowError; end
28
+
29
+ #
30
+ #
31
+ class InvalidSource < RainbowError; end
32
+ end
33
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pagemaster
4
+ #
5
+ #
6
+ class Site
7
+ attr_reader :config, :args, :opts, :collections
8
+
9
+ #
10
+ #
11
+ def initialize(args, opts, config = nil)
12
+ @args = args
13
+ @opts = opts
14
+ @config = config || config_from_file
15
+ @collections = parse_collections
16
+ @collections_dir = @config.dig 'collections_dir'
17
+ @source_dir = @config.dig 'source_dir'
18
+
19
+ raise Error::MissingArgs, 'You must specify one or more collections after `jekyll pagemaster`' if @args.empty?
20
+ raise Error::InvalidCollection, "Cannot find collection(s) #{@args} in config" if @collections.empty?
21
+ end
22
+
23
+ #
24
+ #
25
+ def config_from_file
26
+ YAML.load_file "#{`pwd`.strip}/_config.yml"
27
+ end
28
+
29
+ #
30
+ #
31
+ def parse_collections
32
+ collections_config = @config.dig 'collections'
33
+
34
+ raise Error::InvalidConfig, "Cannot find 'collections' key in _config.yml" if collections_config.nil?
35
+
36
+ args.map do |a|
37
+ raise Error::InvalidArgument, "Cannot find requested collection #{a} in _config.yml" unless collections_config.key? a
38
+
39
+ Collection.new(a, collections_config.fetch(a))
40
+ end
41
+ end
42
+
43
+ #
44
+ #
45
+ def generate_pages
46
+ paths = @collections.map do |c|
47
+ c.generate_pages @opts, @collections_dir, @source_dir
48
+ end.flatten
49
+ puts Rainbow('Done ✔').green
50
+
51
+ paths
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pagemaster
4
+ VERSION = '2.1.2'
5
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Pagemaster::Collection do
4
+ include_context 'shared'
5
+ before(:all) { Pagemaster::Test.reset }
6
+
7
+ let(:csv_collection) { site.collections.first }
8
+ let(:json_collection) { site.collections[1] }
9
+ let(:yaml_collection) { site.collections.last }
10
+
11
+ describe '.new' do
12
+ context 'with valid config' do
13
+ it 'gets the source' do
14
+ expect(csv_collection.source).to be_a String
15
+ end
16
+
17
+ it 'gets the id_key' do
18
+ expect(csv_collection.id_key).to be_a String
19
+ end
20
+ end
21
+ end
22
+
23
+ describe '.ingest_source' do
24
+ context 'with valid csv collection' do
25
+ it 'ingests the source file' do
26
+ result = csv_collection.ingest_source
27
+
28
+ expect(result).to be_an Array
29
+ expect(result.first).to be_a Hash
30
+ end
31
+ end
32
+
33
+ context 'with valid json collection' do
34
+ it 'ingests the source file' do
35
+ result = json_collection.ingest_source
36
+
37
+ expect(result).to be_an Array
38
+ expect(result.first).to be_a Hash
39
+ end
40
+ end
41
+
42
+ context 'with valid yaml collection' do
43
+ it 'ingests the source file' do
44
+ result = yaml_collection.ingest_source
45
+
46
+ expect(result).to be_an Array
47
+ expect(result.first).to be_a Hash
48
+ end
49
+ end
50
+ end
51
+
52
+ describe '.overwrite_pages' do
53
+ context 'if page directory does not exists' do
54
+ it 'does nothing' do
55
+ expect { csv_collection.overwrite_pages }.not_to raise_error
56
+ end
57
+ end
58
+
59
+ it 'removes the page directory' do
60
+ csv_collection.overwrite_pages
61
+ end
62
+ end
63
+ end
data/spec/setup.rb ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+
5
+ # constants
6
+ ROOT = `pwd`.strip
7
+ SAMPLE = "#{ROOT}/spec/sample_site"
8
+ BUILD = "#{ROOT}/test_build"
9
+
10
+ # helper methods
11
+ def quiet_stdout
12
+ if QUIET
13
+ begin
14
+ orig_stderr = $stderr.clone
15
+ orig_stdout = $stdout.clone
16
+ $stderr.reopen File.new('/dev/null', 'w')
17
+ $stdout.reopen File.new('/dev/null', 'w')
18
+ retval = yield
19
+ rescue StandardError => e
20
+ $stdout.reopen orig_stdout
21
+ $stderr.reopen orig_stderr
22
+ raise e
23
+ ensure
24
+ $stdout.reopen orig_stdout
25
+ $stderr.reopen orig_stderr
26
+ end
27
+ retval
28
+ else
29
+ yield
30
+ end
31
+ end
32
+
33
+ module Pagemaster
34
+ module Test
35
+ def self.reset
36
+ Dir.chdir(ROOT)
37
+ FileUtils.rm_r(BUILD) if File.directory?(BUILD)
38
+ FileUtils.copy_entry(SAMPLE, BUILD)
39
+ Dir.chdir(BUILD)
40
+ end
41
+ end
42
+ end
data/spec/site_spec.rb ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Pagemaster::Site do
4
+ include_context 'shared'
5
+ before(:all) { Pagemaster::Test.reset }
6
+
7
+ describe '.new' do
8
+ it 'runs without errors' do
9
+ expect(site).to be_a Pagemaster::Site
10
+ end
11
+
12
+ it 'parses the config' do
13
+ expect(site.config).to be_a Hash
14
+ expect(site.config).to eq config
15
+ end
16
+
17
+ it 'parses the args' do
18
+ expect(site.args).to be_an Array
19
+ expect(site.args).to eq args
20
+ end
21
+
22
+ it 'parses the opts' do
23
+ expect(site.opts).to be_a Hash
24
+ expect(site.opts). to eq opts
25
+ end
26
+
27
+ it 'parses the collections' do
28
+ expect(site.collections).to be_an Array
29
+ expect(site.collections.first).to be_a Pagemaster::Collection
30
+ end
31
+
32
+ context 'when given invalid args' do
33
+ it 'throws an error' do
34
+ expect { Pagemaster::Site.new(['bad_arg'], opts) }.to raise_error Pagemaster::Error::InvalidArgument
35
+ end
36
+ end
37
+ end
38
+
39
+ describe '.generate_pages' do
40
+ it 'generates expected pages' do
41
+ expect(site.generate_pages).to eq page_paths
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'simplecov'
4
+ SimpleCov.start do
5
+ add_filter 'spec'
6
+ end
7
+
8
+ require File.expand_path('../lib/pagemaster.rb', __dir__)
9
+ require 'pagemaster'
10
+ require 'setup'
11
+
12
+ shared_context 'shared', shared_context: :metadata do
13
+ let(:args) { %w[csv_collection json_collection yaml_collection] }
14
+ let(:config) { YAML.load_file "#{BUILD}/_config.yml" }
15
+ let(:opts) { {} }
16
+ let(:site) { Pagemaster::Site.new args, opts }
17
+ let(:page_paths) do
18
+ ['_csv_collection/img_item_1.md',
19
+ '_csv_collection/img_item_2.md',
20
+ '_csv_collection/dir_imgs_item.md',
21
+ '_csv_collection/pdf_imgs_item.md',
22
+ '_json_collection/img_item_1.md',
23
+ '_json_collection/img_item_2.md',
24
+ '_json_collection/dir_imgs_item.md',
25
+ '_json_collection/pdf_imgs_item.md',
26
+ '_yaml_collection/img_item_1.md',
27
+ '_yaml_collection/img_item_2.md',
28
+ '_yaml_collection/dir_imgs_item.md',
29
+ '_yaml_collection/pdf_imgs_item.md']
30
+ end
31
+ end
32
+
33
+ require 'collection_spec'
34
+ require 'site_spec'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pagemaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marii Nyrop
@@ -16,56 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.8'
19
+ version: '4'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '3.8'
26
+ version: '4'
27
27
  - !ruby/object:Gem::Dependency
28
- name: bundler
28
+ name: rainbow
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.16'
34
- type: :development
33
+ version: '3.0'
34
+ type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.16'
40
+ version: '3.0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: faker
42
+ name: safe_yaml
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.9'
48
- type: :development
47
+ version: '1.0'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.9'
54
+ version: '1.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.7'
61
+ version: '3.9'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.7'
68
+ version: '3.9'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,7 +86,17 @@ executables: []
86
86
  extensions: []
87
87
  extra_rdoc_files: []
88
88
  files:
89
+ - Gemfile
89
90
  - lib/pagemaster.rb
91
+ - lib/pagemaster/collection.rb
92
+ - lib/pagemaster/command.rb
93
+ - lib/pagemaster/error.rb
94
+ - lib/pagemaster/site.rb
95
+ - lib/pagemaster/version.rb
96
+ - spec/collection_spec.rb
97
+ - spec/setup.rb
98
+ - spec/site_spec.rb
99
+ - spec/spec_helper.rb
90
100
  homepage: https://github.com/mnyrop/pagemaster
91
101
  licenses:
92
102
  - MIT
@@ -99,7 +109,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
109
  requirements:
100
110
  - - ">="
101
111
  - !ruby/object:Gem::Version
102
- version: '0'
112
+ version: '2.4'
103
113
  required_rubygems_version: !ruby/object:Gem::Requirement
104
114
  requirements:
105
115
  - - ">="
@@ -107,8 +117,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
117
  version: '0'
108
118
  requirements: []
109
119
  rubyforge_project:
110
- rubygems_version: 2.7.6
120
+ rubygems_version: 2.7.6.2
111
121
  signing_key:
112
122
  specification_version: 4
113
123
  summary: jekyll pagemaster plugin
114
- test_files: []
124
+ test_files:
125
+ - spec/spec_helper.rb
126
+ - spec/collection_spec.rb
127
+ - spec/site_spec.rb
128
+ - spec/setup.rb