jekyll 4.2.1 → 4.2.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.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +350 -350
  3. data/LICENSE +21 -21
  4. data/README.markdown +86 -86
  5. data/exe/jekyll +57 -57
  6. data/lib/blank_template/_config.yml +3 -3
  7. data/lib/blank_template/_layouts/default.html +12 -12
  8. data/lib/blank_template/_sass/main.scss +9 -9
  9. data/lib/blank_template/assets/css/main.scss +4 -4
  10. data/lib/blank_template/index.md +8 -8
  11. data/lib/jekyll/cache.rb +190 -190
  12. data/lib/jekyll/cleaner.rb +111 -111
  13. data/lib/jekyll/collection.rb +309 -309
  14. data/lib/jekyll/command.rb +105 -105
  15. data/lib/jekyll/commands/build.rb +93 -93
  16. data/lib/jekyll/commands/clean.rb +45 -45
  17. data/lib/jekyll/commands/doctor.rb +177 -177
  18. data/lib/jekyll/commands/help.rb +34 -34
  19. data/lib/jekyll/commands/new.rb +172 -169
  20. data/lib/jekyll/commands/new_theme.rb +40 -40
  21. data/lib/jekyll/commands/serve/live_reload_reactor.rb +122 -122
  22. data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -1183
  23. data/lib/jekyll/commands/serve/servlet.rb +202 -202
  24. data/lib/jekyll/commands/serve/websockets.rb +81 -81
  25. data/lib/jekyll/commands/serve.rb +362 -362
  26. data/lib/jekyll/configuration.rb +313 -313
  27. data/lib/jekyll/converter.rb +54 -54
  28. data/lib/jekyll/converters/identity.rb +41 -41
  29. data/lib/jekyll/converters/markdown/kramdown_parser.rb +199 -199
  30. data/lib/jekyll/converters/markdown.rb +113 -113
  31. data/lib/jekyll/converters/smartypants.rb +70 -70
  32. data/lib/jekyll/convertible.rb +257 -257
  33. data/lib/jekyll/deprecator.rb +50 -50
  34. data/lib/jekyll/document.rb +544 -544
  35. data/lib/jekyll/drops/collection_drop.rb +20 -20
  36. data/lib/jekyll/drops/document_drop.rb +70 -70
  37. data/lib/jekyll/drops/drop.rb +293 -293
  38. data/lib/jekyll/drops/excerpt_drop.rb +19 -19
  39. data/lib/jekyll/drops/jekyll_drop.rb +32 -32
  40. data/lib/jekyll/drops/site_drop.rb +66 -66
  41. data/lib/jekyll/drops/static_file_drop.rb +14 -14
  42. data/lib/jekyll/drops/unified_payload_drop.rb +26 -26
  43. data/lib/jekyll/drops/url_drop.rb +140 -140
  44. data/lib/jekyll/entry_filter.rb +121 -121
  45. data/lib/jekyll/errors.rb +20 -20
  46. data/lib/jekyll/excerpt.rb +201 -201
  47. data/lib/jekyll/external.rb +79 -79
  48. data/lib/jekyll/filters/date_filters.rb +110 -110
  49. data/lib/jekyll/filters/grouping_filters.rb +64 -64
  50. data/lib/jekyll/filters/url_filters.rb +98 -98
  51. data/lib/jekyll/filters.rb +535 -535
  52. data/lib/jekyll/frontmatter_defaults.rb +240 -240
  53. data/lib/jekyll/generator.rb +5 -5
  54. data/lib/jekyll/hooks.rb +107 -107
  55. data/lib/jekyll/inclusion.rb +32 -32
  56. data/lib/jekyll/layout.rb +67 -67
  57. data/lib/jekyll/liquid_extensions.rb +22 -22
  58. data/lib/jekyll/liquid_renderer/file.rb +77 -77
  59. data/lib/jekyll/liquid_renderer/table.rb +55 -55
  60. data/lib/jekyll/liquid_renderer.rb +80 -80
  61. data/lib/jekyll/log_adapter.rb +151 -151
  62. data/lib/jekyll/mime.types +866 -866
  63. data/lib/jekyll/page.rb +217 -217
  64. data/lib/jekyll/page_excerpt.rb +25 -25
  65. data/lib/jekyll/page_without_a_file.rb +14 -14
  66. data/lib/jekyll/path_manager.rb +74 -74
  67. data/lib/jekyll/plugin.rb +92 -92
  68. data/lib/jekyll/plugin_manager.rb +115 -115
  69. data/lib/jekyll/profiler.rb +58 -58
  70. data/lib/jekyll/publisher.rb +23 -23
  71. data/lib/jekyll/reader.rb +192 -192
  72. data/lib/jekyll/readers/collection_reader.rb +23 -23
  73. data/lib/jekyll/readers/data_reader.rb +79 -79
  74. data/lib/jekyll/readers/layout_reader.rb +62 -62
  75. data/lib/jekyll/readers/page_reader.rb +25 -25
  76. data/lib/jekyll/readers/post_reader.rb +85 -85
  77. data/lib/jekyll/readers/static_file_reader.rb +25 -25
  78. data/lib/jekyll/readers/theme_assets_reader.rb +52 -52
  79. data/lib/jekyll/regenerator.rb +195 -195
  80. data/lib/jekyll/related_posts.rb +52 -52
  81. data/lib/jekyll/renderer.rb +265 -265
  82. data/lib/jekyll/site.rb +551 -551
  83. data/lib/jekyll/static_file.rb +208 -208
  84. data/lib/jekyll/stevenson.rb +60 -60
  85. data/lib/jekyll/tags/highlight.rb +110 -110
  86. data/lib/jekyll/tags/include.rb +275 -275
  87. data/lib/jekyll/tags/link.rb +42 -42
  88. data/lib/jekyll/tags/post_url.rb +106 -106
  89. data/lib/jekyll/theme.rb +86 -86
  90. data/lib/jekyll/theme_builder.rb +121 -121
  91. data/lib/jekyll/url.rb +167 -167
  92. data/lib/jekyll/utils/ansi.rb +57 -57
  93. data/lib/jekyll/utils/exec.rb +26 -26
  94. data/lib/jekyll/utils/internet.rb +37 -37
  95. data/lib/jekyll/utils/platforms.rb +67 -67
  96. data/lib/jekyll/utils/thread_event.rb +31 -31
  97. data/lib/jekyll/utils/win_tz.rb +75 -75
  98. data/lib/jekyll/utils.rb +367 -367
  99. data/lib/jekyll/version.rb +5 -5
  100. data/lib/jekyll.rb +195 -195
  101. data/lib/site_template/.gitignore +5 -5
  102. data/lib/site_template/404.html +25 -25
  103. data/lib/site_template/_config.yml +55 -55
  104. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -29
  105. data/lib/site_template/about.markdown +18 -18
  106. data/lib/site_template/index.markdown +6 -6
  107. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -74
  108. data/lib/theme_template/Gemfile +4 -4
  109. data/lib/theme_template/LICENSE.txt.erb +21 -21
  110. data/lib/theme_template/README.md.erb +52 -52
  111. data/lib/theme_template/_layouts/default.html +1 -1
  112. data/lib/theme_template/_layouts/page.html +5 -5
  113. data/lib/theme_template/_layouts/post.html +5 -5
  114. data/lib/theme_template/example/_config.yml.erb +1 -1
  115. data/lib/theme_template/example/_post.md +12 -12
  116. data/lib/theme_template/example/index.html +14 -14
  117. data/lib/theme_template/example/style.scss +7 -7
  118. data/lib/theme_template/gitignore.erb +6 -6
  119. data/lib/theme_template/theme.gemspec.erb +16 -16
  120. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -149
  121. data/rubocop/jekyll/no_p_allowed.rb +23 -23
  122. data/rubocop/jekyll/no_puts_allowed.rb +23 -23
  123. data/rubocop/jekyll.rb +5 -5
  124. metadata +3 -3
@@ -1,106 +1,106 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- module Tags
5
- class PostComparer
6
- MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!.freeze
7
-
8
- attr_reader :path, :date, :slug, :name
9
-
10
- def initialize(name)
11
- @name = name
12
-
13
- all, @path, @date, @slug = *name.sub(%r!^/!, "").match(MATCHER)
14
- unless all
15
- raise Jekyll::Errors::InvalidPostNameError,
16
- "'#{name}' does not contain valid date and/or title."
17
- end
18
-
19
- basename_pattern = "#{date}-#{Regexp.escape(slug)}\\.[^.]+"
20
- @name_regex = %r!^_posts/#{path}#{basename_pattern}|^#{path}_posts/?#{basename_pattern}!
21
- end
22
-
23
- def post_date
24
- @post_date ||= Utils.parse_date(
25
- date,
26
- "'#{date}' does not contain valid date and/or title."
27
- )
28
- end
29
-
30
- def ==(other)
31
- other.relative_path.match(@name_regex)
32
- end
33
-
34
- def deprecated_equality(other)
35
- slug == post_slug(other) &&
36
- post_date.year == other.date.year &&
37
- post_date.month == other.date.month &&
38
- post_date.day == other.date.day
39
- end
40
-
41
- private
42
-
43
- # Construct the directory-aware post slug for a Jekyll::Post
44
- #
45
- # other - the Jekyll::Post
46
- #
47
- # Returns the post slug with the subdirectory (relative to _posts)
48
- def post_slug(other)
49
- path = other.basename.split("/")[0...-1].join("/")
50
- if path.nil? || path == ""
51
- other.data["slug"]
52
- else
53
- "#{path}/#{other.data["slug"]}"
54
- end
55
- end
56
- end
57
-
58
- class PostUrl < Liquid::Tag
59
- include Jekyll::Filters::URLFilters
60
-
61
- def initialize(tag_name, post, tokens)
62
- super
63
- @orig_post = post.strip
64
- begin
65
- @post = PostComparer.new(@orig_post)
66
- rescue StandardError => e
67
- raise Jekyll::Errors::PostURLError, <<~MSG
68
- Could not parse name of post "#{@orig_post}" in tag 'post_url'.
69
- Make sure the post exists and the name is correct.
70
- #{e.class}: #{e.message}
71
- MSG
72
- end
73
- end
74
-
75
- def render(context)
76
- @context = context
77
- site = context.registers[:site]
78
-
79
- site.posts.docs.each do |document|
80
- return relative_url(document) if @post == document
81
- end
82
-
83
- # New matching method did not match, fall back to old method
84
- # with deprecation warning if this matches
85
-
86
- site.posts.docs.each do |document|
87
- next unless @post.deprecated_equality document
88
-
89
- Jekyll::Deprecator.deprecation_message "A call to "\
90
- "'{% post_url #{@post.name} %}' did not match " \
91
- "a post using the new matching method of checking name " \
92
- "(path-date-slug) equality. Please make sure that you " \
93
- "change this tag to match the post's name exactly."
94
- return relative_url(document)
95
- end
96
-
97
- raise Jekyll::Errors::PostURLError, <<~MSG
98
- Could not find post "#{@orig_post}" in tag 'post_url'.
99
- Make sure the post exists and the name is correct.
100
- MSG
101
- end
102
- end
103
- end
104
- end
105
-
106
- Liquid::Template.register_tag("post_url", Jekyll::Tags::PostUrl)
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ module Tags
5
+ class PostComparer
6
+ MATCHER = %r!^(.+/)*(\d+-\d+-\d+)-(.*)$!.freeze
7
+
8
+ attr_reader :path, :date, :slug, :name
9
+
10
+ def initialize(name)
11
+ @name = name
12
+
13
+ all, @path, @date, @slug = *name.sub(%r!^/!, "").match(MATCHER)
14
+ unless all
15
+ raise Jekyll::Errors::InvalidPostNameError,
16
+ "'#{name}' does not contain valid date and/or title."
17
+ end
18
+
19
+ basename_pattern = "#{date}-#{Regexp.escape(slug)}\\.[^.]+"
20
+ @name_regex = %r!^_posts/#{path}#{basename_pattern}|^#{path}_posts/?#{basename_pattern}!
21
+ end
22
+
23
+ def post_date
24
+ @post_date ||= Utils.parse_date(
25
+ date,
26
+ "'#{date}' does not contain valid date and/or title."
27
+ )
28
+ end
29
+
30
+ def ==(other)
31
+ other.relative_path.match(@name_regex)
32
+ end
33
+
34
+ def deprecated_equality(other)
35
+ slug == post_slug(other) &&
36
+ post_date.year == other.date.year &&
37
+ post_date.month == other.date.month &&
38
+ post_date.day == other.date.day
39
+ end
40
+
41
+ private
42
+
43
+ # Construct the directory-aware post slug for a Jekyll::Post
44
+ #
45
+ # other - the Jekyll::Post
46
+ #
47
+ # Returns the post slug with the subdirectory (relative to _posts)
48
+ def post_slug(other)
49
+ path = other.basename.split("/")[0...-1].join("/")
50
+ if path.nil? || path == ""
51
+ other.data["slug"]
52
+ else
53
+ "#{path}/#{other.data["slug"]}"
54
+ end
55
+ end
56
+ end
57
+
58
+ class PostUrl < Liquid::Tag
59
+ include Jekyll::Filters::URLFilters
60
+
61
+ def initialize(tag_name, post, tokens)
62
+ super
63
+ @orig_post = post.strip
64
+ begin
65
+ @post = PostComparer.new(@orig_post)
66
+ rescue StandardError => e
67
+ raise Jekyll::Errors::PostURLError, <<~MSG
68
+ Could not parse name of post "#{@orig_post}" in tag 'post_url'.
69
+ Make sure the post exists and the name is correct.
70
+ #{e.class}: #{e.message}
71
+ MSG
72
+ end
73
+ end
74
+
75
+ def render(context)
76
+ @context = context
77
+ site = context.registers[:site]
78
+
79
+ site.posts.docs.each do |document|
80
+ return relative_url(document) if @post == document
81
+ end
82
+
83
+ # New matching method did not match, fall back to old method
84
+ # with deprecation warning if this matches
85
+
86
+ site.posts.docs.each do |document|
87
+ next unless @post.deprecated_equality document
88
+
89
+ Jekyll::Deprecator.deprecation_message "A call to "\
90
+ "'{% post_url #{@post.name} %}' did not match " \
91
+ "a post using the new matching method of checking name " \
92
+ "(path-date-slug) equality. Please make sure that you " \
93
+ "change this tag to match the post's name exactly."
94
+ return relative_url(document)
95
+ end
96
+
97
+ raise Jekyll::Errors::PostURLError, <<~MSG
98
+ Could not find post "#{@orig_post}" in tag 'post_url'.
99
+ Make sure the post exists and the name is correct.
100
+ MSG
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ Liquid::Template.register_tag("post_url", Jekyll::Tags::PostUrl)
data/lib/jekyll/theme.rb CHANGED
@@ -1,86 +1,86 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- class Theme
5
- extend Forwardable
6
- attr_reader :name
7
-
8
- def_delegator :gemspec, :version, :version
9
-
10
- def initialize(name)
11
- @name = name.downcase.strip
12
- Jekyll.logger.debug "Theme:", name
13
- Jekyll.logger.debug "Theme source:", root
14
- end
15
-
16
- def root
17
- # Must use File.realpath to resolve symlinks created by rbenv
18
- # Otherwise, Jekyll.sanitized path with prepend the unresolved root
19
- @root ||= File.realpath(gemspec.full_gem_path)
20
- rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
21
- raise "Path #{gemspec.full_gem_path} does not exist, is not accessible "\
22
- "or includes a symbolic link loop"
23
- end
24
-
25
- # The name of theme directory
26
- def basename
27
- @basename ||= File.basename(root)
28
- end
29
-
30
- def includes_path
31
- @includes_path ||= path_for "_includes"
32
- end
33
-
34
- def layouts_path
35
- @layouts_path ||= path_for "_layouts"
36
- end
37
-
38
- def sass_path
39
- @sass_path ||= path_for "_sass"
40
- end
41
-
42
- def assets_path
43
- @assets_path ||= path_for "assets"
44
- end
45
-
46
- def runtime_dependencies
47
- gemspec.runtime_dependencies
48
- end
49
-
50
- private
51
-
52
- def path_for(folder)
53
- path = realpath_for(folder)
54
- path if path && File.directory?(path)
55
- end
56
-
57
- def realpath_for(folder)
58
- # This resolves all symlinks for the theme subfolder and then ensures that the directory
59
- # remains inside the theme root. This prevents the use of symlinks for theme subfolders to
60
- # escape the theme root.
61
- # However, symlinks are allowed to point to other directories within the theme.
62
- Jekyll.sanitized_path(root, File.realpath(Jekyll.sanitized_path(root, folder.to_s)))
63
- rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP => e
64
- log_realpath_exception(e, folder)
65
- nil
66
- end
67
-
68
- def log_realpath_exception(err, folder)
69
- return if err.is_a?(Errno::ENOENT)
70
-
71
- case err
72
- when Errno::EACCES
73
- Jekyll.logger.error "Theme error:", "Directory '#{folder}' is not accessible."
74
- when Errno::ELOOP
75
- Jekyll.logger.error "Theme error:", "Directory '#{folder}' includes a symbolic link loop."
76
- end
77
- end
78
-
79
- def gemspec
80
- @gemspec ||= Gem::Specification.find_by_name(name)
81
- rescue Gem::LoadError
82
- raise Jekyll::Errors::MissingDependencyException,
83
- "The #{name} theme could not be found."
84
- end
85
- end
86
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class Theme
5
+ extend Forwardable
6
+ attr_reader :name
7
+
8
+ def_delegator :gemspec, :version, :version
9
+
10
+ def initialize(name)
11
+ @name = name.downcase.strip
12
+ Jekyll.logger.debug "Theme:", name
13
+ Jekyll.logger.debug "Theme source:", root
14
+ end
15
+
16
+ def root
17
+ # Must use File.realpath to resolve symlinks created by rbenv
18
+ # Otherwise, Jekyll.sanitized path with prepend the unresolved root
19
+ @root ||= File.realpath(gemspec.full_gem_path)
20
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
21
+ raise "Path #{gemspec.full_gem_path} does not exist, is not accessible "\
22
+ "or includes a symbolic link loop"
23
+ end
24
+
25
+ # The name of theme directory
26
+ def basename
27
+ @basename ||= File.basename(root)
28
+ end
29
+
30
+ def includes_path
31
+ @includes_path ||= path_for "_includes"
32
+ end
33
+
34
+ def layouts_path
35
+ @layouts_path ||= path_for "_layouts"
36
+ end
37
+
38
+ def sass_path
39
+ @sass_path ||= path_for "_sass"
40
+ end
41
+
42
+ def assets_path
43
+ @assets_path ||= path_for "assets"
44
+ end
45
+
46
+ def runtime_dependencies
47
+ gemspec.runtime_dependencies
48
+ end
49
+
50
+ private
51
+
52
+ def path_for(folder)
53
+ path = realpath_for(folder)
54
+ path if path && File.directory?(path)
55
+ end
56
+
57
+ def realpath_for(folder)
58
+ # This resolves all symlinks for the theme subfolder and then ensures that the directory
59
+ # remains inside the theme root. This prevents the use of symlinks for theme subfolders to
60
+ # escape the theme root.
61
+ # However, symlinks are allowed to point to other directories within the theme.
62
+ Jekyll.sanitized_path(root, File.realpath(Jekyll.sanitized_path(root, folder.to_s)))
63
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP => e
64
+ log_realpath_exception(e, folder)
65
+ nil
66
+ end
67
+
68
+ def log_realpath_exception(err, folder)
69
+ return if err.is_a?(Errno::ENOENT)
70
+
71
+ case err
72
+ when Errno::EACCES
73
+ Jekyll.logger.error "Theme error:", "Directory '#{folder}' is not accessible."
74
+ when Errno::ELOOP
75
+ Jekyll.logger.error "Theme error:", "Directory '#{folder}' includes a symbolic link loop."
76
+ end
77
+ end
78
+
79
+ def gemspec
80
+ @gemspec ||= Gem::Specification.find_by_name(name)
81
+ rescue Gem::LoadError
82
+ raise Jekyll::Errors::MissingDependencyException,
83
+ "The #{name} theme could not be found."
84
+ end
85
+ end
86
+ end
@@ -1,121 +1,121 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- class ThemeBuilder
5
- SCAFFOLD_DIRECTORIES = %w(
6
- assets _layouts _includes _sass
7
- ).freeze
8
-
9
- attr_reader :name, :path, :code_of_conduct
10
-
11
- def initialize(theme_name, opts)
12
- @name = theme_name.to_s.tr(" ", "_").squeeze("_")
13
- @path = Pathname.new(File.expand_path(name, Dir.pwd))
14
- @code_of_conduct = !!opts["code_of_conduct"]
15
- end
16
-
17
- def create!
18
- create_directories
19
- create_starter_files
20
- create_gemspec
21
- create_accessories
22
- initialize_git_repo
23
- end
24
-
25
- def user_name
26
- @user_name ||= `git config user.name`.chomp
27
- end
28
-
29
- def user_email
30
- @user_email ||= `git config user.email`.chomp
31
- end
32
-
33
- private
34
-
35
- def root
36
- @root ||= Pathname.new(File.expand_path("../", __dir__))
37
- end
38
-
39
- def template_file(filename)
40
- [
41
- root.join("theme_template", "#{filename}.erb"),
42
- root.join("theme_template", filename.to_s),
43
- ].find(&:exist?)
44
- end
45
-
46
- def template(filename)
47
- erb.render(template_file(filename).read)
48
- end
49
-
50
- def erb
51
- @erb ||= ERBRenderer.new(self)
52
- end
53
-
54
- def mkdir_p(directories)
55
- Array(directories).each do |directory|
56
- full_path = path.join(directory)
57
- Jekyll.logger.info "create", full_path.to_s
58
- FileUtils.mkdir_p(full_path)
59
- end
60
- end
61
-
62
- def write_file(filename, contents)
63
- full_path = path.join(filename)
64
- Jekyll.logger.info "create", full_path.to_s
65
- File.write(full_path, contents)
66
- end
67
-
68
- def create_directories
69
- mkdir_p(SCAFFOLD_DIRECTORIES)
70
- end
71
-
72
- def create_starter_files
73
- %w(page post default).each do |layout|
74
- write_file("_layouts/#{layout}.html", template("_layouts/#{layout}.html"))
75
- end
76
- end
77
-
78
- def create_gemspec
79
- write_file("Gemfile", template("Gemfile"))
80
- write_file("#{name}.gemspec", template("theme.gemspec"))
81
- end
82
-
83
- def create_accessories
84
- accessories = %w(README.md LICENSE.txt)
85
- accessories << "CODE_OF_CONDUCT.md" if code_of_conduct
86
- accessories.each do |filename|
87
- write_file(filename, template(filename))
88
- end
89
- end
90
-
91
- def initialize_git_repo
92
- Jekyll.logger.info "initialize", path.join(".git").to_s
93
- Dir.chdir(path.to_s) { `git init` }
94
- write_file(".gitignore", template("gitignore"))
95
- end
96
-
97
- class ERBRenderer
98
- extend Forwardable
99
-
100
- def_delegator :@theme_builder, :name, :theme_name
101
- def_delegator :@theme_builder, :user_name, :user_name
102
- def_delegator :@theme_builder, :user_email, :user_email
103
-
104
- def initialize(theme_builder)
105
- @theme_builder = theme_builder
106
- end
107
-
108
- def jekyll_version_with_minor
109
- Jekyll::VERSION.split(".").take(2).join(".")
110
- end
111
-
112
- def theme_directories
113
- SCAFFOLD_DIRECTORIES
114
- end
115
-
116
- def render(contents)
117
- ERB.new(contents).result binding
118
- end
119
- end
120
- end
121
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Jekyll
4
+ class ThemeBuilder
5
+ SCAFFOLD_DIRECTORIES = %w(
6
+ assets _layouts _includes _sass
7
+ ).freeze
8
+
9
+ attr_reader :name, :path, :code_of_conduct
10
+
11
+ def initialize(theme_name, opts)
12
+ @name = theme_name.to_s.tr(" ", "_").squeeze("_")
13
+ @path = Pathname.new(File.expand_path(name, Dir.pwd))
14
+ @code_of_conduct = !!opts["code_of_conduct"]
15
+ end
16
+
17
+ def create!
18
+ create_directories
19
+ create_starter_files
20
+ create_gemspec
21
+ create_accessories
22
+ initialize_git_repo
23
+ end
24
+
25
+ def user_name
26
+ @user_name ||= `git config user.name`.chomp
27
+ end
28
+
29
+ def user_email
30
+ @user_email ||= `git config user.email`.chomp
31
+ end
32
+
33
+ private
34
+
35
+ def root
36
+ @root ||= Pathname.new(File.expand_path("../", __dir__))
37
+ end
38
+
39
+ def template_file(filename)
40
+ [
41
+ root.join("theme_template", "#{filename}.erb"),
42
+ root.join("theme_template", filename.to_s),
43
+ ].find(&:exist?)
44
+ end
45
+
46
+ def template(filename)
47
+ erb.render(template_file(filename).read)
48
+ end
49
+
50
+ def erb
51
+ @erb ||= ERBRenderer.new(self)
52
+ end
53
+
54
+ def mkdir_p(directories)
55
+ Array(directories).each do |directory|
56
+ full_path = path.join(directory)
57
+ Jekyll.logger.info "create", full_path.to_s
58
+ FileUtils.mkdir_p(full_path)
59
+ end
60
+ end
61
+
62
+ def write_file(filename, contents)
63
+ full_path = path.join(filename)
64
+ Jekyll.logger.info "create", full_path.to_s
65
+ File.write(full_path, contents)
66
+ end
67
+
68
+ def create_directories
69
+ mkdir_p(SCAFFOLD_DIRECTORIES)
70
+ end
71
+
72
+ def create_starter_files
73
+ %w(page post default).each do |layout|
74
+ write_file("_layouts/#{layout}.html", template("_layouts/#{layout}.html"))
75
+ end
76
+ end
77
+
78
+ def create_gemspec
79
+ write_file("Gemfile", template("Gemfile"))
80
+ write_file("#{name}.gemspec", template("theme.gemspec"))
81
+ end
82
+
83
+ def create_accessories
84
+ accessories = %w(README.md LICENSE.txt)
85
+ accessories << "CODE_OF_CONDUCT.md" if code_of_conduct
86
+ accessories.each do |filename|
87
+ write_file(filename, template(filename))
88
+ end
89
+ end
90
+
91
+ def initialize_git_repo
92
+ Jekyll.logger.info "initialize", path.join(".git").to_s
93
+ Dir.chdir(path.to_s) { `git init` }
94
+ write_file(".gitignore", template("gitignore"))
95
+ end
96
+
97
+ class ERBRenderer
98
+ extend Forwardable
99
+
100
+ def_delegator :@theme_builder, :name, :theme_name
101
+ def_delegator :@theme_builder, :user_name, :user_name
102
+ def_delegator :@theme_builder, :user_email, :user_email
103
+
104
+ def initialize(theme_builder)
105
+ @theme_builder = theme_builder
106
+ end
107
+
108
+ def jekyll_version_with_minor
109
+ Jekyll::VERSION.split(".").take(2).join(".")
110
+ end
111
+
112
+ def theme_directories
113
+ SCAFFOLD_DIRECTORIES
114
+ end
115
+
116
+ def render(contents)
117
+ ERB.new(contents).result binding
118
+ end
119
+ end
120
+ end
121
+ end