diff --git a/CHANGELOG.md b/CHANGELOG.md index 860f3406..da4b225e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # master +- Support TOML as frontmatter and data. - Handle the removal of a file in dependencies. Fixes #2292 - Update rubocop + use enable-frozen-string-literal (#2354) - Add ability to external pipeline ignore process exit code (#2353) diff --git a/Gemfile.lock b/Gemfile.lock index ed6b4309..b2d7675e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -29,6 +29,7 @@ PATH sassc (~> 2.0) servolux tilt (~> 2.0.9) + toml uglifier (~> 4.1) GEM @@ -132,7 +133,7 @@ GEM lazy_priority_queue (0.1.1) libv8 (8.4.255.0) liquid (4.0.3) - listen (3.2.1) + listen (3.3.2) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) memoist (0.16.2) @@ -149,7 +150,7 @@ GEM nio4r (2.5.2) nokogiri (1.10.10) mini_portile2 (~> 2.4.0) - oj (3.10.8) + oj (3.10.16) padrino-helpers (0.14.4) i18n (~> 0.6, >= 0.6.7) padrino-support (= 0.14.4) @@ -158,6 +159,7 @@ GEM parallel (1.20.1) parser (2.7.2.0) ast (~> 2.4.1) + parslet (1.8.2) protobuf-cucumber (3.10.8) activesupport (>= 3.2) middleware @@ -243,6 +245,8 @@ GEM thread_safe (0.3.6) tilt (2.0.10) timers (4.3.0) + toml (0.2.0) + parslet (~> 1.8.0) tzinfo (1.2.7) thread_safe (~> 0.1) uglifier (4.2.0) diff --git a/middleman-core/features/data.feature b/middleman-core/features/data.feature index 460658a8..3ba7807e 100644 --- a/middleman-core/features/data.feature +++ b/middleman-core/features/data.feature @@ -92,3 +92,23 @@ Feature: Local Data API Then I should see "

With Content

" Then I should see '

Header 2

' Then I should see "

Paragraph 1

" + + Scenario: Rendering toml + Given the Server is running at "basic-data-app" + When I go to "/data4.html" + Then I should see "One:Two" + When the file "data/test3.toml" has the contents + """ + [titles] + + [titles.first] + title = "Three" + + [titles.second] + title = "Four" + """ + When I go to "/data4.html" + Then I should see "Three:Four" + When the file "data/test3.toml" is removed + When I go to "/data4.html" + Then I should see "No Test Data" \ No newline at end of file diff --git a/middleman-core/features/front-matter-neighbor.feature b/middleman-core/features/front-matter-neighbor.feature index 9260ff41..0e069289 100644 --- a/middleman-core/features/front-matter-neighbor.feature +++ b/middleman-core/features/front-matter-neighbor.feature @@ -23,6 +23,12 @@ Feature: Neighboring YAML Front Matter When I go to "/raw-front-matter.php.frontmatter" Then I should see "File Not Found" + Scenario: Rendering raw (template-less) (toml) + Given the Server is running at "frontmatter-neighbor-app" + When I go to "/raw-front-matter-toml.html" + Then I should see "

<%= current_page.data.title %>

" + Then I should not see "---" + Scenario: YAML not on first line, with encoding Given the Server is running at "frontmatter-neighbor-app" When I go to "/front-matter-encoding.html" @@ -65,10 +71,10 @@ Feature: Neighboring YAML Front Matter Scenario: A template should handle an empty YAML feed Given the Server is running at "frontmatter-neighbor-app" And the file "source/front-matter-change.html.erb.frontmatter" has the contents - """ - --- - --- - """ + """ + --- + --- + """ When I go to "/front-matter-change.html" Then I should not see "Hello World" Then I should not see "Hola Mundo" @@ -78,14 +84,14 @@ Feature: Neighboring YAML Front Matter Scenario: Setting layout, ignoring, and disabling directory indexes through frontmatter (build) Given a successfully built app at "frontmatter-settings-neighbor-app" Then the following files should exist: - | build/proxied.html | + | build/proxied.html | And the file "build/alternate_layout.html" should contain "Alternate layout" And the following files should not exist: - | build/ignored.html | - | build/alternate_layout.html.erb.frontmatter | - | build/ignored.html.erb.frontmatter | + | build/ignored.html | + | build/alternate_layout.html.erb.frontmatter | + | build/ignored.html.erb.frontmatter | | build/override_layout.html.erb.frontmatter | - | build/page_mentioned.html.erb.frontmatter | + | build/page_mentioned.html.erb.frontmatter | Scenario: Setting layout, ignoring, and disabling directory indexes through frontmatter (preview) Given the Server is running at "frontmatter-settings-neighbor-app" @@ -130,22 +136,22 @@ Feature: Neighboring YAML Front Matter When I go to "/page_mentioned.html.erb.frontmatter" Then I should see "File Not Found" - # Scenario: Neighbor frontmatter for destination of proxy resources - # Given the Server is running at "frontmatter-settings-neighbor-app" - # And the file "source/proxied_with_frontmatter.html.frontmatter" has the contents - # """ - # --- - # title: Proxied title - # --- - # """ - # And the file "source/ignored.html.erb" has the contents - # """ - # --- - # ignored: true - # --- +# Scenario: Neighbor frontmatter for destination of proxy resources +# Given the Server is running at "frontmatter-settings-neighbor-app" +# And the file "source/proxied_with_frontmatter.html.frontmatter" has the contents +# """ +# --- +# title: Proxied title +# --- +# """ +# And the file "source/ignored.html.erb" has the contents +# """ +# --- +# ignored: true +# --- - # <%= current_resource.data.inspect %> - # <%= current_resource.data.title %> - # """ - # When I go to "/proxied_with_frontmatter.html" - # Then I should see "Proxied title" +# <%= current_resource.data.inspect %> +# <%= current_resource.data.title %> +# """ +# When I go to "/proxied_with_frontmatter.html" +# Then I should see "Proxied title" diff --git a/middleman-core/features/front-matter.feature b/middleman-core/features/front-matter.feature index 45f20743..9cc3d957 100644 --- a/middleman-core/features/front-matter.feature +++ b/middleman-core/features/front-matter.feature @@ -90,10 +90,16 @@ Feature: YAML Front Matter Scenario: A template should handle an empty YAML feed Given the Server is running at "frontmatter-app" And the file "source/front-matter-change.html.erb" has the contents - """ - --- - --- - Hello World - """ + """ + --- + --- + Hello World + """ When I go to "/front-matter-change.html" Then I should see "Hello World" + + Scenario: Rendering raw (template-less) (toml) + Given the Server is running at "frontmatter-app" + When I go to "/raw-front-matter-toml.html" + Then I should see "

<%= current_page.data.title %>

" + Then I should not see "---" \ No newline at end of file diff --git a/middleman-core/fixtures/basic-data-app/data/test3.toml b/middleman-core/fixtures/basic-data-app/data/test3.toml new file mode 100644 index 00000000..65234e79 --- /dev/null +++ b/middleman-core/fixtures/basic-data-app/data/test3.toml @@ -0,0 +1,7 @@ +[titles] + + [titles.first] + title = "One" + + [titles.second] + title = "Two" diff --git a/middleman-core/fixtures/basic-data-app/source/data4.html.erb b/middleman-core/fixtures/basic-data-app/source/data4.html.erb new file mode 100644 index 00000000..fb532fbc --- /dev/null +++ b/middleman-core/fixtures/basic-data-app/source/data4.html.erb @@ -0,0 +1,5 @@ +<% if data.respond_to?(:test3) && data.test3.respond_to?(:titles) %> + <%= data.test3.titles.map { |r| r[1].title }.join(":") %> +<% else %> + No Test Data +<% end %> \ No newline at end of file diff --git a/middleman-core/fixtures/frontmatter-app/source/raw-front-matter-toml.html b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter-toml.html new file mode 100644 index 00000000..3358a7d4 --- /dev/null +++ b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter-toml.html @@ -0,0 +1,6 @@ ++++ +layout = false +title = "This is the title" ++++ + +

<%= current_page.data.title %>

\ No newline at end of file diff --git a/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html index fcae7374..43aa3c3b 100644 --- a/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html +++ b/middleman-core/fixtures/frontmatter-app/source/raw-front-matter.html @@ -3,4 +3,4 @@ layout: false title: This is the title --- -

<%= current_page.data.title %>

+

<%= current_page.data.title %>

\ No newline at end of file diff --git a/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html new file mode 100644 index 00000000..2797ea86 --- /dev/null +++ b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html @@ -0,0 +1 @@ +

<%= current_page.data.title %>

\ No newline at end of file diff --git a/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html.frontmatter b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html.frontmatter new file mode 100644 index 00000000..b95e0526 --- /dev/null +++ b/middleman-core/fixtures/frontmatter-neighbor-app/source/raw-front-matter-toml.html.frontmatter @@ -0,0 +1,4 @@ ++++ +layout = false +title = "This is the title" ++++ \ No newline at end of file diff --git a/middleman-core/lib/middleman-core/core_extensions/data.rb b/middleman-core/lib/middleman-core/core_extensions/data.rb index 6dfa1180..d4fa9885 100644 --- a/middleman-core/lib/middleman-core/core_extensions/data.rb +++ b/middleman-core/lib/middleman-core/core_extensions/data.rb @@ -21,7 +21,7 @@ module Middleman expose_to_template internal_data_store: :data_store # The regex which tells Middleman which files are for data - DATA_FILE_MATCHER = /^(.*?)[\w-]+\.(yml|yaml|json)$/.freeze + DATA_FILE_MATCHER = /^(.*?)[\w-]+\.(yml|yaml|json|toml)$/.freeze Contract IsA['::Middleman::Application'], Hash => Any def initialize(app, options_hash = ::Middleman::EMPTY_HASH, &block) diff --git a/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb b/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb index e21f3df7..546a21d7 100644 --- a/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb +++ b/middleman-core/lib/middleman-core/core_extensions/data/stores/local_file.rb @@ -18,7 +18,8 @@ module Middleman YAML_EXTS = Set.new %w[.yaml .yml] JSON_EXTS = Set.new %w[.json] - ALL_EXTS = YAML_EXTS | JSON_EXTS + TOML_EXTS = Set.new %w[.toml] + ALL_EXTS = YAML_EXTS | JSON_EXTS | TOML_EXTS def_delegators :@local_data, :keys, :key?, :[] @@ -55,6 +56,8 @@ module Middleman data[:postscript] = postscript if !postscript.nil? && data.is_a?(Hash) elsif JSON_EXTS.include?(extension) data, _postscript = ::Middleman::Util::Data.parse(file, @app.config[:frontmatter_delims], :json) + elsif TOML_EXTS.include?(extension) + data, _postscript = ::Middleman::Util::Data.parse(file, @app.config[:frontmatter_delims], :toml) end data_branch = @local_data diff --git a/middleman-core/lib/middleman-core/core_extensions/front_matter.rb b/middleman-core/lib/middleman-core/core_extensions/front_matter.rb index edae9824..4e469481 100644 --- a/middleman-core/lib/middleman-core/core_extensions/front_matter.rb +++ b/middleman-core/lib/middleman-core/core_extensions/front_matter.rb @@ -16,7 +16,30 @@ module Middleman::CoreExtensions # Set textual delimiters that denote the start and end of frontmatter define_setting :frontmatter_delims, { - json: [%w[;;; ;;;]], + json: [ + %w[;;; ;;;], + + # Haml with commented frontmatter + ["-#\n ;;;", ' ;;;'], + + # Slim with commented frontmatter + ["\/\n ;;;", ' ;;;'], + + # ERb with commented frontmatter + ["<%#\n ;;;", " ;;;\n%>"] + ], + toml: [ + %w[+++ +++], + + # Haml with commented frontmatter + ["-#\n +++", ' +++'], + + # Slim with commented frontmatter + ["\/\n +++", ' +++'], + + # ERb with commented frontmatter + ["<%#\n +++", " +++\n%>"] + ], yaml: [ # Normal %w[--- ---], diff --git a/middleman-core/lib/middleman-core/util/data.rb b/middleman-core/lib/middleman-core/util/data.rb index 4828d9fe..8729076b 100644 --- a/middleman-core/lib/middleman-core/util/data.rb +++ b/middleman-core/lib/middleman-core/util/data.rb @@ -2,6 +2,7 @@ require 'yaml' require 'json' +require 'toml' require 'pathname' require 'hashie' require 'memoist' @@ -72,6 +73,8 @@ module Middleman return [parse_yaml(content, full_path), nil] when :json return [parse_json(content, full_path), nil] + when :toml + return [parse_toml(content, full_path), nil] end end @@ -86,6 +89,11 @@ module Middleman parse_json("{#{match[:frontmatter]}}", full_path), match[:additional_content] ] + when *frontmatter_delims[:toml] + [ + parse_toml(match[:frontmatter], full_path), + match[:additional_content] + ] else [ {}, @@ -129,6 +137,26 @@ module Middleman end memoize :parse_yaml + # Parse TOML frontmatter out of a string + # @param [String] content + # @return [Hash] + Contract String, Pathname => Hash + def parse_toml(content, full_path) + c = begin + ::Middleman::Util.instrument 'parse.toml' do + ::TOML.load(content) + end + rescue StandardError + # TOML parser swallows useful error, so we can't warn about it. + # https://github.com/jm/toml/issues/47 + warn "TOML Exception parsing #{full_path}" + {} + end + + c ? symbolize_recursive(c) : {} + end + memoize :parse_yaml + # Parse JSON frontmatter out of a string # @param [String] content # @return [Hash] diff --git a/middleman-core/middleman-core.gemspec b/middleman-core/middleman-core.gemspec index 9b025601..334b0d76 100644 --- a/middleman-core/middleman-core.gemspec +++ b/middleman-core/middleman-core.gemspec @@ -26,6 +26,7 @@ Gem::Specification.new do |s| s.add_dependency('servolux') s.add_dependency('dotenv') s.add_dependency('rgl', ['~> 0.5.3']) + s.add_dependency('toml') # Helpers s.add_dependency('activesupport', ['>= 5.0.0'])