gumdrop 0.7.5 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  module Gumdrop
2
2
 
3
- VERSION = "0.7.5" unless defined?(::Gumdrop::VERSION)
3
+ VERSION = "0.8.0" unless defined?(::Gumdrop::VERSION)
4
4
 
5
5
  end
data/notes.md ADDED
@@ -0,0 +1,347 @@
1
+ # General
2
+
3
+ Gumdrop is based on personal and project code from several years ago. It's been slowly updated and improved over time. But I've not been able to give it a lot of sustained effort to get it where I want it.
4
+
5
+ Since I started, Jekyl, MiddleMan, and other static site tools have been released. While they are all good in their own ways, each miss something that I want. The main difference, at this point in time, are generators. I want to have a static site, but still have data-driven pages.
6
+
7
+ Anyway, this is just a place for me to put down my thoughts on what I want to do to get it servicable as a 1.0 candidate:
8
+
9
+
10
+ # Architectural Changes
11
+
12
+ - Rendering should be abstracted from Content objects
13
+ - Building should be abstracted from Site object
14
+ - Generators should be able to unload themselves and any pages they created
15
+ - There should be discreet ways of knowing whether a Content object is renderable or not (other than file ext)
16
+ - DSL generators should accept a name, and optional base_path (applied to all generated page paths)
17
+ - Callbacks should have the site var in scope
18
+ - Reporting/logging needs to be abstracted from Site and all dependant objects (Loggable module?)
19
+ - Project Templates should be abstracted from CLI::Internal (and External) into a module
20
+ - Make `DataManager` more OO -- abstract data providers. Each provider would specifiy the file extensions they handle.
21
+ - Bundler.require site.config.env.to_sym
22
+
23
+ ## Nice to Haves
24
+
25
+ - Server should be able to selectively render individual content without rescanning/building the whole tree
26
+
27
+ # Impl Notes
28
+
29
+ ## Content
30
+
31
+ - Content objects can know their `level` based on their `full_path` (basically count the slashes)
32
+
33
+ ```rb
34
+ contentA = Content.new "source/page.html.erb"
35
+ contentB = Content.new "source/logo.png"
36
+
37
+ contentA.binary? #=> false
38
+ contentB.binary? #=> true
39
+ ```
40
+
41
+ Possible `binary?` method (from ptools):
42
+
43
+ ```rb
44
+ class Content
45
+ def initialize(source_path, generator=nil, &block)
46
+ @source_path= source_path
47
+ @filename= File.basename(source_path)
48
+ @generator=generator
49
+ @block= block
50
+ # etc...
51
+ end
52
+
53
+ def binary?(file)
54
+ @is_binary ||= begin
55
+ s = (File.read(file, File.stat(file).blksize) || "").split(//)
56
+ ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30
57
+ end
58
+ end
59
+
60
+ def generated?
61
+ !@generator.nil?
62
+ emd
63
+
64
+ def body # Memoize this?
65
+ if @block
66
+ @block.call
67
+ else
68
+ File.read @source_path
69
+ end
70
+ end
71
+ end
72
+ ```
73
+
74
+ ## Events/Observable
75
+
76
+ Use Observable internally?
77
+
78
+ ```ruby
79
+ module Eventable
80
+ include Observable
81
+
82
+ def fire(action, data={}, sender=self)
83
+ changed
84
+ notify_observers(sender, action, data)
85
+ end
86
+ end
87
+
88
+ # Usage
89
+ class MyClass
90
+ includes Eventable
91
+
92
+ def execute
93
+ fire :my_action, ex:'data'
94
+ end
95
+ end
96
+
97
+ ```
98
+
99
+ Listeners would always have the same signature:
100
+
101
+ ```ruby
102
+ class Listener
103
+ def update(sender, action, data)
104
+ puts "(#{ sender.inspect }) #{action}: #{ data.inspect }"
105
+ end
106
+ end
107
+ ```
108
+ Have the site listen and bubble the events?
109
+
110
+ ```ruby
111
+ class Site
112
+ includes Eventable
113
+
114
+ def # wherever
115
+ renderer= HtmlRenderer.new
116
+ renderer.add_observer self
117
+ renderer.draw # whatever
118
+
119
+ #done
120
+ renderer.delete_observers
121
+ end
122
+
123
+ def update(sender, action, data)
124
+ fire action, data, sender
125
+ end
126
+ end
127
+ ```
128
+
129
+ ## Rendering
130
+
131
+ ```rb
132
+
133
+ class RenderContext
134
+ include ViewHelpers
135
+
136
+ attr_reader :content, :site, :state
137
+ # attr_writer :content, :renderer
138
+
139
+ def initialize(content, renderer, parent_context=nil)
140
+ @content= content
141
+ @renderer= renderer
142
+ @site= renderer.site
143
+ @state= {}
144
+ @parent= parent_context
145
+ end
146
+
147
+ def render(*args) # Not exactly sure yet
148
+ content= # extract/lookup a content object from args
149
+ # maybe allow relative lookups from content?
150
+ @renderer.draw_partial content
151
+ end
152
+
153
+ def get(key)
154
+ @state[key]
155
+ end
156
+
157
+ def set(key, value)
158
+ @state[key]= value
159
+ end
160
+
161
+ def method_missing(*stuff)
162
+ # try to get/set from @state
163
+ # else try to get from @parent unless @parent.nil?
164
+ # else try and get it from @content
165
+ # else return nil ???
166
+ end
167
+ end
168
+
169
+ class Renderer
170
+ includes Eventable
171
+
172
+ attr_reader :site, :context
173
+
174
+ def initialize(site)
175
+ @site= site
176
+ end
177
+
178
+ def draw(content, opts={})
179
+ return nil if content.binary?
180
+ @context= RenderContext.new site, content, self
181
+ output= _render_content content, opts
182
+ fire :render, content:content, output:output
183
+ output
184
+ end
185
+
186
+ def draw_partial(content, opts={})
187
+ return nil if content.binary?
188
+ opts.defaults! no_layout:true
189
+ _sub_context content
190
+ output= _render_content content, opts
191
+ fire :render_partial, content:content, output:output
192
+ _revert_context
193
+ output
194
+ end
195
+
196
+ private
197
+
198
+ def _render_content(content, opts)
199
+ output= content.body
200
+ _render_pipeline(content.filename).each do |template|
201
+ output= _render_text output, template
202
+ end
203
+ output- _render_layout output unless opts[:no_layout]
204
+ output
205
+ end
206
+
207
+ def _render_text(text, tmpl, opts)
208
+ # Tilt Code
209
+ tmpl.new(opts).render(text) # pass opts on through?
210
+ end
211
+
212
+ def _render_layout(text)
213
+ # Look for @context[:layout] or site.config.default_template
214
+ end
215
+
216
+ def _render_pipeline(path)
217
+ # path.split('.') # then sort out how to:
218
+ # return an array of Tilt templates based on file exts
219
+ []
220
+ end
221
+
222
+ def _sub_context(content)
223
+ @old_context= @context
224
+ @context= Context.new site, content, self, @old_context
225
+ end
226
+
227
+ def _revert_context
228
+ @context = @old_context
229
+ end
230
+ end
231
+
232
+
233
+ ```
234
+
235
+ ## Building
236
+
237
+ ```ruby
238
+ class Builder
239
+ include Eventable
240
+
241
+ attr_accessor :site, :renderer
242
+
243
+ def initialize(site=nil, renderer=nil)
244
+ @site= site
245
+ @renderer= renderer.nil? ? Renderer.new(site) : renderer
246
+ end
247
+
248
+ def execute()
249
+ fire :build_start
250
+ site.contents.each do |content|
251
+ if content.binary?
252
+ _copy content.src_path => _output_path(content)
253
+ else
254
+ output = renderer.draw content
255
+ _write output => _output_path(content)
256
+ end
257
+ end
258
+ fire :build_end
259
+ rescue => ex
260
+ fire :exception, source:self, ex:ex
261
+ end
262
+
263
+ private
264
+
265
+ def _copy(files)
266
+ files.each_pair do |from,to|
267
+ # File.write code
268
+ fire :copy, from:from, to:to
269
+ end
270
+ end
271
+
272
+ def _write(files)
273
+ files.each_pair do |text,to|
274
+ # File.write code
275
+ fire :write, from:from, to:to
276
+ end
277
+ end
278
+ end
279
+
280
+
281
+ # Usage
282
+ site= Gumdrop.local_site #=> Site
283
+ renderer= HtmlRenderer.new
284
+ builder= Builder.new site, renderer
285
+ builder.execute()
286
+ ```
287
+
288
+ # Logging via Events?
289
+
290
+ - Only two levels? `:info` and `:warn`? Or add `:error`
291
+
292
+ ```ruby
293
+ # Mixin to your class:
294
+ module Loggable
295
+
296
+ # Assumes Eventable? or:
297
+ # include Eventable
298
+
299
+ def log(level, msg=nil)
300
+ if msg.nil?
301
+ msg= level
302
+ level= :info
303
+ end
304
+ fire :log, level:level, message:msg
305
+ end
306
+
307
+ def warn(msg)
308
+ log :warn, msg
309
+ end
310
+
311
+ end
312
+
313
+ # Loggers
314
+ class ConsoleLogger
315
+ def initialize(levels, format='%<level>s : %<message>s')
316
+ @listen_for= levels
317
+ @format= format
318
+ end
319
+ def update(sender, action, data)
320
+ if action == :log
321
+ if @listen_for.include? data.level
322
+ data[:sender]= sender.to_s
323
+ data[:time]= Time.new
324
+ puts sprintf(@format, data)
325
+ end
326
+ end
327
+ end
328
+ end
329
+ ```
330
+
331
+ Or maybe not... I think maybe this:
332
+
333
+ ```ruby
334
+ module Loggable
335
+ def log
336
+ Gumdrop.logger
337
+ end
338
+ end
339
+
340
+ module Gumdrop
341
+ class << self
342
+ attr_accessor :logger
343
+ end
344
+ end
345
+ ```
346
+
347
+
@@ -1,7 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gem "i18n"
4
- gem "sinatra"
4
+ gem "sinatra", :require=>false
5
5
  gem "active_support"
6
6
 
7
7
  gem "rake"
@@ -1,4 +1,3 @@
1
- puts "Gumdrop v#{Gumdrop::VERSION} building..."
2
1
 
3
2
  configure do
4
3
 
@@ -80,6 +79,12 @@ generate do
80
79
 
81
80
  end
82
81
 
82
+ # All Gumdrop Hooks: on_start, on_before_scan, on_scan, on_before_generate, on_generate, on_before_render, on_render, on_end
83
+ on_start do |site|
84
+ puts "Gumdrop v#{Gumdrop::VERSION} building..."
85
+ end
86
+ # on_end do |site| end
87
+
83
88
  # Example of using a content filter to compress CSS output
84
89
  # require 'yui/compressor'
85
90
  # content_filter do |content, info|
@@ -1,9 +1,9 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gem "i18n"
4
- gem "sinatra"
4
+ gem "sinatra", :require=>false
5
5
  gem "active_support"
6
- gem "rake"
6
+ gem "thor", :require=>false
7
7
  gem "gumdrop"
8
8
 
9
9
  # Add your dependencies here:
@@ -1,4 +1,3 @@
1
- puts "Gumdrop v#{Gumdrop::VERSION} building..."
2
1
 
3
2
  configure do
4
3
 
@@ -14,6 +13,10 @@ configure do
14
13
  # set :server_timeout, 15
15
14
  # set :server_port, 4567
16
15
 
16
+ # set :server, "REMOTE_USERNAME"
17
+ # set :server_user, 'server.com'
18
+ # set :server_path, '~/server.com'
19
+
17
20
  end
18
21
 
19
22
 
@@ -89,7 +92,9 @@ end
89
92
  # end
90
93
 
91
94
  # All Gumdrop Hooks: on_start, on_before_scan, on_scan, on_before_generate, on_generate, on_before_render, on_render, on_end
92
- # on_start do |site| end
95
+ on_start do |site|
96
+ puts "Gumdrop v#{Gumdrop::VERSION} building..."
97
+ end
93
98
  # on_end do |site| end
94
99
 
95
100
 
@@ -112,6 +117,24 @@ view_helpers do
112
117
 
113
118
  end
114
119
 
120
+ # Add (thor) tasks to gumdrop command
121
+ # for more: https://github.com/wycats/thor/wiki
122
+ # tasks do
123
+
124
+ # desc 'sync', "Syncs with public server using rsync (if configured)"
125
+ # method_option :build, :aliases => '-b', :desc => 'Build content before syncing'
126
+ # method_option :dry_run, :aliases => '-d', :desc => 'Dry run'
127
+ # def sync
128
+ # SITE.build if options[:build]
129
+ # config= SITE.config
130
+ # output= SITE.config.output_dir
131
+ # cmd= "rsync -avz --delete #{output} #{config.server_user}@#{config.server}:#{config.server_path}"
132
+ # puts "Running:\n#{cmd}\n"
133
+ # system(cmd) unless options[:dry_run]
134
+ # end
135
+
136
+ # end
137
+
115
138
  # Any specialized code for your site goes here...
116
139
 
117
140
  # require 'slim'
@@ -1,9 +1,9 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gem "i18n"
4
- gem "sinatra"
4
+ gem "sinatra", :require=>false
5
5
  gem "active_support"
6
-
6
+ gem "thor", :require=>false
7
7
  gem "rake"
8
8
  gem "gumdrop"
9
9