bridgetown-core 0.15.0.beta1 → 0.16.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +14 -0
  3. data/bridgetown-core.gemspec +2 -0
  4. data/lib/bridgetown-core.rb +6 -1
  5. data/lib/bridgetown-core/commands/concerns/actions.rb +54 -21
  6. data/lib/bridgetown-core/commands/console.rb +12 -2
  7. data/lib/bridgetown-core/commands/serve.rb +5 -0
  8. data/lib/bridgetown-core/concerns/data_accessible.rb +19 -0
  9. data/lib/bridgetown-core/concerns/layout_placeable.rb +17 -0
  10. data/lib/bridgetown-core/concerns/liquid_renderable.rb +20 -0
  11. data/lib/bridgetown-core/concerns/publishable.rb +10 -0
  12. data/lib/bridgetown-core/concerns/site/configurable.rb +62 -31
  13. data/lib/bridgetown-core/concerns/site/content.rb +88 -29
  14. data/lib/bridgetown-core/concerns/site/extensible.rb +15 -12
  15. data/lib/bridgetown-core/concerns/site/processable.rb +12 -10
  16. data/lib/bridgetown-core/concerns/site/renderable.rb +23 -4
  17. data/lib/bridgetown-core/concerns/site/writable.rb +16 -2
  18. data/lib/bridgetown-core/concerns/validatable.rb +59 -0
  19. data/lib/bridgetown-core/configuration.rb +1 -0
  20. data/lib/bridgetown-core/converter.rb +34 -0
  21. data/lib/bridgetown-core/converters/erb_templates.rb +61 -0
  22. data/lib/bridgetown-core/converters/markdown.rb +6 -23
  23. data/lib/bridgetown-core/converters/smartypants.rb +0 -10
  24. data/lib/bridgetown-core/document.rb +8 -52
  25. data/lib/bridgetown-core/drops/document_drop.rb +9 -1
  26. data/lib/bridgetown-core/drops/page_drop.rb +1 -1
  27. data/lib/bridgetown-core/errors.rb +2 -0
  28. data/lib/bridgetown-core/excerpt.rb +5 -7
  29. data/lib/bridgetown-core/filters.rb +2 -0
  30. data/lib/bridgetown-core/layout.rb +24 -1
  31. data/lib/bridgetown-core/liquid_renderer/file.rb +1 -4
  32. data/lib/bridgetown-core/liquid_renderer/file_system.rb +1 -1
  33. data/lib/bridgetown-core/page.rb +36 -42
  34. data/lib/bridgetown-core/plugin_manager.rb +27 -13
  35. data/lib/bridgetown-core/regenerator.rb +1 -1
  36. data/lib/bridgetown-core/renderer.rb +41 -15
  37. data/lib/bridgetown-core/ruby_template_view.rb +84 -0
  38. data/lib/bridgetown-core/tags/class_map.rb +90 -0
  39. data/lib/bridgetown-core/tags/include.rb +2 -0
  40. data/lib/bridgetown-core/tags/render_content.rb +14 -2
  41. data/lib/bridgetown-core/tags/webpack_path.rb +48 -16
  42. data/lib/bridgetown-core/utils.rb +44 -0
  43. data/lib/bridgetown-core/version.rb +2 -2
  44. data/lib/site_template/bridgetown.config.yml +5 -3
  45. data/lib/site_template/package.json +1 -0
  46. data/lib/site_template/src/_components/{footer.html → footer.liquid} +0 -0
  47. data/lib/site_template/src/_components/{head.html → head.liquid} +0 -0
  48. data/lib/site_template/src/_components/{navbar.html → navbar.liquid} +0 -0
  49. data/lib/site_template/src/_layouts/default.html +1 -1
  50. data/lib/site_template/webpack.config.js +3 -3
  51. metadata +41 -6
  52. data/lib/bridgetown-core/concerns/convertible.rb +0 -238
@@ -4,17 +4,24 @@ module Bridgetown
4
4
  module Site::Content
5
5
  # Construct a Hash of Posts indexed by the specified Post attribute.
6
6
  #
7
- # post_attr - The String name of the Post attribute.
7
+ # @param post_attr [String] The String name of the Post attribute.
8
8
  #
9
- # Examples
9
+ # @example
10
+ # Returns a hash like so: { attr => posts } where
11
+ #
12
+ # attr - One of the values for the requested attribute.
13
+ #
14
+ # posts - The Array of Posts with the given attr value.
15
+ #
16
+ # @example
10
17
  #
11
18
  # post_attr_hash('categories')
12
19
  # # => { 'tech' => [<Post A>, <Post B>],
13
20
  # # 'ruby' => [<Post B>] }
14
21
  #
15
- # Returns the Hash: { attr => posts } where
16
- # attr - One of the values for the requested attribute.
17
- # posts - The Array of Posts with the given attr value.
22
+ # @return [Hash{String, Symbol => Array<Post>}]
23
+ # Returns a hash of !{attr => posts}
24
+ #
18
25
  def post_attr_hash(post_attr)
19
26
  # Build a hash map based on the specified post attribute ( post attr =>
20
27
  # array of posts ) then sort each array in reverse order.
@@ -28,41 +35,85 @@ module Bridgetown
28
35
  end
29
36
  end
30
37
 
38
+ # Returns a hash of "tags" using {#post_attr_hash} where each tag is a key
39
+ # and each value is a post which contains the key.
40
+ # @example
41
+ # tags
42
+ # # => { 'tech': [<Post A>, <Post B>],
43
+ # # 'ruby': [<Post C> }
44
+ # @return [Hash{String, Array<Post>}] Returns a hash of all tags and their corresponding posts
45
+ # @see post_attr_hash
31
46
  def tags
32
47
  post_attr_hash("tags")
33
48
  end
34
49
 
50
+ # Returns a hash of "categories" using {#post_attr_hash} where each tag is
51
+ # a key and each value is a post which contains the key.
52
+ # @example
53
+ # categories
54
+ # # => { 'tech': [<Post A>, <Post B>],
55
+ # # 'ruby': [<Post C> }
56
+ # @return [Hash{String, Array<Post>}] Returns a hash of all categories and
57
+ # their corresponding posts
58
+ # @see post_attr_hash
35
59
  def categories
36
60
  post_attr_hash("categories")
37
61
  end
38
62
 
63
+ # Returns the value of +data+["site_metadata"] or creates a new instance of
64
+ # +ActiveSupport::HashWithIndifferentAccess+
65
+ # @return [Hash] Returns a hash of site metadata
39
66
  def metadata
40
67
  data["site_metadata"] ||= ActiveSupport::HashWithIndifferentAccess.new
41
68
  end
42
69
 
43
70
  # The Hash payload containing site-wide data.
44
71
  #
45
- # Returns the Hash: { "site" => data } where data is a Hash with keys:
46
- # "time" - The Time as specified in the configuration or the
47
- # current time if none was specified.
48
- # "posts" - The Array of Posts, sorted chronologically by post date
49
- # and then title.
50
- # "pages" - The Array of all Pages.
51
- # "html_pages" - The Array of HTML Pages.
52
- # "categories" - The Hash of category values and Posts.
53
- # See Site#post_attr_hash for type info.
54
- # "tags" - The Hash of tag values and Posts.
55
- # See Site#post_attr_hash for type info.
72
+ # @example
73
+ # site_payload
74
+ # # => { "site" => data } Where data is a Hash. See example below
75
+ #
76
+ # site = site_payload["site"]
77
+ # # => Returns a Hash with the following keys:
78
+ # #
79
+ # # site["time"] - The Time as specified in the configuration or the
80
+ # # current time if none was specified.
81
+ # #
82
+ # # site["posts"] - The Array of Posts, sorted chronologically by post date
83
+ # # and then title.
84
+ # #
85
+ # # site["pages"] - The Array of all Pages.
86
+ # #
87
+ # # site["html_pages"] - The Array of HTML Pages.
88
+ # #
89
+ # # site["categories"] - The Hash of category values and Posts.
90
+ # # See Site#post_attr_hash for type info.
91
+ # #
92
+ # # site["tags"] - The Hash of tag values and Posts.
93
+ # # See Site#post_attr_hash for type info.
94
+ #
95
+ # @return [Hash] Returns a hash in the structure of { "site" => data }
96
+ #
97
+ # See above example for usage.
98
+ #
99
+ # @see #post_attr_hash
56
100
  def site_payload
57
101
  Drops::UnifiedPayloadDrop.new self
58
102
  end
59
103
  alias_method :to_liquid, :site_payload
60
104
 
61
- # The list of collections and their corresponding Bridgetown::Collection instances.
62
- # If config['collections'] is set, a new instance is created
63
- # for each item in the collection, a new hash is returned otherwise.
105
+ # The list of {#collections} and their corresponding {Bridgetown::Collection} instances.
106
+ #
107
+ # If +config+['collections'] is set, a new instance of {Bridgetown::Collection} is created
108
+ # for each entry in the collections configuration.
109
+ #
110
+ # If +config+["collections"] is not specified, a blank hash is returned.
64
111
  #
65
- # Returns a Hash containing collection name-to-instance pairs.
112
+ # @return [Hash{String, Symbol => Bridgetown::Collection}] A Hash
113
+ # containing a collection name-to-instance pairs.
114
+ #
115
+ # @return [Hash] Returns a blank hash if no items found
116
+ # @see Collection
66
117
  def collections
67
118
  @collections ||= collection_names.each_with_object(
68
119
  ActiveSupport::HashWithIndifferentAccess.new
@@ -71,10 +122,11 @@ module Bridgetown
71
122
  end
72
123
  end
73
124
 
74
- # The list of collection names.
75
- #
76
- # Returns an array of collection names from the configuration,
77
- # or an empty array if the `collections` key is not set.
125
+ # An array of collection names.
126
+ # @return [Array<Collection>] an array of collection names from the configuration,
127
+ # or an empty array if the +config+["collections"] key is not set.
128
+ # @raise ArgumentError Raise an error if +config+["collections"] is not
129
+ # an Array or a Hash
78
130
  def collection_names
79
131
  case config["collections"]
80
132
  when Hash
@@ -88,22 +140,29 @@ module Bridgetown
88
140
  end
89
141
  end
90
142
 
91
- # Get all the documents
92
- #
93
- # Returns an Array of all Documents
143
+ # Get all documents.
144
+ # @return [Array<String>] an array of documents from the configuration
94
145
  def documents
95
146
  collections.each_with_object(Set.new) do |(_, collection), set|
96
147
  set.merge(collection.docs).merge(collection.files)
97
148
  end.to_a
98
149
  end
99
150
 
100
- # Get the to be written documents
151
+ # Get the documents to be written
101
152
  #
102
- # Returns an Array of Documents which should be written
153
+ # @return [Array<String, File>] an Array of Documents which should be written and
154
+ # that +respond_to :write?+
155
+ # @see #documents
156
+ # @see Collection
103
157
  def docs_to_write
104
158
  documents.select(&:write?)
105
159
  end
106
160
 
161
+ # Get all posts.
162
+ #
163
+ # @return [Collection] A #Collection of posts. Returns +#collections+["posts"]
164
+ # @return [Collection] Return a new #Collection if +#collections+["posts"] is nil
165
+ # @see Collection
107
166
  def posts
108
167
  collections["posts"] ||= Collection.new(self, "posts")
109
168
  end
@@ -3,17 +3,19 @@
3
3
  module Bridgetown
4
4
  module Site::Extensible
5
5
  # Load necessary libraries, plugins, converters, and generators.
6
- #
7
- # Returns nothing.
6
+ # @see Bridgetown::Converter
7
+ # @see Bridgetown::Generator
8
+ # @see PluginManager
9
+ # @return [void]
8
10
  def setup
9
11
  plugin_manager.require_plugin_files
10
12
  self.converters = instantiate_subclasses(Bridgetown::Converter)
11
13
  self.generators = instantiate_subclasses(Bridgetown::Generator)
12
14
  end
13
15
 
14
- # Run each of the Generators.
15
- #
16
- # Returns nothing.
16
+ # Run all Generators.
17
+ # @see Bridgetown::Generator
18
+ # @return [void]
17
19
  def generate
18
20
  generators.each do |generator|
19
21
  start = Time.now
@@ -32,8 +34,9 @@ module Bridgetown
32
34
  end
33
35
 
34
36
  # Get the implementation class for the given Converter.
35
- # Returns the Converter instance implementing the given Converter.
36
- # klass - The Class of the Converter to fetch.
37
+ # @param klass [Object] The Class of the Converter to fetch.
38
+ # @return [Bridgetown::Converter] Returns the {Bridgetown::Converter}
39
+ # instance implementing the given +Converter+.
37
40
  def find_converter_instance(klass)
38
41
  @find_converter_instance ||= {}
39
42
  @find_converter_instance[klass] ||= begin
@@ -42,11 +45,11 @@ module Bridgetown
42
45
  end
43
46
  end
44
47
 
45
- # klass - class or module containing the subclasses.
46
- # Returns array of instances of subclasses of parameter.
47
- # Create array of instances of the subclasses of the class or module
48
- # passed in as argument.
49
-
48
+ # Create an array of instances of the subclasses of the class or module
49
+ # passed in as argument.
50
+ # @param klass [Class, Module] - class or module containing the subclasses.
51
+ # @return [Array<Object>] Returns an array of instances of subclasses of
52
+ # +klass+.
50
53
  def instantiate_subclasses(klass)
51
54
  klass.descendants.sort.map do |c|
52
55
  c.new(config)
@@ -2,9 +2,14 @@
2
2
 
3
3
  module Bridgetown
4
4
  module Site::Processable
5
- # Public: Read, process, and write this Site to output.
6
- #
7
- # Returns nothing.
5
+ # Reset, Read, Generate, Render, Cleanup, Process, and Write this Site to output.
6
+ # @return [void]
7
+ # @see #reset
8
+ # @see #read
9
+ # @see #generate
10
+ # @see #render
11
+ # @see #cleanup
12
+ # @see #write
8
13
  def process
9
14
  reset
10
15
  read
@@ -16,10 +21,9 @@ module Bridgetown
16
21
  end
17
22
 
18
23
  # rubocop:disable Metrics/AbcSize
19
- #
24
+
20
25
  # Reset Site details.
21
- #
22
- # Returns nothing
26
+ # @return [void]
23
27
  def reset
24
28
  self.time = if config["time"]
25
29
  Utils.parse_date(config["time"].to_s, "Invalid time in bridgetown.config.yml.")
@@ -43,11 +47,11 @@ module Bridgetown
43
47
  Bridgetown::Cache.clear_if_config_changed config
44
48
  Bridgetown::Hooks.trigger :site, :after_reset, self
45
49
  end
50
+
46
51
  # rubocop:enable Metrics/AbcSize
47
52
 
48
53
  # Read Site data from disk and load it into internal data structures.
49
- #
50
- # Returns nothing.
54
+ # @return [void]
51
55
  def read
52
56
  Bridgetown::Hooks.trigger :site, :pre_read, self
53
57
  reader.read
@@ -58,8 +62,6 @@ module Bridgetown
58
62
  private
59
63
 
60
64
  # Limits the current posts; removes the posts which exceed the limit_posts
61
- #
62
- # Returns nothing
63
65
  def limit_posts!
64
66
  if limit_posts.positive?
65
67
  limit = posts.docs.length < limit_posts ? posts.docs.length : limit_posts
@@ -3,8 +3,7 @@
3
3
  module Bridgetown
4
4
  module Site::Renderable
5
5
  # Render the site to the destination.
6
- #
7
- # Returns nothing.
6
+ # @return [void]
8
7
  def render
9
8
  payload = site_payload
10
9
 
@@ -18,6 +17,14 @@ module Bridgetown
18
17
  Bridgetown::Hooks.trigger :site, :post_render, self, payload
19
18
  end
20
19
 
20
+ # Executes inline Ruby frontmatter if
21
+ # +ENV+["BRIDGETOWN_RUBY_IN_FRONTMATTER"] equals "true"
22
+ #
23
+ # @example
24
+ # calculation: !ruby/string:Rb |
25
+ # [2 * 4, 5 + 2].min
26
+ # @return [void]
27
+ # @see https://www.bridgetownrb.com/docs/front-matter#ruby-front-matter
21
28
  def execute_inline_ruby_for_layouts!
22
29
  return unless config.should_execute_inline_ruby?
23
30
 
@@ -26,6 +33,10 @@ module Bridgetown
26
33
  end
27
34
  end
28
35
 
36
+ # Renders all documents
37
+ # @param payload [Hash] A hash of site data.
38
+ # @return [void]
39
+ # @see Bridgetown::Site::Content#site_payload
29
40
  def render_docs(payload)
30
41
  collections.each_value do |collection|
31
42
  collection.docs.each do |document|
@@ -34,17 +45,25 @@ module Bridgetown
34
45
  end
35
46
  end
36
47
 
48
+ # Renders all pages
49
+ # @param payload [Hash] A hash of site data.
50
+ # @return [void]
51
+ # @see Bridgetown::Site::Content#site_payload
37
52
  def render_pages(payload)
38
53
  pages.each do |page|
39
54
  render_regenerated(page, payload)
40
55
  end
41
56
  end
42
57
 
58
+ # Regenerates a site using {Bridgetown::Renderer}
59
+ # @param document [Post] The document to regenerate.
60
+ # @param payload [Hash] A hash of site data.
61
+ # @return [void]
62
+ # @see Bridgetown::Renderer
43
63
  def render_regenerated(document, payload)
44
64
  return unless regenerator.regenerate?(document)
45
65
 
46
- document.output = Bridgetown::Renderer.new(self, document, payload).run
47
- document.trigger_hooks(:post_render)
66
+ Bridgetown::Renderer.new(self, document, payload).run
48
67
  end
49
68
  end
50
69
  end
@@ -4,14 +4,14 @@ module Bridgetown
4
4
  module Site::Writable
5
5
  # Remove orphaned files and empty directories in destination.
6
6
  #
7
- # Returns nothing.
7
+ # @return [void]
8
8
  def cleanup
9
9
  @cleaner.cleanup!
10
10
  end
11
11
 
12
12
  # Write static files, pages, and posts.
13
13
  #
14
- # Returns nothing.
14
+ # @return [void]
15
15
  def write
16
16
  each_site_file do |item|
17
17
  item.write(dest) if regenerator.regenerate?(item)
@@ -20,6 +20,20 @@ module Bridgetown
20
20
  Bridgetown::Hooks.trigger :site, :post_write, self
21
21
  end
22
22
 
23
+ # Yields the pages from {#pages}, {#static_files}, and {#docs_to_write}.
24
+ #
25
+ # @yieldparam item [Document, Page, StaticFile] Yields a
26
+ # {#Bridgetown::Page}, {#Bridgetown::StaticFile}, or
27
+ # {#Bridgetown::Document} object.
28
+ #
29
+ # @return [void]
30
+ #
31
+ # @see #pages
32
+ # @see #static_files
33
+ # @see #docs_to_write
34
+ # @see Page
35
+ # @see StaticFile
36
+ # @see Document
23
37
  def each_site_file
24
38
  %w(pages static_files docs_to_write).each do |type|
25
39
  send(type).each do |item|
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bridgetown
4
+ module Validatable
5
+ # FIXME: there should be ONE TRUE METHOD to read the YAML frontmatter
6
+ # in the entire project. Both this and the equivalent Document method
7
+ # should be extracted and generalized.
8
+ #
9
+ # Read the YAML frontmatter.
10
+ #
11
+ # base - The String path to the dir containing the file.
12
+ # name - The String filename of the file.
13
+ # opts - optional parameter to File.read, default at site configs
14
+ #
15
+ # Returns nothing.
16
+ # rubocop:disable Metrics/AbcSize
17
+ def read_yaml(base, name, opts = {})
18
+ filename = File.join(base, name)
19
+
20
+ begin
21
+ self.content = File.read(@path || site.in_source_dir(base, name),
22
+ **Utils.merged_file_read_opts(site, opts))
23
+ if content =~ Document::YAML_FRONT_MATTER_REGEXP
24
+ self.content = $POSTMATCH
25
+ self.data = SafeYAML.load(Regexp.last_match(1))&.with_indifferent_access
26
+ end
27
+ rescue Psych::SyntaxError => e
28
+ Bridgetown.logger.warn "YAML Exception reading #{filename}: #{e.message}"
29
+ raise e if site.config["strict_front_matter"]
30
+ rescue StandardError => e
31
+ Bridgetown.logger.warn "Error reading file #{filename}: #{e.message}"
32
+ raise e if site.config["strict_front_matter"]
33
+ end
34
+
35
+ self.data ||= ActiveSupport::HashWithIndifferentAccess.new
36
+
37
+ validate_data! filename
38
+ validate_permalink! filename
39
+
40
+ self.data
41
+ end
42
+ # rubocop:enable Metrics/AbcSize
43
+
44
+ # FIXME: why doesn't Document validate data too?
45
+ def validate_data!(filename)
46
+ unless self.data.is_a?(Hash)
47
+ raise Errors::InvalidYAMLFrontMatterError,
48
+ "Invalid YAML front matter in #{filename}"
49
+ end
50
+ end
51
+
52
+ # FIXME: Layouts don't have permalinks...d'oh
53
+ def validate_permalink!(filename)
54
+ if self.data["permalink"]&.to_s&.empty?
55
+ raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
56
+ end
57
+ end
58
+ end
59
+ end
@@ -19,6 +19,7 @@ module Bridgetown
19
19
  "data_dir" => "_data",
20
20
  "components_dir" => "_components",
21
21
  "includes_dir" => "_includes",
22
+ "partials_dir" => "_partials",
22
23
  "collections" => {},
23
24
 
24
25
  # Handling Reading