dimples 10.7.2 → 11.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b348602f3096e0062a5bfe4a1a69c7396e28e06fb505b86e6f265418b31ae1e
4
- data.tar.gz: 2335b720796fdbd545f0ca7813f720de50ad6cf39f6aabf9a624f26cf569707c
3
+ metadata.gz: f1d981c9f939077c2f4adc12e16ab8247cd3265eb9fcdef78bbe8b98edbd9a8b
4
+ data.tar.gz: 59ee25fcbed829882e7da7f590cb52124f00e49ea6ed13a8e6c0c3a6227cd645
5
5
  SHA512:
6
- metadata.gz: 907c0fec40c9bbd9f2b572021008f30cfa8e37a5c07a696eafdc9c7f4f45328e07ce05945be9806bc0df6dc9c67b090688a73918645df5b7d46390f10c9fc37b
7
- data.tar.gz: 9ad1d9698bd51ca77010a172e4901887f919a724285b20b0e451f11d33742aada0442aacb66f3ecd6e338ab195794dab40773be208131744188171892d8099c8
6
+ metadata.gz: 6b099e52f6d5940af4ba514ef72333d09b71de7b00804980455ef2b17f7078b6ded70e5852aed00c863c87d0f35a58028ffa98ad20bed338084c8598e83cdaaa
7
+ data.tar.gz: 2dcaade059713c73f0d690a7a483cb5f21761164be764cdf3ebe8deffa411b0151e98fb4deb38402220c1556cb0c339e084c50f4082cf1268c5cc6ecacd55082
data/bin/dimples CHANGED
@@ -19,9 +19,9 @@ if File.exist?(config_path)
19
19
  end
20
20
 
21
21
  OptionParser.new do |parser|
22
- parser.banner = "Usage: dimples [options]"
22
+ parser.banner = 'Usage: dimples [options]'
23
23
 
24
- parser.on("-o [path]", "--output-path [path]", String, "The directory where your site will be generated") do |option|
24
+ parser.on('-o [path]', '--output-path [path]', String, 'The directory where your site will be generated') do |option|
25
25
  config[:build] = option unless option.nil?
26
26
  end
27
27
  end.parse!
@@ -6,7 +6,7 @@ module Dimples
6
6
  SOURCE_PATHS = {
7
7
  pages: 'pages',
8
8
  posts: 'posts',
9
- layouts: 'layouts',
9
+ templates: 'templates',
10
10
  static: 'static'
11
11
  }.freeze
12
12
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dimples
4
+ # Context used when rendering an item in a template
5
+ class Context
6
+ def self.from_hash(hash)
7
+ hash.transform_values! { |value| value.is_a?(Hash) ? Context.from_hash(value) : value }
8
+
9
+ Struct.new(*hash.keys) do |_klass|
10
+ def method_missing(_method_name, *_args)
11
+ nil
12
+ end
13
+
14
+ def respond_to_missing?(_method_name, _include_private = false)
15
+ true
16
+ end
17
+ end.new(*hash.values)
18
+ end
19
+ end
20
+ end
data/lib/dimples/entry.rb CHANGED
@@ -4,18 +4,15 @@ require 'forwardable'
4
4
  require 'pathname'
5
5
 
6
6
  module Dimples
7
- # A class representing a dynamic source entry
7
+ # A class representing a dynamic source entry that can generate rendered content
8
8
  class Entry
9
- include Forwardable
10
-
11
9
  FRONT_MATTER_PATTERN = /^(-{3}\n.*?\n?)^(-{3}*$\n?)/m
10
+ DEFAULT_FILENAME = 'index.html'
12
11
 
13
12
  attr_accessor :path, :contents, :rendered_contents
14
13
  attr_reader :metadata
15
14
 
16
- def initialize(site:, source:)
17
- @site = site
18
-
15
+ def initialize(source:)
19
16
  contents = case source
20
17
  when Pathname
21
18
  @path = File.expand_path(source)
@@ -28,79 +25,36 @@ module Dimples
28
25
  end
29
26
 
30
27
  def parse_metadata(contents)
31
- metadata = default_metadata
28
+ @metadata = default_metadata
32
29
 
33
30
  matches = contents.match(FRONT_MATTER_PATTERN)
34
31
  if matches
35
- metadata.merge!(YAML.safe_load(matches[1], symbolize_names: true, permitted_classes: [Date]))
32
+ @metadata.merge!(YAML.safe_load(matches[1], symbolize_names: true, permitted_classes: [Date]))
36
33
  @contents = matches.post_match.strip
37
34
  else
38
35
  @contents = contents
39
36
  end
40
-
41
- @metadata = Metadata.new(metadata)
42
- end
43
-
44
- def generate(output_path: nil, context: {})
45
- output_path = File.join(output_directory, filename) if output_path.nil?
46
- write(output_path: output_path, body: render(context: context))
47
37
  end
48
38
 
49
- def write(output_path:, body:)
50
- parent_directory = File.dirname(output_path)
51
-
52
- FileUtils.mkdir_p(parent_directory) unless File.directory?(parent_directory)
53
- File.write(output_path, body)
54
- end
55
-
56
- def url
57
- @url ||= output_directory.gsub(@site.config.build_paths[:root], '').tap do |url|
58
- url.concat(filename) unless filename == 'index.html'
59
- end
60
- end
61
-
62
- def render(context: {}, body: nil)
63
- context[:site] ||= @site
64
- context[:page] ||= self
65
-
66
- @rendered_contents = template.render(
67
- Object.new.tap do |render_context|
68
- context.each do |key, value|
69
- render_context.instance_variable_set("@#{key}", value)
70
- end
71
- end
72
- ) { body }
73
-
74
- template = @site.layouts[layout.to_sym] unless layout.nil?
75
- return @rendered_contents if template.nil?
76
-
77
- template.render(context: context, body: @rendered_contents)
78
- end
79
-
80
- def output_directory
81
- @output_directory ||= @site.config.build_paths[:root]
82
- end
83
-
84
- def template
85
- @template ||= Tilt::ERBTemplate.new { @contents }
39
+ def render(context: nil)
40
+ contents
86
41
  end
87
42
 
88
43
  def method_missing(method_name, *_args)
89
- method_sym = method_name.to_sym
90
-
91
- @metadata.send(method_sym)
44
+ metadata[method_name.to_sym]
92
45
  end
93
46
 
94
47
  def respond_to_missing?(method_name, _include_private = false)
95
- @metadata.respond_to?(method_name.to_sym) || super
48
+ metadata.key?(method_name.to_sym) || super
96
49
  end
97
50
 
98
51
  private
99
52
 
100
53
  def default_metadata
101
54
  {
55
+ date: @path ? File.birthtime(@path) : Time.now,
102
56
  layout: nil,
103
- filename: 'index.html'
57
+ filename: DEFAULT_FILENAME
104
58
  }
105
59
  end
106
60
  end
data/lib/dimples/pager.rb CHANGED
@@ -5,20 +5,21 @@ module Dimples
5
5
  class Pager
6
6
  include Enumerable
7
7
 
8
+ DEFAULT_OPTIONS = { per_page: 5, page_prefix: 'page_' }.freeze
9
+
8
10
  attr_reader :current_page, :previous_page, :next_page, :page_count
9
11
 
10
- def self.paginate(site:, url:, posts:, context: {}, &block)
11
- new(site: site, url: url, posts: posts).paginate(context: context, &block)
12
+ def self.paginate(url:, posts:, options: {}, context: {}, &block)
13
+ new(url: url, posts: posts, options: options).paginate(context: context, &block)
12
14
  end
13
15
 
14
- def initialize(site:, url:, posts:)
15
- @site = site
16
+ def initialize(url:, posts:, options: {})
16
17
  @url = url
17
- @posts = posts
18
+ @url << '/' unless @url[-1] == '/'
18
19
 
19
- @per_page = @site.config.pagination[:per_page]
20
- @page_prefix = @site.config.pagination[:page_prefix]
21
- @page_count = (posts.length.to_f / @per_page.to_i).ceil
20
+ @posts = posts
21
+ @options = DEFAULT_OPTIONS.merge(options)
22
+ @page_count = (posts.length.to_f / @options[:per_page].to_i).ceil
22
23
 
23
24
  step_to(1)
24
25
  end
@@ -27,14 +28,7 @@ module Dimples
27
28
  (1..@page_count).each do |index|
28
29
  step_to(index)
29
30
 
30
- output_directory = File.join(@site.config.build_paths[:root], current_page_path)
31
-
32
- @site.layouts[:posts]&.generate(
33
- output_path: File.join(output_directory, 'index.html'),
34
- context: metadata.merge(context, url: current_page_url)
35
- )
36
-
37
- yield(output_directory, context) if block_given?
31
+ yield(current_page_path, context.merge(metadata)) if block_given?
38
32
  end
39
33
  end
40
34
 
@@ -47,7 +41,7 @@ module Dimples
47
41
  end
48
42
 
49
43
  def posts_at(page)
50
- @posts.slice((page - 1) * @per_page, @per_page)
44
+ @posts.slice((page - 1) * @options[:per_page], @options[:per_page])
51
45
  end
52
46
 
53
47
  def previous_page?
@@ -63,7 +57,7 @@ module Dimples
63
57
  end
64
58
 
65
59
  def current_page_url
66
- @current_page == 1 ? @url : "#{@url}#{@page_prefix}#{@current_page}"
60
+ @current_page == 1 ? @url : "#{@url}#{@options[:page_prefix]}#{@current_page}"
67
61
  end
68
62
 
69
63
  def first_page_url
@@ -71,17 +65,17 @@ module Dimples
71
65
  end
72
66
 
73
67
  def last_page_url
74
- @page_count == 1 ? @url : "#{@url}#{@page_prefix}#{@page_count}"
68
+ @page_count == 1 ? @url : "#{@url}#{@options[:page_prefix]}#{@page_count}"
75
69
  end
76
70
 
77
71
  def previous_page_url
78
72
  return unless @previous_page
79
73
 
80
- @previous_page == 1 ? @url : "#{@url}#{@page_prefix}#{@previous_page}"
74
+ @previous_page == 1 ? @url : "#{@url}#{@options[:page_prefix]}#{@previous_page}"
81
75
  end
82
76
 
83
77
  def next_page_url
84
- "#{@url}#{@page_prefix}#{@next_page}" if @next_page
78
+ "#{@url}#{@options[:page_prefix]}#{@next_page}" if @next_page
85
79
  end
86
80
 
87
81
  def urls
@@ -97,14 +91,14 @@ module Dimples
97
91
  def metadata
98
92
  {
99
93
  posts: posts_at(current_page),
100
- pagination: Metadata.new(
94
+ pagination: {
101
95
  current_page: @current_page,
102
96
  page_count: @page_count,
103
97
  post_count: @posts.count,
104
98
  previous_page: @previous_page,
105
99
  next_page: @next_page,
106
100
  urls: urls
107
- )
101
+ }
108
102
  }
109
103
  end
110
104
  end
data/lib/dimples/post.rb CHANGED
@@ -1,36 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dimples
4
- # A page from a site with a date.
4
+ # A single post for a site.
5
5
  class Post < Entry
6
- def initialize(site:, path:)
7
- super(site: site, source: Pathname.new(path))
6
+ @markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML)
7
+
8
+ class << self
9
+ attr_reader :markdown
8
10
  end
9
11
 
10
- def output_directory
11
- @output_directory ||= File.dirname(@path).gsub(
12
- @site.config.source_paths[:posts],
13
- @site.config.build_paths[:posts]
14
- ).concat("/#{slug}/")
12
+ def initialize(path:)
13
+ super(source: Pathname.new(path))
15
14
  end
16
15
 
17
16
  def slug
18
- File.basename(@path, File.extname(@path))&.downcase
17
+ File.basename(path, File.extname(path))&.downcase
19
18
  end
20
19
 
21
- def template
22
- @template ||= Tilt::RedcarpetTemplate.new { @contents }
20
+ def render(context: nil)
21
+ Dimples::Post.markdown.render(contents)
23
22
  end
24
23
 
25
24
  private
26
25
 
27
26
  def default_metadata
28
- super.tap do |defaults|
29
- defaults[:layout] = 'post'
30
- defaults[:slug] = slug
31
- defaults[:date] = File.birthtime(@path)
32
- defaults[:categories] = []
33
- end
27
+ super.merge!(
28
+ layout: 'post',
29
+ slug: slug,
30
+ categories: []
31
+ )
34
32
  end
35
33
  end
36
34
  end
data/lib/dimples/site.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'date'
4
4
  require 'fileutils'
5
- require 'tilt'
5
+ require 'redcarpet'
6
6
  require 'yaml'
7
7
 
8
8
  module Dimples
@@ -29,20 +29,22 @@ module Dimples
29
29
  end
30
30
 
31
31
  def posts
32
- @posts ||= Dir.glob(File.join(@config.source_paths[:posts], '**', '*.markdown')).map do |path|
33
- Dimples::Post.new(site: self, path: path)
34
- end.sort_by! { |post| post.date }.reverse!
32
+ @posts ||= source_files(path: :posts, extension: 'markdown').map do |path|
33
+ Dimples::Post.new(path: path)
34
+ end
35
+ .sort_by!(&:date)
36
+ .reverse!
35
37
  end
36
38
 
37
39
  def pages
38
- @pages ||= Dir.glob(File.join(@config.source_paths[:pages], '**', '*.erb')).map do |path|
39
- Dimples::Page.new(site: self, path: path)
40
+ @pages ||= source_files(path: :pages, extension: 'erb').map do |path|
41
+ Dimples::Template.new(path: path)
40
42
  end
41
43
  end
42
44
 
43
- def layouts
44
- @layouts ||= Dir.glob(File.join(@config.source_paths[:layouts], '**', '*.erb')).to_h do |path|
45
- [File.basename(path, '.erb').to_sym, Dimples::Layout.new(site: self, path: path)]
45
+ def templates
46
+ @templates ||= source_files(path: :templates, extension: 'erb').to_h do |path|
47
+ [File.basename(path, '.erb').to_sym, Dimples::Template.new(path: path)]
46
48
  end
47
49
  end
48
50
 
@@ -59,20 +61,33 @@ module Dimples
59
61
 
60
62
  private
61
63
 
64
+ def source_files(path:, extension:)
65
+ Dir.glob(File.join(@config.source_paths[path], '**', "*.#{extension}"))
66
+ end
67
+
62
68
  def generate_posts
63
69
  posts.each { |post| generate_post(post) }
64
70
 
65
- Pager.paginate(
66
- site: self,
67
- url: @config.build_paths[:posts].gsub(@config.build_paths[:root], '').concat('/'),
68
- posts: posts
69
- )
71
+ url = @config.build_paths[:posts].gsub(@config.build_paths[:root], '').concat('/')
72
+
73
+ Pager.paginate(url: url, posts: posts, options: @config.pagination) do |url, page_context|
74
+ generate_entry(
75
+ entry: templates[:posts],
76
+ output_path: File.join(@config.build_paths[:root], url),
77
+ context: page_context
78
+ )
79
+ end
70
80
 
71
81
  generate_feed(output_path: @config.build_paths[:root], posts: posts) if @config.generation[:main_feed]
72
82
  end
73
83
 
74
84
  def generate_post(post)
75
- post.generate
85
+ path = File.dirname(post.path).gsub(
86
+ @config.source_paths[:posts],
87
+ @config.build_paths[:posts]
88
+ ).concat("/#{post.slug}/")
89
+
90
+ generate_entry(entry: post, output_path: path)
76
91
  end
77
92
 
78
93
  def generate_pages
@@ -80,7 +95,12 @@ module Dimples
80
95
  end
81
96
 
82
97
  def generate_page(page)
83
- page.generate
98
+ path = File.dirname(page.path).gsub(
99
+ @config.source_paths[:pages],
100
+ @config.build_paths[:root]
101
+ ).concat('/')
102
+
103
+ generate_entry(entry: page, output_path: path)
84
104
  end
85
105
 
86
106
  def generate_categories
@@ -88,11 +108,17 @@ module Dimples
88
108
  context = { title: category.capitalize, category: category }
89
109
 
90
110
  Pager.paginate(
91
- site: self,
92
111
  url: "/categories/#{category}/",
93
112
  posts: posts,
94
- context: context
95
- )
113
+ context: context,
114
+ options: @config.pagination
115
+ ) do |url, page_context|
116
+ generate_entry(
117
+ entry: templates[:posts],
118
+ output_path: File.join(@config.build_paths[:root], url),
119
+ context: page_context
120
+ )
121
+ end
96
122
 
97
123
  if @config.generation[:category_feeds]
98
124
  generate_feed(output_path: File.join(@config.build_paths[:root], 'categories', category), posts: posts)
@@ -101,14 +127,36 @@ module Dimples
101
127
  end
102
128
 
103
129
  def generate_feed(output_path:, posts:)
104
- return if layouts[:feed].nil?
130
+ return if templates[:feed].nil?
105
131
 
106
- layouts[:feed].generate(
107
- output_path: File.join(output_path, 'feed.atom'),
132
+ generate_entry(
133
+ entry: templates[:feed],
134
+ output_path: output_path,
108
135
  context: { posts: posts.slice(0, 10) }
109
136
  )
110
137
  end
111
138
 
139
+ def generate_entry(entry:, output_path:, context: {})
140
+ unless context[:url]
141
+ url = output_path.gsub(@config.build_paths[:root], '')
142
+ url = File.join(url, entry.filename) unless entry.filename == Dimples::Entry::DEFAULT_FILENAME
143
+
144
+ context[:url] = url
145
+ end
146
+
147
+ context = { page: Context.from_hash(entry.metadata.merge(context)), site: self }
148
+ body = entry.contents
149
+ full_path = File.join(output_path, entry.filename)
150
+
151
+ until entry.nil?
152
+ body = entry.render(context: context) { body }
153
+ entry = templates[entry.layout&.to_sym]
154
+ end
155
+
156
+ FileUtils.mkdir_p(output_path) unless File.directory?(output_path)
157
+ File.write(full_path, body)
158
+ end
159
+
112
160
  def prepare_output_directory
113
161
  if Dir.exist?(@config.build_paths[:root])
114
162
  unless @config.generation[:overwrite_existing_site]
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+
5
+ module Dimples
6
+ # A class for a single ERB template file used on a site.
7
+ class Template < Entry
8
+ def initialize(path:)
9
+ super(source: Pathname.new(path))
10
+ end
11
+
12
+ def render(context:)
13
+ context.merge!(metadata)
14
+
15
+ context.each do |key, value|
16
+ instance_variable_set("@#{key}", value)
17
+ end
18
+
19
+ erb = ERB.new(contents)
20
+ erb.result(binding)
21
+ end
22
+ end
23
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dimples
4
- VERSION = '10.7.2'
4
+ VERSION = '11.0.1'
5
5
  end
data/lib/dimples.rb CHANGED
@@ -3,10 +3,9 @@
3
3
  $LOAD_PATH.unshift(__dir__)
4
4
 
5
5
  require 'dimples/config'
6
- require 'dimples/metadata'
6
+ require 'dimples/context'
7
7
  require 'dimples/pager'
8
8
  require 'dimples/site'
9
9
  require 'dimples/entry'
10
- require 'dimples/page'
10
+ require 'dimples/template'
11
11
  require 'dimples/post'
12
- require 'dimples/layout'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dimples
3
3
  version: !ruby/object:Gem::Version
4
- version: 10.7.2
4
+ version: 11.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Bogan
@@ -37,20 +37,6 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '3.6'
40
- - !ruby/object:Gem::Dependency
41
- name: tilt
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '2.3'
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '2.3'
54
40
  description: A simple tool for building static websites.
55
41
  email:
56
42
  - d+dimples@waferbaby.com
@@ -62,13 +48,12 @@ files:
62
48
  - bin/dimples
63
49
  - lib/dimples.rb
64
50
  - lib/dimples/config.rb
51
+ - lib/dimples/context.rb
65
52
  - lib/dimples/entry.rb
66
- - lib/dimples/layout.rb
67
- - lib/dimples/metadata.rb
68
- - lib/dimples/page.rb
69
53
  - lib/dimples/pager.rb
70
54
  - lib/dimples/post.rb
71
55
  - lib/dimples/site.rb
56
+ - lib/dimples/template.rb
72
57
  - lib/dimples/version.rb
73
58
  homepage: http://github.com/waferbaby/dimples
74
59
  licenses:
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dimples
4
- # A class for a single layout used on a site.
5
- class Layout < Entry
6
- def initialize(site:, path:)
7
- super(site: site, source: Pathname.new(path))
8
- end
9
- end
10
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dimples
4
- # A tiny wrapper around metadata for rendering
5
- class Metadata
6
- def initialize(source)
7
- source.each do |key, value|
8
- self.class.send(:attr_reader, key)
9
- instance_variable_set("@#{key}", value.is_a?(Hash) ? Metadata.new(value) : value)
10
- end
11
- end
12
-
13
- def method_missing(_method_name, *_args)
14
- nil
15
- end
16
-
17
- def respond_to_missing?(_method_name, _include_private = false)
18
- true
19
- end
20
- end
21
- end
data/lib/dimples/page.rb DELETED
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dimples
4
- # A single page on a site.
5
- class Page < Entry
6
- def initialize(site:, path:)
7
- super(site: site, source: Pathname.new(path))
8
- end
9
-
10
- def output_directory
11
- @output_directory ||= File.dirname(@path).gsub(
12
- @site.config.source_paths[:pages],
13
- @site.config.build_paths[:root]
14
- ).concat('/')
15
- end
16
-
17
- private
18
-
19
- def default_metadata
20
- super.merge!(layout: 'page')
21
- end
22
- end
23
- end