jekyll 4.2.1 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +474 -350
  3. data/LICENSE +21 -21
  4. data/README.markdown +83 -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 +186 -190
  12. data/lib/jekyll/cleaner.rb +111 -111
  13. data/lib/jekyll/collection.rb +310 -309
  14. data/lib/jekyll/command.rb +105 -105
  15. data/lib/jekyll/commands/build.rb +82 -93
  16. data/lib/jekyll/commands/clean.rb +44 -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 +168 -169
  20. data/lib/jekyll/commands/new_theme.rb +39 -40
  21. data/lib/jekyll/commands/serve/live_reload_reactor.rb +119 -122
  22. data/lib/jekyll/commands/serve/livereload_assets/livereload.js +1183 -1183
  23. data/lib/jekyll/commands/serve/mime_types_charset.json +71 -0
  24. data/lib/jekyll/commands/serve/servlet.rb +206 -202
  25. data/lib/jekyll/commands/serve/websockets.rb +81 -81
  26. data/lib/jekyll/commands/serve.rb +367 -362
  27. data/lib/jekyll/configuration.rb +313 -313
  28. data/lib/jekyll/converter.rb +54 -54
  29. data/lib/jekyll/converters/identity.rb +41 -41
  30. data/lib/jekyll/converters/markdown/kramdown_parser.rb +197 -199
  31. data/lib/jekyll/converters/markdown.rb +113 -113
  32. data/lib/jekyll/converters/smartypants.rb +70 -70
  33. data/lib/jekyll/convertible.rb +257 -257
  34. data/lib/jekyll/data_entry.rb +83 -0
  35. data/lib/jekyll/data_hash.rb +61 -0
  36. data/lib/jekyll/deprecator.rb +50 -50
  37. data/lib/jekyll/document.rb +543 -544
  38. data/lib/jekyll/drops/collection_drop.rb +20 -20
  39. data/lib/jekyll/drops/document_drop.rb +71 -70
  40. data/lib/jekyll/drops/drop.rb +293 -293
  41. data/lib/jekyll/drops/excerpt_drop.rb +23 -19
  42. data/lib/jekyll/drops/jekyll_drop.rb +32 -32
  43. data/lib/jekyll/drops/site_drop.rb +71 -66
  44. data/lib/jekyll/drops/static_file_drop.rb +14 -14
  45. data/lib/jekyll/drops/theme_drop.rb +36 -0
  46. data/lib/jekyll/drops/unified_payload_drop.rb +30 -26
  47. data/lib/jekyll/drops/url_drop.rb +140 -140
  48. data/lib/jekyll/entry_filter.rb +117 -121
  49. data/lib/jekyll/errors.rb +20 -20
  50. data/lib/jekyll/excerpt.rb +200 -201
  51. data/lib/jekyll/external.rb +75 -79
  52. data/lib/jekyll/filters/date_filters.rb +110 -110
  53. data/lib/jekyll/filters/grouping_filters.rb +64 -64
  54. data/lib/jekyll/filters/url_filters.rb +98 -98
  55. data/lib/jekyll/filters.rb +532 -535
  56. data/lib/jekyll/frontmatter_defaults.rb +238 -240
  57. data/lib/jekyll/generator.rb +5 -5
  58. data/lib/jekyll/hooks.rb +107 -107
  59. data/lib/jekyll/inclusion.rb +32 -32
  60. data/lib/jekyll/layout.rb +55 -67
  61. data/lib/jekyll/liquid_extensions.rb +22 -22
  62. data/lib/jekyll/liquid_renderer/file.rb +77 -77
  63. data/lib/jekyll/liquid_renderer/table.rb +55 -55
  64. data/lib/jekyll/liquid_renderer.rb +80 -80
  65. data/lib/jekyll/log_adapter.rb +151 -151
  66. data/lib/jekyll/mime.types +939 -866
  67. data/lib/jekyll/page.rb +215 -217
  68. data/lib/jekyll/page_excerpt.rb +25 -25
  69. data/lib/jekyll/page_without_a_file.rb +14 -14
  70. data/lib/jekyll/path_manager.rb +74 -74
  71. data/lib/jekyll/plugin.rb +92 -92
  72. data/lib/jekyll/plugin_manager.rb +123 -115
  73. data/lib/jekyll/profiler.rb +55 -58
  74. data/lib/jekyll/publisher.rb +23 -23
  75. data/lib/jekyll/reader.rb +209 -192
  76. data/lib/jekyll/readers/collection_reader.rb +23 -23
  77. data/lib/jekyll/readers/data_reader.rb +116 -79
  78. data/lib/jekyll/readers/layout_reader.rb +62 -62
  79. data/lib/jekyll/readers/page_reader.rb +25 -25
  80. data/lib/jekyll/readers/post_reader.rb +85 -85
  81. data/lib/jekyll/readers/static_file_reader.rb +25 -25
  82. data/lib/jekyll/readers/theme_assets_reader.rb +52 -52
  83. data/lib/jekyll/regenerator.rb +195 -195
  84. data/lib/jekyll/related_posts.rb +52 -52
  85. data/lib/jekyll/renderer.rb +263 -265
  86. data/lib/jekyll/site.rb +582 -551
  87. data/lib/jekyll/static_file.rb +205 -208
  88. data/lib/jekyll/stevenson.rb +60 -60
  89. data/lib/jekyll/tags/highlight.rb +114 -110
  90. data/lib/jekyll/tags/include.rb +275 -275
  91. data/lib/jekyll/tags/link.rb +42 -42
  92. data/lib/jekyll/tags/post_url.rb +106 -106
  93. data/lib/jekyll/theme.rb +90 -86
  94. data/lib/jekyll/theme_builder.rb +121 -121
  95. data/lib/jekyll/url.rb +167 -167
  96. data/lib/jekyll/utils/ansi.rb +57 -57
  97. data/lib/jekyll/utils/exec.rb +26 -26
  98. data/lib/jekyll/utils/internet.rb +37 -37
  99. data/lib/jekyll/utils/platforms.rb +67 -67
  100. data/lib/jekyll/utils/thread_event.rb +31 -31
  101. data/lib/jekyll/utils/win_tz.rb +46 -75
  102. data/lib/jekyll/utils.rb +378 -367
  103. data/lib/jekyll/version.rb +5 -5
  104. data/lib/jekyll.rb +197 -195
  105. data/lib/site_template/.gitignore +5 -5
  106. data/lib/site_template/404.html +25 -25
  107. data/lib/site_template/_config.yml +55 -55
  108. data/lib/site_template/_posts/0000-00-00-welcome-to-jekyll.markdown.erb +29 -29
  109. data/lib/site_template/about.markdown +18 -18
  110. data/lib/site_template/index.markdown +6 -6
  111. data/lib/theme_template/CODE_OF_CONDUCT.md.erb +74 -74
  112. data/lib/theme_template/Gemfile +4 -4
  113. data/lib/theme_template/LICENSE.txt.erb +21 -21
  114. data/lib/theme_template/README.md.erb +50 -52
  115. data/lib/theme_template/_layouts/default.html +1 -1
  116. data/lib/theme_template/_layouts/page.html +5 -5
  117. data/lib/theme_template/_layouts/post.html +5 -5
  118. data/lib/theme_template/example/_config.yml.erb +1 -1
  119. data/lib/theme_template/example/_post.md +12 -12
  120. data/lib/theme_template/example/index.html +14 -14
  121. data/lib/theme_template/example/style.scss +7 -7
  122. data/lib/theme_template/gitignore.erb +6 -6
  123. data/lib/theme_template/theme.gemspec.erb +16 -16
  124. data/rubocop/jekyll/assert_equal_literal_actual.rb +149 -149
  125. data/rubocop/jekyll/no_p_allowed.rb +23 -23
  126. data/rubocop/jekyll/no_puts_allowed.rb +23 -23
  127. data/rubocop/jekyll.rb +5 -5
  128. metadata +62 -14
@@ -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(
90
+ "A call to '{% post_url #{@post.name} %}' did not match a post using the new " \
91
+ "matching method of checking name (path-date-slug) equality. Please make sure " \
92
+ "that you change this tag to match the post's name exactly."
93
+ )
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,90 @@
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 or includes " \
22
+ "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 data_path
47
+ @data_path ||= path_for "_data"
48
+ end
49
+
50
+ def runtime_dependencies
51
+ gemspec.runtime_dependencies
52
+ end
53
+
54
+ private
55
+
56
+ def path_for(folder)
57
+ path = realpath_for(folder)
58
+ path if path && File.directory?(path)
59
+ end
60
+
61
+ def realpath_for(folder)
62
+ # This resolves all symlinks for the theme subfolder and then ensures that the directory
63
+ # remains inside the theme root. This prevents the use of symlinks for theme subfolders to
64
+ # escape the theme root.
65
+ # However, symlinks are allowed to point to other directories within the theme.
66
+ Jekyll.sanitized_path(root, File.realpath(Jekyll.sanitized_path(root, folder.to_s)))
67
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP => e
68
+ log_realpath_exception(e, folder)
69
+ nil
70
+ end
71
+
72
+ def log_realpath_exception(err, folder)
73
+ return if err.is_a?(Errno::ENOENT)
74
+
75
+ case err
76
+ when Errno::EACCES
77
+ Jekyll.logger.error "Theme error:", "Directory '#{folder}' is not accessible."
78
+ when Errno::ELOOP
79
+ Jekyll.logger.error "Theme error:", "Directory '#{folder}' includes a symbolic link loop."
80
+ end
81
+ end
82
+
83
+ def gemspec
84
+ @gemspec ||= Gem::Specification.find_by_name(name)
85
+ rescue Gem::LoadError
86
+ raise Jekyll::Errors::MissingDependencyException,
87
+ "The #{name} theme could not be found."
88
+ end
89
+ end
90
+ 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 _data _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