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,169 +1,172 @@
1
- # frozen_string_literal: true
2
-
3
- require "erb"
4
-
5
- module Jekyll
6
- module Commands
7
- class New < Command
8
- class << self
9
- def init_with_program(prog)
10
- prog.command(:new) do |c|
11
- c.syntax "new PATH"
12
- c.description "Creates a new Jekyll site scaffold in PATH"
13
-
14
- c.option "force", "--force", "Force creation even if PATH already exists"
15
- c.option "blank", "--blank", "Creates scaffolding but with empty files"
16
- c.option "skip-bundle", "--skip-bundle", "Skip 'bundle install'"
17
-
18
- c.action do |args, options|
19
- Jekyll::Commands::New.process(args, options)
20
- end
21
- end
22
- end
23
-
24
- def process(args, options = {})
25
- raise ArgumentError, "You must specify a path." if args.empty?
26
-
27
- new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
28
- FileUtils.mkdir_p new_blog_path
29
- if preserve_source_location?(new_blog_path, options)
30
- Jekyll.logger.error "Conflict:", "#{new_blog_path} exists and is not empty."
31
- Jekyll.logger.abort_with "", "Ensure #{new_blog_path} is empty or else " \
32
- "try again with `--force` to proceed and overwrite any files."
33
- end
34
-
35
- if options["blank"]
36
- create_blank_site new_blog_path
37
- else
38
- create_site new_blog_path
39
- end
40
-
41
- after_install(new_blog_path, options)
42
- end
43
-
44
- def blank_template
45
- File.expand_path("../../blank_template", __dir__)
46
- end
47
-
48
- def create_blank_site(path)
49
- FileUtils.cp_r blank_template + "/.", path
50
- FileUtils.chmod_R "u+w", path
51
-
52
- Dir.chdir(path) do
53
- FileUtils.mkdir(%w(_data _drafts _includes _posts))
54
- end
55
- end
56
-
57
- def scaffold_post_content
58
- ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
59
- end
60
-
61
- # Internal: Gets the filename of the sample post to be created
62
- #
63
- # Returns the filename of the sample post, as a String
64
- def initialized_post_name
65
- "_posts/#{Time.now.strftime("%Y-%m-%d")}-welcome-to-jekyll.markdown"
66
- end
67
-
68
- private
69
-
70
- def gemfile_contents
71
- <<~RUBY
72
- source "https://rubygems.org"
73
- # Hello! This is where you manage which Jekyll version is used to run.
74
- # When you want to use a different version, change it below, save the
75
- # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
76
- #
77
- # bundle exec jekyll serve
78
- #
79
- # This will help ensure the proper Jekyll version is running.
80
- # Happy Jekylling!
81
- gem "jekyll", "~> #{Jekyll::VERSION}"
82
- # This is the default theme for new Jekyll sites. You may change this to anything you like.
83
- gem "minima", "~> 2.5"
84
- # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
85
- # uncomment the line below. To upgrade, run `bundle update github-pages`.
86
- # gem "github-pages", group: :jekyll_plugins
87
- # If you have any plugins, put them here!
88
- group :jekyll_plugins do
89
- gem "jekyll-feed", "~> 0.12"
90
- end
91
-
92
- # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
93
- # and associated library.
94
- platforms :mingw, :x64_mingw, :mswin, :jruby do
95
- gem "tzinfo", "~> 1.2"
96
- gem "tzinfo-data"
97
- end
98
-
99
- # Performance-booster for watching directories on Windows
100
- gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
101
-
102
- RUBY
103
- end
104
-
105
- def create_site(new_blog_path)
106
- create_sample_files new_blog_path
107
-
108
- File.open(File.expand_path(initialized_post_name, new_blog_path), "w") do |f|
109
- f.write(scaffold_post_content)
110
- end
111
-
112
- File.open(File.expand_path("Gemfile", new_blog_path), "w") do |f|
113
- f.write(gemfile_contents)
114
- end
115
- end
116
-
117
- def preserve_source_location?(path, options)
118
- !options["force"] && !Dir["#{path}/**/*"].empty?
119
- end
120
-
121
- def create_sample_files(path)
122
- FileUtils.cp_r site_template + "/.", path
123
- FileUtils.chmod_R "u+w", path
124
- FileUtils.rm File.expand_path(scaffold_path, path)
125
- end
126
-
127
- def site_template
128
- File.expand_path("../../site_template", __dir__)
129
- end
130
-
131
- def scaffold_path
132
- "_posts/0000-00-00-welcome-to-jekyll.markdown.erb"
133
- end
134
-
135
- # After a new blog has been created, print a success notification and
136
- # then automatically execute bundle install from within the new blog dir
137
- # unless the user opts to generate a blank blog or skip 'bundle install'.
138
-
139
- def after_install(path, options = {})
140
- unless options["blank"] || options["skip-bundle"]
141
- begin
142
- require "bundler"
143
- bundle_install path
144
- rescue LoadError
145
- Jekyll.logger.info "Could not load Bundler. Bundle install skipped."
146
- end
147
- end
148
-
149
- Jekyll.logger.info "New jekyll site installed in #{path.cyan}."
150
- Jekyll.logger.info "Bundle install skipped." if options["skip-bundle"]
151
- end
152
-
153
- def bundle_install(path)
154
- Jekyll.logger.info "Running bundle install in #{path.cyan}..."
155
- Dir.chdir(path) do
156
- exe = Gem.bin_path("bundler", "bundle")
157
- process, output = Jekyll::Utils::Exec.run("ruby", exe, "install")
158
-
159
- output.to_s.each_line do |line|
160
- Jekyll.logger.info("Bundler:".green, line.strip) unless line.to_s.empty?
161
- end
162
-
163
- raise SystemExit unless process.success?
164
- end
165
- end
166
- end
167
- end
168
- end
169
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class New < Command
8
+ class << self
9
+ def init_with_program(prog)
10
+ prog.command(:new) do |c|
11
+ c.syntax "new PATH"
12
+ c.description "Creates a new Jekyll site scaffold in PATH"
13
+
14
+ c.option "force", "--force", "Force creation even if PATH already exists"
15
+ c.option "blank", "--blank", "Creates scaffolding but with empty files"
16
+ c.option "skip-bundle", "--skip-bundle", "Skip 'bundle install'"
17
+
18
+ c.action do |args, options|
19
+ Jekyll::Commands::New.process(args, options)
20
+ end
21
+ end
22
+ end
23
+
24
+ def process(args, options = {})
25
+ raise ArgumentError, "You must specify a path." if args.empty?
26
+
27
+ new_blog_path = File.expand_path(args.join(" "), Dir.pwd)
28
+ FileUtils.mkdir_p new_blog_path
29
+ if preserve_source_location?(new_blog_path, options)
30
+ Jekyll.logger.error "Conflict:", "#{new_blog_path} exists and is not empty."
31
+ Jekyll.logger.abort_with "", "Ensure #{new_blog_path} is empty or else " \
32
+ "try again with `--force` to proceed and overwrite any files."
33
+ end
34
+
35
+ if options["blank"]
36
+ create_blank_site new_blog_path
37
+ else
38
+ create_site new_blog_path
39
+ end
40
+
41
+ after_install(new_blog_path, options)
42
+ end
43
+
44
+ def blank_template
45
+ File.expand_path("../../blank_template", __dir__)
46
+ end
47
+
48
+ def create_blank_site(path)
49
+ FileUtils.cp_r blank_template + "/.", path
50
+ FileUtils.chmod_R "u+w", path
51
+
52
+ Dir.chdir(path) do
53
+ FileUtils.mkdir(%w(_data _drafts _includes _posts))
54
+ end
55
+ end
56
+
57
+ def scaffold_post_content
58
+ ERB.new(File.read(File.expand_path(scaffold_path, site_template))).result
59
+ end
60
+
61
+ # Internal: Gets the filename of the sample post to be created
62
+ #
63
+ # Returns the filename of the sample post, as a String
64
+ def initialized_post_name
65
+ "_posts/#{Time.now.strftime("%Y-%m-%d")}-welcome-to-jekyll.markdown"
66
+ end
67
+
68
+ private
69
+
70
+ def gemfile_contents
71
+ <<~RUBY
72
+ source "https://rubygems.org"
73
+ # Hello! This is where you manage which Jekyll version is used to run.
74
+ # When you want to use a different version, change it below, save the
75
+ # file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
76
+ #
77
+ # bundle exec jekyll serve
78
+ #
79
+ # This will help ensure the proper Jekyll version is running.
80
+ # Happy Jekylling!
81
+ gem "jekyll", "~> #{Jekyll::VERSION}"
82
+ # This is the default theme for new Jekyll sites. You may change this to anything you like.
83
+ gem "minima", "~> 2.5"
84
+ # If you want to use GitHub Pages, remove the "gem "jekyll"" above and
85
+ # uncomment the line below. To upgrade, run `bundle update github-pages`.
86
+ # gem "github-pages", group: :jekyll_plugins
87
+ # If you have any plugins, put them here!
88
+ group :jekyll_plugins do
89
+ gem "jekyll-feed", "~> 0.12"
90
+ end
91
+
92
+ # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
93
+ # and associated library.
94
+ platforms :mingw, :x64_mingw, :mswin, :jruby do
95
+ gem "tzinfo", "~> 1.2"
96
+ gem "tzinfo-data"
97
+ end
98
+
99
+ # Performance-booster for watching directories on Windows
100
+ gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
101
+
102
+ # Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem
103
+ # do not have a Java counterpart.
104
+ gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby]
105
+ RUBY
106
+ end
107
+
108
+ def create_site(new_blog_path)
109
+ create_sample_files new_blog_path
110
+
111
+ File.open(File.expand_path(initialized_post_name, new_blog_path), "w") do |f|
112
+ f.write(scaffold_post_content)
113
+ end
114
+
115
+ File.open(File.expand_path("Gemfile", new_blog_path), "w") do |f|
116
+ f.write(gemfile_contents)
117
+ end
118
+ end
119
+
120
+ def preserve_source_location?(path, options)
121
+ !options["force"] && !Dir["#{path}/**/*"].empty?
122
+ end
123
+
124
+ def create_sample_files(path)
125
+ FileUtils.cp_r site_template + "/.", path
126
+ FileUtils.chmod_R "u+w", path
127
+ FileUtils.rm File.expand_path(scaffold_path, path)
128
+ end
129
+
130
+ def site_template
131
+ File.expand_path("../../site_template", __dir__)
132
+ end
133
+
134
+ def scaffold_path
135
+ "_posts/0000-00-00-welcome-to-jekyll.markdown.erb"
136
+ end
137
+
138
+ # After a new blog has been created, print a success notification and
139
+ # then automatically execute bundle install from within the new blog dir
140
+ # unless the user opts to generate a blank blog or skip 'bundle install'.
141
+
142
+ def after_install(path, options = {})
143
+ unless options["blank"] || options["skip-bundle"]
144
+ begin
145
+ require "bundler"
146
+ bundle_install path
147
+ rescue LoadError
148
+ Jekyll.logger.info "Could not load Bundler. Bundle install skipped."
149
+ end
150
+ end
151
+
152
+ Jekyll.logger.info "New jekyll site installed in #{path.cyan}."
153
+ Jekyll.logger.info "Bundle install skipped." if options["skip-bundle"]
154
+ end
155
+
156
+ def bundle_install(path)
157
+ Jekyll.logger.info "Running bundle install in #{path.cyan}..."
158
+ Dir.chdir(path) do
159
+ exe = Gem.bin_path("bundler", "bundle")
160
+ process, output = Jekyll::Utils::Exec.run("ruby", exe, "install")
161
+
162
+ output.to_s.each_line do |line|
163
+ Jekyll.logger.info("Bundler:".green, line.strip) unless line.to_s.empty?
164
+ end
165
+
166
+ raise SystemExit unless process.success?
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -1,40 +1,40 @@
1
- # frozen_string_literal: true
2
-
3
- require "erb"
4
-
5
- module Jekyll
6
- module Commands
7
- class NewTheme < Jekyll::Command
8
- class << self
9
- def init_with_program(prog)
10
- prog.command(:"new-theme") do |c|
11
- c.syntax "new-theme NAME"
12
- c.description "Creates a new Jekyll theme scaffold"
13
- c.option "code_of_conduct", \
14
- "-c", "--code-of-conduct", \
15
- "Include a Code of Conduct. (defaults to false)"
16
-
17
- c.action do |args, opts|
18
- Jekyll::Commands::NewTheme.process(args, opts)
19
- end
20
- end
21
- end
22
-
23
- def process(args, opts)
24
- if !args || args.empty?
25
- raise Jekyll::Errors::InvalidThemeName, "You must specify a theme name."
26
- end
27
-
28
- new_theme_name = args.join("_")
29
- theme = Jekyll::ThemeBuilder.new(new_theme_name, opts)
30
- Jekyll.logger.abort_with "Conflict:", "#{theme.path} already exists." if theme.path.exist?
31
-
32
- theme.create!
33
- Jekyll.logger.info "Your new Jekyll theme, #{theme.name.cyan}," \
34
- " is ready for you in #{theme.path.to_s.cyan}!"
35
- Jekyll.logger.info "For help getting started, read #{theme.path}/README.md."
36
- end
37
- end
38
- end
39
- end
40
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module Jekyll
6
+ module Commands
7
+ class NewTheme < Jekyll::Command
8
+ class << self
9
+ def init_with_program(prog)
10
+ prog.command(:"new-theme") do |c|
11
+ c.syntax "new-theme NAME"
12
+ c.description "Creates a new Jekyll theme scaffold"
13
+ c.option "code_of_conduct", \
14
+ "-c", "--code-of-conduct", \
15
+ "Include a Code of Conduct. (defaults to false)"
16
+
17
+ c.action do |args, opts|
18
+ Jekyll::Commands::NewTheme.process(args, opts)
19
+ end
20
+ end
21
+ end
22
+
23
+ def process(args, opts)
24
+ if !args || args.empty?
25
+ raise Jekyll::Errors::InvalidThemeName, "You must specify a theme name."
26
+ end
27
+
28
+ new_theme_name = args.join("_")
29
+ theme = Jekyll::ThemeBuilder.new(new_theme_name, opts)
30
+ Jekyll.logger.abort_with "Conflict:", "#{theme.path} already exists." if theme.path.exist?
31
+
32
+ theme.create!
33
+ Jekyll.logger.info "Your new Jekyll theme, #{theme.name.cyan}," \
34
+ " is ready for you in #{theme.path.to_s.cyan}!"
35
+ Jekyll.logger.info "For help getting started, read #{theme.path}/README.md."
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,122 +1,122 @@
1
- # frozen_string_literal: true
2
-
3
- require "em-websocket"
4
-
5
- require_relative "websockets"
6
-
7
- module Jekyll
8
- module Commands
9
- class Serve
10
- class LiveReloadReactor
11
- attr_reader :started_event
12
- attr_reader :stopped_event
13
- attr_reader :thread
14
-
15
- def initialize
16
- @websockets = []
17
- @connections_count = 0
18
- @started_event = Utils::ThreadEvent.new
19
- @stopped_event = Utils::ThreadEvent.new
20
- end
21
-
22
- def stop
23
- # There is only one EventMachine instance per Ruby process so stopping
24
- # it here will stop the reactor thread we have running.
25
- EM.stop if EM.reactor_running?
26
- Jekyll.logger.debug "LiveReload Server:", "halted"
27
- end
28
-
29
- def running?
30
- EM.reactor_running?
31
- end
32
-
33
- def handle_websockets_event(websocket)
34
- websocket.onopen { |handshake| connect(websocket, handshake) }
35
- websocket.onclose { disconnect(websocket) }
36
- websocket.onmessage { |msg| print_message(msg) }
37
- websocket.onerror { |error| log_error(error) }
38
- end
39
-
40
- def start(opts)
41
- @thread = Thread.new do
42
- # Use epoll if the kernel supports it
43
- EM.epoll
44
- EM.run do
45
- EM.error_handler { |e| log_error(e) }
46
-
47
- EM.start_server(
48
- opts["host"],
49
- opts["livereload_port"],
50
- HttpAwareConnection,
51
- opts
52
- ) do |ws|
53
- handle_websockets_event(ws)
54
- end
55
-
56
- # Notify blocked threads that EventMachine has started or shutdown
57
- EM.schedule { @started_event.set }
58
- EM.add_shutdown_hook { @stopped_event.set }
59
-
60
- Jekyll.logger.info "LiveReload address:",
61
- "http://#{opts["host"]}:#{opts["livereload_port"]}"
62
- end
63
- end
64
- @thread.abort_on_exception = true
65
- end
66
-
67
- # For a description of the protocol see
68
- # http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol
69
- def reload(pages)
70
- pages.each do |p|
71
- json_message = JSON.dump(
72
- :command => "reload",
73
- :path => p.url,
74
- :liveCSS => true
75
- )
76
-
77
- Jekyll.logger.debug "LiveReload:", "Reloading #{p.url}"
78
- Jekyll.logger.debug "", json_message
79
- @websockets.each { |ws| ws.send(json_message) }
80
- end
81
- end
82
-
83
- private
84
-
85
- def connect(websocket, handshake)
86
- @connections_count += 1
87
- if @connections_count == 1
88
- message = "Browser connected"
89
- message += " over SSL/TLS" if handshake.secure?
90
- Jekyll.logger.info "LiveReload:", message
91
- end
92
- websocket.send(
93
- JSON.dump(
94
- :command => "hello",
95
- :protocols => ["http://livereload.com/protocols/official-7"],
96
- :serverName => "jekyll"
97
- )
98
- )
99
-
100
- @websockets << websocket
101
- end
102
-
103
- def disconnect(websocket)
104
- @websockets.delete(websocket)
105
- end
106
-
107
- def print_message(json_message)
108
- msg = JSON.parse(json_message)
109
- # Not sure what the 'url' command even does in LiveReload. The spec is silent
110
- # on its purpose.
111
- Jekyll.logger.info "LiveReload:", "Browser URL: #{msg["url"]}" if msg["command"] == "url"
112
- end
113
-
114
- def log_error(error)
115
- Jekyll.logger.error "LiveReload experienced an error. " \
116
- "Run with --trace for more information."
117
- raise error
118
- end
119
- end
120
- end
121
- end
122
- end
1
+ # frozen_string_literal: true
2
+
3
+ require "em-websocket"
4
+
5
+ require_relative "websockets"
6
+
7
+ module Jekyll
8
+ module Commands
9
+ class Serve
10
+ class LiveReloadReactor
11
+ attr_reader :started_event
12
+ attr_reader :stopped_event
13
+ attr_reader :thread
14
+
15
+ def initialize
16
+ @websockets = []
17
+ @connections_count = 0
18
+ @started_event = Utils::ThreadEvent.new
19
+ @stopped_event = Utils::ThreadEvent.new
20
+ end
21
+
22
+ def stop
23
+ # There is only one EventMachine instance per Ruby process so stopping
24
+ # it here will stop the reactor thread we have running.
25
+ EM.stop if EM.reactor_running?
26
+ Jekyll.logger.debug "LiveReload Server:", "halted"
27
+ end
28
+
29
+ def running?
30
+ EM.reactor_running?
31
+ end
32
+
33
+ def handle_websockets_event(websocket)
34
+ websocket.onopen { |handshake| connect(websocket, handshake) }
35
+ websocket.onclose { disconnect(websocket) }
36
+ websocket.onmessage { |msg| print_message(msg) }
37
+ websocket.onerror { |error| log_error(error) }
38
+ end
39
+
40
+ def start(opts)
41
+ @thread = Thread.new do
42
+ # Use epoll if the kernel supports it
43
+ EM.epoll
44
+ EM.run do
45
+ EM.error_handler { |e| log_error(e) }
46
+
47
+ EM.start_server(
48
+ opts["host"],
49
+ opts["livereload_port"],
50
+ HttpAwareConnection,
51
+ opts
52
+ ) do |ws|
53
+ handle_websockets_event(ws)
54
+ end
55
+
56
+ # Notify blocked threads that EventMachine has started or shutdown
57
+ EM.schedule { @started_event.set }
58
+ EM.add_shutdown_hook { @stopped_event.set }
59
+
60
+ Jekyll.logger.info "LiveReload address:",
61
+ "http://#{opts["host"]}:#{opts["livereload_port"]}"
62
+ end
63
+ end
64
+ @thread.abort_on_exception = true
65
+ end
66
+
67
+ # For a description of the protocol see
68
+ # http://feedback.livereload.com/knowledgebase/articles/86174-livereload-protocol
69
+ def reload(pages)
70
+ pages.each do |p|
71
+ json_message = JSON.dump(
72
+ :command => "reload",
73
+ :path => p.url,
74
+ :liveCSS => true
75
+ )
76
+
77
+ Jekyll.logger.debug "LiveReload:", "Reloading #{p.url}"
78
+ Jekyll.logger.debug "", json_message
79
+ @websockets.each { |ws| ws.send(json_message) }
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def connect(websocket, handshake)
86
+ @connections_count += 1
87
+ if @connections_count == 1
88
+ message = "Browser connected"
89
+ message += " over SSL/TLS" if handshake.secure?
90
+ Jekyll.logger.info "LiveReload:", message
91
+ end
92
+ websocket.send(
93
+ JSON.dump(
94
+ :command => "hello",
95
+ :protocols => ["http://livereload.com/protocols/official-7"],
96
+ :serverName => "jekyll"
97
+ )
98
+ )
99
+
100
+ @websockets << websocket
101
+ end
102
+
103
+ def disconnect(websocket)
104
+ @websockets.delete(websocket)
105
+ end
106
+
107
+ def print_message(json_message)
108
+ msg = JSON.parse(json_message)
109
+ # Not sure what the 'url' command even does in LiveReload. The spec is silent
110
+ # on its purpose.
111
+ Jekyll.logger.info "LiveReload:", "Browser URL: #{msg["url"]}" if msg["command"] == "url"
112
+ end
113
+
114
+ def log_error(error)
115
+ Jekyll.logger.error "LiveReload experienced an error. " \
116
+ "Run with --trace for more information."
117
+ raise error
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end