bridgetown-core 0.19.2 → 0.21.0.beta3
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.
- checksums.yaml +4 -4
- data/bridgetown-core.gemspec +1 -2
- data/lib/bridgetown-core.rb +37 -29
- data/lib/bridgetown-core/cleaner.rb +9 -3
- data/lib/bridgetown-core/collection.rb +177 -78
- data/lib/bridgetown-core/commands/base.rb +9 -0
- data/lib/bridgetown-core/commands/build.rb +0 -11
- data/lib/bridgetown-core/commands/concerns/git_helpers.rb +20 -0
- data/lib/bridgetown-core/commands/configure.rb +8 -3
- data/lib/bridgetown-core/commands/console.rb +4 -0
- data/lib/bridgetown-core/commands/doctor.rb +1 -19
- data/lib/bridgetown-core/commands/new.rb +2 -2
- data/lib/bridgetown-core/commands/plugins.rb +14 -13
- data/lib/bridgetown-core/commands/serve.rb +0 -14
- data/lib/bridgetown-core/component.rb +178 -0
- data/lib/bridgetown-core/concerns/data_accessible.rb +1 -0
- data/lib/bridgetown-core/concerns/front_matter_importer.rb +52 -0
- data/lib/bridgetown-core/concerns/site/configurable.rb +10 -10
- data/lib/bridgetown-core/concerns/site/content.rb +56 -15
- data/lib/bridgetown-core/concerns/site/localizable.rb +3 -5
- data/lib/bridgetown-core/concerns/site/processable.rb +6 -4
- data/lib/bridgetown-core/concerns/site/renderable.rb +26 -0
- data/lib/bridgetown-core/concerns/site/writable.rb +12 -2
- data/lib/bridgetown-core/concerns/validatable.rb +2 -5
- data/lib/bridgetown-core/configuration.rb +51 -30
- data/lib/bridgetown-core/configurations/bt-postcss.rb +1 -3
- data/lib/bridgetown-core/configurations/netlify.rb +1 -0
- data/lib/bridgetown-core/configurations/tailwindcss.rb +1 -3
- data/lib/bridgetown-core/converter.rb +23 -0
- data/lib/bridgetown-core/converters/erb_templates.rb +51 -35
- data/lib/bridgetown-core/converters/identity.rb +0 -9
- data/lib/bridgetown-core/converters/liquid_templates.rb +1 -1
- data/lib/bridgetown-core/converters/markdown.rb +14 -4
- data/lib/bridgetown-core/converters/markdown/kramdown_parser.rb +5 -38
- data/lib/bridgetown-core/converters/ruby_templates.rb +17 -0
- data/lib/bridgetown-core/converters/smartypants.rb +3 -1
- data/lib/bridgetown-core/core_ext/psych.rb +19 -0
- data/lib/bridgetown-core/current.rb +10 -0
- data/lib/bridgetown-core/document.rb +9 -16
- data/lib/bridgetown-core/drops/collection_drop.rb +1 -1
- data/lib/bridgetown-core/drops/page_drop.rb +4 -0
- data/lib/bridgetown-core/drops/relations_drop.rb +23 -0
- data/lib/bridgetown-core/drops/resource_drop.rb +83 -0
- data/lib/bridgetown-core/drops/site_drop.rb +33 -8
- data/lib/bridgetown-core/drops/unified_payload_drop.rb +5 -0
- data/lib/bridgetown-core/entry_filter.rb +17 -28
- data/lib/bridgetown-core/errors.rb +0 -2
- data/lib/bridgetown-core/filters.rb +3 -26
- data/lib/bridgetown-core/filters/from_liquid.rb +23 -0
- data/lib/bridgetown-core/filters/url_filters.rb +12 -0
- data/lib/bridgetown-core/frontmatter_defaults.rb +1 -1
- data/lib/bridgetown-core/generators/prototype_generator.rb +37 -19
- data/lib/bridgetown-core/helpers.rb +48 -9
- data/lib/bridgetown-core/layout.rb +28 -13
- data/lib/bridgetown-core/liquid_renderer/file.rb +1 -0
- data/lib/bridgetown-core/liquid_renderer/table.rb +1 -0
- data/lib/bridgetown-core/model/base.rb +138 -0
- data/lib/bridgetown-core/model/builder_origin.rb +40 -0
- data/lib/bridgetown-core/model/origin.rb +38 -0
- data/lib/bridgetown-core/model/repo_origin.rb +126 -0
- data/lib/bridgetown-core/page.rb +11 -2
- data/lib/bridgetown-core/plugin_manager.rb +1 -3
- data/lib/bridgetown-core/publisher.rb +8 -2
- data/lib/bridgetown-core/reader.rb +37 -22
- data/lib/bridgetown-core/readers/data_reader.rb +5 -5
- data/lib/bridgetown-core/readers/defaults_reader.rb +1 -1
- data/lib/bridgetown-core/readers/page_reader.rb +1 -0
- data/lib/bridgetown-core/readers/post_reader.rb +5 -4
- data/lib/bridgetown-core/regenerator.rb +9 -2
- data/lib/bridgetown-core/related_posts.rb +9 -6
- data/lib/bridgetown-core/renderer.rb +6 -13
- data/lib/bridgetown-core/resource/base.rb +313 -0
- data/lib/bridgetown-core/resource/destination.rb +49 -0
- data/lib/bridgetown-core/resource/permalink_processor.rb +179 -0
- data/lib/bridgetown-core/resource/relations.rb +132 -0
- data/lib/bridgetown-core/resource/taxonomy_term.rb +34 -0
- data/lib/bridgetown-core/resource/taxonomy_type.rb +56 -0
- data/lib/bridgetown-core/resource/transformer.rb +177 -0
- data/lib/bridgetown-core/ruby_template_view.rb +11 -11
- data/lib/bridgetown-core/site.rb +13 -6
- data/lib/bridgetown-core/static_file.rb +33 -10
- data/lib/bridgetown-core/tags/highlight.rb +2 -15
- data/lib/bridgetown-core/tags/include.rb +1 -1
- data/lib/bridgetown-core/tags/post_url.rb +2 -2
- data/lib/bridgetown-core/url.rb +1 -0
- data/lib/bridgetown-core/utils.rb +49 -43
- data/lib/bridgetown-core/utils/require_gems.rb +60 -0
- data/lib/bridgetown-core/utils/ruby_exec.rb +6 -9
- data/lib/bridgetown-core/utils/ruby_front_matter.rb +39 -0
- data/lib/bridgetown-core/version.rb +2 -2
- data/lib/bridgetown-core/watcher.rb +1 -1
- data/lib/bridgetown-core/yaml_parser.rb +22 -0
- data/lib/site_template/package.json.erb +2 -2
- data/lib/site_template/plugins/site_builder.rb +1 -1
- data/lib/site_template/src/_posts/0000-00-00-welcome-to-bridgetown.md.erb +1 -1
- data/lib/site_template/webpack.config.js.erb +26 -6
- metadata +39 -40
- data/lib/bridgetown-core/external.rb +0 -58
- data/lib/bridgetown-core/page_without_a_file.rb +0 -17
- data/lib/bridgetown-core/path_manager.rb +0 -31
- data/lib/bridgetown-core/readers/collection_reader.rb +0 -23
- data/lib/bridgetown-core/readers/static_file_reader.rb +0 -25
- data/lib/bridgetown-core/utils/exec.rb +0 -26
- data/lib/bridgetown-core/utils/internet.rb +0 -37
- data/lib/bridgetown-core/utils/platforms.rb +0 -80
- data/lib/bridgetown-core/utils/thread_event.rb +0 -31
- data/lib/bridgetown-core/utils/win_tz.rb +0 -75
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Handles Legacy Pages
|
|
3
4
|
Bridgetown::Hooks.register :pages, :post_init, reloadable: false do |page|
|
|
4
5
|
if page.class != Bridgetown::PrototypePage && page.data["prototype"].is_a?(Hash)
|
|
5
6
|
Bridgetown::PrototypeGenerator.add_matching_template(page)
|
|
6
7
|
end
|
|
7
8
|
end
|
|
8
9
|
|
|
10
|
+
# Handles Resources
|
|
11
|
+
Bridgetown::Hooks.register :resources, :post_read, reloadable: false do |resource|
|
|
12
|
+
if resource.data["prototype"].is_a?(Hash)
|
|
13
|
+
Bridgetown::PrototypeGenerator.add_matching_template(resource)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
9
17
|
module Bridgetown
|
|
10
18
|
class PrototypeGenerator < Generator
|
|
11
19
|
priority :low
|
|
@@ -13,27 +21,27 @@ module Bridgetown
|
|
|
13
21
|
# @return [Bridgetown::Site]
|
|
14
22
|
attr_reader :site
|
|
15
23
|
|
|
16
|
-
@
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@matching_templates << template
|
|
24
|
+
# @return [Array<Bridgetown::Page, Bridgetown::Resource::Base>]
|
|
25
|
+
def self.matching_templates
|
|
26
|
+
@matching_templates ||= []
|
|
20
27
|
end
|
|
21
28
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
attr_reader :matching_templates
|
|
29
|
+
def self.add_matching_template(template)
|
|
30
|
+
matching_templates << template
|
|
25
31
|
end
|
|
26
32
|
|
|
33
|
+
# @param site [Bridgetown::Site]
|
|
27
34
|
def generate(site)
|
|
28
35
|
@site = site
|
|
29
|
-
@configured_collection = "posts"
|
|
36
|
+
@configured_collection = "posts" unless site.uses_resource?
|
|
37
|
+
page_list = site.uses_resource? ? site.collections.pages.resources : site.pages
|
|
30
38
|
|
|
31
39
|
prototype_pages = self.class.matching_templates.select do |page|
|
|
32
|
-
|
|
40
|
+
page_list.include?(page)
|
|
33
41
|
end
|
|
34
42
|
|
|
35
43
|
if prototype_pages.length.positive?
|
|
36
|
-
|
|
44
|
+
page_list.reject! do |page|
|
|
37
45
|
prototype_pages.include? page
|
|
38
46
|
end
|
|
39
47
|
|
|
@@ -42,7 +50,7 @@ module Bridgetown
|
|
|
42
50
|
next if search_term.nil?
|
|
43
51
|
|
|
44
52
|
terms_matching_pages(search_term).each do |term|
|
|
45
|
-
generate_new_page_from_prototype(prototype_page, search_term, term)
|
|
53
|
+
generate_new_page_from_prototype(prototype_page, search_term, term)
|
|
46
54
|
end
|
|
47
55
|
end
|
|
48
56
|
end
|
|
@@ -50,7 +58,7 @@ module Bridgetown
|
|
|
50
58
|
|
|
51
59
|
# Check incoming prototype configuration and normalize options.
|
|
52
60
|
#
|
|
53
|
-
# @param prototype_page [
|
|
61
|
+
# @param prototype_page [Bridgetown::Page, Bridgetown::Resource::Base]
|
|
54
62
|
#
|
|
55
63
|
# @return [String, nil]
|
|
56
64
|
def validate_search_term(prototype_page)
|
|
@@ -71,7 +79,7 @@ module Bridgetown
|
|
|
71
79
|
|
|
72
80
|
def generate_new_page_from_prototype(prototype_page, search_term, term)
|
|
73
81
|
new_page = PrototypePage.new(prototype_page, @configured_collection, search_term, term)
|
|
74
|
-
site.
|
|
82
|
+
site.add_generated_page new_page
|
|
75
83
|
new_page
|
|
76
84
|
end
|
|
77
85
|
|
|
@@ -81,16 +89,26 @@ module Bridgetown
|
|
|
81
89
|
#
|
|
82
90
|
# @return [Array<String>]
|
|
83
91
|
def terms_matching_pages(search_term)
|
|
92
|
+
pages_list = if site.uses_resource?
|
|
93
|
+
site.collections[@configured_collection].resources
|
|
94
|
+
else
|
|
95
|
+
site.collections[@configured_collection].docs
|
|
96
|
+
end
|
|
97
|
+
|
|
84
98
|
Bridgetown::Paginate::PaginationIndexer.index_documents_by(
|
|
85
|
-
|
|
99
|
+
pages_list, search_term
|
|
86
100
|
).keys
|
|
87
101
|
end
|
|
88
102
|
end
|
|
89
103
|
|
|
90
|
-
class PrototypePage <
|
|
91
|
-
# @return [Page]
|
|
104
|
+
class PrototypePage < GeneratedPage
|
|
105
|
+
# @return [Bridgetown::Page, Bridgetown::Resource::Base]
|
|
92
106
|
attr_reader :prototyped_page
|
|
93
107
|
|
|
108
|
+
# @param prototyped_page [Bridgetown::Page, Bridgetown::Resource::Base]
|
|
109
|
+
# @param collection [Bridgetown::Collection]
|
|
110
|
+
# @param search_term [String]
|
|
111
|
+
# @param term [String]
|
|
94
112
|
def initialize(prototyped_page, collection, search_term, term)
|
|
95
113
|
@prototyped_page = prototyped_page
|
|
96
114
|
@site = prototyped_page.site
|
|
@@ -107,7 +125,7 @@ module Bridgetown
|
|
|
107
125
|
validate_data! prototyped_page.path
|
|
108
126
|
validate_permalink! prototyped_page.path
|
|
109
127
|
|
|
110
|
-
@dir = Pathname.new(prototyped_page.relative_path).dirname.to_s
|
|
128
|
+
@dir = Pathname.new(prototyped_page.relative_path).dirname.to_s.sub(%r{^_pages}, "")
|
|
111
129
|
@path = site.in_source_dir(@dir, @name)
|
|
112
130
|
|
|
113
131
|
process_prototype_page_data(collection, search_term, term)
|
|
@@ -132,7 +150,7 @@ module Bridgetown
|
|
|
132
150
|
slugify_term(term)
|
|
133
151
|
end
|
|
134
152
|
|
|
135
|
-
# rubocop:
|
|
153
|
+
# rubocop:todo Metrics/AbcSize
|
|
136
154
|
def process_title_data_placeholder(search_term, term)
|
|
137
155
|
if prototyped_page.data["prototype"]["data"]
|
|
138
156
|
if data["title"]&.include?(":prototype-data-label")
|
|
@@ -164,7 +182,7 @@ module Bridgetown
|
|
|
164
182
|
end
|
|
165
183
|
|
|
166
184
|
def slugify_term(term)
|
|
167
|
-
term_slug = Bridgetown::Utils.slugify(term)
|
|
185
|
+
term_slug = Bridgetown::Utils.slugify(term, mode: site.config.slugify_mode)
|
|
168
186
|
@url = if permalink.is_a?(String)
|
|
169
187
|
data["permalink"] = data["permalink"].sub(":term", term_slug)
|
|
170
188
|
else
|
|
@@ -4,8 +4,13 @@ module Bridgetown
|
|
|
4
4
|
class RubyTemplateView
|
|
5
5
|
class Helpers
|
|
6
6
|
include Bridgetown::Filters
|
|
7
|
+
include Bridgetown::Filters::FromLiquid
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
# @return [Bridgetown::RubyTemplateView]
|
|
10
|
+
attr_reader :view
|
|
11
|
+
|
|
12
|
+
# @return [Bridgetown::Site]
|
|
13
|
+
attr_reader :site
|
|
9
14
|
|
|
10
15
|
Context = Struct.new(:registers)
|
|
11
16
|
|
|
@@ -28,20 +33,44 @@ module Bridgetown
|
|
|
28
33
|
pairs.select { |_key, truthy| truthy }.keys.join(" ")
|
|
29
34
|
end
|
|
30
35
|
|
|
36
|
+
# Convert a Markdown string into HTML output.
|
|
37
|
+
#
|
|
38
|
+
# @param input [String] the Markdown to convert, if no block is passed
|
|
39
|
+
# @return [String]
|
|
40
|
+
def markdownify(input = nil, &block)
|
|
41
|
+
content = Bridgetown::Utils.reindent_for_markdown(
|
|
42
|
+
block.nil? ? input.to_s : view.capture(&block)
|
|
43
|
+
)
|
|
44
|
+
converter = site.find_converter_instance(Bridgetown::Converters::Markdown)
|
|
45
|
+
safe(converter.convert(content).strip)
|
|
46
|
+
end
|
|
47
|
+
|
|
31
48
|
# This helper will generate the correct permalink URL for the file path.
|
|
32
49
|
#
|
|
33
50
|
# @param relative_path [String, Object] source file path, e.g.
|
|
34
|
-
# "_posts/2020-10-20-my-post.md", or object that responds to
|
|
51
|
+
# "_posts/2020-10-20-my-post.md", or object that responds to either
|
|
52
|
+
# `url` or `relative_url`
|
|
35
53
|
# @return [String] the permalink URL for the file
|
|
36
|
-
# @raise [ArgumentError] if the file cannot be found
|
|
37
54
|
def url_for(relative_path)
|
|
38
|
-
|
|
55
|
+
if relative_path.respond_to?(:relative_url)
|
|
56
|
+
return safe(relative_path.relative_url) # new resource engine
|
|
57
|
+
elsif relative_path.respond_to?(:url)
|
|
58
|
+
return safe(relative_url(relative_path.url)) # old legacy engine
|
|
59
|
+
elsif relative_path.start_with?("/", "http")
|
|
60
|
+
return safe(relative_path)
|
|
61
|
+
end
|
|
39
62
|
|
|
40
|
-
|
|
63
|
+
find_relative_url_for_path(relative_path)
|
|
64
|
+
end
|
|
65
|
+
alias_method :link, :url_for
|
|
41
66
|
|
|
67
|
+
# @param relative_path [String] source file path, e.g.
|
|
68
|
+
# "_posts/2020-10-20-my-post.md"
|
|
69
|
+
# @raise [ArgumentError] if the file cannot be found
|
|
70
|
+
def find_relative_url_for_path(relative_path)
|
|
42
71
|
site.each_site_file do |item|
|
|
43
|
-
if item.relative_path ==
|
|
44
|
-
return relative_url(item)
|
|
72
|
+
if item.relative_path == relative_path || item.relative_path == "/#{relative_path}"
|
|
73
|
+
return safe(item.respond_to?(:relative_url) ? item.relative_url : relative_url(item))
|
|
45
74
|
end
|
|
46
75
|
end
|
|
47
76
|
|
|
@@ -51,7 +80,6 @@ module Bridgetown
|
|
|
51
80
|
Make sure the document exists and the path is correct.
|
|
52
81
|
MSG
|
|
53
82
|
end
|
|
54
|
-
alias_method :link, :url_for
|
|
55
83
|
|
|
56
84
|
# This helper will generate the correct permalink URL for the file path.
|
|
57
85
|
#
|
|
@@ -69,7 +97,8 @@ module Bridgetown
|
|
|
69
97
|
attr = attr.to_s.tr("_", "-")
|
|
70
98
|
segments << "#{attr}=\"#{Utils.xml_escape(option)}\""
|
|
71
99
|
end
|
|
72
|
-
|
|
100
|
+
# TODO: this might leak an XSS string into text, need to check
|
|
101
|
+
safe("<#{segments.join(" ")}>#{text}</a>")
|
|
73
102
|
end
|
|
74
103
|
|
|
75
104
|
# Forward all arguments to I18n.t method
|
|
@@ -79,6 +108,16 @@ module Bridgetown
|
|
|
79
108
|
def t(*args)
|
|
80
109
|
I18n.send :t, *args
|
|
81
110
|
end
|
|
111
|
+
|
|
112
|
+
# For template contexts where ActiveSupport's output safety is loaded, we
|
|
113
|
+
# can ensure a string has been marked safe
|
|
114
|
+
#
|
|
115
|
+
# @param input [Object]
|
|
116
|
+
# @return [String]
|
|
117
|
+
def safe(input)
|
|
118
|
+
input.to_s.html_safe
|
|
119
|
+
end
|
|
120
|
+
alias_method :raw, :safe
|
|
82
121
|
end
|
|
83
122
|
end
|
|
84
123
|
end
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
module Bridgetown
|
|
4
4
|
class Layout
|
|
5
5
|
include DataAccessible
|
|
6
|
+
include FrontMatterImporter
|
|
6
7
|
include LiquidRenderable
|
|
7
|
-
include Validatable
|
|
8
8
|
|
|
9
9
|
# Gets the Site object.
|
|
10
10
|
attr_reader :site
|
|
@@ -21,12 +21,18 @@ module Bridgetown
|
|
|
21
21
|
# Gets/Sets the extension of this layout.
|
|
22
22
|
attr_accessor :ext
|
|
23
23
|
|
|
24
|
+
alias_method :extname, :ext
|
|
25
|
+
|
|
24
26
|
# Gets/Sets the Hash that holds the metadata for this layout.
|
|
25
27
|
attr_accessor :data
|
|
26
28
|
|
|
27
29
|
# Gets/Sets the content of this layout.
|
|
30
|
+
# @return [String]
|
|
28
31
|
attr_accessor :content
|
|
29
32
|
|
|
33
|
+
# @return [Integer]
|
|
34
|
+
attr_accessor :front_matter_line_count
|
|
35
|
+
|
|
30
36
|
# Gets/Sets the current document (for layout-compatible converters)
|
|
31
37
|
attr_accessor :current_document
|
|
32
38
|
|
|
@@ -52,11 +58,29 @@ module Bridgetown
|
|
|
52
58
|
@path = site.in_source_dir(base, name)
|
|
53
59
|
end
|
|
54
60
|
@relative_path = @path.sub(@base_dir, "")
|
|
61
|
+
@ext = File.extname(name)
|
|
62
|
+
|
|
63
|
+
@data = read_front_matter(@path)&.with_dot_access
|
|
64
|
+
rescue SyntaxError => e
|
|
65
|
+
Bridgetown.logger.error "Error:",
|
|
66
|
+
"Ruby Exception in #{e.message}"
|
|
67
|
+
rescue StandardError => e
|
|
68
|
+
handle_read_error(e)
|
|
69
|
+
ensure
|
|
70
|
+
@data ||= HashWithDotAccess::Hash.new
|
|
71
|
+
end
|
|
55
72
|
|
|
56
|
-
|
|
73
|
+
def handle_read_error(error)
|
|
74
|
+
if error.is_a? Psych::SyntaxError
|
|
75
|
+
Bridgetown.logger.warn "YAML Exception reading #{@path}: #{error.message}"
|
|
76
|
+
else
|
|
77
|
+
Bridgetown.logger.warn "Error reading file #{@path}: #{error.message}"
|
|
78
|
+
end
|
|
57
79
|
|
|
58
|
-
|
|
59
|
-
|
|
80
|
+
if site.config["strict_front_matter"] ||
|
|
81
|
+
error.is_a?(Bridgetown::Errors::FatalException)
|
|
82
|
+
raise error
|
|
83
|
+
end
|
|
60
84
|
end
|
|
61
85
|
|
|
62
86
|
# The inspect string for this document.
|
|
@@ -67,15 +91,6 @@ module Bridgetown
|
|
|
67
91
|
"#<#{self.class} #{@path}>"
|
|
68
92
|
end
|
|
69
93
|
|
|
70
|
-
# Extract information from the layout filename.
|
|
71
|
-
#
|
|
72
|
-
# name - The String filename of the layout file.
|
|
73
|
-
#
|
|
74
|
-
# Returns nothing.
|
|
75
|
-
def process(name)
|
|
76
|
-
self.ext = File.extname(name)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
94
|
# Provide this Layout's data to a Hash suitable for use by Liquid.
|
|
80
95
|
#
|
|
81
96
|
# Returns the Hash representation of this Layout.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model"
|
|
4
|
+
|
|
5
|
+
module Bridgetown
|
|
6
|
+
module Model
|
|
7
|
+
class Base
|
|
8
|
+
include ActiveModel::Model
|
|
9
|
+
extend ActiveModel::Callbacks # also extends with DescendantsTracker
|
|
10
|
+
define_model_callbacks :load, :save, :destroy
|
|
11
|
+
|
|
12
|
+
def self.loads_id?(id)
|
|
13
|
+
name == ActiveSupport::Inflector.classify(
|
|
14
|
+
URI.parse(id).host.chomp(".collection")
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.find(id)
|
|
19
|
+
unless Bridgetown::Current.site
|
|
20
|
+
raise "A Bridgetown site must be initialized and added to Current"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
model_klass = klass_for_id(id)
|
|
24
|
+
model_klass.new(read_data_for_id(id))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.klass_for_id(id)
|
|
28
|
+
descendants.find do |klass|
|
|
29
|
+
klass.loads_id?(id)
|
|
30
|
+
end || self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.read_data_for_id(id)
|
|
34
|
+
origin_for_id(id).read
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.origin_for_id(id)
|
|
38
|
+
scheme = URI.parse(id).scheme
|
|
39
|
+
origin_klass = Origin.descendants.find do |klass|
|
|
40
|
+
klass.handle_scheme?(scheme)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
raise "No origin could be found for #{id}" unless origin_klass
|
|
44
|
+
|
|
45
|
+
origin_klass.new(id)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class << self
|
|
49
|
+
def build(collection_name, path, data)
|
|
50
|
+
data = Bridgetown::Model::BuilderOrigin.new("builder://#{path}").read do
|
|
51
|
+
data[:_collection_] = Bridgetown::Current.site.collections[collection_name]
|
|
52
|
+
data
|
|
53
|
+
end
|
|
54
|
+
new(data)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def initialize(attributes = {})
|
|
59
|
+
run_callbacks :load do
|
|
60
|
+
super
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def id
|
|
65
|
+
attributes[:id] || attributes[:_id_]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# @return [Bridgetown::Model::Origin]
|
|
69
|
+
def origin
|
|
70
|
+
attributes[:_origin_]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def persisted?
|
|
74
|
+
id && origin.exists?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# @return [Bridgetown::Resource::Base]
|
|
78
|
+
def to_resource
|
|
79
|
+
Bridgetown::Resource::Base.new(model: self)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def as_resource_in_collection
|
|
83
|
+
collection.resources << to_resource.read!
|
|
84
|
+
collection.resources.last
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# override if need be
|
|
88
|
+
# @return [Bridgetown::Site]
|
|
89
|
+
def site
|
|
90
|
+
Bridgetown::Current.site
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# @return [Bridgetown::Collection]
|
|
94
|
+
def collection
|
|
95
|
+
attributes[:_collection_]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @return [String]
|
|
99
|
+
def content
|
|
100
|
+
attributes[:_content_]
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def attributes
|
|
104
|
+
@attributes ||= HashWithDotAccess::Hash.new
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Strip out keys like _origin_, _collection_, etc.
|
|
108
|
+
# @return [HashWithDotAccess::Hash]
|
|
109
|
+
def data_attributes
|
|
110
|
+
attributes.reject { |k| k.starts_with?("_") && k.ends_with?("_") }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def respond_to_missing?(method_name, include_private = false)
|
|
114
|
+
attributes.key?(method_name) || method_name.to_s.end_with?("=") || super
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def method_missing(method_name, *args) # rubocop:disable Style/MethodMissingSuper
|
|
118
|
+
return attributes[method_name] if attributes.key?(method_name)
|
|
119
|
+
|
|
120
|
+
key = method_name.to_s
|
|
121
|
+
if key.end_with?("=")
|
|
122
|
+
key.chop!
|
|
123
|
+
# attribute_will_change!(key)
|
|
124
|
+
attributes[key] = args.first
|
|
125
|
+
return attributes[key]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
Bridgetown.logger.warn "key `#{method_name}' not found in attributes for" \
|
|
129
|
+
" #{attributes[:id].presence || ("new " + self.class.to_s)}"
|
|
130
|
+
nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def inspect
|
|
134
|
+
"#<#{self.class} #{data_attributes.inspect.delete_prefix("{").delete_suffix("}")}>"
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|