dimples 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9af69955701e46818367fbe965f4bb1071427319
4
+ data.tar.gz: 2d2c2861d73eef0348bb98f7d06ec6e94c3b007e
5
+ SHA512:
6
+ metadata.gz: 422c790ef28519c67b634dffe74515cf52f6941e62bff67180822f26cb95c6f89be25608a9c73761a65812d4efbb4e0e80c1e34976bad0dac20d5dbc3d39442e
7
+ data.tar.gz: d30324038e2fad5432ca578ba84f7936fe961c2e30885a473893dfa2844bb012a9b055ede5bf8d48958de458e20fbe3ff089d1adbed049637774db0a216183a0
data/lib/dimples.rb ADDED
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift(__dir__)
2
+
3
+ require 'fileutils'
4
+ require 'yaml'
5
+ require 'erubis'
6
+ require 'redcarpet'
7
+
8
+ require 'dimples/frontable'
9
+ require 'dimples/publishable'
10
+ require 'dimples/configuration'
11
+ require 'dimples/page'
12
+ require 'dimples/post'
13
+ require 'dimples/site'
14
+ require 'dimples/template'
@@ -0,0 +1,74 @@
1
+ module Dimples
2
+ class Configuration
3
+ def initialize(config = {})
4
+ @settings = Dimples::Configuration.default_settings
5
+
6
+ if config
7
+ @settings.each_key do |key|
8
+ if config.key?(key)
9
+ if @settings[key].is_a?(Hash)
10
+ @settings[key].merge!(config[key])
11
+ else
12
+ @settings[key] = config[key]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ def [](key)
20
+ @settings[key]
21
+ end
22
+
23
+ def self.default_settings
24
+ current_path = Dir.pwd
25
+
26
+ {
27
+ 'source_path' => current_path,
28
+ 'destination_path' => File.join(current_path, 'site'),
29
+
30
+ 'paths' => {
31
+ 'posts' => 'archives',
32
+ 'post' => '%Y/%m/%d',
33
+ },
34
+
35
+ 'layouts' => {
36
+ 'posts' => 'posts',
37
+ 'post' => 'post',
38
+ 'category' => 'category',
39
+ },
40
+
41
+ 'markdown' => {
42
+ 'enabled' => true,
43
+ 'options' => {},
44
+ },
45
+
46
+ 'pagination' => {
47
+ 'enabled' => true,
48
+ 'per_page' => 10,
49
+ },
50
+
51
+ 'generation' => {
52
+ 'paginated_posts' => false,
53
+ 'categories' => true,
54
+ 'year_archives' => true,
55
+ 'month_archives' => true,
56
+ 'day_archives' => true,
57
+ 'feed' => true,
58
+ 'category_feeds' => true,
59
+ },
60
+
61
+ 'file_extensions' => {
62
+ 'pages' => 'html',
63
+ 'posts' => 'html',
64
+ },
65
+
66
+ 'date_formats' => {
67
+ 'year' => '%Y',
68
+ 'month' => '%Y-%m',
69
+ 'day' => '%Y-%m-%d',
70
+ }
71
+ }
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,29 @@
1
+ module Dimples
2
+ module Frontable
3
+ def read_with_yaml(path)
4
+ if path =~ /.yml$/
5
+ contents = ''
6
+ metadata = YAML.load_file(path)
7
+ else
8
+ contents = File.read(path)
9
+ matches = contents.match(/^(-{3}\n.*?\n?)^(-{3}*$\n?)/m)
10
+
11
+ if matches
12
+ metadata = YAML.load(matches[1])
13
+ contents = matches.post_match.strip!
14
+ end
15
+ end
16
+
17
+ if metadata
18
+ metadata.each_pair do |key, value|
19
+ unless instance_variable_get("@#{key}")
20
+ self.class.send(:attr_accessor, key.to_sym)
21
+ instance_variable_set("@#{key}", value)
22
+ end
23
+ end
24
+ end
25
+
26
+ contents
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,47 @@
1
+ module Dimples
2
+ class Page
3
+ include Frontable
4
+ include Publishable
5
+
6
+ attr_accessor :path
7
+ attr_accessor :title
8
+ attr_accessor :template
9
+ attr_accessor :filename
10
+ attr_accessor :extension
11
+ attr_accessor :layout
12
+
13
+ attr_writer :contents
14
+
15
+ def initialize(site, path = nil)
16
+ @site = site
17
+
18
+ if path
19
+ @path = path
20
+ @contents = read_with_yaml(path)
21
+ @filename = File.basename(path, File.extname(path))
22
+ else
23
+ @filename = 'index'
24
+ end
25
+
26
+ @extension = @site.config['file_extensions']['pages']
27
+ @layout ||= @site.config['layouts']['page']
28
+ end
29
+
30
+ def type
31
+ :page
32
+ end
33
+
34
+ def contents
35
+ @contents
36
+ end
37
+
38
+ def output_file_path(parent_path)
39
+ parts = [parent_path]
40
+
41
+ parts << File.dirname(@path).gsub(@site.source_paths[:pages], '') unless @path.nil?
42
+ parts << "#{@filename}.#{@extension}"
43
+
44
+ File.join(parts)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,70 @@
1
+ module Dimples
2
+ class Post
3
+ include Frontable
4
+ include Publishable
5
+
6
+ attr_accessor :path
7
+ attr_accessor :title
8
+ attr_accessor :template
9
+ attr_accessor :filename
10
+ attr_accessor :extension
11
+ attr_accessor :layout
12
+ attr_accessor :slug
13
+ attr_accessor :date
14
+ attr_accessor :categories
15
+ attr_accessor :year
16
+ attr_accessor :month
17
+ attr_accessor :day
18
+
19
+ attr_writer :contents
20
+ attr_writer :markdown
21
+
22
+ def initialize(site, path)
23
+ @site = site
24
+
25
+ @path = path
26
+ @contents = read_with_yaml(path)
27
+
28
+ @filename = 'index'
29
+ @extension = @site.config['file_extensions']['posts']
30
+
31
+ parts = File.basename(path, File.extname(path)).match(/(\d{4})-(\d{2})-(\d{2})-(.+)/)
32
+
33
+ @slug = parts[4]
34
+ @date = Time.mktime(parts[1], parts[2], parts[3])
35
+
36
+ @layout ||= @site.config['layouts']['post']
37
+ @categories ||= []
38
+
39
+ @year = @date.strftime('%Y')
40
+ @month = @date.strftime('%m')
41
+ @day = @date.strftime('%d')
42
+ end
43
+
44
+ def type
45
+ :post
46
+ end
47
+
48
+ def contents
49
+ @contents
50
+ end
51
+
52
+ def markdown
53
+ @markdown ||= @site.markdown_engine.render(contents())
54
+ end
55
+
56
+ def output_file_path(parent_path)
57
+ parts = [parent_path]
58
+
59
+ if @site.config['paths']['post']
60
+ path = @date.strftime(@site.config['paths']['post'])
61
+ parts.concat(path.split('/')) if path
62
+ end
63
+
64
+ parts << @slug
65
+ parts << "#{@filename}.#{@extension}"
66
+
67
+ File.join(parts)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,32 @@
1
+ module Dimples
2
+ module Publishable
3
+ def write(path, context = false)
4
+ output = context ? render(contents(), {this: self}.merge(context)) : contents()
5
+
6
+ publish_path = output_file_path(path)
7
+ parent_path = File.dirname(publish_path)
8
+
9
+ FileUtils.mkdir_p(parent_path) unless Dir.exist?(parent_path)
10
+
11
+ File.open(publish_path, 'w') do |file|
12
+ file.write(output)
13
+ end
14
+ end
15
+
16
+ def render(body, context = {}, use_layout = true)
17
+ context[:site] ||= @site
18
+
19
+ begin
20
+ output = Erubis::Eruby.new(contents()).evaluate(context) { body }
21
+ rescue SyntaxError => e
22
+ raise "Syntax error in #{path.gsub(site.source_paths[:root], '')}"
23
+ end
24
+
25
+ if use_layout && @layout && @site.templates[@layout]
26
+ output = @site.templates[@layout].render(output, context)
27
+ end
28
+
29
+ output
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,278 @@
1
+ module Dimples
2
+ class Site
3
+ attr_accessor :source_paths
4
+ attr_accessor :output_paths
5
+ attr_accessor :config
6
+ attr_accessor :templates
7
+ attr_accessor :categories
8
+ attr_accessor :archives
9
+ attr_accessor :pages
10
+ attr_accessor :posts
11
+ attr_accessor :latest_post
12
+ attr_accessor :markdown_engine
13
+ attr_accessor :page_class
14
+ attr_accessor :post_class
15
+
16
+ def initialize(config = {})
17
+ @source_paths = {}
18
+ @output_paths = {}
19
+ @templates = {}
20
+ @categories = {}
21
+ @archives = {}
22
+
23
+ @pages = []
24
+ @posts = []
25
+
26
+ @latest_post = false
27
+
28
+ @page_class = Dimples::Page
29
+ @post_class = Dimples::Post
30
+
31
+ @config = Dimples::Configuration.new(config)
32
+
33
+ @source_paths[:root] = File.expand_path(@config['source_path'])
34
+ @output_paths[:site] = File.expand_path(@config['destination_path'])
35
+
36
+ %w{pages posts templates public}.each do |path|
37
+ @source_paths[path.to_sym] = File.join(@source_paths[:root], path)
38
+ end
39
+
40
+ @output_paths[:posts] = File.join(@output_paths[:site], @config['paths']['posts'])
41
+
42
+ @markdown_engine = if @config['markdown']['enabled']
43
+ Redcarpet::Markdown.new(Redcarpet::Render::HTML, @config['markdown']['options'])
44
+ else
45
+ false
46
+ end
47
+ end
48
+
49
+ def scan_files
50
+ Dir.glob(File.join(@source_paths[:templates], '**', '*.*')).each do |path|
51
+ template = Dimples::Template.new(self, path)
52
+ @templates[template.slug] = template
53
+ end
54
+
55
+ Dir.glob(File.join(@source_paths[:pages], '**', '*.*')).each do |path|
56
+ @pages << @page_class.new(self, path)
57
+ end
58
+
59
+ Dir.glob(File.join(@source_paths[:posts], '*.*')).each do |path|
60
+ @posts << @post_class.new(self, path)
61
+ end
62
+
63
+ @posts.reverse!
64
+ @latest_post = @posts.first
65
+
66
+ @posts.each do |post|
67
+
68
+ year = post.year.to_s
69
+ month = post.month.to_s
70
+ day = post.day.to_s
71
+
72
+ @archives[year] ||= {posts: [], months: {}}
73
+
74
+ @archives[year][:posts] << post
75
+ @archives[year][:months][month] ||= {posts: [], days: {}, name: post.date.strftime('%B')}
76
+ @archives[year][:months][month][:posts] << post
77
+ @archives[year][:months][month][:days][day] ||= []
78
+ @archives[year][:months][month][:days][day] << post
79
+
80
+ post.categories.each do |category|
81
+ (@categories[category] ||= []) << post
82
+ end
83
+ end
84
+ end
85
+
86
+ def generate
87
+ scan_files
88
+
89
+ begin
90
+ FileUtils.remove_dir(@output_paths[:site]) if Dir.exist?(@output_paths[:site])
91
+ Dir.mkdir(@output_paths[:site])
92
+ rescue => e
93
+ raise "Failed to prepare the site directory (#{e})"
94
+ end
95
+
96
+ @posts.each do |post|
97
+ begin
98
+ post.write(@output_paths[:posts], {})
99
+ rescue => e
100
+ raise "Failed to render post #{File.basename(post.path)} (#{e})"
101
+ end
102
+ end
103
+
104
+ @pages.each do |page|
105
+ begin
106
+ page.write(@output_paths[:site], {})
107
+ rescue => e
108
+ raise "Failed to render page from #{page.path.gsub(@source_paths[:root], '')} (#{e})"
109
+ end
110
+ end
111
+
112
+ if @config['generation']['paginated_posts'] && @posts.length > 0
113
+ begin
114
+ paginate(@posts, false, @config['pagination']['per_page'], [@output_paths[:posts]], @config['layouts']['posts'])
115
+ rescue => e
116
+ raise "Failed to paginate main posts (#{e})"
117
+ end
118
+ end
119
+
120
+ if @config['generation']['year_archives'] && @archives.length > 0
121
+ begin
122
+ generate_archives
123
+ rescue => e
124
+ raise "Failed to generate archives (#{e})"
125
+ end
126
+ end
127
+
128
+ if @config['generation']['categories'] && @categories.length > 0
129
+ @categories.each_pair do |slug, posts|
130
+ if @config['generation']['category_feeds']
131
+ begin
132
+ generate_feed(File.join(@output_paths[:posts], slug), {posts: posts[0..@config['pagination']['per_page'] - 1], category: slug})
133
+ rescue => e
134
+ raise "Failed to generate category feed for '#{slug}' (#{e})"
135
+ end
136
+ end
137
+
138
+ begin
139
+ paginate(posts, slug.capitalize, @config['pagination']['per_page'], [@output_paths[:posts], slug], @config['layouts']['category'])
140
+ rescue => e
141
+ raise "Failed to generate category pages for '#{slug}' (#{e})"
142
+ end
143
+ end
144
+ end
145
+
146
+ if @config['generation']['feed'] && @posts.length > 0
147
+ begin
148
+ generate_feed(@output_paths[:site], {posts: @posts[0..@config['pagination']['per_page'] - 1]})
149
+ rescue => e
150
+ raise "Failed to generate main feed (#{e})"
151
+ end
152
+ end
153
+
154
+ begin
155
+ FileUtils.cp_r(File.join(@source_paths[:public], '.'), @output_paths[:site]) if Dir.exists?(@source_paths[:public])
156
+ rescue => e
157
+ raise "Failed to copy site assets (#{e})"
158
+ end
159
+ end
160
+
161
+ def generate_archives
162
+ if @config['layouts'].has_key?('year')
163
+ year_template = @config['layouts']['year']
164
+ elsif @config['layouts'].has_key?('archives')
165
+ year_template = @config['layouts']['archives']
166
+ else
167
+ year_template = @config['layouts']['posts']
168
+ end
169
+
170
+ @archives.each do |year, year_archive|
171
+
172
+ if @config['generation']['month_archives']
173
+ if @config['layouts'].has_key?('month')
174
+ month_template = @config['layouts']['month']
175
+ elsif @config['layouts'].has_key?('archives')
176
+ month_template = @config['layouts']['archives']
177
+ else
178
+ month_template = @config['layouts']['posts']
179
+ end
180
+
181
+ year_archive[:months].each do |month, month_archive|
182
+
183
+ if @config['generation']['day_archives']
184
+
185
+ if @config['layouts'].has_key?('day')
186
+ day_template = @config['layouts']['day']
187
+ elsif @config['layouts'].has_key?('archives')
188
+ day_template = @config['layouts']['archives']
189
+ else
190
+ day_template = @config['layouts']['posts']
191
+ end
192
+
193
+ month_archive[:days].each do |day, posts|
194
+ day_title = posts[0].date.strftime(@config['date_formats']['day'])
195
+ paginate(posts, day_title, @config['pagination']['per_page'], [@output_paths[:posts], year.to_s, month.to_s, day.to_s], day_template)
196
+ end
197
+ end
198
+
199
+ month_title = month_archive[:posts][0].date.strftime(@config['date_formats']['month'])
200
+ paginate(month_archive[:posts], month_title, @config['pagination']['per_page'], [@output_paths[:posts], year.to_s, month.to_s], month_template)
201
+ end
202
+ end
203
+
204
+ year_title = year_archive[:posts][0].date.strftime(@config['date_formats']['year'])
205
+ paginate(year_archive[:posts], year_title, @config['pagination']['per_page'], [@output_paths[:posts], year.to_s], year_template)
206
+ end
207
+ end
208
+
209
+ def generate_feed(path, params)
210
+ feed = @page_class.new(self)
211
+
212
+ feed.filename = 'feed'
213
+ feed.extension = 'atom'
214
+ feed.layout = 'feed'
215
+
216
+ feed.write(path, params)
217
+ end
218
+
219
+ def paginate(posts, title, per_page, paths, layout, params = {})
220
+ fail "'#{layout}' template not found" unless @templates.has_key?(layout)
221
+
222
+ pages = (posts.length.to_f / per_page.to_i).ceil
223
+
224
+ for index in 0...pages
225
+ range = posts.slice(index * per_page, per_page)
226
+
227
+ page = @page_class.new(self)
228
+
229
+ page_paths = paths.clone
230
+ page_title = title ? title : @templates[layout].title
231
+
232
+ if page_paths[0] == @output_paths[:site]
233
+ url_path = '/'
234
+ else
235
+ url_path = "/#{File.split(page_paths[0])[-1]}/"
236
+ end
237
+
238
+ url_path += "#{page_paths[1..-1].join('/')}/" if page_paths.length > 1
239
+
240
+ if index > 0
241
+ page_paths.push("page#{index + 1}")
242
+ end
243
+
244
+ pagination = {
245
+ page: index + 1,
246
+ pages: pages,
247
+ total: posts.length,
248
+ path: url_path
249
+ }
250
+
251
+ if (pagination[:page] - 1) > 0
252
+ pagination[:previous_page] = pagination[:page] - 1
253
+ end
254
+
255
+ if (pagination[:page] + 1) <= pagination[:pages]
256
+ pagination[:next_page] = pagination[:page] + 1
257
+ end
258
+
259
+ page.layout = layout
260
+ page.title = page_title
261
+
262
+ page.write(File.join(page_paths), {posts: range, pagination: pagination}.merge(params))
263
+ end
264
+ end
265
+
266
+ def render(template_slug, content, layout = true)
267
+ return '' unless @templates[template_slug]
268
+
269
+ if content.is_a? String
270
+ @templates[template_slug].render(content, {}, layout)
271
+ elsif content.is_a? Hash
272
+ @templates[template_slug].render('', content, layout)
273
+ else
274
+ ''
275
+ end
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,19 @@
1
+ module Dimples
2
+ class Template
3
+ include Frontable
4
+ include Publishable
5
+
6
+ attr_accessor :slug
7
+ attr_accessor :title
8
+ attr_accessor :path
9
+ attr_accessor :contents
10
+
11
+ def initialize(site, path)
12
+ @site = site
13
+ @slug = File.basename(path, File.extname(path))
14
+ @path = path
15
+
16
+ @contents = read_with_yaml(path)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module Dimples
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dimples
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Daniel Bogan
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: erubis
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: redcarpet
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.2'
41
+ description: This is a very simple static site generator, born out of the loins of
42
+ usesthis.com.
43
+ email:
44
+ - d+dimples@waferbaby.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - lib/dimples.rb
50
+ - lib/dimples/configuration.rb
51
+ - lib/dimples/frontable.rb
52
+ - lib/dimples/page.rb
53
+ - lib/dimples/post.rb
54
+ - lib/dimples/publishable.rb
55
+ - lib/dimples/site.rb
56
+ - lib/dimples/template.rb
57
+ - lib/dimples/version.rb
58
+ homepage: http://github.com/waferbaby/dimples
59
+ licenses:
60
+ - LICENSE
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.2.2
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: A very silly static site generator
82
+ test_files: []