Shazburg-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 +171 -0
- data/README.txt +92 -0
- data/Rakefile +54 -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/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 +184 -0
- data/examples/webby/content/css/uv/twilight.css +137 -0
- data/examples/webby/content/index.txt +37 -0
- data/examples/webby/content/manual/index.txt +430 -0
- data/examples/webby/content/reference/index.txt +202 -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/layouts/default.txt +55 -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.rb +227 -0
- data/lib/webby/apps.rb +12 -0
- data/lib/webby/apps/generator.rb +283 -0
- data/lib/webby/apps/main.rb +221 -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.rb +91 -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 +308 -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/helpers.rb +30 -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/link_validator.rb +152 -0
- data/lib/webby/renderer.rb +379 -0
- data/lib/webby/resources.rb +96 -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/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/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 +287 -0
@@ -0,0 +1,96 @@
|
|
1
|
+
module Webby::Resources
|
2
|
+
|
3
|
+
class << self
|
4
|
+
# Returns the pages hash object.
|
5
|
+
#
|
6
|
+
def pages
|
7
|
+
@pages ||= ::Webby::Resources::DB.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the layouts hash object.
|
11
|
+
#
|
12
|
+
def layouts
|
13
|
+
@layouts ||= ::Webby::Resources::DB.new
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the partials hash object.
|
17
|
+
#
|
18
|
+
def partials
|
19
|
+
@partials ||= ::Webby::Resources::DB.new
|
20
|
+
end
|
21
|
+
|
22
|
+
# Clear the contents of the +layouts+, +pages+ and +partials+ hash
|
23
|
+
# objects.
|
24
|
+
#
|
25
|
+
def clear
|
26
|
+
self.pages.clear
|
27
|
+
self.layouts.clear
|
28
|
+
self.partials.clear
|
29
|
+
end
|
30
|
+
|
31
|
+
# call-seq:
|
32
|
+
# Resources.new( filename )
|
33
|
+
#
|
34
|
+
#
|
35
|
+
def new( fn )
|
36
|
+
# normalize the path
|
37
|
+
fn = self.path(fn)
|
38
|
+
|
39
|
+
# see if we are dealing with a layout
|
40
|
+
if %r/\A#{::Webby.site.layout_dir}\//o =~ fn
|
41
|
+
r = ::Webby::Resources::Layout.new(fn)
|
42
|
+
self.layouts << r
|
43
|
+
return r
|
44
|
+
end
|
45
|
+
|
46
|
+
# see if we are dealing with a partial
|
47
|
+
filename = ::Webby::Resources::File.basename(fn)
|
48
|
+
if %r/\A_/o =~ filename
|
49
|
+
r = ::Webby::Resources::Partial.new(fn)
|
50
|
+
self.partials << r
|
51
|
+
return r
|
52
|
+
end
|
53
|
+
|
54
|
+
# see if we are dealing with a static resource
|
55
|
+
meta = ::Webby::Resources::File.meta_data(fn)
|
56
|
+
if meta.nil?
|
57
|
+
r = ::Webby::Resources::Static.new(fn)
|
58
|
+
self.pages << r
|
59
|
+
return r
|
60
|
+
end
|
61
|
+
|
62
|
+
# this is a renderable page
|
63
|
+
r = ::Webby::Resources::Page.new(fn)
|
64
|
+
self.pages << r
|
65
|
+
return r
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns a normalized path for the given filename.
|
69
|
+
#
|
70
|
+
def path( filename )
|
71
|
+
filename.sub(%r/\A(?:\.\/|\/)/o, '').freeze
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the layout resource corresponding to the given _filename_ or
|
75
|
+
# +nil+ if no layout exists under that filename.
|
76
|
+
#
|
77
|
+
def find_layout( filename )
|
78
|
+
return if filename.nil?
|
79
|
+
|
80
|
+
fn = ::Webby::Resources::File.basename(filename)
|
81
|
+
dir = ::File.dirname(filename)
|
82
|
+
dir = '.' == dir ? '' : dir
|
83
|
+
|
84
|
+
layouts.find(:filename => fn, :in_directory => dir)
|
85
|
+
|
86
|
+
rescue RuntimeError
|
87
|
+
raise Webby::Error, "could not find layout #{filename.inspect}"
|
88
|
+
end
|
89
|
+
|
90
|
+
end # class << self
|
91
|
+
|
92
|
+
end # module Webby::Resources
|
93
|
+
|
94
|
+
Webby.require_all_libs_relative_to(__FILE__)
|
95
|
+
|
96
|
+
# EOF
|
@@ -0,0 +1,251 @@
|
|
1
|
+
module Webby::Resources
|
2
|
+
|
3
|
+
# A rudimentary "database" for holding resource objects and finding them.
|
4
|
+
# The database is held in a Ruby hash keyed by the directories in the
|
5
|
+
# content folder.
|
6
|
+
#
|
7
|
+
class DB
|
8
|
+
|
9
|
+
# call-seq:
|
10
|
+
# DB.new
|
11
|
+
#
|
12
|
+
# Create a new resources database object. This is used to store resources
|
13
|
+
# and to find them by their attributes.
|
14
|
+
#
|
15
|
+
def initialize
|
16
|
+
@db = Hash.new {|h,k| h[k] = []}
|
17
|
+
end
|
18
|
+
|
19
|
+
# call-seq:
|
20
|
+
# add( resource ) => resource
|
21
|
+
#
|
22
|
+
# Add the given _resource_ to the database. It will not be added a second
|
23
|
+
# time if it already exists in the database.
|
24
|
+
#
|
25
|
+
def add( page )
|
26
|
+
ary = @db[page.dir]
|
27
|
+
|
28
|
+
# make sure we don't duplicate pages
|
29
|
+
ary.delete page if ary.include? page
|
30
|
+
ary << page
|
31
|
+
|
32
|
+
page
|
33
|
+
end
|
34
|
+
alias :<< :add
|
35
|
+
|
36
|
+
# call-seq:
|
37
|
+
# clear => self
|
38
|
+
#
|
39
|
+
# Removes all resources from the database.
|
40
|
+
#
|
41
|
+
def clear
|
42
|
+
@db.clear
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
# call-seq:
|
47
|
+
# each {|resource| block}
|
48
|
+
#
|
49
|
+
# Iterate over each resource in the database and pass it to the given
|
50
|
+
# block.
|
51
|
+
#
|
52
|
+
def each( &block )
|
53
|
+
keys = @db.keys.sort
|
54
|
+
keys.each do |k|
|
55
|
+
@db[k].sort.each(&block)
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# call-seq:
|
61
|
+
# find( limit = nil, opts = {} ) => resource or nil
|
62
|
+
# find( limit = nil, opts = {} ) {|resource| block} => resource or nil
|
63
|
+
#
|
64
|
+
# Find a specific resource or collection of resources in the pages database.
|
65
|
+
# The first resource found will be returned if the _limit_ is nil. If the
|
66
|
+
# _limit_ is an integer, then up to that number of resources will be
|
67
|
+
# returned as an array. If the limit is :all, then all resources matching
|
68
|
+
# the given attributes will be returned.
|
69
|
+
#
|
70
|
+
# Resources can be found using any combination of attributes by passing them
|
71
|
+
# in as options to the +find+ method. This will used simple equality
|
72
|
+
# comparison to find the resource or resources.
|
73
|
+
#
|
74
|
+
# If the :include option is given as :all then all resources that match
|
75
|
+
# the finder criteria will be returned in an array. If none are found, an
|
76
|
+
# empty array will be returned. If the :include option is given as an
|
77
|
+
# integer then the first n resources found will be returned. Otherwise, or
|
78
|
+
# if the :include option is not given, the first resource found will be
|
79
|
+
# returned
|
80
|
+
#
|
81
|
+
# For more complex finders, a block should be supplied. The usage follows
|
82
|
+
# that of of the Enumerable#find or Enumerable#find_all methods, depending
|
83
|
+
# on the limit. The method will return the first resource or all
|
84
|
+
# resources, respectively, for which the block returns true.
|
85
|
+
#
|
86
|
+
# ==== Options
|
87
|
+
# :in_directory<String>::
|
88
|
+
# The directory to search.
|
89
|
+
# :recursive<Boolean>::
|
90
|
+
# Whether or not to recurse into subdirectories
|
91
|
+
# :sort_by<Symbol>::
|
92
|
+
# Sort results using the given attribute
|
93
|
+
# :reverse<Boolean>::
|
94
|
+
# Reverse the order of the search results
|
95
|
+
#
|
96
|
+
# ==== Examples
|
97
|
+
# # find the "index" resource in the "foo/bar" directory
|
98
|
+
# @pages.find( :filename => 'index', :in_directory => 'foo/bar' )
|
99
|
+
#
|
100
|
+
# # find all resources under the "foo/bar" directory recursively
|
101
|
+
# @pages.find( :all, :in_directory => 'foo/bar', :recursive => true )
|
102
|
+
#
|
103
|
+
# # find the resource named "widgets" whose color is "blue"
|
104
|
+
# @pages.find( :name => 'widgets', :color => 'blue' )
|
105
|
+
#
|
106
|
+
# # find all resources created in the past week
|
107
|
+
# @pages.find( :all ) do |resource|
|
108
|
+
# resource.created_at > Time.now - (7 * 24 * 3600)
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
def find( *args, &block )
|
112
|
+
opts = Hash === args.last ? args.pop : {}
|
113
|
+
|
114
|
+
limit = args.shift
|
115
|
+
limit = opts.delete(:limit) if opts.has_key?(:limit)
|
116
|
+
sort_by = opts.delete(:sort_by)
|
117
|
+
reverse = opts.delete(:reverse)
|
118
|
+
|
119
|
+
# figure out which directories to search through and whether to recurse
|
120
|
+
# into directories or not
|
121
|
+
search = if (dir = opts.delete(:in_directory))
|
122
|
+
dir = dir.sub(%r/^\//, '')
|
123
|
+
strategy = if opts.delete(:recursive)
|
124
|
+
rgxp = dir.empty? ? '.*' : Regexp.escape(dir)
|
125
|
+
lambda { |key| key =~ %r/^#{rgxp}(\/.*)?$/ }
|
126
|
+
else
|
127
|
+
lambda { |key| key == dir }
|
128
|
+
end
|
129
|
+
matching_keys = @db.keys.select(&strategy)
|
130
|
+
raise RuntimeError, "unknown directory '#{dir}'" if matching_keys.empty?
|
131
|
+
matching_keys.map { |key| @db[key] }.flatten
|
132
|
+
else
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
136
|
+
# construct a search block if one was not supplied by the user
|
137
|
+
block ||= lambda do |page|
|
138
|
+
found = true
|
139
|
+
opts.each do |key, value|
|
140
|
+
found &&= page.__send__(key.to_sym) == value
|
141
|
+
break if not found
|
142
|
+
end
|
143
|
+
found
|
144
|
+
end
|
145
|
+
|
146
|
+
# search through the directories for the desired pages
|
147
|
+
ary = []
|
148
|
+
search.each do |page|
|
149
|
+
ary << page if block.call(page)
|
150
|
+
end
|
151
|
+
|
152
|
+
# sort the search results if the user gave an attribute to sort by
|
153
|
+
if sort_by
|
154
|
+
m = sort_by.to_sym
|
155
|
+
ary.delete_if {|p| p.__send__(m).nil?}
|
156
|
+
reverse ?
|
157
|
+
ary.sort! {|a,b| b.__send__(m) <=> a.__send__(m)} :
|
158
|
+
ary.sort! {|a,b| a.__send__(m) <=> b.__send__(m)}
|
159
|
+
end
|
160
|
+
|
161
|
+
# limit the search results
|
162
|
+
case limit
|
163
|
+
when :all, 'all'
|
164
|
+
ary
|
165
|
+
when Integer
|
166
|
+
ary.slice(0,limit)
|
167
|
+
else
|
168
|
+
ary.first
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# call-seq:
|
173
|
+
# siblings( page, opts = {} ) => array
|
174
|
+
#
|
175
|
+
# Returns an array of resources that are siblings of the given _page_
|
176
|
+
# resource. A sibling is any resource that is in the same directory as the
|
177
|
+
# _page_.
|
178
|
+
#
|
179
|
+
# ==== Options
|
180
|
+
# :sorty_by<Symbol>::
|
181
|
+
# The attribute to sort by
|
182
|
+
# :reverse<Boolean>::
|
183
|
+
# Reverse the order of the results
|
184
|
+
#
|
185
|
+
def siblings( page, opts = {} )
|
186
|
+
ary = @db[page.dir].dup
|
187
|
+
ary.delete page
|
188
|
+
return ary unless opts.has_key? :sort_by
|
189
|
+
|
190
|
+
m = opts[:sort_by]
|
191
|
+
ary.sort! {|a,b| a.__send__(m) <=> b.__send__(m)}
|
192
|
+
ary.reverse! if opts[:reverse]
|
193
|
+
ary
|
194
|
+
end
|
195
|
+
|
196
|
+
# call-seq:
|
197
|
+
# children( page, opts = {} ) => array
|
198
|
+
#
|
199
|
+
# Returns an array of resources that are children of the given _page_
|
200
|
+
# resource. A child is any resource that exists in a subdirectory of the
|
201
|
+
# page's directory.
|
202
|
+
#
|
203
|
+
# ==== Options
|
204
|
+
# :sorty_by<Symbol>::
|
205
|
+
# The attribute to sort by
|
206
|
+
# :reverse<Boolean>::
|
207
|
+
# Reverse the order of the results
|
208
|
+
#
|
209
|
+
def children( page, opts = {} )
|
210
|
+
rgxp = Regexp.new "\\A#{page.dir}/[^/]+"
|
211
|
+
|
212
|
+
keys = @db.keys.find_all {|k| rgxp =~ k}
|
213
|
+
ary = keys.map {|k| @db[k]}
|
214
|
+
ary.flatten!
|
215
|
+
|
216
|
+
return ary unless opts.has_key? :sort_by
|
217
|
+
|
218
|
+
m = opts[:sort_by]
|
219
|
+
ary.sort! {|a,b| a.__send__(m) <=> b.__send__(m)}
|
220
|
+
ary.reverse! if opts[:reverse]
|
221
|
+
ary
|
222
|
+
end
|
223
|
+
|
224
|
+
# call-seq:
|
225
|
+
# parent_of( resource ) => resource or nil
|
226
|
+
#
|
227
|
+
# Returns the parent page of the given resource or nil if the resource is
|
228
|
+
# at the root of the directory structure. The parent is the "index" page
|
229
|
+
# of the current directory or the next directory up the chain.
|
230
|
+
#
|
231
|
+
def parent_of( page )
|
232
|
+
dir = page.dir
|
233
|
+
|
234
|
+
loop do
|
235
|
+
if @db.has_key? dir
|
236
|
+
parent = @db[dir].find {|p| p.filename == 'index'}
|
237
|
+
return parent unless parent.nil? or parent == page
|
238
|
+
end
|
239
|
+
|
240
|
+
break if dir.empty?
|
241
|
+
dir = ::File.dirname(dir)
|
242
|
+
dir = '' if dir == '.'
|
243
|
+
end
|
244
|
+
|
245
|
+
return
|
246
|
+
end
|
247
|
+
|
248
|
+
end # class DB
|
249
|
+
end # module Webby
|
250
|
+
|
251
|
+
# EOF
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Webby::Resources
|
4
|
+
|
5
|
+
# The Webby::Resources::File class is identical to the core Ruby file class
|
6
|
+
# except for YAML meta-data stored at the top of the file. This meta-data
|
7
|
+
# is made available through the <code>meta_data</code> and
|
8
|
+
# <code>meta_data=</code> functions.
|
9
|
+
#
|
10
|
+
# The meta-data data must be found between two YAML block separators "---",
|
11
|
+
# each on their own line.
|
12
|
+
#
|
13
|
+
# Example:
|
14
|
+
#
|
15
|
+
# ---
|
16
|
+
# layout: blog
|
17
|
+
# filter: markdown
|
18
|
+
# tags:
|
19
|
+
# - ruby
|
20
|
+
# - web development
|
21
|
+
# ---
|
22
|
+
# This is a blog entry formatted using MarkDown and tagged as "ruby" and
|
23
|
+
# "web development". The layout being used is the "blog" format.
|
24
|
+
#
|
25
|
+
class File < ::File
|
26
|
+
|
27
|
+
META_SEP = %r/\A---\s*\r?\n\z/o # :nodoc:
|
28
|
+
|
29
|
+
class << self
|
30
|
+
# call-seq:
|
31
|
+
# File.read( name [, length [, offset]]) => string
|
32
|
+
#
|
33
|
+
# Opens the file, optionally seeks to the given _offset_, then returns
|
34
|
+
# _length_ bytes (defaulting to the rest of the file). +read+ ensures
|
35
|
+
# the file is closed before returning.
|
36
|
+
#
|
37
|
+
def read( name, *args )
|
38
|
+
fd = new name, 'r'
|
39
|
+
fd.read(*args)
|
40
|
+
ensure
|
41
|
+
fd.close unless fd.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
# call-seq:
|
45
|
+
# File.readlines( name, sep_string = $/ ) => array
|
46
|
+
#
|
47
|
+
# Reads the entire file specified by _name_ as individual lines, and
|
48
|
+
# returns those lines in an array. Lines are separated by _sep_string_.
|
49
|
+
# +readlines+ ensures the file is closed before returning.
|
50
|
+
#
|
51
|
+
def readlines( name, sep = $/ )
|
52
|
+
fd = new name, 'r'
|
53
|
+
fd.readlines sep
|
54
|
+
ensure
|
55
|
+
fd.close unless fd.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
# call-seq:
|
59
|
+
# File.meta_data( name ) => object or nil
|
60
|
+
#
|
61
|
+
# Reads the meta-data from the file specified by _name_. +meta_data+
|
62
|
+
# ensures the files is closed before returning.
|
63
|
+
#
|
64
|
+
def meta_data( name )
|
65
|
+
fd = new name, 'r'
|
66
|
+
fd.meta_data
|
67
|
+
ensure
|
68
|
+
fd.close unless fd.nil?
|
69
|
+
end
|
70
|
+
|
71
|
+
# call-seq:
|
72
|
+
# File.dirname( filename ) => dir_name
|
73
|
+
#
|
74
|
+
# Returns all components of the _filename_ except the last one. The
|
75
|
+
# filename must be formed using forward slashes ("/") regardless of the
|
76
|
+
# separator used on the local file system.
|
77
|
+
#
|
78
|
+
def dirname( fn )
|
79
|
+
::File.dirname(fn).sub(%r/\A[^\/]+\/?/o, '')
|
80
|
+
end
|
81
|
+
|
82
|
+
# call-seq:
|
83
|
+
# File.basename( filename ) => base_name
|
84
|
+
#
|
85
|
+
# Returns the last component of the _filename_, which must be formed
|
86
|
+
# using forward slashes ("/"regardless of the separator used on the
|
87
|
+
# local file system. The suffix is removed from the filename.
|
88
|
+
#
|
89
|
+
def basename( fn )
|
90
|
+
::File.basename(fn, '.*')
|
91
|
+
end
|
92
|
+
|
93
|
+
# call-seq:
|
94
|
+
# File.extname( filename ) => ext_name
|
95
|
+
#
|
96
|
+
# Returns the extension (the portion of file name in path after the
|
97
|
+
# period). This method excludes the period from the extension name.
|
98
|
+
#
|
99
|
+
def extname( fn )
|
100
|
+
::File.extname(fn).tr('.', '')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# call-seq:
|
105
|
+
# File.new( filename, mode = "r" ) => file
|
106
|
+
# File.new( filename [, mode [, perm]] ) => file
|
107
|
+
#
|
108
|
+
# Opens the file named by _filename_ according to _mode_ (default is 'r')
|
109
|
+
# and returns a new +Webby::Resources::File+ object. See the description
|
110
|
+
# of class +IO+ for a description of _mode_. The file _mode_ may
|
111
|
+
# optionally be specified as a +Fixnum+ by or-ing together the flags
|
112
|
+
# (+O_RDONLY+ etc, again described under +IO+). Optional permission bits
|
113
|
+
# may be given in _perm_. These _mode_ and permission bits are platform
|
114
|
+
# dependent; on Unix systems, see +open(2)+ for details.
|
115
|
+
#
|
116
|
+
# f = File.new("testfile", "r")
|
117
|
+
# f = File.new("newfile", "w+")
|
118
|
+
# f = File.new("newfile", File::CREAT|File::TRUNC|File::RDWR, 0644)
|
119
|
+
#
|
120
|
+
def initialize( *args )
|
121
|
+
super
|
122
|
+
@meta_end = end_of_meta_data
|
123
|
+
end
|
124
|
+
|
125
|
+
# call-seq:
|
126
|
+
# meta_data
|
127
|
+
#
|
128
|
+
# Returns the meta-data defined at the top of the file. Returns +nil+ if
|
129
|
+
# no meta-data is defined. The meta-data is returned as Ruby objects
|
130
|
+
#
|
131
|
+
# Meta-data is stored in YAML format between two YAML separators "---" on
|
132
|
+
# their own lines.
|
133
|
+
#
|
134
|
+
def meta_data
|
135
|
+
return if @meta_end.nil?
|
136
|
+
|
137
|
+
cur, meta_end, @meta_end = tell, @meta_end, nil
|
138
|
+
seek 0
|
139
|
+
return YAML.load(self)
|
140
|
+
|
141
|
+
ensure
|
142
|
+
@meta_end = meta_end if defined? meta_end and meta_end
|
143
|
+
seek cur if defined? cur and cur
|
144
|
+
end
|
145
|
+
|
146
|
+
# call-seq
|
147
|
+
# meta_data = object
|
148
|
+
#
|
149
|
+
# Stores the given _object_ as meta-data in YAML format at the top of the
|
150
|
+
# file. If the _objectc_ is +nil+, then the meta-data section will be
|
151
|
+
# removed from the file.
|
152
|
+
#
|
153
|
+
# Meta-data is stored in YAML format between two YAML separators "---" on
|
154
|
+
# their own lines.
|
155
|
+
#
|
156
|
+
def meta_data=( data )
|
157
|
+
return if data.nil? and @meta_end.nil?
|
158
|
+
|
159
|
+
seek 0
|
160
|
+
lines = readlines
|
161
|
+
|
162
|
+
truncate 0
|
163
|
+
unless data.nil?
|
164
|
+
write YAML.dump(data)
|
165
|
+
write "--- #$/"
|
166
|
+
end
|
167
|
+
lines.each {|line| write line}
|
168
|
+
ensure
|
169
|
+
@meta_end = end_of_meta_data
|
170
|
+
seek 0, IO::SEEK_END
|
171
|
+
end
|
172
|
+
|
173
|
+
alias :_gets :gets
|
174
|
+
private :_gets
|
175
|
+
|
176
|
+
%w(getc gets read read_nonblock readbytes readchar readline readlines readpartial scanf).each do |m|
|
177
|
+
self.class_eval <<-CODE
|
178
|
+
def #{m}(*a)
|
179
|
+
skip_meta_data
|
180
|
+
super
|
181
|
+
end
|
182
|
+
CODE
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
private
|
187
|
+
|
188
|
+
# Moves the file pointer to the end of the meta-data section. Does nothing
|
189
|
+
# if there is no meta-data section or if the file pointer is already past
|
190
|
+
# the meta-data section.
|
191
|
+
#
|
192
|
+
def skip_meta_data
|
193
|
+
return if @meta_end.nil?
|
194
|
+
return if tell >= @meta_end
|
195
|
+
seek @meta_end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Returns the position in this file where the meta-data ends and the file
|
199
|
+
# data begins. If there is no meta-data in the file, returns +nil+.
|
200
|
+
#
|
201
|
+
def end_of_meta_data
|
202
|
+
cur = tell
|
203
|
+
|
204
|
+
seek 0
|
205
|
+
line = _gets
|
206
|
+
return unless META_SEP =~ line
|
207
|
+
|
208
|
+
while line = _gets
|
209
|
+
break if META_SEP =~ line
|
210
|
+
end
|
211
|
+
return if line.nil?
|
212
|
+
tell
|
213
|
+
|
214
|
+
ensure
|
215
|
+
seek cur
|
216
|
+
end
|
217
|
+
|
218
|
+
end # class File
|
219
|
+
end # module Webby::Resources
|
220
|
+
|
221
|
+
# EOF
|