edison 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +0 -0
  2. data/bin/edison +262 -0
  3. metadata +135 -0
data/README.md ADDED
File without changes
data/bin/edison ADDED
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+ require 'listen'
5
+ require 'kramdown'
6
+ require 'hashie'
7
+ require 'mustache'
8
+ require 'pp'
9
+ require 'webrick'
10
+ require 'yaml'
11
+
12
+ module Edison
13
+ end
14
+
15
+ module Edison::YAMLFrontMatter
16
+ def self.read(fname)
17
+ contents = File.read(fname).strip
18
+ if contents =~ /\A---/
19
+ _, yaml, body = contents.split("---", 3)
20
+ yaml = YAML.load(yaml)
21
+ body ||= ""
22
+ body.strip!
23
+ if yaml.include? "body"
24
+ raise Exception, "YAML Front Matter can't contain a 'body' key. Put it after the front matter."
25
+ end
26
+ {"body" => body}.merge(yaml)
27
+ else
28
+ {"body" => contents}
29
+ end
30
+ end
31
+ end
32
+
33
+ class Edison::ModelsLoader
34
+ def load(directory)
35
+ klasses = Dir[File.join(directory, "*")].map &File.method(:basename)
36
+ hash = Hashie::Mash.new
37
+ klasses.each do |klass|
38
+ objects = Dir[File.join(directory, klass, "*")]
39
+ objects.map! do |fname|
40
+ puts "Loading model #{File.join(klass, File.basename(fname))}..."
41
+
42
+ data = Hashie::Mash.new(case File.extname(fname)
43
+ when /(html)|(md)$/
44
+ Edison::YAMLFrontMatter.read(fname)
45
+ when /ya?ml$/
46
+ YAML.load_file(fname)
47
+ else
48
+ {}
49
+ end)
50
+
51
+ if data._ext
52
+ raise Exception, "Restricted key '_ext' appears in model!"
53
+ end
54
+ data._ext = File.extname(fname)
55
+
56
+ if data._ext == ".md"
57
+ data.body = Kramdown::Document.new(data.body).to_html
58
+ end
59
+
60
+ if data._fname
61
+ raise Exception, "Restricted key '_fname' appears in model!"
62
+ end
63
+ data._fname = File.basename(fname).sub(/#{File.extname(fname)}$/,'')
64
+
65
+ data
66
+ end
67
+ hash[klass] = objects
68
+ end
69
+ hash
70
+ end
71
+ end
72
+
73
+ class Edison::Renderer
74
+ attr_accessor :templates
75
+ def initialize(templates)
76
+ self.templates = templates
77
+ end
78
+ def render(template_name, data)
79
+ template = self.templates[template_name]
80
+ if template.nil?
81
+ raise Exception, "Called for template #{template_name}, but _templates/#{template_name} does not exist"
82
+ end
83
+ body = Mustache.render(template.body, data)
84
+ if template.layout
85
+ newdata = data.merge("yield" => body)
86
+ self.render(template.layout, newdata)
87
+ else
88
+ body
89
+ end
90
+ end
91
+ end
92
+
93
+ class Edison::Router
94
+ attr_reader :urls, :static
95
+ def initialize
96
+ @urls = []
97
+ @static = []
98
+ end
99
+ def url(url, template=nil, data={}, &b)
100
+ if b and template and data
101
+ raise Exception, "Please pass data or block, not both!"
102
+ end
103
+ if b
104
+ b.call(@urls.find { |(url, _, _)| url == url}[2])
105
+ else
106
+ @urls << [url, template, Hashie::Mash.new(data)]
107
+ end
108
+ end
109
+ def copy(url)
110
+ @static << url
111
+ end
112
+ end
113
+
114
+ module Edison
115
+ class <<self
116
+ attr_reader :models, :routes, :renderer
117
+ end
118
+ def self.initialize!(directory)
119
+ @directory = directory
120
+
121
+ @routes = Router.new
122
+
123
+ loader = ModelsLoader.new
124
+ @models = loader.load(File.join(directory, "_models"))
125
+
126
+ templates = Hash[Dir[File.join(directory, "_templates", "*")].map do |fname|
127
+ puts "Loading template _templates/#{File.basename(fname)}..."
128
+ name = File.basename(fname).sub(/\.[^\.]+$/,'')
129
+ data = Hashie::Mash.new Edison::YAMLFrontMatter.read(fname)
130
+ [name, data]
131
+ end]
132
+
133
+ static = Dir[File.join(directory, "**/*")]
134
+ blacklist = ["Gemfile", "Gemfile.lock", "config.rb", "gen.rb", "serve.rb"]
135
+ static.reject! do |fname|
136
+ name = fname.sub(/^#{directory}\//,'')
137
+ dirname = File.dirname(fname)
138
+ blacklist.include?(name) or name =~ /^_/ or File.directory?(fname)
139
+ end
140
+ static.each do |fname|
141
+ name = fname.sub(/^#{directory}\//,'')
142
+ if %w{.html .md}.include?(File.extname(fname))
143
+ data = Hashie::Mash.new Edison::YAMLFrontMatter.read(fname)
144
+ url = name.sub(/\.md$/,'')
145
+ templates[url] = data
146
+ @routes.url url, url, data
147
+ else
148
+ @routes.copy name
149
+ end
150
+ end
151
+
152
+ @renderer = Renderer.new(templates)
153
+ end
154
+ def self.config(&b)
155
+ instance_eval &b
156
+ end
157
+ def self.generate!
158
+ site = File.join(@directory, "_site")
159
+
160
+ FileUtils.rm_rf(site)
161
+ Dir.mkdir(site)
162
+ puts "Copying static files..."
163
+ routes.static.each do |name|
164
+ src = File.join(@directory, name)
165
+ dest = File.join(site, name)
166
+ FileUtils.mkdir_p File.dirname(dest)
167
+ FileUtils.copy src, dest
168
+ end
169
+ routes.urls.each do |(url, template_name, data)|
170
+ puts "Creating /#{url}..."
171
+
172
+ fname = File.join(site, url)
173
+ FileUtils.mkdir_p(File.dirname(fname))
174
+ File.open(fname, "w") do |f|
175
+ f.write @renderer.render(template_name, data)
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ module Edison::Helpers
182
+ def self.date_from_filename(data)
183
+ if data.date
184
+ raise Exception, "Date will be inferred from filename, but found in data"
185
+ end
186
+
187
+ if File.basename(data._fname) =~ /^(\d{4}-\d{1,2}-\d{1,2})/
188
+ data.date = Date.parse($1)
189
+ else
190
+ raise Exception, "Expected filename to start with date (YYYY-M?M-D?D)"
191
+ end
192
+
193
+ data
194
+ end
195
+
196
+ def self.default_layout(data)
197
+ unless data.layout
198
+ data.layout = "default"
199
+ end
200
+
201
+ data
202
+ end
203
+ end
204
+
205
+ def build
206
+ directory = Dir.pwd
207
+ puts "Running in #{directory}..."
208
+ Edison.initialize!(directory)
209
+ load File.join(directory, "config.rb")
210
+ site = File.join(directory, "_site")
211
+ Edison.generate!
212
+ puts "Done!"
213
+ end
214
+
215
+ require 'commander/import'
216
+
217
+ program :name, "Edison"
218
+ program :version, "0.0.1"
219
+ program :description, "Static website generator"
220
+
221
+ default_command :help
222
+
223
+ command :up do |c|
224
+ c.description = "Build static files"
225
+ c.action do |args, options|
226
+ build
227
+ end
228
+ end
229
+ command :serve do |c|
230
+ c.description = "Auto-generating webserver"
231
+ c.action do |args, options|
232
+ directory = Dir.pwd
233
+
234
+ begin
235
+ build
236
+ rescue => e
237
+ pp e
238
+ end
239
+
240
+ listener = Listen.to(directory, :ignore => /^_site\//)
241
+ server = WEBrick::HTTPServer.new(
242
+ :Port => 4000,
243
+ :DocumentRoot => File.expand_path("_site", directory)
244
+ )
245
+ listener.change do |*args|
246
+ t = Time.now.strftime("%Y-%m-%d %H:%M:%S")
247
+ puts "Regenerating at #{t}"
248
+ begin
249
+ build
250
+ rescue => e
251
+ pp e
252
+ end
253
+ end
254
+ listener.start(false)
255
+
256
+ Signal.trap("INT") do
257
+ server.shutdown
258
+ listener.stop
259
+ end
260
+ server.start
261
+ end
262
+ end
metadata ADDED
@@ -0,0 +1,135 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: edison
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Michael Maltese
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-03-17 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: commander
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: listen
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: hashie
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ hash: 3
57
+ segments:
58
+ - 0
59
+ version: "0"
60
+ type: :runtime
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: kramdown
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ type: :runtime
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: mustache
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ type: :runtime
89
+ version_requirements: *id005
90
+ description: ""
91
+ email: michael.maltese@pomona.edu
92
+ executables:
93
+ - edison
94
+ extensions: []
95
+
96
+ extra_rdoc_files: []
97
+
98
+ files:
99
+ - bin/edison
100
+ - README.md
101
+ homepage: http://github.com/michaelmaltese/jefe
102
+ licenses: []
103
+
104
+ post_install_message:
105
+ rdoc_options: []
106
+
107
+ require_paths:
108
+ - - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ hash: 3
115
+ segments:
116
+ - 0
117
+ version: "0"
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ none: false
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ hash: 3
124
+ segments:
125
+ - 0
126
+ version: "0"
127
+ requirements: []
128
+
129
+ rubyforge_project:
130
+ rubygems_version: 1.8.24
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: A static (website) generator.
134
+ test_files: []
135
+