jekyll-theme-specs 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c601c43be1e92a24bf68448352572103dcf62238
4
+ data.tar.gz: 7aff260a5ccb49fd6e85247afa9f7c0435ce7a35
5
+ SHA512:
6
+ metadata.gz: 2f6b06cfc339376055d653ef26b1ca12932755fb2c313d29f80f383e1b3c0e5047a428450ff78ff86a3d46eabed41c98daf729141d78785d1889005e63389d4f
7
+ data.tar.gz: be6c8e9e3b357ebad5902e32da195e0554d351cf56ecca36bf597bd9b03e619e528ef2d1065db56f32a0fbe408c571500bdebf77eeba380089c4969fd3c3dd4e
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at TODO: Write your email address. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jekyll-theme-specs.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Pavel Tsurbeleu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,49 @@
1
+ # Jekyll Theme Specs
2
+
3
+ This gem is a simple wrap up of behavior-driven (BDD) validations borrowed from the original
4
+ source code of Jekyll. The only reason it has been extracted into a gem is to be able to validate
5
+ gem-based themes for Jekyll using Jekyll's original validation tools & techniques.
6
+
7
+ All the credits belong to Jekyll's contributors & maintainers. Again, this gem is a
8
+ carbon-copy of what is already available in Jekyll's code base in a bit more reusable package.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your Jekyll's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'jekyll-theme-specs'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install jekyll-theme-specs
25
+
26
+ ## Usage
27
+
28
+ At this point the tool makes quite a few assumptions and very rigid in terms of the configuration options available.
29
+
30
+ - All your features MUST be placed in `features` folder (Cucumber default);
31
+ - Before running your theme's specs, it is a MUST to run `bundle` or `bundle install`;
32
+ - Always run the tool via Bundler, eq. `bundle exec theme-specs`;
33
+ - You can opt-in for more concise reporting style (Jekyll's favorite) by using `-f Jekyll::Cucumber::Formatter` option, eq. `bundle exec theme-specs -f Jekyll::Cucumber::Formatter`;
34
+
35
+ There is also `minima-theme-specs` repository that is a work in progress of building `minima` theme
36
+ validations. We will start with a few simple things and expand coverage further.
37
+
38
+ ## Development
39
+
40
+ ...
41
+
42
+ ## Contributing
43
+
44
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ptsurbeleu/jekyll-theme-specs. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
45
+
46
+
47
+ ## License
48
+
49
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "jekyll/theme/specs"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ require 'cucumber'
3
+ require 'pry'
4
+
5
+ # Require our own step definitions and other files to support steps execution
6
+ ARGV << "--require"
7
+ ARGV << File.dirname(__FILE__) + '/../lib'
8
+
9
+ # The dup is to keep ARGV intact, so that tools like ruby-debug can respawn.
10
+ Cucumber::Cli::Main.new(ARGV.dup).execute!
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "jekyll-theme-specs"
7
+ spec.version = '0.1.0'
8
+ spec.authors = ["Pavel Tsurbeleu"]
9
+ spec.email = ["pavel.tsurbeleu@me.com"]
10
+
11
+ spec.summary = %q{Helps you to write & exercise behavior-driven (BDD) specifications for your gem-based Jekyll theme}
12
+ spec.description = %q{Helps you to write & exercise behavior-driven (BDD) specifications for your gem-based Jekyll theme}
13
+ spec.homepage = "https://github.com/ptsurbeleu/jekyll-theme-specs"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency "cucumber", "~> 2.1"
24
+ spec.add_dependency "rspec"
25
+ spec.add_dependency "jekyll", ">= 3.0", "~> 3.1"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.14"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "minitest", "~> 5.0"
30
+ end
@@ -0,0 +1,366 @@
1
+ Before do
2
+ # TODO: Figure out how to activate these snippets using configuration flags
3
+ # FileUtils.rm_rf(Paths.test_dir) if Paths.test_dir.exist?
4
+ # FileUtils.mkdir_p(Paths.test_dir) unless Paths.test_dir.directory?
5
+ # Dir.chdir(Paths.source_dir)
6
+ end
7
+
8
+ #
9
+
10
+ After do
11
+ # TODO: Figure out how to activate these snippets using configuration flags
12
+ # FileUtils.rm_rf(Paths.test_dir) if Paths.test_dir.exist?
13
+ # Paths.output_file.delete if Paths.output_file.exist?
14
+ # Paths.status_file.delete if Paths.status_file.exist?
15
+ # Dir.chdir(Paths.test_dir.parent)
16
+ end
17
+
18
+ #
19
+
20
+ Given(%r!^I have a blank site in "(.*)"$!) do |path|
21
+ unless File.exist?(path)
22
+ then FileUtils.mkdir_p(path)
23
+ end
24
+ end
25
+
26
+ #
27
+
28
+ Given(%r!^I do not have a "(.*)" directory$!) do |path|
29
+ Paths.test_dir.join(path).directory?
30
+ end
31
+
32
+ #
33
+
34
+ Given(%r!^I have an? "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$!) do |file, key, value, text|
35
+ File.write(file, Jekyll::Utils.strip_heredoc(<<-DATA))
36
+ ---
37
+ #{key || "layout"}: #{value || "nil"}
38
+ ---
39
+
40
+ #{text}
41
+ DATA
42
+ end
43
+
44
+ #
45
+
46
+ Given(%r!^I have an? "(.*)" file that contains "(.*)"$!) do |file, text|
47
+ File.write(file, text)
48
+ end
49
+
50
+ #
51
+
52
+ Given(%r!^I have an? (.*) (layout|theme) that contains "(.*)"$!) do |name, type, text|
53
+ folder = type == "layout" ? "_layouts" : "_theme"
54
+
55
+ destination_file = Pathname.new(File.join(folder, "#{name}.html"))
56
+ FileUtils.mkdir_p(destination_file.parent) unless destination_file.parent.directory?
57
+ File.write(destination_file, text)
58
+ end
59
+
60
+ #
61
+
62
+ Given(%r!^I have an? "(.*)" file with content:$!) do |file, text|
63
+ File.write(file, text)
64
+ end
65
+
66
+ #
67
+
68
+ Given(%r!^I have an? (.*) directory$!) do |dir|
69
+ unless File.directory?(dir)
70
+ then FileUtils.mkdir_p(dir)
71
+ end
72
+ end
73
+
74
+ #
75
+
76
+ Given(%r!^I have the following (draft|page|post)s?(?: (in|under) "([^"]+)")?:$!) do |status, direction, folder, table|
77
+ table.hashes.each do |input_hash|
78
+ title = slug(input_hash["title"])
79
+ ext = input_hash["type"] || "markdown"
80
+ filename = "#{title}.#{ext}" if %w(draft page).include?(status)
81
+ before, after = location(folder, direction)
82
+ dest_folder = "_drafts" if status == "draft"
83
+ dest_folder = "_posts" if status == "post"
84
+ dest_folder = "" if status == "page"
85
+
86
+ if status == "post"
87
+ parsed_date = Time.xmlschema(input_hash["date"]) rescue Time.parse(input_hash["date"])
88
+ filename = "#{parsed_date.strftime("%Y-%m-%d")}-#{title}.#{ext}"
89
+ end
90
+
91
+ path = File.join(before, dest_folder, after, filename)
92
+ File.write(path, file_content_from_hash(input_hash))
93
+ end
94
+ end
95
+
96
+ #
97
+
98
+ Given(%r!^I have the following documents? under the (.*) collection:$!) do |folder, table|
99
+ table.hashes.each do |input_hash|
100
+ title = slug(input_hash["title"])
101
+ filename = "#{title}.md"
102
+ dest_folder = "_#{folder}"
103
+
104
+ path = File.join(dest_folder, filename)
105
+ File.write(path, file_content_from_hash(input_hash))
106
+ end
107
+ end
108
+
109
+ #
110
+
111
+ Given(%r!^I have a configuration file with "(.*)" set to "(.*)"$!) do |key, value|
112
+ # NOTE: This snippet has been tweaked as well to load '_config.yml'
113
+ # from the source directory, which is supposed to be the current directory.
114
+ config = \
115
+ if Paths::SOURCE_DIR.join("_config.yml").exist?
116
+ SafeYAML.load_file(Paths::SOURCE_DIR.join("_config.yml"))
117
+ else
118
+ {}
119
+ end
120
+ # NOTE: The original snippet was replaced with this code. In the given context we must
121
+ # assert configuration values to ensure our expectations are valid.
122
+ expect(config[key]).to eq value
123
+ end
124
+
125
+ #
126
+
127
+ Given(%r!^I have a configuration file with:$!) do |table|
128
+ table.hashes.each do |row|
129
+ step %(I have a configuration file with "#{row["key"]}" set to "#{row["value"]}")
130
+ end
131
+ end
132
+
133
+ #
134
+
135
+ Given(%r!^I have a configuration file with "([^\"]*)" set to:$!) do |key, table|
136
+ File.open("_config.yml", "w") do |f|
137
+ f.write("#{key}:\n")
138
+ table.hashes.each do |row|
139
+ f.write("- #{row["value"]}\n")
140
+ end
141
+ end
142
+ end
143
+
144
+ #
145
+
146
+ Given(%r!^I have fixture collections$!) do
147
+ FileUtils.cp_r Paths.source_dir.join("test", "source", "_methods"), source_dir
148
+ FileUtils.cp_r Paths.source_dir.join("test", "source", "_thanksgiving"), source_dir
149
+ end
150
+
151
+ #
152
+
153
+ Given(%r!^I wait (\d+) second(s?)$!) do |time, _|
154
+ sleep(time.to_f)
155
+ end
156
+
157
+ #
158
+
159
+ When(%r!^I run jekyll(.*)$!) do |args|
160
+ run_jekyll(args)
161
+ # TODO: Figure out how to activate this snippet with configuration flag...
162
+ # if args.include?("--verbose") || ENV["DEBUG"]
163
+ # $stderr.puts "\n#{jekyll_run_output}\n"
164
+ # end
165
+ end
166
+
167
+ #
168
+
169
+ When(%r!^I run bundle(.*)$!) do |args|
170
+ run_bundle(args)
171
+ if args.include?("--verbose") || ENV["DEBUG"]
172
+ $stderr.puts "\n#{jekyll_run_output}\n"
173
+ end
174
+ end
175
+
176
+ #
177
+
178
+ When(%r!^I run gem(.*)$!) do |args|
179
+ run_rubygem(args)
180
+ if args.include?("--verbose") || ENV["DEBUG"]
181
+ $stderr.puts "\n#{jekyll_run_output}\n"
182
+ end
183
+ end
184
+
185
+ #
186
+
187
+ When(%r!^I run git add .$!) do
188
+ run_in_shell("git", "add", ".", "--verbose")
189
+ end
190
+
191
+ #
192
+
193
+ When(%r!^I decide to build the theme gem$!) do
194
+ Dir.chdir(Paths.theme_gem_dir)
195
+ gemspec = "my-cool-theme.gemspec"
196
+ File.write(gemspec, File.read(gemspec).sub("TODO: ", ""))
197
+ File.new("_includes/blank.html", "w")
198
+ File.new("_sass/blank.scss", "w")
199
+ File.new("assets/blank.scss", "w")
200
+ end
201
+
202
+ #
203
+
204
+ When(%r!^I change "(.*)" to contain "(.*)"$!) do |file, text|
205
+ File.open(file, "a") do |f|
206
+ f.write(text)
207
+ end
208
+ end
209
+
210
+ #
211
+
212
+ When(%r!^I delete the file "(.*)"$!) do |file|
213
+ File.delete(file)
214
+ end
215
+
216
+ #
217
+
218
+ Then(%r!^the (.*) directory should +(not )?exist$!) do |dir, negative|
219
+ if negative.nil?
220
+ expect(Pathname.new(dir)).to exist
221
+ else
222
+ expect(Pathname.new(dir)).to_not exist
223
+ end
224
+ end
225
+
226
+ #
227
+
228
+ Then(%r!^I should (not )?see "(.*)" in "(.*)"$!) do |negative, text, file|
229
+ step %(the "#{file}" file should exist)
230
+ regexp = Regexp.new(text, Regexp::MULTILINE)
231
+ if negative.nil? || negative.empty?
232
+ expect(file_contents(file)).to match regexp
233
+ else
234
+ expect(file_contents(file)).not_to match regexp
235
+ end
236
+ end
237
+
238
+ #
239
+
240
+ Then(%r!^I should (not )?see "(.*)" in "(.*)" if on Windows$!) do |negative, text, file|
241
+ step %(the "#{file}" file should exist)
242
+ regexp = Regexp.new(text, Regexp::MULTILINE)
243
+ if negative.nil? || negative.empty?
244
+ if Jekyll::Utils::Platforms.really_windows?
245
+ expect(file_contents(file)).to match regexp
246
+ else
247
+ expect(file_contents(file)).not_to match regexp
248
+ end
249
+ end
250
+ end
251
+
252
+ #
253
+
254
+ Then(%r!^I should (not )?see "(.*)" in "(.*)" unless Windows$!) do |negative, text, file|
255
+ step %(the "#{file}" file should exist)
256
+ regexp = Regexp.new(text, Regexp::MULTILINE)
257
+ if negative.nil? || negative.empty?
258
+ if Jekyll::Utils::Platforms.really_windows?
259
+ expect(file_contents(file)).not_to match regexp
260
+ else
261
+ expect(file_contents(file)).to match regexp
262
+ end
263
+ end
264
+ end
265
+
266
+ #
267
+
268
+ Then(%r!^I should see date "(.*)" in "(.*)" unless Windows$!) do |text, file|
269
+ step %(the "#{file}" file should exist)
270
+ regexp = Regexp.new(text)
271
+ if Jekyll::Utils::Platforms.really_windows? && !dst_active?
272
+ expect(file_contents(file)).not_to match regexp
273
+ else
274
+ expect(file_contents(file)).to match regexp
275
+ end
276
+ end
277
+
278
+ #
279
+
280
+ Then(%r!^I should see date "(.*)" in "(.*)" if on Windows$!) do |text, file|
281
+ step %(the "#{file}" file should exist)
282
+ regexp = Regexp.new(text)
283
+ if Jekyll::Utils::Platforms.really_windows? && !dst_active?
284
+ expect(file_contents(file)).to match regexp
285
+ else
286
+ expect(file_contents(file)).not_to match regexp
287
+ end
288
+ end
289
+
290
+ #
291
+
292
+ Then(%r!^I should see exactly "(.*)" in "(.*)"$!) do |text, file|
293
+ step %(the "#{file}" file should exist)
294
+ expect(file_contents(file).strip).to eq text
295
+ end
296
+
297
+ #
298
+
299
+ Then(%r!^I should see escaped "(.*)" in "(.*)"$!) do |text, file|
300
+ step %(I should see "#{Regexp.escape(text)}" in "#{file}")
301
+ end
302
+
303
+ #
304
+
305
+ Then(%r!^the "(.*)" file should +(not )?exist$!) do |file, negative|
306
+ if negative.nil?
307
+ expect(Pathname.new(file)).to exist
308
+ else
309
+ expect(Pathname.new(file)).to_not exist
310
+ end
311
+ end
312
+
313
+ #
314
+
315
+ Then(%r!^I should see today's time in "(.*)"$!) do |file|
316
+ step %(I should see "#{seconds_agnostic_time(Time.now)}" in "#{file}")
317
+ end
318
+
319
+ #
320
+
321
+ Then(%r!^I should see today's date in "(.*)"$!) do |file|
322
+ step %(I should see "#{Date.today}" in "#{file}")
323
+ end
324
+
325
+ #
326
+
327
+ Then(%r!^I should (not )?see "(.*)" in the build output$!) do |negative, text|
328
+ if negative.nil? || negative.empty?
329
+ expect(jekyll_run_output).to match Regexp.new(text)
330
+ else
331
+ expect(jekyll_run_output).not_to match Regexp.new(text)
332
+ end
333
+ end
334
+
335
+ #
336
+
337
+ Then(%r!^I should get an updated git index$!) do
338
+ index = %w(
339
+ .gitignore
340
+ Gemfile
341
+ LICENSE.txt
342
+ README.md
343
+ _includes/blank.html
344
+ _layouts/default.html
345
+ _layouts/page.html
346
+ _layouts/post.html
347
+ _sass/blank.scss
348
+ assets/blank.scss
349
+ my-cool-theme.gemspec
350
+ )
351
+ index.each do |file|
352
+ expect(jekyll_run_output).to match file
353
+ end
354
+ end
355
+
356
+ #
357
+
358
+ Then(%r!^I should get a zero exit(?:\-| )status$!) do
359
+ step %(I should see "EXIT STATUS: 0" in the build output)
360
+ end
361
+
362
+ #
363
+
364
+ Then(%r!^I should get a non-zero exit(?:\-| )status$!) do
365
+ step %(I should not see "EXIT STATUS: 0" in the build output)
366
+ end
@@ -0,0 +1,214 @@
1
+ require "fileutils"
2
+ require "colorator"
3
+ require "cucumber/formatter/console"
4
+ require "cucumber/formatter/io"
5
+
6
+ module Jekyll
7
+ module Cucumber
8
+ class Formatter
9
+ attr_accessor :indent, :runtime
10
+ include ::Cucumber::Formatter::Console
11
+ include ::Cucumber::Formatter::Io
12
+ include FileUtils
13
+
14
+ CHARS = {
15
+ :failed => "\u2718".red,
16
+ :pending => "\u203D".yellow,
17
+ :undefined => "\u2718".red,
18
+ :passed => "\u2714".green,
19
+ :skipped => "\u203D".blue,
20
+ }.freeze
21
+
22
+ #
23
+
24
+ def initialize(runtime, path_or_io, options)
25
+ @runtime = runtime
26
+ @snippets_input = []
27
+ @io = ensure_io(path_or_io)
28
+ @prefixes = options[:prefixes] || {}
29
+ @delayed_messages = []
30
+ @options = options
31
+ @exceptions = []
32
+ @indent = 0
33
+ @timings = {}
34
+ end
35
+
36
+ #
37
+
38
+ def before_features(_features)
39
+ print_profile_information
40
+ end
41
+
42
+ #
43
+
44
+ def after_features(features)
45
+ @io.puts
46
+ print_worst_offenders
47
+ print_summary(features)
48
+ end
49
+
50
+ #
51
+
52
+ def before_feature(_feature)
53
+ @exceptions = []
54
+ @indent = 0
55
+ end
56
+
57
+ #
58
+
59
+ def feature_element_timing_key(feature_element)
60
+ "\"#{feature_element.name.to_s.sub("Scenario: ", "")}\" (#{feature_element.location})"
61
+ end
62
+
63
+ #
64
+
65
+ def before_feature_element(feature_element)
66
+ @indent = 2
67
+ @scenario_indent = 2
68
+ @timings[feature_element_timing_key(feature_element)] = Time.now
69
+ end
70
+
71
+ #
72
+
73
+ def after_feature_element(feature_element)
74
+ @timings[feature_element_timing_key(feature_element)] = Time.now - @timings[feature_element_timing_key(feature_element)]
75
+ @io.print " (#{@timings[feature_element_timing_key(feature_element)]}s)"
76
+ end
77
+
78
+ #
79
+
80
+ def tag_name(tag_name); end
81
+
82
+ def comment_line(comment_line); end
83
+
84
+ def after_tags(tags); end
85
+
86
+ #
87
+
88
+ def before_background(_background)
89
+ @scenario_indent = 2
90
+ @in_background = true
91
+ @indent = 2
92
+ end
93
+
94
+ #
95
+
96
+ def after_background(_background)
97
+ @in_background = nil
98
+ end
99
+
100
+ #
101
+
102
+ def background_name(keyword, name, source_line, indent)
103
+ print_feature_element_name(
104
+ keyword, name, source_line, indent
105
+ )
106
+ end
107
+
108
+ #
109
+
110
+ def scenario_name(keyword, name, source_line, indent)
111
+ print_feature_element_name(
112
+ keyword, name, source_line, indent
113
+ )
114
+ end
115
+
116
+ #
117
+
118
+ def before_step(step)
119
+ @current_step = step
120
+ end
121
+
122
+ #
123
+
124
+ # rubocop:disable Metrics/ParameterLists
125
+ def before_step_result(_keyword, _step_match, _multiline_arg, status, exception, \
126
+ _source_indent, background, _file_colon_line)
127
+
128
+ @hide_this_step = false
129
+ if exception
130
+ if @exceptions.include?(exception)
131
+ @hide_this_step = true
132
+ return
133
+ end
134
+
135
+ @exceptions << exception
136
+ end
137
+
138
+ if status != :failed && @in_background ^ background
139
+ @hide_this_step = true
140
+ return
141
+ end
142
+
143
+ @status = status
144
+ end
145
+
146
+ #
147
+
148
+ def step_name(_keyword, _step_match, status, _source_indent, _background, _file_colon_line)
149
+ @io.print CHARS[status]
150
+ @io.print " "
151
+ end
152
+ # rubocop:enable Metrics/ParameterLists
153
+
154
+ #
155
+
156
+ def exception(exception, status)
157
+ return if @hide_this_step
158
+
159
+ @io.puts
160
+ print_exception(exception, status, @indent)
161
+ @io.flush
162
+ end
163
+
164
+ #
165
+
166
+ def after_test_step(test_step, result)
167
+ collect_snippet_data(
168
+ test_step, result
169
+ )
170
+ end
171
+
172
+ #
173
+
174
+ private
175
+ def print_feature_element_name(keyword, name, source_line, _indent)
176
+ @io.puts
177
+
178
+ names = name.empty? ? [name] : name.each_line.to_a
179
+ line = " #{keyword}: #{names[0]}"
180
+
181
+ @io.print(source_line) if @options[:source]
182
+ @io.print(line)
183
+ @io.print " "
184
+ @io.flush
185
+ end
186
+
187
+ #
188
+
189
+ def cell_prefix(status)
190
+ @prefixes[status]
191
+ end
192
+
193
+ #
194
+
195
+ def print_worst_offenders
196
+ @io.puts
197
+ @io.puts "Worst offenders:"
198
+ @timings.sort_by { |_f, t| -t }.take(10).each do |(f, t)|
199
+ @io.puts " #{t}s for #{f}"
200
+ end
201
+ @io.puts
202
+ end
203
+
204
+ #
205
+
206
+ def print_summary(features)
207
+ @io.puts
208
+ print_stats(features, @options)
209
+ print_snippets(@options)
210
+ print_passing_wip(@options)
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,183 @@
1
+ require "fileutils"
2
+ require "jekyll"
3
+ require "time"
4
+ require "safe_yaml/load"
5
+
6
+ class Paths
7
+ SOURCE_DIR = Pathname.new(Dir.pwd)
8
+
9
+ # NOTE: I'm not sure how to reuse this code... therefore raise if someone calls it.
10
+ def self.test_dir; raise 'NOT SUPPORTED!' ; end
11
+
12
+ def self.theme_gem_dir; 'NOT SUPPORTED!'; end
13
+
14
+ def self.output_file; source_dir.join("jekyll_output.txt"); end
15
+
16
+ def self.status_file; source_dir.join("jekyll_status.txt"); end
17
+
18
+ # NOTE: I'm not sure how to reuse this code... therefore raise if someone calls it.
19
+ def self.jekyll_bin; raise 'NOT SUPPORTED!'; end
20
+
21
+ def self.source_dir; SOURCE_DIR; end
22
+ end
23
+
24
+ #
25
+
26
+ def file_content_from_hash(input_hash)
27
+ matter_hash = input_hash.reject { |k, _v| k == "content" }
28
+ matter = matter_hash.map do |k, v|
29
+ "#{k}: #{v}\n"
30
+ end
31
+
32
+ matter = matter.join.chomp
33
+ content = \
34
+ if !input_hash["input"] || !input_hash["filter"]
35
+ then input_hash["content"]
36
+ else "{{ #{input_hash["input"]} | " \
37
+ "#{input_hash["filter"]} }}"
38
+ end
39
+
40
+ Jekyll::Utils.strip_heredoc(<<-EOF)
41
+ ---
42
+ #{matter.gsub(
43
+ %r!\n!, "\n "
44
+ )}
45
+ ---
46
+ #{content}
47
+ EOF
48
+ end
49
+
50
+ #
51
+
52
+ def source_dir(*files)
53
+ return Paths.test_dir(*files)
54
+ end
55
+
56
+ #
57
+
58
+ def all_steps_to_path(path)
59
+ source = source_dir
60
+ dest = Pathname.new(path).expand_path
61
+ paths = []
62
+
63
+ dest.ascend do |f|
64
+ break if f == source
65
+ paths.unshift f.to_s
66
+ end
67
+
68
+ paths
69
+ end
70
+
71
+ #
72
+
73
+ def jekyll_run_output
74
+ if Paths.output_file.file?
75
+ then return Paths.output_file.read
76
+ end
77
+ end
78
+
79
+ #
80
+
81
+ def jekyll_run_status
82
+ if Paths.status_file.file?
83
+ then return Paths.status_file.read
84
+ end
85
+ end
86
+
87
+ #
88
+
89
+ def run_bundle(args)
90
+ run_in_shell("bundle", *args.strip.split(" "))
91
+ end
92
+
93
+ #
94
+
95
+ def run_rubygem(args)
96
+ run_in_shell("gem", *args.strip.split(" "))
97
+ end
98
+
99
+ #
100
+
101
+ def run_jekyll(args)
102
+ args = args.strip.split(" ") # Shellwords?
103
+ # process = run_in_shell("ruby", Paths.jekyll_bin.to_s, *args, "--trace")
104
+
105
+ # NOTE: We MUST execute Jekyll CLI that is from the gem installed
106
+ # but we need to leave the rest as is.
107
+ process = run_in_shell("jekyll", *args, "--trace")
108
+ process.exitstatus.zero?
109
+ end
110
+
111
+ #
112
+ def run_in_shell(*args)
113
+ p, output = Jekyll::Utils::Exec.run(*args)
114
+
115
+ File.write(Paths.status_file, p.exitstatus)
116
+ File.open(Paths.output_file, "wb") do |f|
117
+ f.puts "$ " << args.join(" ")
118
+ f.puts output
119
+ f.puts "EXIT STATUS: #{p.exitstatus}"
120
+ end
121
+
122
+ p
123
+ end
124
+
125
+ #
126
+
127
+ def slug(title = nil)
128
+ if !title
129
+ then Time.now.strftime("%s%9N") # nanoseconds since the Epoch
130
+ else title.downcase.gsub(%r![^\w]!, " ").strip.gsub(%r!\s+!, "-")
131
+ end
132
+ end
133
+
134
+ #
135
+
136
+ def location(folder, direction)
137
+ if folder
138
+ before = folder if direction == "in"
139
+ after = folder if direction == "under"
140
+ end
141
+
142
+ [before || ".",
143
+ after || ".",]
144
+ end
145
+
146
+ #
147
+
148
+ def file_contents(path)
149
+ return Pathname.new(path).read
150
+ end
151
+
152
+ #
153
+
154
+ def seconds_agnostic_datetime(datetime = Time.now)
155
+ date, time, zone = datetime.to_s.split(" ")
156
+ time = seconds_agnostic_time(time)
157
+
158
+ [
159
+ Regexp.escape(date),
160
+ "#{time}:\\d{2}",
161
+ Regexp.escape(zone),
162
+ ] \
163
+ .join("\\ ")
164
+ end
165
+
166
+ #
167
+
168
+ def seconds_agnostic_time(time)
169
+ time = time.strftime("%H:%M:%S") if time.is_a?(Time)
170
+ hour, minutes, = time.split(":")
171
+ "#{hour}:#{minutes}"
172
+ end
173
+
174
+ # Helper method for Windows
175
+ def dst_active?
176
+ config = Jekyll.configuration("quiet" => true)
177
+ ENV["TZ"] = config["timezone"]
178
+ dst = Time.now.isdst
179
+
180
+ # reset variable to default state on Windows
181
+ ENV["TZ"] = nil
182
+ dst
183
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jekyll-theme-specs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Pavel Tsurbeleu
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cucumber
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: jekyll
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '3.1'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '3.0'
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.1'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.14'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.14'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: minitest
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '5.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '5.0'
103
+ description: Helps you to write & exercise behavior-driven (BDD) specifications for
104
+ your gem-based Jekyll theme
105
+ email:
106
+ - pavel.tsurbeleu@me.com
107
+ executables:
108
+ - theme-specs
109
+ extensions: []
110
+ extra_rdoc_files: []
111
+ files:
112
+ - ".gitignore"
113
+ - CODE_OF_CONDUCT.md
114
+ - Gemfile
115
+ - LICENSE.txt
116
+ - README.md
117
+ - Rakefile
118
+ - bin/console
119
+ - bin/setup
120
+ - exe/theme-specs
121
+ - jekyll-theme-specs.gemspec
122
+ - lib/step_definitions.rb
123
+ - lib/support/formatter.rb
124
+ - lib/support/helpers.rb
125
+ homepage: https://github.com/ptsurbeleu/jekyll-theme-specs
126
+ licenses:
127
+ - MIT
128
+ metadata: {}
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project:
145
+ rubygems_version: 2.6.12
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: Helps you to write & exercise behavior-driven (BDD) specifications for your
149
+ gem-based Jekyll theme
150
+ test_files: []