TwP-webby 0.9.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.
- data/History.txt +176 -0
- data/Manifest.txt +173 -0
- data/README.txt +92 -0
- data/Rakefile +50 -0
- data/bin/webby +8 -0
- data/bin/webby-gen +8 -0
- data/examples/blog/Sitefile +7 -0
- data/examples/blog/tasks/blog.rake +72 -0
- data/examples/blog/templates/atom_feed.erb +40 -0
- data/examples/blog/templates/blog/month.erb +22 -0
- data/examples/blog/templates/blog/post.erb +16 -0
- data/examples/blog/templates/blog/year.erb +22 -0
- data/examples/presentation/Sitefile +10 -0
- data/examples/presentation/content/css/uv/twilight.css +137 -0
- data/examples/presentation/content/presentation/_sample_code.txt +10 -0
- data/examples/presentation/content/presentation/index.txt +63 -0
- data/examples/presentation/content/presentation/s5/blank.gif +0 -0
- data/examples/presentation/content/presentation/s5/bodybg.gif +0 -0
- data/examples/presentation/content/presentation/s5/framing.css +23 -0
- data/examples/presentation/content/presentation/s5/iepngfix.htc +42 -0
- data/examples/presentation/content/presentation/s5/opera.css +7 -0
- data/examples/presentation/content/presentation/s5/outline.css +15 -0
- data/examples/presentation/content/presentation/s5/pretty.css +86 -0
- data/examples/presentation/content/presentation/s5/print.css +1 -0
- data/examples/presentation/content/presentation/s5/s5-core.css +9 -0
- data/examples/presentation/content/presentation/s5/slides.css +3 -0
- data/examples/presentation/content/presentation/s5/slides.js +553 -0
- data/examples/presentation/layouts/presentation.txt +43 -0
- data/examples/presentation/templates/_code_partial.erb +13 -0
- data/examples/presentation/templates/presentation.erb +40 -0
- data/examples/tumblog/Sitefile +9 -0
- data/examples/tumblog/content/css/tumblog.css +308 -0
- data/examples/tumblog/content/images/tumblog/permalink.gif +0 -0
- data/examples/tumblog/content/images/tumblog/rss.gif +0 -0
- data/examples/tumblog/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
- data/examples/tumblog/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
- data/examples/tumblog/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
- data/examples/tumblog/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
- data/examples/tumblog/content/tumblog/200807/up-a-tree/index.txt +13 -0
- data/examples/tumblog/content/tumblog/index.txt +37 -0
- data/examples/tumblog/content/tumblog/rss.txt +37 -0
- data/examples/tumblog/layouts/tumblog/default.txt +44 -0
- data/examples/tumblog/layouts/tumblog/post.txt +15 -0
- data/examples/tumblog/lib/tumblog_helper.rb +32 -0
- data/examples/tumblog/tasks/tumblog.rake +30 -0
- data/examples/tumblog/templates/atom_feed.erb +40 -0
- data/examples/tumblog/templates/tumblog/conversation.erb +12 -0
- data/examples/tumblog/templates/tumblog/link.erb +10 -0
- data/examples/tumblog/templates/tumblog/photo.erb +13 -0
- data/examples/tumblog/templates/tumblog/post.erb +12 -0
- data/examples/tumblog/templates/tumblog/quote.erb +11 -0
- data/examples/webby/Sitefile +19 -0
- data/examples/webby/content/communicate/index.txt +28 -0
- data/examples/webby/content/css/background.gif +0 -0
- data/examples/webby/content/css/blueprint/print.css +76 -0
- data/examples/webby/content/css/blueprint/screen.css +696 -0
- data/examples/webby/content/css/coderay.css +96 -0
- data/examples/webby/content/css/site.css +196 -0
- data/examples/webby/content/css/uv/twilight.css +137 -0
- data/examples/webby/content/index.txt +37 -0
- data/examples/webby/content/learn/index.txt +28 -0
- data/examples/webby/content/reference/index.txt +204 -0
- data/examples/webby/content/release-notes/rel-0-9-0/index.txt +73 -0
- data/examples/webby/content/robots.txt +6 -0
- data/examples/webby/content/script/jquery.corner.js +152 -0
- data/examples/webby/content/script/jquery.js +31 -0
- data/examples/webby/content/sitemap.txt +31 -0
- data/examples/webby/content/tips_and_tricks/index.txt +96 -0
- data/examples/webby/content/tutorial/index.txt +131 -0
- data/examples/webby/content/user-manual/index.txt +419 -0
- data/examples/webby/layouts/default.txt +49 -0
- data/examples/webby/templates/page.erb +10 -0
- data/examples/website/Sitefile +7 -0
- data/examples/website/content/css/blueprint/License.txt +21 -0
- data/examples/website/content/css/blueprint/Readme.txt +100 -0
- data/examples/website/content/css/blueprint/compressed/print.css +76 -0
- data/examples/website/content/css/blueprint/compressed/screen.css +696 -0
- data/examples/website/content/css/blueprint/lib/forms.css +45 -0
- data/examples/website/content/css/blueprint/lib/grid.css +193 -0
- data/examples/website/content/css/blueprint/lib/grid.png +0 -0
- data/examples/website/content/css/blueprint/lib/ie.css +30 -0
- data/examples/website/content/css/blueprint/lib/reset.css +39 -0
- data/examples/website/content/css/blueprint/lib/typography.css +116 -0
- data/examples/website/content/css/blueprint/plugins/buttons/Readme +31 -0
- data/examples/website/content/css/blueprint/plugins/buttons/buttons.css +97 -0
- data/examples/website/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
- data/examples/website/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
- data/examples/website/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
- data/examples/website/content/css/blueprint/plugins/css-classes/Readme +14 -0
- data/examples/website/content/css/blueprint/plugins/css-classes/css-classes.css +24 -0
- data/examples/website/content/css/blueprint/plugins/fancy-type/Readme +22 -0
- data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +5 -0
- data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type.css +74 -0
- data/examples/website/content/css/blueprint/print.css +68 -0
- data/examples/website/content/css/blueprint/screen.css +22 -0
- data/examples/website/content/css/coderay.css +111 -0
- data/examples/website/content/css/site.css +67 -0
- data/examples/website/content/index.txt +19 -0
- data/examples/website/layouts/default.txt +58 -0
- data/examples/website/lib/breadcrumbs.rb +28 -0
- data/examples/website/templates/_partial.erb +10 -0
- data/examples/website/templates/page.erb +18 -0
- data/examples/website/templates/presentation.erb +40 -0
- data/lib/webby/apps/generator.rb +283 -0
- data/lib/webby/apps/main.rb +221 -0
- data/lib/webby/apps.rb +12 -0
- data/lib/webby/auto_builder.rb +83 -0
- data/lib/webby/builder.rb +183 -0
- data/lib/webby/core_ext/enumerable.rb +11 -0
- data/lib/webby/core_ext/hash.rb +28 -0
- data/lib/webby/core_ext/kernel.rb +21 -0
- data/lib/webby/core_ext/string.rb +163 -0
- data/lib/webby/core_ext/time.rb +9 -0
- data/lib/webby/filters/basepath.rb +97 -0
- data/lib/webby/filters/erb.rb +9 -0
- data/lib/webby/filters/haml.rb +18 -0
- data/lib/webby/filters/markdown.rb +16 -0
- data/lib/webby/filters/outline.rb +309 -0
- data/lib/webby/filters/sass.rb +17 -0
- data/lib/webby/filters/slides.rb +56 -0
- data/lib/webby/filters/textile.rb +16 -0
- data/lib/webby/filters/tidy.rb +76 -0
- data/lib/webby/filters.rb +91 -0
- data/lib/webby/helpers/capture_helper.rb +141 -0
- data/lib/webby/helpers/coderay_helper.rb +69 -0
- data/lib/webby/helpers/graphviz_helper.rb +136 -0
- data/lib/webby/helpers/tag_helper.rb +65 -0
- data/lib/webby/helpers/tex_img_helper.rb +133 -0
- data/lib/webby/helpers/ultraviolet_helper.rb +63 -0
- data/lib/webby/helpers/url_helper.rb +235 -0
- data/lib/webby/helpers.rb +30 -0
- data/lib/webby/link_validator.rb +152 -0
- data/lib/webby/renderer.rb +379 -0
- data/lib/webby/resources/db.rb +251 -0
- data/lib/webby/resources/file.rb +221 -0
- data/lib/webby/resources/layout.rb +63 -0
- data/lib/webby/resources/page.rb +118 -0
- data/lib/webby/resources/partial.rb +79 -0
- data/lib/webby/resources/resource.rb +160 -0
- data/lib/webby/resources/static.rb +52 -0
- data/lib/webby/resources.rb +96 -0
- data/lib/webby/stelan/mktemp.rb +135 -0
- data/lib/webby/stelan/paginator.rb +150 -0
- data/lib/webby/stelan/spawner.rb +339 -0
- data/lib/webby/tasks/build.rake +27 -0
- data/lib/webby/tasks/create.rake +22 -0
- data/lib/webby/tasks/deploy.rake +22 -0
- data/lib/webby/tasks/growl.rake +15 -0
- data/lib/webby/tasks/heel.rake +28 -0
- data/lib/webby/tasks/validate.rake +19 -0
- data/lib/webby.rb +227 -0
- data/spec/core_ext/hash_spec.rb +47 -0
- data/spec/core_ext/string_spec.rb +110 -0
- data/spec/core_ext/time_spec.rb +19 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/webby/apps/generator_spec.rb +111 -0
- data/spec/webby/apps/main_spec.rb +75 -0
- data/spec/webby/helpers/capture_helper_spec.rb +56 -0
- data/spec/webby/resources/file_spec.rb +104 -0
- data/spec/webby/resources_spec.rb +17 -0
- data/tasks/ann.rake +81 -0
- data/tasks/bones.rake +21 -0
- data/tasks/gem.rake +126 -0
- data/tasks/git.rake +41 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/notes.rake +28 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +268 -0
- data/tasks/spec.rake +55 -0
- data/tasks/website.rake +38 -0
- metadata +289 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
require 'rbconfig'
|
|
2
|
+
require 'thread'
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
|
|
5
|
+
# :stopdoc:
|
|
6
|
+
|
|
7
|
+
# == Synopsis
|
|
8
|
+
#
|
|
9
|
+
# A class for spawning child processes and ensuring those children continue
|
|
10
|
+
# running.
|
|
11
|
+
#
|
|
12
|
+
# == Details
|
|
13
|
+
#
|
|
14
|
+
# When a spawner is created it is given the command to run in a child
|
|
15
|
+
# process. This child process has +stdin+, +stdout+, and +stderr+ redirected
|
|
16
|
+
# to +/dev/null+ (this works even on Windows). When the child dies for any
|
|
17
|
+
# reason, the spawner will restart a new child process in the exact same
|
|
18
|
+
# manner as the original.
|
|
19
|
+
#
|
|
20
|
+
class Spawner
|
|
21
|
+
|
|
22
|
+
@dev_null = test(?e, "/dev/null") ? "/dev/null" : "NUL:"
|
|
23
|
+
|
|
24
|
+
c = ::Config::CONFIG
|
|
25
|
+
ruby = File.join(c['bindir'], c['ruby_install_name']) << c['EXEEXT']
|
|
26
|
+
@ruby = if system('%s -e exit' % ruby) then ruby
|
|
27
|
+
elsif system('ruby -e exit') then 'ruby'
|
|
28
|
+
else warn 'no ruby in PATH/CONFIG'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class << self
|
|
32
|
+
attr_reader :ruby
|
|
33
|
+
attr_reader :dev_null
|
|
34
|
+
|
|
35
|
+
def finalizer( cids )
|
|
36
|
+
pid = $$
|
|
37
|
+
lambda do
|
|
38
|
+
break unless pid == $$
|
|
39
|
+
cids.kill 'TERM', :all
|
|
40
|
+
end # lambda
|
|
41
|
+
end # finalizer
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# call-seq:
|
|
45
|
+
# Spawner.new( command, *args, opts = {} )
|
|
46
|
+
#
|
|
47
|
+
# Creates a new spawner that will execute the given external _command_ in
|
|
48
|
+
# a sub-process. The calling semantics of <code>Kernel::exec</code> are
|
|
49
|
+
# used to execute the _command_. Any number of optional _args_ can be
|
|
50
|
+
# passed to the _command_.
|
|
51
|
+
#
|
|
52
|
+
# Available options:
|
|
53
|
+
#
|
|
54
|
+
# :spawn => the number of child processes to spawn
|
|
55
|
+
# :pause => wait time (in seconds) before respawning after termination
|
|
56
|
+
# :ruby => the Ruby interpreter to use when spawning children
|
|
57
|
+
# :env => a hash for the child process environment
|
|
58
|
+
# :stdin => stdin child processes will read from
|
|
59
|
+
# :stdout => stdout child processes will write to
|
|
60
|
+
# :stderr => stderr child processes will write to
|
|
61
|
+
#
|
|
62
|
+
# The <code>:env</code> option is used to add environemnt variables to
|
|
63
|
+
# child processes when they are spawned.
|
|
64
|
+
#
|
|
65
|
+
# *Note:* all spawned child processes will use the same stdin, stdout, and
|
|
66
|
+
# stderr if they are given in the options. Otherwise they all default to
|
|
67
|
+
# <code>/dev/null</code> on *NIX and <code>NUL:</code> on Windows.
|
|
68
|
+
#
|
|
69
|
+
def initialize( *args )
|
|
70
|
+
config = {
|
|
71
|
+
:ruby => self.class.ruby,
|
|
72
|
+
:spawn => 1,
|
|
73
|
+
:pause => 0,
|
|
74
|
+
:stdin => self.class.dev_null,
|
|
75
|
+
:stdout => self.class.dev_null,
|
|
76
|
+
:stderr => self.class.dev_null
|
|
77
|
+
}
|
|
78
|
+
config.merge! args.pop if Hash === args.last
|
|
79
|
+
config[:argv] = args
|
|
80
|
+
|
|
81
|
+
raise ArgumentError, 'wrong number of arguments' if args.empty?
|
|
82
|
+
|
|
83
|
+
@stop = true
|
|
84
|
+
@cids = []
|
|
85
|
+
@group = ThreadGroup.new
|
|
86
|
+
|
|
87
|
+
@spawn = config.delete(:spawn)
|
|
88
|
+
@pause = config.delete(:pause)
|
|
89
|
+
@ruby = config.delete(:ruby)
|
|
90
|
+
|
|
91
|
+
@tmp = child_program(config)
|
|
92
|
+
|
|
93
|
+
class << @cids
|
|
94
|
+
# call-seq:
|
|
95
|
+
# sync {block}
|
|
96
|
+
#
|
|
97
|
+
# Executes the given block in a synchronized fashion -- i.e. only a
|
|
98
|
+
# single thread can execute at a time. Uses Mutex under the hood.
|
|
99
|
+
#
|
|
100
|
+
def sync(&b)
|
|
101
|
+
@mutex ||= Mutex.new
|
|
102
|
+
@mutex.synchronize(&b)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# call-seq:
|
|
106
|
+
# kill( signal, num ) => number killed
|
|
107
|
+
# kill( signal, :all ) => number killed
|
|
108
|
+
#
|
|
109
|
+
# Send the _signal_ to a given _num_ of child processes or all child
|
|
110
|
+
# processes if <code>:all</code> is given instead of a number. Returns
|
|
111
|
+
# the number of child processes killed.
|
|
112
|
+
#
|
|
113
|
+
def kill( signal, arg )
|
|
114
|
+
return if empty?
|
|
115
|
+
|
|
116
|
+
ary = sync do
|
|
117
|
+
case arg
|
|
118
|
+
when :all; self.dup
|
|
119
|
+
when Integer; self.slice(0,arg)
|
|
120
|
+
else raise ArgumentError end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
ary.each do |cid|
|
|
124
|
+
begin
|
|
125
|
+
Process.kill(signal, cid)
|
|
126
|
+
rescue SystemCallError
|
|
127
|
+
sync {delete cid}
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
ary.length
|
|
131
|
+
end # def kill
|
|
132
|
+
end # class << @cids
|
|
133
|
+
|
|
134
|
+
end # def initialize
|
|
135
|
+
|
|
136
|
+
attr_reader :spawn
|
|
137
|
+
attr_accessor :pause
|
|
138
|
+
|
|
139
|
+
# call-seq:
|
|
140
|
+
# spawner.spawn = num
|
|
141
|
+
#
|
|
142
|
+
# Set the number of child processes to spawn. If the new spawn number is
|
|
143
|
+
# less than the current number, then spawner threads will die
|
|
144
|
+
#
|
|
145
|
+
def spawn=( num )
|
|
146
|
+
num = num.abs
|
|
147
|
+
diff, @spawn = num - @spawn, num
|
|
148
|
+
return unless running?
|
|
149
|
+
|
|
150
|
+
if diff > 0
|
|
151
|
+
diff.times {_spawn}
|
|
152
|
+
elsif diff < 0
|
|
153
|
+
@cids.kill 'TERM', diff.abs
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# call-seq:
|
|
158
|
+
# start => self
|
|
159
|
+
#
|
|
160
|
+
# Spawn the sub-processes.
|
|
161
|
+
#
|
|
162
|
+
def start
|
|
163
|
+
return self if running?
|
|
164
|
+
@stop = false
|
|
165
|
+
|
|
166
|
+
@cleanup = Spawner.finalizer(@cids)
|
|
167
|
+
ObjectSpace.define_finalizer(self, @cleanup)
|
|
168
|
+
|
|
169
|
+
@spawn.times {_spawn}
|
|
170
|
+
self
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# call-seq:
|
|
174
|
+
# stop( timeout = 5 ) => self
|
|
175
|
+
#
|
|
176
|
+
# Stop any spawned sub-processes.
|
|
177
|
+
#
|
|
178
|
+
def stop( timeout = 5 )
|
|
179
|
+
return self unless running?
|
|
180
|
+
@stop = true
|
|
181
|
+
|
|
182
|
+
@cleanup.call
|
|
183
|
+
ObjectSpace.undefine_finalizer(self)
|
|
184
|
+
|
|
185
|
+
# the cleanup call sends SIGTERM to all the child processes
|
|
186
|
+
# however, some might still be hanging around, so we are going to wait
|
|
187
|
+
# for a timeout interval and then send a SIGKILL to any remaining child
|
|
188
|
+
# processes
|
|
189
|
+
nap_time = 0.05 * timeout # sleep for 5% of the timeout interval
|
|
190
|
+
timeout = Time.now + timeout
|
|
191
|
+
|
|
192
|
+
until @cids.empty?
|
|
193
|
+
sleep nap_time
|
|
194
|
+
unless Time.now < timeout
|
|
195
|
+
@cids.kill 'KILL', :all
|
|
196
|
+
@cids.clear
|
|
197
|
+
@group.list.each {|t| t.kill}
|
|
198
|
+
break
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
self
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# call-seq:
|
|
206
|
+
# restart( timeout = 5 )
|
|
207
|
+
#
|
|
208
|
+
def restart( timeout = 5 )
|
|
209
|
+
stop( timeout )
|
|
210
|
+
start
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# call-seq:
|
|
214
|
+
# running?
|
|
215
|
+
#
|
|
216
|
+
# Returns +true+ if the spawner is currently running; returns +false+
|
|
217
|
+
# otherwise.
|
|
218
|
+
#
|
|
219
|
+
def running?
|
|
220
|
+
!@stop
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# call-seq:
|
|
224
|
+
# join( timeout = nil ) => spawner or nil
|
|
225
|
+
#
|
|
226
|
+
# The calling thread will suspend execution until all child processes have
|
|
227
|
+
# been stopped. Does not return until all spawner threads have exited (the
|
|
228
|
+
# child processes have been stopped) or until _timeout seconds have
|
|
229
|
+
# passed. If the timeout expires +nil+ will be returned; otherwise the
|
|
230
|
+
# spawner is returned.
|
|
231
|
+
#
|
|
232
|
+
def join( limit = nil )
|
|
233
|
+
loop do
|
|
234
|
+
t = @group.list.first
|
|
235
|
+
break if t.nil?
|
|
236
|
+
return nil unless t.join(limit)
|
|
237
|
+
end
|
|
238
|
+
self
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
private
|
|
243
|
+
|
|
244
|
+
# call-seq:
|
|
245
|
+
# _spawn => thread
|
|
246
|
+
#
|
|
247
|
+
# Creates a thread that will spawn the sub-process via
|
|
248
|
+
# <code>IO::popen</code>. If the sub-process terminates, it will be
|
|
249
|
+
# respawned until the +stop+ message is sent to this spawner.
|
|
250
|
+
#
|
|
251
|
+
# If an Exception is encountered during the spawning process, a message
|
|
252
|
+
# will be printed to stderr and the thread will exit.
|
|
253
|
+
#
|
|
254
|
+
def _spawn
|
|
255
|
+
t = Thread.new do
|
|
256
|
+
catch(:die) do
|
|
257
|
+
loop do
|
|
258
|
+
begin
|
|
259
|
+
io = IO.popen("#{@ruby} #{@tmp.path}", 'r')
|
|
260
|
+
cid = io.gets.to_i
|
|
261
|
+
|
|
262
|
+
@cids.sync {@cids << cid} if cid > 0
|
|
263
|
+
Process.wait cid
|
|
264
|
+
rescue Exception => e
|
|
265
|
+
STDERR.puts e.inspect
|
|
266
|
+
STDERR.puts e.backtrace.join("\n")
|
|
267
|
+
throw :die
|
|
268
|
+
ensure
|
|
269
|
+
io.close rescue nil
|
|
270
|
+
@cids.sync {
|
|
271
|
+
@cids.delete cid
|
|
272
|
+
throw :die unless @cids.length < @spawn
|
|
273
|
+
}
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
throw :die if @stop
|
|
277
|
+
sleep @pause
|
|
278
|
+
|
|
279
|
+
end # loop
|
|
280
|
+
end # catch(:die)
|
|
281
|
+
end # Thread.new
|
|
282
|
+
|
|
283
|
+
@group.add t
|
|
284
|
+
t
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
# call-seq:
|
|
288
|
+
# child_program( config ) => tempfile
|
|
289
|
+
#
|
|
290
|
+
# Creates a child Ruby program based on the given _config_ hash. The
|
|
291
|
+
# following hash keys are used:
|
|
292
|
+
#
|
|
293
|
+
# :argv => command and arguments passed to <code>Kernel::exec</code>
|
|
294
|
+
# :env => environment variables for the child process
|
|
295
|
+
# :cwd => the current working directory to use for the child process
|
|
296
|
+
# :stdin => stdin the child process will read from
|
|
297
|
+
# :stdout => stdout the child process will write to
|
|
298
|
+
# :stderr => stderr the child process will write to
|
|
299
|
+
#
|
|
300
|
+
def child_program( config )
|
|
301
|
+
config = Marshal.dump(config)
|
|
302
|
+
|
|
303
|
+
tmp = Tempfile.new(self.class.name.downcase)
|
|
304
|
+
tmp.write <<-PROG
|
|
305
|
+
begin
|
|
306
|
+
config = Marshal.load(#{config.inspect})
|
|
307
|
+
|
|
308
|
+
argv = config[:argv]
|
|
309
|
+
env = config[:env]
|
|
310
|
+
cwd = config[:cwd]
|
|
311
|
+
stdin = config[:stdin]
|
|
312
|
+
stdout = config[:stdout]
|
|
313
|
+
stderr = config[:stderr]
|
|
314
|
+
|
|
315
|
+
Dir.chdir cwd if cwd
|
|
316
|
+
env.each {|k,v| ENV[k.to_s] = v.to_s} if env
|
|
317
|
+
rescue Exception => e
|
|
318
|
+
STDERR.warn e
|
|
319
|
+
abort
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
STDOUT.puts Process.pid
|
|
323
|
+
STDOUT.flush
|
|
324
|
+
|
|
325
|
+
STDIN.reopen stdin
|
|
326
|
+
STDOUT.reopen stdout
|
|
327
|
+
STDERR.reopen stderr
|
|
328
|
+
|
|
329
|
+
exec *argv
|
|
330
|
+
PROG
|
|
331
|
+
|
|
332
|
+
tmp.close
|
|
333
|
+
tmp
|
|
334
|
+
end
|
|
335
|
+
end # class Spawner
|
|
336
|
+
|
|
337
|
+
# :startdoc:
|
|
338
|
+
|
|
339
|
+
# EOF
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
task :configure_basepath do
|
|
3
|
+
Webby.site.base = ENV['BASE'] if ENV.has_key?('BASE')
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
desc "Build the website"
|
|
7
|
+
task :build => :configure_basepath do |t|
|
|
8
|
+
Webby::Builder.run
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
desc "Rebuild the website"
|
|
12
|
+
task :rebuild => :configure_basepath do |t|
|
|
13
|
+
Webby::Builder.run :rebuild => true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
desc "Continuously build the website"
|
|
17
|
+
task :autobuild => :configure_basepath do |t|
|
|
18
|
+
Webby::AutoBuilder.run
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
desc "Delete the website"
|
|
22
|
+
task :clobber do |t|
|
|
23
|
+
rm_rf Webby.site.output_dir
|
|
24
|
+
mkdir Webby.site.output_dir
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# EOF
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
namespace :create do
|
|
3
|
+
|
|
4
|
+
FileList["#{Webby.site.template_dir}/*"].each do |template|
|
|
5
|
+
next unless test(?f, template)
|
|
6
|
+
name = template.pathmap '%n'
|
|
7
|
+
|
|
8
|
+
# if the file is a partial template
|
|
9
|
+
name = $1 if name =~ %r/^_(.*)/
|
|
10
|
+
|
|
11
|
+
desc "Create a new #{name}"
|
|
12
|
+
task name do |t|
|
|
13
|
+
page, title, dir = Webby::Builder.new_page_info
|
|
14
|
+
page = Webby::Builder.create(page, :from => template,
|
|
15
|
+
:locals => {:title => title, :directory => dir})
|
|
16
|
+
exec(::Webby.editor, page) unless ::Webby.editor.nil?
|
|
17
|
+
end
|
|
18
|
+
end # each
|
|
19
|
+
|
|
20
|
+
end # namespace :create
|
|
21
|
+
|
|
22
|
+
# EOF
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
require 'rake/contrib/sshpublisher'
|
|
3
|
+
|
|
4
|
+
namespace :deploy do
|
|
5
|
+
|
|
6
|
+
desc 'Deploy to the server using rsync'
|
|
7
|
+
task :rsync do
|
|
8
|
+
cmd = "rsync #{SITE.rsync_args.join(' ')} "
|
|
9
|
+
cmd << "#{SITE.output_dir}/ #{SITE.user}@#{SITE.host}:#{SITE.remote_dir}"
|
|
10
|
+
sh cmd
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc 'Deploy to the server using ssh'
|
|
14
|
+
task :ssh do
|
|
15
|
+
Rake::SshDirPublisher.new(
|
|
16
|
+
"#{SITE.user}@#{SITE.host}", SITE.remote_dir, SITE.output_dir
|
|
17
|
+
).upload
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end # deploy
|
|
21
|
+
|
|
22
|
+
# EOF
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
unless WINDOWS
|
|
3
|
+
|
|
4
|
+
task :growl do
|
|
5
|
+
Logging::Logger['Webby'].add_appenders(Logging::Appenders::Growl.new(
|
|
6
|
+
"Webby",
|
|
7
|
+
:layout => Logging::Layouts::Pattern.new(:pattern => "%5l - Webby\000%m"),
|
|
8
|
+
:coalesce => true,
|
|
9
|
+
:separator => "\000"
|
|
10
|
+
))
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
end # unless WINDOWS
|
|
14
|
+
|
|
15
|
+
# EOF
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
|
|
2
|
+
namespace :heel do
|
|
3
|
+
|
|
4
|
+
desc 'Start the heel server to view website (not for Windows)'
|
|
5
|
+
task :start do
|
|
6
|
+
sh "heel --root #{SITE.output_dir} --port #{SITE.heel_port} --daemonize"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
desc 'Stop the heel server'
|
|
10
|
+
task :stop do
|
|
11
|
+
sh "heel --kill"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
task :autorun do
|
|
15
|
+
heel_exe = File.join(Gem.bindir, 'heel')
|
|
16
|
+
@heel_spawner = Spawner.new(Spawner.ruby, heel_exe, '--root', SITE.output_dir, '--port', SITE.heel_port.to_s, :pause => 86_400)
|
|
17
|
+
@heel_spawner.start
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
task :autobuild => :autorun do
|
|
21
|
+
at_exit {@heel_spawner.stop if defined? @heel_spawner and not @heel_spawner.nil?}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
task :autobuild => 'heel:autobuild'
|
|
27
|
+
|
|
28
|
+
# EOF
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
namespace :validate do
|
|
3
|
+
|
|
4
|
+
desc 'Validate hyperlinks (exclude exteranl sites)'
|
|
5
|
+
task :internal => :build do
|
|
6
|
+
Webby::LinkValidator.validate(:external => false)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
desc 'Validate hyperlinks (include external sites)'
|
|
10
|
+
task :external => :build do
|
|
11
|
+
Webby::LinkValidator.validate(:external => true)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end # validate
|
|
15
|
+
|
|
16
|
+
desc 'Alias to validate:internal'
|
|
17
|
+
task :validate => 'validate:internal'
|
|
18
|
+
|
|
19
|
+
# EOF
|
data/lib/webby.rb
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Equivalent to a header guard in C/C++
|
|
2
|
+
# Used to prevent the spec helper from being loaded more than once
|
|
3
|
+
unless defined? ::Webby
|
|
4
|
+
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
require 'logging'
|
|
7
|
+
require 'ostruct'
|
|
8
|
+
require 'date'
|
|
9
|
+
|
|
10
|
+
# Configure Webby to log to STDOUT at the 'info' level
|
|
11
|
+
Logging::Logger['Webby'].level = :info
|
|
12
|
+
Logging::Logger['Webby'].add_appenders(Logging::Appender.stdout)
|
|
13
|
+
Logging::Appender.stdout.layout = Logging::Layouts::Pattern.new(
|
|
14
|
+
:pattern => "[%d] %5l: %m\n", # [date] LEVEL: message
|
|
15
|
+
:date_pattern => "%H:%M:%S" # date == HH:MM:SS
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
module Webby
|
|
19
|
+
|
|
20
|
+
# :stopdoc:
|
|
21
|
+
VERSION = '0.9.0' # :nodoc:
|
|
22
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
|
23
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
|
24
|
+
# :startdoc:
|
|
25
|
+
|
|
26
|
+
class Error < StandardError; end # :nodoc:
|
|
27
|
+
|
|
28
|
+
# call-seq:
|
|
29
|
+
# Webby.site => struct
|
|
30
|
+
#
|
|
31
|
+
# Returns a struct containing the configuration parameters for the
|
|
32
|
+
# Webby site. These defaults should be overridden as needed in the
|
|
33
|
+
# site specific Rakefile.
|
|
34
|
+
#
|
|
35
|
+
def self.site
|
|
36
|
+
return @site if defined? @site
|
|
37
|
+
@site = OpenStruct.new(
|
|
38
|
+
:output_dir => 'output',
|
|
39
|
+
:content_dir => 'content',
|
|
40
|
+
:layout_dir => 'layouts',
|
|
41
|
+
:template_dir => 'templates',
|
|
42
|
+
:exclude => %w(tmp$ bak$ ~$ CVS \.svn),
|
|
43
|
+
:page_defaults => {
|
|
44
|
+
'layout' => 'default'
|
|
45
|
+
},
|
|
46
|
+
:find_by => 'title',
|
|
47
|
+
:base => nil,
|
|
48
|
+
:create_mode => 'page',
|
|
49
|
+
:blog_dir => 'blog',
|
|
50
|
+
:tumblog_dir => 'tumblog',
|
|
51
|
+
|
|
52
|
+
# Items for running the heel webserver
|
|
53
|
+
:heel_port => 4331,
|
|
54
|
+
|
|
55
|
+
# Items used to deploy the website
|
|
56
|
+
:user => ENV['USER'] || ENV['USERNAME'],
|
|
57
|
+
:host => 'example.com',
|
|
58
|
+
:remote_dir => '/not/a/valid/dir',
|
|
59
|
+
:rsync_args => %w(-av),
|
|
60
|
+
|
|
61
|
+
# Global options for HAML and SASS
|
|
62
|
+
:haml_options => {},
|
|
63
|
+
:sass_options => {},
|
|
64
|
+
|
|
65
|
+
# Options passed to the 'tidy' program when the tidy filter is used
|
|
66
|
+
:tidy_options => '-indent -wrap 80',
|
|
67
|
+
|
|
68
|
+
# List of valid URIs (these automatically pass validation)
|
|
69
|
+
:valid_uris => [],
|
|
70
|
+
|
|
71
|
+
# Options for coderay processing
|
|
72
|
+
:coderay => {
|
|
73
|
+
:lang => :ruby,
|
|
74
|
+
:line_numbers => nil,
|
|
75
|
+
:line_number_start => 1,
|
|
76
|
+
:bold_every => 10,
|
|
77
|
+
:tab_width => 8
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
# Options for graphviz processing
|
|
81
|
+
:graphviz => {
|
|
82
|
+
:path => nil,
|
|
83
|
+
:cmd => 'dot',
|
|
84
|
+
:type => 'png'
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
# Options for tex2img processing
|
|
88
|
+
:tex2img => {
|
|
89
|
+
:path => nil,
|
|
90
|
+
:type => 'png',
|
|
91
|
+
:bg => 'white',
|
|
92
|
+
:fg => 'black',
|
|
93
|
+
:resolution => '150x150'
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
# Options for ultraviolet syntax highlighting
|
|
97
|
+
:uv => {
|
|
98
|
+
:lang => 'ruby',
|
|
99
|
+
:line_numbers => false,
|
|
100
|
+
:theme => 'mac_classic'
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
# XPath identifiers used by the basepath filter
|
|
104
|
+
:xpaths => %w(
|
|
105
|
+
/html/head//base[@href]
|
|
106
|
+
/html/head//link[@href]
|
|
107
|
+
//script[@src]
|
|
108
|
+
/html/body[@background]
|
|
109
|
+
/html/body//a[@href]
|
|
110
|
+
/html/body//object[@data]
|
|
111
|
+
/html/body//img[@src]
|
|
112
|
+
/html/body//area[@href]
|
|
113
|
+
/html/body//form[@action]
|
|
114
|
+
/html/body//input[@src]
|
|
115
|
+
)
|
|
116
|
+
# other possible XPaths to include for base path substitution
|
|
117
|
+
# /html/body//object[@usemap]
|
|
118
|
+
# /html/body//img[@usemap]
|
|
119
|
+
# /html/body//input[@usemap]
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# call-seq
|
|
124
|
+
# Webby.exclude => regexp
|
|
125
|
+
#
|
|
126
|
+
# Returns a regular expression used to exclude resources from the content
|
|
127
|
+
# directory from being processed by Webby. This same regular expression is
|
|
128
|
+
# also used to exclude layouts.
|
|
129
|
+
#
|
|
130
|
+
def self.exclude
|
|
131
|
+
@exclude ||= Regexp.new(site.exclude.join('|'))
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# call-seq:
|
|
135
|
+
# Webby.editor => string or nil
|
|
136
|
+
#
|
|
137
|
+
# Returns the default editor to use when creating new pages. This editor
|
|
138
|
+
# will be spawned to allow the user to edit the newly created page.
|
|
139
|
+
#
|
|
140
|
+
def self.editor
|
|
141
|
+
return @editor if defined? @editor
|
|
142
|
+
|
|
143
|
+
@editor = if ENV['EDITOR'].nil? or ENV['EDITOR'].empty? then nil
|
|
144
|
+
else ENV['EDITOR'] end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# call-seq:
|
|
148
|
+
# cairn => filename
|
|
149
|
+
#
|
|
150
|
+
# The Webby _cairn_ file is used to mark the last time the content was
|
|
151
|
+
# built into the output directory. It is an empty file; only the
|
|
152
|
+
# modification time of the file is important.
|
|
153
|
+
#
|
|
154
|
+
def self.cairn
|
|
155
|
+
@cairn ||= ::File.join(site.output_dir, '.cairn')
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# Returns the library path for Webby. If any arguments are given,
|
|
159
|
+
# they will be joined to the end of the libray path using
|
|
160
|
+
# <tt>File.join</tt>.
|
|
161
|
+
#
|
|
162
|
+
def self.libpath( *args )
|
|
163
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Returns the path for Webby. If any arguments are given,
|
|
167
|
+
# they will be joined to the end of the path using
|
|
168
|
+
# <tt>File.join</tt>.
|
|
169
|
+
#
|
|
170
|
+
def self.path( *args )
|
|
171
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# call-seq:
|
|
175
|
+
# Webby.require_all_libs_relative_to( filename, directory = nil )
|
|
176
|
+
#
|
|
177
|
+
# Utility method used to rquire all files ending in .rb that lie in the
|
|
178
|
+
# directory below this file that has the same name as the filename passed
|
|
179
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
|
180
|
+
# the _filename_ does not have to be equivalent to the directory.
|
|
181
|
+
#
|
|
182
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
|
183
|
+
dir ||= ::File.basename(fname, '.*')
|
|
184
|
+
search_me = ::File.expand_path(
|
|
185
|
+
::File.join(::File.dirname(fname), dir, '*.rb'))
|
|
186
|
+
|
|
187
|
+
Dir.glob(search_me).sort.each {|rb| require rb}
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Prints a deprecation warning using the logger. The message states that
|
|
191
|
+
# the given method is being deprecated. An optional message can be give to
|
|
192
|
+
# -- somthing nice and fuzzy about a new method or why this one has to go
|
|
193
|
+
# away; sniff, we'll miss you little buddy.
|
|
194
|
+
#
|
|
195
|
+
def self.deprecated( method, message = nil )
|
|
196
|
+
msg = "'#{method}' has been deprecated"
|
|
197
|
+
msg << "\n\t#{message}" unless message.nil?
|
|
198
|
+
Logging::Logger['Webby'].warn msg
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
end # module Webby
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
# call-seq:
|
|
205
|
+
# try_require( library, gemname = nil ) => true or false
|
|
206
|
+
#
|
|
207
|
+
# Try to laod the given _library_ using the built-in require, but do not
|
|
208
|
+
# raise a LoadError if unsuccessful. Returns +true+ if the _library_ was
|
|
209
|
+
# successfully loaded; returns +false+ otherwise.
|
|
210
|
+
#
|
|
211
|
+
# If a _gemname_ is given, then the "gem gemname" command will be called
|
|
212
|
+
# before the library is loaded.
|
|
213
|
+
#
|
|
214
|
+
def try_require( lib, gemname = nil )
|
|
215
|
+
gem gemname unless gemname.nil?
|
|
216
|
+
require lib
|
|
217
|
+
true
|
|
218
|
+
rescue LoadError
|
|
219
|
+
false
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
Webby.require_all_libs_relative_to(__FILE__, ::File.join(%w[webby core_ext]))
|
|
223
|
+
Webby.require_all_libs_relative_to(__FILE__)
|
|
224
|
+
|
|
225
|
+
end # unless defined?
|
|
226
|
+
|
|
227
|
+
# EOF
|