├── script ├── bootstrap ├── cucumber ├── fmt ├── cibuild ├── rubies ├── test-site └── test ├── test ├── fixtures │ ├── test-theme │ │ ├── _sass │ │ │ ├── test-theme-red.scss │ │ │ └── test-theme-black.scss │ │ ├── assets │ │ │ ├── application.coffee │ │ │ ├── style.scss │ │ │ └── logo.png │ │ ├── _data │ │ │ ├── locales │ │ │ │ ├── fr.yml │ │ │ │ └── en.yml │ │ │ ├── string.yml │ │ │ ├── navigation │ │ │ │ ├── footer-links.yml │ │ │ │ └── topnav.yml │ │ │ ├── blank.yml │ │ │ ├── sidemenu.yml │ │ │ └── config-hash.yml │ │ ├── _includes │ │ │ └── footer-links.html │ │ ├── _layouts │ │ │ ├── default.html │ │ │ ├── test.html │ │ │ ├── home.html │ │ │ └── page.html │ │ ├── test-theme.gemspec │ │ └── _config.yml │ ├── test-site │ │ ├── .gitignore │ │ ├── index.md │ │ ├── _config.yml │ │ ├── Gemfile │ │ └── _posts │ │ │ └── 2017-01-01-welcome-to-jekyll.markdown │ ├── test-plugin │ │ ├── test-plugin.gemspec │ │ └── lib │ │ │ └── test-plugin.rb │ ├── another-test-plugin │ │ ├── another-test-plugin.gemspec │ │ └── lib │ │ │ └── another-test-plugin.rb │ ├── no_data_output.html │ ├── no_data_config_output.html │ ├── same_data_output.html │ ├── same_data_override.html │ └── different_data_output.html ├── source │ ├── empty_config_override │ │ ├── _data │ │ │ └── test-theme.yml │ │ └── no_data.md │ ├── diff_data_keys │ │ ├── _data │ │ │ └── mu.yml │ │ └── different_data_key.md │ ├── same_data_files │ │ ├── _data │ │ │ └── locales │ │ │ │ └── en.yml │ │ └── same_data_key.md │ ├── no_data_files │ │ └── no_data.md │ ├── no_data_config │ │ └── no_data.md │ └── not_hash_config_override │ │ ├── no_data.md │ │ └── _data │ │ └── test-theme.yml ├── test_theme_configuration.rb ├── helper.rb └── test_theme_reader.rb ├── lib ├── jekyll-data │ ├── version.rb │ ├── themed_site_drop.rb │ ├── theme_data_reader.rb │ ├── theme_configuration.rb │ └── reader.rb ├── jekyll │ ├── data_path.rb │ ├── build_options.rb │ └── theme_drop.rb └── jekyll-data.rb ├── Rakefile ├── .gitignore ├── .travis.yml ├── Gemfile ├── .rubocop.yml ├── LICENSE.txt ├── jekyll-data.gemspec ├── features ├── theme_configuration.feature ├── support │ ├── helpers.rb │ └── formatter.rb ├── theme_data_reader.feature └── step_definitions.rb ├── README.md └── CHANGELOG.md /script/bootstrap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | bundle install 5 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/_sass/test-theme-red.scss: -------------------------------------------------------------------------------- 1 | .sample { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /test/source/empty_config_override/_data/test-theme.yml: -------------------------------------------------------------------------------- 1 | # empty theme config override 2 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/_sass/test-theme-black.scss: -------------------------------------------------------------------------------- 1 | .sample { 2 | color: black; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/assets/application.coffee: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | alert "From your theme." 4 | -------------------------------------------------------------------------------- /script/cucumber: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | time ruby -S bundle exec cucumber \ 4 | --format progress "$@" 5 | -------------------------------------------------------------------------------- /test/source/diff_data_keys/_data/mu.yml: -------------------------------------------------------------------------------- 1 | greeting: Welcome to The Matrix! 2 | prev: Red Pill 3 | next: Blue Pill 4 | -------------------------------------------------------------------------------- /lib/jekyll-data/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module JekyllData 4 | VERSION = "1.1.1" 5 | end 6 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/_data/locales/fr.yml: -------------------------------------------------------------------------------- 1 | greeting: "Bonjour, Bienvenue!" 2 | prev: précédent 3 | next: prochain 4 | -------------------------------------------------------------------------------- /test/source/same_data_files/_data/locales/en.yml: -------------------------------------------------------------------------------- 1 | greeting: "Welcome to the Future!" 2 | prev: older 3 | next: newer 4 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/assets/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | @import "test-theme-{{ site.theme-color | default: "red" }}"; 4 | -------------------------------------------------------------------------------- /script/fmt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo "Rubocop $(bundle exec rubocop --version)" 5 | bundle exec rubocop -D 6 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ashmaroli/jekyll-data/HEAD/test/fixtures/test-theme/assets/logo.png -------------------------------------------------------------------------------- /test/source/no_data_files/no_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: home 3 | permalink: output.html 4 | --- 5 | 6 | This site does not have a _data directory at source. 7 | -------------------------------------------------------------------------------- /test/source/no_data_config/no_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | permalink: output.html 4 | --- 5 | 6 | This site does not have a _data directory at source. 7 | -------------------------------------------------------------------------------- /test/source/empty_config_override/no_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | permalink: output.html 4 | --- 5 | 6 | This site does not have a _data directory at source. 7 | -------------------------------------------------------------------------------- /test/source/not_hash_config_override/no_data.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: page 3 | permalink: output.html 4 | --- 5 | 6 | This site does not have a _data directory at source. 7 | -------------------------------------------------------------------------------- /lib/jekyll/data_path.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Jekyll 4 | class Theme 5 | def data_path 6 | @data_path ||= path_for "_data" 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/_data/string.yml: -------------------------------------------------------------------------------- 1 | > 2 | No keys. Just a file with a lone string. Is this a data file then? This 3 | string is still accessible via `{{ site.data.string }}` in the templates. 4 | -------------------------------------------------------------------------------- /test/fixtures/test-theme/_includes/footer-links.html: -------------------------------------------------------------------------------- 1 |
8 | {{ site.data.locales[site.lang].prev }} 9 | {{ site.data.locales[site.lang].next }} 10 |
11 |Is logo enabled? {% unless theme.logo == 'disabled' %}{{ theme.logo }}{% endunless %}
9 |Theme Variant: {{ theme.theme_variant }}
10 |Show recent posts in a: {{ theme.recent_posts.style }}
11 |Max no. of recent posts: {{ theme.recent_posts.quantity }}
12 |This site does not have a _data directory at source.
6 | 7 |Is logo enabled? logo.png
9 |Theme Variant: Charcoal
10 |Show recent posts in a: list
11 |Max no. of recent posts: 4
12 |
" in "_site/page.html"
65 | And I should see "theme-variant : Charcoal" in "_site/page.html"
66 |
--------------------------------------------------------------------------------
/test/test_theme_reader.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "helper"
4 |
5 | class TestThemeReader < JekyllDataTest
6 | context "site without data files but with a valid theme" do
7 | setup do
8 | @site = fixture_site(
9 | "source" => File.join(source_dir, "no_data_files"),
10 | "destination" => File.join(dest_dir, "no_data_files")
11 | )
12 | assert @site.theme
13 | @theme_data = ThemeDataReader.new(@site).read("_data")
14 | @site.process
15 | end
16 | should "read data files in theme gem" do
17 | assert_equal @site.data["navigation"]["topnav"],
18 | @theme_data["navigation"]["topnav"]
19 | end
20 |
21 | should "use data from theme gem" do
22 | assert_equal(
23 | File.read(File.join(fixture_dir, "no_data_output.html")),
24 | File.read(@site.in_dest_dir("output.html"))
25 | )
26 | end
27 | end
28 |
29 | context "site with data keys different from a valid theme data hash" do
30 | setup do
31 | @site = fixture_site(
32 | "source" => File.join(source_dir, "diff_data_keys"),
33 | "destination" => File.join(dest_dir, "diff_data_keys")
34 | )
35 | assert @site.theme
36 | @theme_data = ThemeDataReader.new(@site).read("_data")
37 | @site.process
38 | end
39 | should "read and use data from other keys in theme gem" do
40 | assert_equal(
41 | File.read(File.join(fixture_dir, "different_data_output.html")),
42 | File.read(@site.in_dest_dir("output.html"))
43 | )
44 | end
45 |
46 | should "not override theme data" do
47 | assert_equal(
48 | File.read(File.join(fixture_dir, "different_data_output.html")),
49 | File.read(@site.in_dest_dir("output.html"))
50 | )
51 | end
52 | end
53 |
54 | context "site with same data keys as a valid theme data hash" do
55 | setup do
56 | @site = fixture_site(
57 | "source" => File.join(source_dir, "same_data_files"),
58 | "destination" => File.join(dest_dir, "same_data_files")
59 | )
60 | assert @site.theme
61 | @theme_data = ThemeDataReader.new(@site).read("_data")
62 | @site.process
63 | end
64 | should "override theme data" do
65 | assert_equal(
66 | File.read(File.join(fixture_dir, "same_data_override.html")),
67 | File.read(@site.in_dest_dir("override.html"))
68 | )
69 | end
70 |
71 | should "also use data from other keys in theme gem" do
72 | assert_equal(
73 | File.read(File.join(fixture_dir, "same_data_output.html")),
74 | File.read(@site.in_dest_dir("override.html"))
75 | )
76 | end
77 | end
78 |
79 | context "theme gem shipped with a '_config.yml'" do
80 | setup do
81 | @site = fixture_site(
82 | "title" => "Config Test"
83 | )
84 | end
85 |
86 | should "have its hash appended to site's config hash" do
87 | assert_contains @site.config, %w(post_excerpts enabled)
88 | end
89 |
90 | should "have its hash added only where its not already set" do
91 | refute_equal "Test Theme", @site.config["title"]
92 | assert_equal "Config Test", @site.config["title"]
93 | end
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/features/support/helpers.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "fileutils"
4 | require "jekyll"
5 | require "open3"
6 | require "time"
7 | require "safe_yaml/load"
8 |
9 | class Paths
10 | SOURCE_DIR = Pathname.new(File.expand_path("../..", __dir__))
11 | def self.test_dir; source_dir.join("tmp", "jekyll-data"); end
12 |
13 | def self.output_file; test_dir.join("jekyll_output.txt"); end
14 |
15 | def self.status_file; test_dir.join("jekyll_status.txt"); end
16 |
17 | def self.source_dir; SOURCE_DIR; end
18 | end
19 |
20 | def file_content_from_hash(input_hash)
21 | matter_hash = input_hash.reject { |k, _v| k == "content" }
22 | matter = matter_hash.map { |k, v| "#{k}: #{v}\n" }.join
23 | matter.chomp!
24 | content = if input_hash["input"] && input_hash["filter"]
25 | "{{ #{input_hash["input"]} | #{input_hash["filter"]} }}"
26 | else
27 | input_hash["content"]
28 | end
29 |
30 | <<~RESULT
31 | ---
32 | #{matter}
33 | ---
34 |
35 | #{content}
36 | RESULT
37 | end
38 |
39 | def source_dir(*files)
40 | Paths.test_dir(*files)
41 | end
42 |
43 | def all_steps_to_path(path)
44 | source = source_dir
45 | dest = Pathname.new(path).expand_path
46 | paths = []
47 |
48 | dest.ascend do |f|
49 | break if f == source
50 |
51 | paths.unshift f.to_s
52 | end
53 |
54 | paths
55 | end
56 |
57 | def jekyll_run_output
58 | Paths.output_file.read if Paths.output_file.file?
59 | end
60 |
61 | def jekyll_run_status
62 | Paths.status_file.read if Paths.status_file.file?
63 | end
64 |
65 | def run_bundle(args)
66 | run_in_shell("bundle", *args.strip.split(" "))
67 | end
68 |
69 | def run_rubygem(args)
70 | run_in_shell("gem", *args.strip.split(" "))
71 | end
72 |
73 | def run_jekyll(args)
74 | args = args.strip.split(" ") # Shellwords?
75 | process = run_in_shell("ruby", Paths.jekyll_bin.to_s, *args, "--trace")
76 | process.exitstatus.zero?
77 | end
78 |
79 | # rubocop:disable Metrics/AbcSize
80 | def run_in_shell(*args)
81 | i, o, e, p = Open3.popen3(*args)
82 | out = o.read.strip
83 | err = e.read.strip
84 |
85 | [i, o, e].each(&:close)
86 |
87 | File.write(Paths.status_file, p.value.exitstatus)
88 | File.open(Paths.output_file, "wb") do |f|
89 | f.print "$ "
90 | f.puts args.join(" ")
91 | f.puts out
92 | f.puts err
93 | f.puts "EXIT STATUS: #{p.value.exitstatus}"
94 | end
95 |
96 | p.value
97 | end
98 | # rubocop:enable Metrics/AbcSize
99 |
100 | def slug(title = nil)
101 | if !title
102 | Time.now.strftime("%s%9N") # nanoseconds since the Epoch
103 | else title.downcase.gsub(%r![^\w]!, " ").strip.gsub(%r!\s+!, "-")
104 | end
105 | end
106 |
107 | def location(folder, direction)
108 | if folder
109 | before = folder if direction == "in"
110 | after = folder if direction == "under"
111 | end
112 |
113 | [
114 | before || ".",
115 | after || ".",
116 | ]
117 | end
118 |
119 | def file_contents(path)
120 | Pathname.new(path).read
121 | end
122 |
123 | def seconds_agnostic_datetime(datetime = Time.now)
124 | date, time, zone = datetime.to_s.split(" ")
125 | time = seconds_agnostic_time(time)
126 |
127 | [
128 | Regexp.escape(date),
129 | "#{time}:\\d{2}",
130 | Regexp.escape(zone),
131 | ].join("\\ ")
132 | end
133 |
134 | def seconds_agnostic_time(time)
135 | time = time.strftime("%H:%M:%S") if time.is_a?(Time)
136 | hour, minutes, = time.split(":")
137 | "#{hour}:#{minutes}"
138 | end
139 |
--------------------------------------------------------------------------------
/features/theme_data_reader.feature:
--------------------------------------------------------------------------------
1 | Feature: Reading Data files in Gem-based Themes
2 | As a hacker who likes to share my expertise
3 | I want to be able to include data files in my gemified theme
4 | In order to supplement the templates with default text-strings
5 |
6 | Scenario: A site not using a gem-based theme
7 | Given I have a configuration file with:
8 | | key | value |
9 | | exclude | [Gemfile, Gemfile.lock] |
10 | And I have a Gemfile with plugin:
11 | | name | path |
12 | | test-plugin | ../../test/fixtures/test-plugin |
13 | When I run bundle exec jekyll build
14 | Then I should get a zero exit status
15 | And the _site directory should exist
16 | And the "_site/test-feed.xml" file should exist
17 |
18 | Scenario: Theme-gem has a data file to support i18n
19 | Given I have a configuration file with:
20 | | key | value |
21 | | lang | fr |
22 | | theme | test-theme |
23 | | gems | [jekyll-data] |
24 | | exclude | [Gemfile, Gemfile.lock] |
25 | And I have a "locales.md" file with content:
26 | """
27 | ---
28 | ---
29 |
30 | {% assign ui = site.data.locales[site.lang] %}
31 | {% assign user = "John Smith" %}
32 |
33 | {{ ui.greeting }} {{ user }}
34 |
35 | {{ ui.prev }}
36 |
37 | {{ ui.next }}
38 | """
39 | And I have a valid Gemfile
40 | When I run bundle exec jekyll build
41 | Then I should get a zero exit status
42 | And the _site directory should exist
43 | And I should see "Bonjour, Bienvenue! John Smith" in "_site/locales.html"
44 | And I should see "précédent" in "_site/locales.html"
45 | And I should see "prochain" in "_site/locales.html"
46 |
47 | Scenario: Overriding a data file within theme-gem - Method I
48 | Given I have a configuration file with:
49 | | key | value |
50 | | lang | fr |
51 | | theme | test-theme |
52 | | gems | [jekyll-data] |
53 | | exclude | [Gemfile, Gemfile.lock] |
54 | And I have a "locales.md" file with content:
55 | """
56 | ---
57 | ---
58 |
59 | {% assign ui = site.data.locales[site.lang] %}
60 | {% assign user = "John Smith" %}
61 |
62 | {{ ui.greeting }} {{ user }}!
63 |
64 | {{ ui.prev }}
65 |
66 | {{ ui.next }}
67 | """
68 | And I have a _data directory
69 | And I have a "_data/locales.yml" file with content:
70 | """
71 | fr:
72 | greeting: "Bonjour! Bienvenue"
73 | """
74 | And I have a valid Gemfile
75 | When I run bundle exec jekyll build
76 | Then I should get a zero exit status
77 | And the _site directory should exist
78 | And I should see "Bonjour! Bienvenue John Smith!" in "_site/locales.html"
79 | And I should see "précédent" in "_site/locales.html"
80 | And I should see "prochain" in "_site/locales.html"
81 |
82 | Scenario: Overriding a data file within theme-gem - Method II
83 | Given I have a configuration file with:
84 | | key | value |
85 | | lang | fr |
86 | | theme | test-theme |
87 | | gems | [jekyll-data] |
88 | | exclude | [Gemfile, Gemfile.lock] |
89 | And I have a "locales.md" file with content:
90 | """
91 | ---
92 | ---
93 |
94 | {% assign ui = site.data.locales[site.lang] %}
95 | {% assign user = "John Smith" %}
96 |
97 | {{ ui.greeting }} {{ user }}!
98 |
99 | {{ ui.prev }}
100 |
101 | {{ ui.next }}
102 | """
103 | And I have a _data/locales directory
104 | And I have a "_data/locales/fr.yml" file with content:
105 | """
106 | greeting: "Bonjour! Bienvenue"
107 | """
108 | And I have a valid Gemfile
109 | When I run bundle exec jekyll build
110 | Then I should get a zero exit status
111 | And the _site directory should exist
112 | And I should see "Bonjour! Bienvenue John Smith!" in "_site/locales.html"
113 | And I should see "précédent" in "_site/locales.html"
114 | And I should see "prochain" in "_site/locales.html"
115 |
--------------------------------------------------------------------------------
/features/step_definitions.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | Before do
4 | FileUtils.rm_rf(Paths.test_dir) if Paths.test_dir.exist?
5 | FileUtils.mkdir_p(Paths.test_dir) unless Paths.test_dir.directory?
6 | Dir.chdir(Paths.test_dir)
7 | end
8 |
9 | #
10 |
11 | After do
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 an? "(.*)" file that contains "(.*)"$!) do |file, text|
21 | File.write(file, text)
22 | end
23 |
24 | #
25 |
26 | Given(%r!^I have an? "(.*)" file with content:$!) do |file, text|
27 | File.write(file, text)
28 | end
29 |
30 | #
31 |
32 | Given(%r!^I have an? (.*) directory$!) do |dir|
33 | FileUtils.mkdir_p(dir) unless File.directory?(dir)
34 | end
35 |
36 | #
37 |
38 | Given(%r!^I have a configuration file with "(.*)" set to "(.*)"$!) do |key, value|
39 | config = \
40 | if source_dir.join("_config.yml").exist?
41 | SafeYAML.load_file(source_dir.join("_config.yml"))
42 | else
43 | {}
44 | end
45 | config[key] = YAML.safe_load(value)
46 | File.write("_config.yml", YAML.dump(config))
47 | end
48 |
49 | #
50 |
51 | Given(%r!^I have a configuration file with:$!) do |table|
52 | table.hashes.each do |row|
53 | step %(I have a configuration file with "#{row["key"]}" set to "#{row["value"]}")
54 | end
55 | end
56 |
57 | #
58 |
59 | Given(%r!^I have a configuration file with "([^\"]*)" set to:$!) do |key, table|
60 | File.open("_config.yml", "w") do |f|
61 | f.write("#{key}:\n")
62 | table.hashes.each do |row|
63 | f.write("- #{row["value"]}\n")
64 | end
65 | end
66 | end
67 |
68 | #
69 |
70 | Given(%r!^I have a valid Gemfile$!) do
71 | File.write("Gemfile", <<~DATA)
72 | gem "test-theme", path: File.expand_path(
73 | "../../test/fixtures/test-theme", __dir__
74 | )
75 |
76 | group :jekyll_plugins do
77 | gem "jekyll-data", path: File.expand_path("../../", __dir__)
78 | # any other plugins
79 | end
80 |
81 | DATA
82 | end
83 |
84 | #
85 |
86 | Given(%r!^I have a Gemfile with plugins?:$!) do |table|
87 | step %(I have a valid Gemfile)
88 | table.hashes.each do |row|
89 | step %(I have a Gemfile with "#{row["name"]}" plugin set to "#{row["path"]}")
90 | end
91 | end
92 |
93 | #
94 |
95 | Given(%r!^I have a Gemfile with (.*) plugin set to (.*)$!) do |name, path|
96 | content = File.read("Gemfile")
97 | File.write(
98 | "Gemfile",
99 | content.gsub(
100 | "# any other plugins",
101 | "gem #{name}, path: File.expand_path(#{path}, __dir__)\n # any other plugins"
102 | )
103 | )
104 | end
105 |
106 | #
107 |
108 | When(%r!^I run jekyll(.*)$!) do |args|
109 | run_jekyll(args)
110 | warn "\n#{jekyll_run_output}\n" if args.include?("--verbose") || ENV["DEBUG"]
111 | end
112 |
113 | #
114 |
115 | When(%r!^I run bundle(.*)$!) do |args|
116 | ENV["BUNDLE_GEMFILE"] = Paths.test_dir.join("Gemfile").to_s
117 | run_bundle(args)
118 | warn "\n#{jekyll_run_output}\n" if args.include?("--verbose") || ENV["DEBUG"]
119 | end
120 |
121 | #
122 |
123 | When(%r!^I change "(.*)" to contain "(.*)"$!) do |file, text|
124 | File.open(file, "a") do |f|
125 | f.write(text)
126 | end
127 | end
128 |
129 | #
130 |
131 | When(%r!^I delete the file "(.*)"$!) do |file|
132 | File.delete(file)
133 | end
134 |
135 | #
136 |
137 | Then(%r!^the (.*) directory should +(not )?exist$!) do |dir, negative|
138 | if negative.nil?
139 | expect(Pathname.new(dir)).to exist
140 | else
141 | expect(Pathname.new(dir)).to_not exist
142 | end
143 | end
144 |
145 | #
146 |
147 | Then(%r!^I should (not )?see "(.*)" in "(.*)"$!) do |negative, text, file|
148 | step %(the "#{file}" file should exist)
149 | regexp = Regexp.new(text, Regexp::MULTILINE)
150 | if negative.nil? || negative.empty?
151 | expect(file_contents(file)).to match regexp
152 | else
153 | expect(file_contents(file)).not_to match regexp
154 | end
155 | end
156 |
157 | #
158 |
159 | Then(%r!^I should see exactly "(.*)" in "(.*)"$!) do |text, file|
160 | step %(the "#{file}" file should exist)
161 | expect(file_contents(file).strip).to eq text
162 | end
163 |
164 | #
165 |
166 | Then(%r!^the "(.*)" file should +(not )?exist$!) do |file, negative|
167 | if negative.nil?
168 | expect(Pathname.new(file)).to exist
169 | else
170 | expect(Pathname.new(file)).to_not exist
171 | end
172 | end
173 |
174 | #
175 |
176 | Then(%r!^I should (not )?see "(.*)" in the build output$!) do |negative, text|
177 | if negative.nil? || negative.empty?
178 | expect(jekyll_run_output).to match Regexp.new(text)
179 | else
180 | expect(jekyll_run_output).not_to match Regexp.new(text)
181 | end
182 | end
183 |
184 | #
185 |
186 | Then(%r!^I should get a zero exit(?:\-| )status$!) do
187 | step %(I should see "EXIT STATUS: 0" in the build output)
188 | end
189 |
190 | #
191 |
192 | Then(%r!^I should get a non-zero exit(?:\-| )status$!) do
193 | step %(I should not see "EXIT STATUS: 0" in the build output)
194 | end
195 |
--------------------------------------------------------------------------------
/features/support/formatter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require "fileutils"
4 | require "colorator"
5 | require "cucumber/formatter/console"
6 | require "cucumber/formatter/io"
7 |
8 | module Jekyll
9 | module Cucumber
10 | class Formatter
11 | attr_accessor :indent, :runtime
12 | include ::Cucumber::Formatter::Console
13 | include ::Cucumber::Formatter::Io
14 | include FileUtils
15 |
16 | CHARS = {
17 | :failed => "\u2718".red,
18 | :pending => "\u203D".yellow,
19 | :undefined => "\u2718".red,
20 | :passed => "\u2714".green,
21 | :skipped => "\u203D".blue,
22 | }.freeze
23 |
24 | #
25 |
26 | def initialize(runtime, path_or_io, options)
27 | @runtime = runtime
28 | @snippets_input = []
29 | @io = ensure_io(path_or_io)
30 | @prefixes = options[:prefixes] || {}
31 | @delayed_messages = []
32 | @options = options
33 | @exceptions = []
34 | @indent = 0
35 | @timings = {}
36 | end
37 |
38 | #
39 |
40 | def before_features(_features)
41 | print_profile_information
42 | end
43 |
44 | #
45 |
46 | def after_features(features)
47 | @io.puts
48 | print_worst_offenders
49 | print_summary(features)
50 | end
51 |
52 | #
53 |
54 | def before_feature(_feature)
55 | @exceptions = []
56 | @indent = 0
57 | end
58 |
59 | #
60 |
61 | def feature_element_timing_key(feature_element)
62 | "\"#{feature_element.name}\" (#{feature_element.location})"
63 | end
64 |
65 | #
66 |
67 | def before_feature_element(feature_element)
68 | @indent = 2
69 | @scenario_indent = 2
70 | @timings[feature_element_timing_key(feature_element)] = Time.now
71 | end
72 |
73 | #
74 |
75 | def after_feature_element(feature_element)
76 | @timings[feature_element_timing_key(feature_element)] = Time.now - @timings[feature_element_timing_key(feature_element)]
77 | @io.print " (#{@timings[feature_element_timing_key(feature_element)]}s)"
78 | end
79 |
80 | #
81 |
82 | def tag_name(tag_name); end
83 |
84 | def comment_line(comment_line); end
85 |
86 | def after_tags(tags); end
87 |
88 | #
89 |
90 | def before_background(_background)
91 | @scenario_indent = 2
92 | @in_background = true
93 | @indent = 2
94 | end
95 |
96 | #
97 |
98 | def after_background(_background)
99 | @in_background = nil
100 | end
101 |
102 | #
103 |
104 | def background_name(keyword, name, source_line, indent)
105 | print_feature_element_name(
106 | keyword, name, source_line, indent
107 | )
108 | end
109 |
110 | #
111 |
112 | def scenario_name(keyword, name, source_line, indent)
113 | print_feature_element_name(
114 | keyword, name, source_line, indent
115 | )
116 | end
117 |
118 | #
119 |
120 | def before_step(step)
121 | @current_step = step
122 | end
123 |
124 | #
125 |
126 | # rubocop:disable Metrics/ParameterLists
127 | def before_step_result(_keyword, _step_match, _multiline_arg, status, exception, \
128 | _source_indent, background, _file_colon_line)
129 |
130 | @hide_this_step = false
131 | if exception
132 | if @exceptions.include?(exception)
133 | @hide_this_step = true
134 | return
135 | end
136 |
137 | @exceptions << exception
138 | end
139 |
140 | if status != :failed && @in_background ^ background
141 | @hide_this_step = true
142 | return
143 | end
144 |
145 | @status = status
146 | end
147 |
148 | #
149 |
150 | def step_name(_keyword, _step_match, status, _source_indent, _background, _file_colon_line)
151 | @io.print CHARS[status]
152 | @io.print " "
153 | end
154 | # rubocop:enable Metrics/ParameterLists
155 |
156 | #
157 |
158 | def exception(exception, status)
159 | return if @hide_this_step
160 |
161 | @io.puts
162 | print_exception(exception, status, @indent)
163 | @io.flush
164 | end
165 |
166 | #
167 |
168 | def after_test_step(test_step, result)
169 | collect_snippet_data(
170 | test_step, result
171 | )
172 | end
173 |
174 | #
175 |
176 | def print_feature_element_name(feature_element)
177 | @io.print "\n#{feature_element.location} Scenario: #{feature_element.name} "
178 | @io.flush
179 | end
180 |
181 | #
182 |
183 | def cell_prefix(status)
184 | @prefixes[status]
185 | end
186 |
187 | #
188 |
189 | def print_worst_offenders
190 | @io.puts
191 | @io.puts "Worst offenders:"
192 | @timings.sort_by { |_f, t| -t }.take(10).each do |(f, t)|
193 | @io.puts " #{t}s for #{f}"
194 | end
195 | @io.puts
196 | end
197 |
198 | #
199 |
200 | def print_summary(features)
201 | @io.puts
202 | print_stats(features, @options)
203 | print_snippets(@options)
204 | print_passing_wip(@options)
205 | end
206 | end
207 | end
208 | end
209 |
210 | AfterConfiguration do |config|
211 | f = Jekyll::Cucumber::Formatter.new(nil, $stdout, {})
212 |
213 | config.on_event :test_case_started do |event|
214 | f.print_feature_element_name(event.test_case)
215 | f.before_feature_element(event.test_case)
216 | end
217 |
218 | config.on_event :test_case_finished do |event|
219 | f.after_feature_element(event.test_case)
220 | end
221 |
222 | config.on_event :test_run_finished do
223 | f.print_worst_offenders
224 | end
225 | end
226 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JekyllData
2 |
3 | [](https://rubygems.org/gems/jekyll-data)
4 | [][travis]
5 |
6 | [travis]: https://travis-ci.org/ashmaroli/jekyll-data
7 |
8 | Introducing a plugin that reads data files within **jekyll theme-gems** and adds the resulting hash to the site's internal data hash. If a **`_config.yml`** is present at the root of the theme-gem, it will be evaluated and the extracted hash data will be incorporated into the site's existing config hash.
9 |
10 |
11 | ## Installation
12 |
13 | Simply add the plugin to your site's Gemfile and config file like every other jekyll plugin gem:
14 |
15 | ```ruby
16 | # Gemfile
17 |
18 | group :jekyll_plugins do
19 | gem "jekyll-data"
20 | end
21 | ```
22 | ..and run
23 |
24 | bundle install
25 |
26 |
27 | > **Note: If the plugin has been marked as a `runtime_dependency` by the theme-gem's author it will be installed automatically with the theme-gem. Yet, it is recommended that the plugin be added to `:jekyll_plugins` group in the Gemfile rather than the `gems:` array in the config file while building or serving the site to avoid 'overriding' the `gems:` array data that may have been read-in from the theme-gem.**
28 |
29 |
30 | ## Usage
31 |
32 | As long as the plugin-gem has been installed properly, and is included in the Gemfile's `:jekyll_plugins` group, data files supported by Jekyll and present in the `_data` directory at the root of your theme-gem will be read. Their contents will be added to the site's internal data hash, provided, an identical data hash doesn't already exist at the site-source.
33 |
34 | If the theme-gem also includes a `_config.yml` at its root, then it will be read as well. The resulting config hash will be mixed into the site's existing config hash, filling in where the *keys* are not already defined. In other words, the config file at `source` will override corresponding identical keys in a `_config.yml` within the theme-gem which would in turn override corresponding `DEFAULTS` from Jekyll:
35 |
36 | **DEFAULTS** < **_config.yml in theme-gem** < **_config.yml at source** < **Override configs via command-line**.
37 |
38 |
39 | ### Theme Configuration
40 |
41 | Jekyll themes (built prior to `Jekyll 3.2`) usually ship with configuration settings defined in the config file, which are then used within the theme's template files directly under the `site` namespace (e.g. `{{ site.myvariable }}`). This is not possible with theme-gems as a config file and data files within gems are not natively read (as of Jekyll 3.3), and hence require end-users to inspect a *demo* or *example* directory to source those files.
42 |
43 | This plugin provides a solution to that hurdle:
44 |
45 | JekyllData now reads the config file (at present only `_config.yml`) present within the theme-gem and uses the data to modify the site's config hash. This allows the theme-gem to continue using `{{ site.myvariable }}` within its templates and work out-of-the-box as intended, with minimal user intervention.
46 |
47 | **Note: the plugins required by the theme may be listed under the `gems:` array and will be automatically `required` by Jekyll while building/serving, provided that the user doesn't have a different `gems:` array in the config file at source. Hence it is recommended to add all other plugins ( including `jekyll-data` ) via the Gemfile's `:jekyll_plugins` group.**
48 |
49 | #### The `theme` namespace
50 |
51 | From `v1.0`, JekyllData no longer supports reading theme configuration provided as a `[theme-name].***` file within the `_data` directory and instead the `theme` namespace points to a certain key in the bundled `_config.yml`.
52 |
53 | For `{{ theme.variable }}` to work, the config file should nest all such key-value pairs under the `[theme-name]` key, as outlined in the example below for a theme-gem called `solitude`:
54 |
55 | ```yaml
56 | #