pagemaster 2.0.2 → 2.1.2

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