gumdrop 0.7.5 → 0.8.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.
@@ -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