gumdrop 0.5.2 → 0.6.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.
@@ -3,7 +3,8 @@ module Gumdrop
3
3
  class Generator
4
4
  attr_reader :filename, :base_path, :params, :pages
5
5
 
6
- def initialize(content, opts={})
6
+ def initialize(content, site, opts={})
7
+ @site= site
7
8
  @content= content
8
9
  if @content.is_a? Proc
9
10
  @filename= ""
@@ -23,9 +24,13 @@ module Gumdrop
23
24
  run_dsl_from_source IO.readlines(@content.path).join('')
24
25
  end
25
26
  end
27
+
28
+ def site
29
+ @site
30
+ end
26
31
 
27
32
  def data
28
- Gumdrop.data
33
+ @site.data
29
34
  end
30
35
 
31
36
  def set(var_name, value)
@@ -40,16 +45,16 @@ module Gumdrop
40
45
  else
41
46
  "/#{@base_path}/#{name}"
42
47
  end
43
- content= GeneratedContent.new(filepath, block, opts)
48
+ content= GeneratedContent.new(filepath, block, @site, opts)
44
49
  if opts.has_key? :template and !opts[:template].nil?
45
- content.template = if Gumdrop.layouts.has_key?( opts[:template] )
46
- Gumdrop.layouts[ opts[:template] ]
50
+ content.template = if @site.layouts.has_key?( opts[:template] )
51
+ @site.layouts[ opts[:template] ]
47
52
  else
48
- Gumdrop.layouts[ "#{opts[:template]}.template" ]
53
+ @site.layouts[ "#{opts[:template]}.template" ]
49
54
  end.template
50
55
  end
51
-
52
- Gumdrop.site[content.uri]= content
56
+ @site.report "-generated: #{content.uri}", :info
57
+ @site.node_tree[content.uri]= content
53
58
  end
54
59
 
55
60
  # FIXME: Does redirect require abs-paths?
@@ -62,9 +67,9 @@ module Gumdrop
62
67
  EOF
63
68
  end
64
69
  opts[:from]= from
65
- Gumdrop.redirects << opts
70
+ @site.redirects << opts
66
71
  else
67
- Gumdrop.report "You must specify :to in a redirect", :warning
72
+ @site.report "You must specify :to in a redirect", :warning
68
73
  end
69
74
  end
70
75
 
@@ -93,7 +98,7 @@ module Gumdrop
93
98
 
94
99
  else
95
100
  # UNKNOWN Compressor type!
96
- Gumdrop.report "Unknown javascript compressor type! (#{ opts[:compressor] })", :warning
101
+ @site.report "Unknown javascript compressor type! (#{ opts[:compressor] })", :warning
97
102
  content
98
103
  end
99
104
  end
@@ -104,13 +109,13 @@ module Gumdrop
104
109
  end
105
110
  end
106
111
  if opts[:prune] and opts[:root]
107
- sp = File.expand_path( Gumdrop.config.source_dir )
112
+ sp = File.expand_path( @site.config.source_dir )
108
113
  rp = File.expand_path(opts[:root])
109
114
  relative_root = rp.gsub(sp, '')[1..-1]
110
115
  rrlen= relative_root.length - 1
111
- Gumdrop.site.keys.each do |path|
116
+ @site.node_tree.keys.each do |path|
112
117
  if path[0..rrlen] == relative_root and name != path
113
- Gumdrop.site.delete path
118
+ @site.node_tree.delete path
114
119
  end
115
120
  end
116
121
  end
@@ -131,14 +136,14 @@ module Gumdrop
131
136
  class GeneratedContent < Content
132
137
  # Nothing special, per se...
133
138
 
134
- def initialize(path, block, params={})
139
+ def initialize(path, block, site, params={})
135
140
  @content_block= block
136
- super(path, params)
141
+ super(path, site, params)
137
142
  end
138
143
 
139
- def render(ignore_layout=false, reset_context=true, locals={})
144
+ def render(context=nil, ignore_layout=false, reset_context=true, locals={})
140
145
  if @content_block.nil?
141
- super(ignore_layout, reset_context, locals)
146
+ super(context, ignore_layout, reset_context, locals)
142
147
  else
143
148
  @content_block.call
144
149
  end
@@ -1,4 +1,4 @@
1
- # Rework this to be nicer.. Extend Sintra::Base
1
+ # Rework this to be nicer.. Extend Sintra::Base?
2
2
 
3
3
  require 'sinatra/base'
4
4
  require 'logger'
@@ -6,49 +6,68 @@ require 'logger'
6
6
  module Gumdrop
7
7
 
8
8
  class Server < Sinatra::Base
9
+ site_file= Gumdrop.fetch_site_file
10
+ unless site_file.nil?
11
+ site= Site.new site_file
12
+ site.scan()
9
13
 
10
- set :port, Gumdrop.config.port if Gumdrop.config.port
14
+ set :port, site.config.server_port if site.config.server_port
15
+
16
+ if site.config.proxy_enabled
17
+ require 'gumdrop/proxy_handler'
18
+ get '/-proxy/*' do handle_proxy(params, env) end
19
+ post '/-proxy/*' do handle_proxy(params, env) end
20
+ put '/-proxy/*' do handle_proxy(params, env) end
21
+ delete '/-proxy/*' do handle_proxy(params, env) end
22
+ patch '/-proxy/*' do handle_proxy(params, env) end
23
+ options '/-proxy/*' do handle_proxy(params, env) end
24
+ site.report 'Enabled proxy at /-proxy/*', :info
25
+ end
11
26
 
27
+ get '/*' do
28
+ site.report "- - - - - - - - - - - - - - - - - - - - - - - - - - - - -"
12
29
 
13
- server_log= 'logs/server.log'
14
-
15
- # get '/' do
16
- # redirect '/index.html'
17
- # end
18
-
19
- Gumdrop.run dry_run:true, log:server_log, auto_run:true
20
-
21
- if Gumdrop.config.proxy_enabled
22
- require 'gumdrop/proxy_handler'
23
- Gumdrop.report 'Enabled proxy at /-proxy/*', :info
24
- get '/-proxy/*' do
25
- proxy_to= params[:splat][0]
26
- proxy_parts= proxy_to.split('/')
27
- host= proxy_parts.shift
28
- path_info= "/#{proxy_parts.join('/')}"
29
- #puts "HOST: #{host} PATH_INFO: #{path_info}"
30
- opts={ :to=>host, :path_info=>path_info }
31
- Gumdrop.handle_proxy opts, proxy_to, env
32
- end
33
- post '/-proxy/*' do
34
- proxy_to= params[:splat][0]
35
- proxy_parts= proxy_to.split('/')
36
- host= proxy_parts.shift
37
- path_info= "/#{proxy_parts.join('/')}"
38
- #puts "HOST: #{host} PATH_INFO: #{path_info}"
39
- opts={ :to=>host, :path_info=>path_info }
40
- Gumdrop.handle_proxy opts, proxy_to, env
41
- end
42
- delete '/-proxy/*' do
43
- proxy_to= params[:splat][0]
44
- proxy_parts= proxy_to.split('/')
45
- host= proxy_parts.shift
46
- path_info= "/#{proxy_parts.join('/')}"
47
- #puts "HOST: #{host} PATH_INFO: #{path_info}"
48
- opts={ :to=>host, :path_info=>path_info }
49
- Gumdrop.handle_proxy opts, proxy_to, env
30
+ file_path= get_content_path params[:splat].join('/'), site
31
+ site.report "[#{$$}] GET /#{params[:splat].join('/')} -> #{file_path}"
32
+ since_last_build= Time.now.to_i - site.last_run.to_i
33
+ # site.report "!>!>>>>> since_last_build: #{since_last_build}"
34
+ if since_last_build > site.config.server_timeout
35
+ site.report "[#{$$}] Rebuilding from Source (#{since_last_build} > #{site.config.server_timeout})"
36
+ site.rescan()
37
+ end
38
+
39
+ if site.node_tree.has_key? file_path
40
+ content= site.node_tree[file_path]
41
+ if content.useLayout?
42
+ site.report "[#{$$}] *Dynamic: #{file_path} (#{content.ext})"
43
+ content_type :css if content.ext == '.css' # Meh?
44
+ content_type :js if content.ext == '.js' # Meh?
45
+ content_type :xml if content.ext == '.xml' # Meh?
46
+ content.render
47
+ else
48
+ site.report "[#{$$}] *Static: #{file_path}"
49
+ send_file File.join( site.src_path, file_path)
50
+ end
51
+ else
52
+ site.report "[#{$$}] *Missing: #{file_path}", :error
53
+ "#{file_path} Not Found"
54
+ end
55
+ end
56
+
57
+ def get_content_path(file_path, site)
58
+ keys= [
59
+ file_path,
60
+ "#{file_path}.html",
61
+ "#{file_path}/index.html"
62
+ ]
63
+ if file_path == ""
64
+ "index.html"
65
+ else
66
+ keys.detect {|k| site.node_tree.has_key?(k) }
67
+ end
50
68
  end
51
- put '/-proxy/*' do
69
+
70
+ def handle_proxy(params, env)
52
71
  proxy_to= params[:splat][0]
53
72
  proxy_parts= proxy_to.split('/')
54
73
  host= proxy_parts.shift
@@ -58,76 +77,9 @@ module Gumdrop
58
77
  Gumdrop.handle_proxy opts, proxy_to, env
59
78
  end
60
79
 
61
- end
62
-
63
- get '/*' do
64
- # Gumdrop.log.info "[#{$$}] !>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
65
- file_path= get_content_path params[:splat].join('/')
66
- Gumdrop.log.info "[#{$$}] GET /#{params[:splat].join('/')} -> #{file_path}"
67
- # Gumdrop.log.info " last built: #{Gumdrop.last_run}"
68
- # Gumdrop.log.info "#{Gumdrop.config.inspect}"
69
-
70
- if Gumdrop.site.has_key? file_path
71
- content= Gumdrop.site[file_path]
72
- if content.useLayout?
73
- # Only do a force_reload if the resource is dynamic!
74
- if Gumdrop.config.force_reload
75
- unless %w(.jpg .jpe .jpeg .gif .ico .png).include? File.extname(file_path).to_s
76
- since_last_build= Time.now.to_i - Gumdrop.last_run.to_i
77
- # Gumdrop.log.info "!>!>>>>> since_last_build: #{since_last_build}"
78
- if since_last_build > 10
79
- Gumdrop.log.info "[#{$$}] Rebuilding from Source"
80
- Gumdrop.run dry_run:true, log:server_log
81
- end
82
- end
83
- end
84
- Gumdrop.log.info "[#{$$}] *Dynamic: #{file_path} (#{content.ext})"
85
- content_type :css if content.ext == '.css' # Meh?
86
- content_type :js if content.ext == '.js' # Meh?
87
- content_type :xml if content.ext == '.xml' # Meh?
88
- content.render
89
- else
90
- Gumdrop.log.info "[#{$$}] *Static: #{file_path}"
91
- source_base_path= File.expand_path(Gumdrop.config.source_dir)
92
- send_file File.join( source_base_path, file_path)
93
- end
94
- else
95
- Gumdrop.log.error "[#{$$}] *Missing: #{file_path}"
96
- # Gumdrop.log.info "------------------------"
97
- # Gumdrop.log.info Gumdrop.site.keys.join("\n")
98
- # Gumdrop.log.info "------------------------"
99
- puts "NOT FOUND: #{file_path}"
100
- "#{file_path} Not Found"
101
- end
102
- end
103
-
104
-
105
- def get_content_path(file_path)
106
- keys= [
107
- file_path,
108
- "#{file_path}.html",
109
- "#{file_path}/index.html"
110
- ]
111
- if file_path == ""
112
- "index.html"
113
- else
114
- keys.detect {|k| Gumdrop.site.has_key?(k) }
115
- end
116
- end
117
-
118
- if Gumdrop.config.auto_run
119
- #Gumdrop.run dry_run:true
120
80
  run!
121
- end
122
-
123
- def self.start(opts={})
124
- # Options
125
- opts.reverse_merge! auto_run:true, cache_data:false
126
- Gumdrop.config.merge! opts
127
- Gumdrop.run dry_run:true, log:server_log
128
- ::Gumdrop::Server
81
+ else
82
+ puts "Not in a valid Gumdrop site directory."
129
83
  end
130
-
131
84
  end
132
-
133
- end
85
+ end
@@ -0,0 +1,295 @@
1
+ require 'pathname'
2
+
3
+ # WORK IN PROGRESS!
4
+
5
+ module Gumdrop
6
+
7
+ DEFAULT_OPTIONS= {
8
+ relative_paths: true,
9
+ proxy_enabled: true,
10
+ output_dir: "./output",
11
+ source_dir: "./source",
12
+ data_dir: './data',
13
+ log: './logs/build.log',
14
+ ignore: %w(.DS_Store .gitignore .git .svn .sass-cache),
15
+ server_timeout: 15,
16
+ # server_port: 4567
17
+ }
18
+
19
+ LOG_LEVELS = {
20
+ info: 0,
21
+ warning: 1,
22
+ error: 2
23
+ }
24
+
25
+ class Site
26
+
27
+ attr_reader :opts,
28
+ :root_path,
29
+ :root_path_parts,
30
+ :src_path,
31
+ :src_path_parts,
32
+ :blacklist,
33
+ :greylist,
34
+ :redirects,
35
+ :content_filters,
36
+ :layouts,
37
+ :partials,
38
+ :generators,
39
+ :config,
40
+ :data,
41
+ :sitefile,
42
+ :node_tree,
43
+ :last_run
44
+
45
+
46
+ def initialize(sitefile, opts={})
47
+ @sitefile = File.expand_path sitefile
48
+ @root_path = File.dirname @sitefile
49
+ @root_path_parts = @root_path.split('/')
50
+ @opts = opts
51
+ reset_all()
52
+ end
53
+
54
+ def contents(pattern=nil, opts={})
55
+ if pattern.nil?
56
+ if opts[:as] == :hash
57
+ @node_tree
58
+ else
59
+ @node_tree.values
60
+ end
61
+ else
62
+ nodes = opts[:as] == :hash ? {} : []
63
+ @node_tree.keys.each do |path|
64
+ if path_match path, pattern
65
+ if opts[:as] == :hash
66
+ nodes[path]= @node_tree[path]
67
+ else
68
+ nodes << @node_tree[path]
69
+ end
70
+ end
71
+ end
72
+ nodes
73
+ end
74
+ end
75
+
76
+ def scan
77
+ build_tree()
78
+ run_generators()
79
+ @last_run= Time.now
80
+ self
81
+ end
82
+
83
+ def rescan
84
+ reset_all()
85
+ scan()
86
+ @last_run= Time.now
87
+ self
88
+ end
89
+
90
+ def build
91
+ scan()
92
+ render()
93
+ @last_run= Time.now
94
+ self
95
+ end
96
+
97
+ def report(msg, level=:info)
98
+ # ll= @config.log_level
99
+ case level
100
+ when :info
101
+ @log.info msg
102
+ when :warning
103
+ @log.warn msg
104
+ else
105
+ puts msg
106
+ @log.error msg
107
+ end
108
+ end
109
+
110
+ # FIXME: Should a new Context be created for every page? For now
111
+ # it's a single context for whole site
112
+ def render_context
113
+ @context ||= Context.new self
114
+ @context
115
+ end
116
+
117
+
118
+ private
119
+
120
+ def reset_all
121
+ @content_filters = []
122
+ @blacklist = []
123
+ @greylist = []
124
+ @redirects = []
125
+ @last_run = nil
126
+ @node_tree = Hash.new {|h,k| h[k]= nil }
127
+ @layouts = Hash.new {|h,k| h[k]= nil }
128
+ @partials = Hash.new {|h,k| h[k]= nil }
129
+ @generators = Hash.new {|h,k| h[k]= nil }
130
+ @config = Gumdrop::Config.new DEFAULT_OPTIONS
131
+
132
+ load_sitefile()
133
+
134
+ @data_path = get_expanded_path(@config.data_dir)
135
+ @data = Gumdrop::DataManager.new self, @data_path
136
+ @src_path = get_expanded_path(@config.source_dir)
137
+ @src_path_parts = @src_path.split('/')
138
+ @out_path = get_expanded_path(@config.output_dir)
139
+
140
+ init_logging()
141
+ end
142
+
143
+ def init_logging
144
+ begin
145
+ @log = Logger.new @config.log, 'daily'
146
+ rescue
147
+ @log = Logger.new STDOUT
148
+ end
149
+ @log.formatter = proc do |severity, datetime, progname, msg|
150
+ "#{datetime}: #{msg}\n"
151
+ end
152
+ end
153
+
154
+ def get_expanded_path(path)
155
+ if (Pathname.new path).absolute?
156
+ path
157
+ else
158
+ File.expand_path File.join(@root_path, path)
159
+ end
160
+ end
161
+
162
+ def load_sitefile
163
+ source= IO.readlines( @sitefile ).join('')
164
+ dsl = SitefileDSL.new self
165
+ dsl.instance_eval source
166
+ dsl
167
+ end
168
+
169
+ def build_tree
170
+ report "[Scanning from #{src_path}]", :info
171
+ # Report blacklists and greylists
172
+ blacklist.each do |path|
173
+ report " blacklist: #{path}", :info
174
+ end
175
+ greylist.each do |path|
176
+ report " greylist: #{path}", :info
177
+ end
178
+
179
+ # Scan Filesystem
180
+ #puts "Running in: #{root}"
181
+ Dir.glob("#{src_path}/**/*", File::FNM_DOTMATCH).each do |path|
182
+ unless File.directory? path or @config.ignore.include?( File.basename(path) )
183
+ file_path = (path.split('/') - @root_path_parts).join '/'
184
+ node= Content.new(file_path, self)
185
+ path= node.to_s
186
+ if blacklist.any? {|pattern| path_match path, pattern }
187
+ report "-excluding: #{path}", :info
188
+ else
189
+ node.ignored= greylist.any? {|pattern| path_match path, pattern }
190
+
191
+ # Sort out Layouts, Generators, and Partials
192
+ if File.extname(path) == ".template"
193
+ layouts[path]= node
194
+ layouts[File.basename(path)]= node
195
+
196
+ elsif File.extname(path) == ".generator"
197
+ generators[File.basename(path)]= Generator.new( node, self )
198
+
199
+ elsif File.basename(path).starts_with?("_")
200
+ partial_name= File.basename(path)[1..-1].gsub(File.extname(File.basename(path)), '')
201
+ partial_node_path= File.join File.dirname(path), partial_name
202
+ # puts "Creating partial #{partial_name} from #{path}"
203
+ partials[partial_name]= node
204
+ partials[partial_node_path]= node
205
+ else
206
+ @node_tree[path]= node
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ end
213
+
214
+ def run_generators
215
+ report "[Executing Generators]", :info
216
+ generators.each_pair do |path, generator|
217
+ generator.execute()
218
+ end
219
+ end
220
+
221
+ def render
222
+ unless opts[:dry_run]
223
+ report "[Compiling to #{@out_path}]", :info
224
+ @node_tree.keys.sort.each do |path|
225
+ node= @node_tree[path]
226
+ unless node.ignored #greylist.any? {|pattern| path_match path, pattern }
227
+ # node= @node_tree[path]
228
+ output_path= File.join(@out_path, node.to_s)
229
+ FileUtils.mkdir_p File.dirname(output_path)
230
+ node.renderTo render_context, output_path, content_filters
231
+ else
232
+ report " -ignoring: #{node.to_s}", :info
233
+ end
234
+ end
235
+ end
236
+ end
237
+
238
+ # Match a path using a glob-like file pattern
239
+ def path_match(path, pattern)
240
+ File.fnmatch pattern, path, File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_CASEFOLD
241
+ end
242
+ end
243
+
244
+ class SitefileDSL
245
+
246
+ def initialize(site)
247
+ @site= site
248
+ end
249
+
250
+ def generate(&block)
251
+ # Auto-generated, numerical, key for a site-level generator
252
+ @site.generators[@site.generators.keys.length] = Generator.new(block, @site)
253
+ end
254
+
255
+ def content_filter(&block)
256
+ @site.content_filters << block
257
+ end
258
+
259
+ def skip(path)
260
+ @site.blacklist << path
261
+ end
262
+ alias_method :blacklist, :skip
263
+
264
+ def ignore(path)
265
+ @site.greylist << path
266
+ end
267
+ alias_method :greylist, :ignore
268
+ alias_method :graylist, :ignore
269
+
270
+ def view_helpers(&block)
271
+ Gumdrop::ViewHelpers.class_eval &block
272
+ end
273
+
274
+ def configure(&block)
275
+ if block.arity > 0
276
+ block.call @site.config
277
+ else
278
+ @site.config.instance_eval &block
279
+ end
280
+ end
281
+
282
+ end
283
+
284
+ class Config < HashObject
285
+
286
+ def set(key, value)
287
+ self[key]= value
288
+ end
289
+ def get(key)
290
+ self[key]
291
+ end
292
+
293
+ end
294
+
295
+ end
@@ -1,5 +1,5 @@
1
1
  module Gumdrop
2
2
 
3
- VERSION = "0.5.2" unless defined?(::Gumdrop::VERSION)
3
+ VERSION = "0.6.0" unless defined?(::Gumdrop::VERSION)
4
4
 
5
5
  end
@@ -22,4 +22,4 @@ module Gumdrop
22
22
 
23
23
  end
24
24
 
25
- end
25
+ end