jekyll 4.0.1 → 4.2.1

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 -163
  3. data/LICENSE +21 -21
  4. data/README.markdown +86 -90
  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 -103
  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 -173
  18. data/lib/jekyll/commands/help.rb +34 -34
  19. data/lib/jekyll/commands/new.rb +169 -169
  20. data/lib/jekyll/commands/new_theme.rb +40 -42
  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 -354
  26. data/lib/jekyll/configuration.rb +313 -316
  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 -130
  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 -254
  33. data/lib/jekyll/deprecator.rb +50 -50
  34. data/lib/jekyll/document.rb +544 -522
  35. data/lib/jekyll/drops/collection_drop.rb +20 -20
  36. data/lib/jekyll/drops/document_drop.rb +70 -69
  37. data/lib/jekyll/drops/drop.rb +293 -215
  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 -132
  44. data/lib/jekyll/entry_filter.rb +121 -110
  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 -68
  51. data/lib/jekyll/filters.rb +535 -454
  52. data/lib/jekyll/frontmatter_defaults.rb +240 -245
  53. data/lib/jekyll/generator.rb +5 -5
  54. data/lib/jekyll/hooks.rb +107 -106
  55. data/lib/jekyll/inclusion.rb +32 -0
  56. data/lib/jekyll/layout.rb +67 -62
  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 -75
  60. data/lib/jekyll/liquid_renderer.rb +80 -77
  61. data/lib/jekyll/log_adapter.rb +151 -151
  62. data/lib/jekyll/mime.types +866 -866
  63. data/lib/jekyll/page.rb +217 -186
  64. data/lib/jekyll/page_excerpt.rb +25 -0
  65. data/lib/jekyll/page_without_a_file.rb +14 -14
  66. data/lib/jekyll/path_manager.rb +74 -31
  67. data/lib/jekyll/plugin.rb +92 -92
  68. data/lib/jekyll/plugin_manager.rb +115 -115
  69. data/lib/jekyll/profiler.rb +58 -0
  70. data/lib/jekyll/publisher.rb +23 -23
  71. data/lib/jekyll/reader.rb +192 -187
  72. data/lib/jekyll/readers/collection_reader.rb +23 -22
  73. data/lib/jekyll/readers/data_reader.rb +79 -75
  74. data/lib/jekyll/readers/layout_reader.rb +62 -61
  75. data/lib/jekyll/readers/page_reader.rb +25 -24
  76. data/lib/jekyll/readers/post_reader.rb +85 -84
  77. data/lib/jekyll/readers/static_file_reader.rb +25 -24
  78. data/lib/jekyll/readers/theme_assets_reader.rb +52 -51
  79. data/lib/jekyll/regenerator.rb +195 -195
  80. data/lib/jekyll/related_posts.rb +52 -52
  81. data/lib/jekyll/renderer.rb +265 -267
  82. data/lib/jekyll/site.rb +551 -527
  83. data/lib/jekyll/static_file.rb +208 -203
  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 -221
  87. data/lib/jekyll/tags/link.rb +42 -41
  88. data/lib/jekyll/tags/post_url.rb +106 -107
  89. data/lib/jekyll/theme.rb +86 -80
  90. data/lib/jekyll/theme_builder.rb +121 -121
  91. data/lib/jekyll/url.rb +167 -164
  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 -82
  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 -206
  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 -19
  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 +20 -38
@@ -1,107 +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
- escaped_slug = Regexp.escape(slug)
20
- @name_regex = %r!^_posts/#{path}#{date}-#{escaped_slug}\.[^.]+|
21
- ^#{path}_posts/?#{date}-#{escaped_slug}\.[^.]+!x
22
- end
23
-
24
- def post_date
25
- @post_date ||= Utils.parse_date(
26
- date,
27
- "'#{date}' does not contain valid date and/or title."
28
- )
29
- end
30
-
31
- def ==(other)
32
- other.relative_path.match(@name_regex)
33
- end
34
-
35
- def deprecated_equality(other)
36
- slug == post_slug(other) &&
37
- post_date.year == other.date.year &&
38
- post_date.month == other.date.month &&
39
- post_date.day == other.date.day
40
- end
41
-
42
- private
43
-
44
- # Construct the directory-aware post slug for a Jekyll::Post
45
- #
46
- # other - the Jekyll::Post
47
- #
48
- # Returns the post slug with the subdirectory (relative to _posts)
49
- def post_slug(other)
50
- path = other.basename.split("/")[0...-1].join("/")
51
- if path.nil? || path == ""
52
- other.data["slug"]
53
- else
54
- path + "/" + other.data["slug"]
55
- end
56
- end
57
- end
58
-
59
- class PostUrl < Liquid::Tag
60
- include Jekyll::Filters::URLFilters
61
-
62
- def initialize(tag_name, post, tokens)
63
- super
64
- @orig_post = post.strip
65
- begin
66
- @post = PostComparer.new(@orig_post)
67
- rescue StandardError => e
68
- raise Jekyll::Errors::PostURLError, <<~MSG
69
- Could not parse name of post "#{@orig_post}" in tag 'post_url'.
70
- Make sure the post exists and the name is correct.
71
- #{e.class}: #{e.message}
72
- MSG
73
- end
74
- end
75
-
76
- def render(context)
77
- @context = context
78
- site = context.registers[:site]
79
-
80
- site.posts.docs.each do |document|
81
- return relative_url(document) if @post == document
82
- end
83
-
84
- # New matching method did not match, fall back to old method
85
- # with deprecation warning if this matches
86
-
87
- site.posts.docs.each do |document|
88
- next unless @post.deprecated_equality document
89
-
90
- Jekyll::Deprecator.deprecation_message "A call to "\
91
- "'{% post_url #{@post.name} %}' did not match " \
92
- "a post using the new matching method of checking name " \
93
- "(path-date-slug) equality. Please make sure that you " \
94
- "change this tag to match the post's name exactly."
95
- return relative_url(document)
96
- end
97
-
98
- raise Jekyll::Errors::PostURLError, <<~MSG
99
- Could not find post "#{@orig_post}" in tag 'post_url'.
100
- Make sure the post exists and the name is correct.
101
- MSG
102
- end
103
- end
104
- end
105
- end
106
-
107
- 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,80 +1,86 @@
1
- # frozen_string_literal: true
2
-
3
- module Jekyll
4
- class Theme
5
- extend Forwardable
6
- attr_reader :name
7
- def_delegator :gemspec, :version, :version
8
-
9
- def initialize(name)
10
- @name = name.downcase.strip
11
- Jekyll.logger.debug "Theme:", name
12
- Jekyll.logger.debug "Theme source:", root
13
- end
14
-
15
- def root
16
- # Must use File.realpath to resolve symlinks created by rbenv
17
- # Otherwise, Jekyll.sanitized path with prepend the unresolved root
18
- @root ||= File.realpath(gemspec.full_gem_path)
19
- rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP
20
- raise "Path #{gemspec.full_gem_path} does not exist, is not accessible "\
21
- "or includes a symbolic link loop"
22
- end
23
-
24
- def includes_path
25
- @includes_path ||= path_for "_includes"
26
- end
27
-
28
- def layouts_path
29
- @layouts_path ||= path_for "_layouts"
30
- end
31
-
32
- def sass_path
33
- @sass_path ||= path_for "_sass"
34
- end
35
-
36
- def assets_path
37
- @assets_path ||= path_for "assets"
38
- end
39
-
40
- def runtime_dependencies
41
- gemspec.runtime_dependencies
42
- end
43
-
44
- private
45
-
46
- def path_for(folder)
47
- path = realpath_for(folder)
48
- path if path && File.directory?(path)
49
- end
50
-
51
- def realpath_for(folder)
52
- # This resolves all symlinks for the theme subfolder and then ensures that the directory
53
- # remains inside the theme root. This prevents the use of symlinks for theme subfolders to
54
- # escape the theme root.
55
- # However, symlinks are allowed to point to other directories within the theme.
56
- Jekyll.sanitized_path(root, File.realpath(Jekyll.sanitized_path(root, folder.to_s)))
57
- rescue Errno::ENOENT, Errno::EACCES, Errno::ELOOP => e
58
- log_realpath_exception(e, folder)
59
- nil
60
- end
61
-
62
- def log_realpath_exception(err, folder)
63
- return if err.is_a?(Errno::ENOENT)
64
-
65
- case err
66
- when Errno::EACCES
67
- Jekyll.logger.error "Theme error:", "Directory '#{folder}' is not accessible."
68
- when Errno::ELOOP
69
- Jekyll.logger.error "Theme error:", "Directory '#{folder}' includes a symbolic link loop."
70
- end
71
- end
72
-
73
- def gemspec
74
- @gemspec ||= Gem::Specification.find_by_name(name)
75
- rescue Gem::LoadError
76
- raise Jekyll::Errors::MissingDependencyException,
77
- "The #{name} theme could not be found."
78
- end
79
- end
80
- 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