webby 0.9.3-x86-mswin32
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 +206 -0
- data/Manifest.txt +228 -0
- data/README.txt +92 -0
- data/Rakefile +49 -0
- data/bin/webby +41 -0
- data/bin/webby-gen +41 -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 +25 -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/index.txt +21 -0
- data/examples/webby/content/release-notes/rel-0-9-0/index.txt +74 -0
- data/examples/webby/content/release-notes/rel-0-9-1/index.txt +93 -0
- data/examples/webby/content/release-notes/rel-0-9-2/index.txt +14 -0
- data/examples/webby/content/release-notes/rel-0-9-3/index.txt +49 -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 +97 -0
- data/examples/webby/content/tutorial/index.txt +135 -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/lib/webby.rb +221 -0
- data/lib/webby/apps.rb +12 -0
- data/lib/webby/apps/generator.rb +276 -0
- data/lib/webby/apps/main.rb +255 -0
- data/lib/webby/auto_builder.rb +157 -0
- data/lib/webby/builder.rb +180 -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 +26 -0
- data/lib/webby/core_ext/string.rb +163 -0
- data/lib/webby/core_ext/time.rb +9 -0
- data/lib/webby/filters.rb +83 -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/wiki_words.rb +14 -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 +241 -0
- data/lib/webby/journal.rb +126 -0
- data/lib/webby/link_validator.rb +152 -0
- data/lib/webby/renderer.rb +386 -0
- data/lib/webby/resources.rb +136 -0
- data/lib/webby/resources/db.rb +251 -0
- data/lib/webby/resources/layout.rb +54 -0
- data/lib/webby/resources/meta_file.rb +211 -0
- data/lib/webby/resources/page.rb +81 -0
- data/lib/webby/resources/partial.rb +85 -0
- data/lib/webby/resources/resource.rb +201 -0
- data/lib/webby/resources/static.rb +36 -0
- data/lib/webby/stelan/mktemp.rb +135 -0
- data/lib/webby/stelan/paginator.rb +165 -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 +16 -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/data/hooligans/bad_meta_data_1.txt +34 -0
- data/spec/data/hooligans/bad_meta_data_2.txt +34 -0
- data/spec/data/outline/basic.out +81 -0
- data/spec/data/outline/basic.txt +25 -0
- data/spec/data/outline/no_clobber.out +86 -0
- data/spec/data/outline/numbering.out +81 -0
- data/spec/data/outline/numbering_only.out +21 -0
- data/spec/data/outline/toc_range_1.out +66 -0
- data/spec/data/outline/toc_range_2.out +55 -0
- data/spec/data/outline/toc_style.out +81 -0
- data/spec/data/site/Sitefile +9 -0
- data/spec/data/site/content/_partial.txt +10 -0
- data/spec/data/site/content/css/coderay.css +111 -0
- data/spec/data/site/content/css/site.css +67 -0
- data/spec/data/site/content/css/tumblog.css +308 -0
- data/spec/data/site/content/images/tumblog/permalink.gif +0 -0
- data/spec/data/site/content/images/tumblog/rss.gif +0 -0
- data/spec/data/site/content/index.txt +19 -0
- data/spec/data/site/content/photos.txt +21 -0
- data/spec/data/site/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
- data/spec/data/site/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
- data/spec/data/site/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
- data/spec/data/site/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
- data/spec/data/site/content/tumblog/200807/up-a-tree/index.txt +13 -0
- data/spec/data/site/content/tumblog/index.txt +37 -0
- data/spec/data/site/content/tumblog/rss.txt +37 -0
- data/spec/data/site/layouts/default.txt +58 -0
- data/spec/data/site/layouts/tumblog/default.txt +44 -0
- data/spec/data/site/layouts/tumblog/post.txt +15 -0
- data/spec/data/site/lib/breadcrumbs.rb +28 -0
- data/spec/data/site/lib/tumblog_helper.rb +32 -0
- data/spec/data/site/tasks/tumblog.rake +30 -0
- data/spec/data/site/templates/_partial.erb +10 -0
- data/spec/data/site/templates/atom_feed.erb +40 -0
- data/spec/data/site/templates/page.erb +18 -0
- data/spec/data/site/templates/presentation.erb +40 -0
- data/spec/data/site/templates/tumblog/conversation.erb +12 -0
- data/spec/data/site/templates/tumblog/link.erb +10 -0
- data/spec/data/site/templates/tumblog/photo.erb +13 -0
- data/spec/data/site/templates/tumblog/post.erb +12 -0
- data/spec/data/site/templates/tumblog/quote.erb +11 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/webby/apps/generator_spec.rb +116 -0
- data/spec/webby/apps/main_spec.rb +88 -0
- data/spec/webby/filters/basepath_spec.rb +167 -0
- data/spec/webby/filters/outline_spec.rb +92 -0
- data/spec/webby/filters/textile_spec.rb +20 -0
- data/spec/webby/helpers/capture_helper_spec.rb +56 -0
- data/spec/webby/renderer_spec.rb +139 -0
- data/spec/webby/resources/db_spec.rb +250 -0
- data/spec/webby/resources/layout_spec.rb +83 -0
- data/spec/webby/resources/meta_file_spec.rb +171 -0
- data/spec/webby/resources/page_spec.rb +111 -0
- data/spec/webby/resources/partial_spec.rb +58 -0
- data/spec/webby/resources/resource_spec.rb +219 -0
- data/spec/webby/resources/static_spec.rb +49 -0
- data/spec/webby/resources_spec.rb +69 -0
- data/tasks/ann.rake +81 -0
- data/tasks/bones.rake +21 -0
- data/tasks/gem.rake +187 -0
- data/tasks/git.rake +41 -0
- data/tasks/manifest.rake +48 -0
- data/tasks/notes.rake +28 -0
- data/tasks/post_load.rake +39 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +268 -0
- data/tasks/spec.rake +55 -0
- data/tasks/website.rake +38 -0
- metadata +365 -0
@@ -0,0 +1,136 @@
|
|
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 = self.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
|
+
begin
|
55
|
+
fd = ::File.open(fn, 'r')
|
56
|
+
mf = MetaFile.new fd
|
57
|
+
|
58
|
+
# see if we are dealing with a static resource
|
59
|
+
unless mf.meta_data?
|
60
|
+
r = ::Webby::Resources::Static.new(fn)
|
61
|
+
self.pages << r
|
62
|
+
return r
|
63
|
+
end
|
64
|
+
|
65
|
+
# this is a renderable page
|
66
|
+
mf.each do |meta_data|
|
67
|
+
r = ::Webby::Resources::Page.new(fn, meta_data)
|
68
|
+
self.pages << r
|
69
|
+
r
|
70
|
+
end
|
71
|
+
rescue MetaFile::Error => err
|
72
|
+
logger.error "error loading file #{fn.inspect}"
|
73
|
+
logger.error err
|
74
|
+
ensure
|
75
|
+
fd.close if fd
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns a normalized path for the given filename.
|
80
|
+
#
|
81
|
+
def path( filename )
|
82
|
+
filename.sub(%r/\A(?:\.\/|\/)/o, '').freeze
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the layout resource corresponding to the given _filename_ or
|
86
|
+
# +nil+ if no layout exists under that filename.
|
87
|
+
#
|
88
|
+
def find_layout( filename )
|
89
|
+
return if filename.nil?
|
90
|
+
|
91
|
+
fn = self.basename(filename)
|
92
|
+
dir = ::File.dirname(filename)
|
93
|
+
dir = '.' == dir ? '' : dir
|
94
|
+
|
95
|
+
layouts.find(:filename => fn, :in_directory => dir)
|
96
|
+
|
97
|
+
rescue RuntimeError
|
98
|
+
raise Webby::Error, "could not find layout #{filename.inspect}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns the directory component of the _filename_ with the content
|
102
|
+
# directory removed from the beginning if it is present.
|
103
|
+
#
|
104
|
+
def dirname( filename )
|
105
|
+
rgxp = %r/\A(?:#{::Webby.site.content_dir}|#{::Webby.site.layout_dir})\//o
|
106
|
+
dirname = ::File.dirname(filename)
|
107
|
+
dirname << '/' if dirname.index(?/) == nil
|
108
|
+
dirname.sub(rgxp, '')
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns the last component of the _filename_ with any extension
|
112
|
+
# information removed.
|
113
|
+
#
|
114
|
+
def basename( filename )
|
115
|
+
::File.basename(filename, '.*')
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns the extension (the portion of file name in path after the
|
119
|
+
# period). This method excludes the period from the extension name.
|
120
|
+
#
|
121
|
+
def extname( filename )
|
122
|
+
::File.extname(filename).tr('.', '')
|
123
|
+
end
|
124
|
+
|
125
|
+
# :stopdoc:
|
126
|
+
def logger
|
127
|
+
@logger ||= ::Logging::Logger[self]
|
128
|
+
end
|
129
|
+
# :startdoc:
|
130
|
+
|
131
|
+
end # class << self
|
132
|
+
end # module Webby::Resources
|
133
|
+
|
134
|
+
Webby.require_all_libs_relative_to(__FILE__)
|
135
|
+
|
136
|
+
# 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.directory]
|
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.directory].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.directory}/[^/]+"
|
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.directory
|
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,54 @@
|
|
1
|
+
require Webby.libpath(*%w[webby resources resource])
|
2
|
+
|
3
|
+
module Webby::Resources
|
4
|
+
|
5
|
+
# A Layout is any file that is found in the layout folder of the webiste
|
6
|
+
# directory. Layouts container the common elements of all the pages in a
|
7
|
+
# website, and pages from the content folder are rendered into the layout.
|
8
|
+
#
|
9
|
+
class Layout < Resource
|
10
|
+
|
11
|
+
# call-seq:
|
12
|
+
# Layout.new( path )
|
13
|
+
#
|
14
|
+
# Creates a new Layout object given the full path to the layout file.
|
15
|
+
#
|
16
|
+
def initialize( fn )
|
17
|
+
super
|
18
|
+
|
19
|
+
@_meta_data = MetaFile.meta_data(@path)
|
20
|
+
@_meta_data ||= {}
|
21
|
+
@_meta_data.sanitize!
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the extension to be applied to output files rendered by the
|
25
|
+
# layotut. This will either be a string or +nil+ if the layout does not
|
26
|
+
# specify an extension to use.
|
27
|
+
#
|
28
|
+
def extension
|
29
|
+
return _meta_data['extension'] if _meta_data.has_key? 'extension'
|
30
|
+
|
31
|
+
if _meta_data.has_key? 'layout'
|
32
|
+
lyt = ::Webby::Resources.find_layout(_meta_data['layout'])
|
33
|
+
lyt ? lyt.extension : nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# The output file destination for the layout. This is the ".cairn" file in
|
38
|
+
# the output folder. It is used to determine if the layout is newer than
|
39
|
+
# the build products.
|
40
|
+
#
|
41
|
+
def destination
|
42
|
+
::Webby.cairn
|
43
|
+
end
|
44
|
+
|
45
|
+
# Layouts do not have a URL. This method will alwasy return +nil+.
|
46
|
+
#
|
47
|
+
def url
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
end # class Layout
|
52
|
+
end # module Webby::Resources
|
53
|
+
|
54
|
+
# EOF
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Webby::Resources
|
4
|
+
|
5
|
+
# The MetaFile class is used to read meta-data and content from files. The
|
6
|
+
# meta-data is in a YAML block located at the top of the file. The content
|
7
|
+
# is the remainder of the file (everything after the YAML block).
|
8
|
+
#
|
9
|
+
# The meta-data data must be found between two YAML block separators "---",
|
10
|
+
# each on their own line.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
#
|
14
|
+
# ---
|
15
|
+
# layout: blog
|
16
|
+
# filter: markdown
|
17
|
+
# tags:
|
18
|
+
# - ruby
|
19
|
+
# - web development
|
20
|
+
# ---
|
21
|
+
# This is a blog entry formatted using MarkDown and tagged as "ruby" and
|
22
|
+
# "web development". The layout being used is the "blog" format.
|
23
|
+
#
|
24
|
+
class MetaFile
|
25
|
+
|
26
|
+
class Error < StandardError; end
|
27
|
+
|
28
|
+
META_SEP = %r/\A---\s*(?:\r\n|\n)?\z/ # :nodoc:
|
29
|
+
ERR_MSG = "corrupt meta-data (perhaps there is an errant YAML marker '---' in the file)" # :nodoc:
|
30
|
+
|
31
|
+
# call-seq:
|
32
|
+
# MetaFile.read( filename ) => string
|
33
|
+
#
|
34
|
+
# Opens the file identified by _filename_ and returns the contents of the
|
35
|
+
# file as a string. Any meta-data at the top of the file is skipped and
|
36
|
+
# is not included in the returned string. If the file contains no
|
37
|
+
# meta-data, then this method behaves the same as File#read.
|
38
|
+
#
|
39
|
+
def self.read( name )
|
40
|
+
::File.open(name, 'r') {|fd| MetaFile.new(fd).read}
|
41
|
+
end
|
42
|
+
|
43
|
+
# call-seq:
|
44
|
+
# MetaFile.meta_data( filename ) => object or nil
|
45
|
+
#
|
46
|
+
# Opens the file identified by _filename_ and returns the meta-data
|
47
|
+
# located at the top of the file. If the file contains no meta-data, then
|
48
|
+
# +nil+ is returned.
|
49
|
+
#
|
50
|
+
def self.meta_data( name )
|
51
|
+
::File.open(name, 'r') {|fd| MetaFile.new(fd).meta_data}
|
52
|
+
end
|
53
|
+
|
54
|
+
# call-seq:
|
55
|
+
# MetaFile.meta_data?( filename ) => true or false
|
56
|
+
#
|
57
|
+
# Opens the file identified by _filename_ and returns true if there is a
|
58
|
+
# meta-data block at the top of the file, and returns false if there is
|
59
|
+
# not a meta-data block at the top of the file.
|
60
|
+
#
|
61
|
+
def self.meta_data?( name )
|
62
|
+
::File.open(name, 'r') {|fd| MetaFile.new(fd).meta_data?}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Creates a new MetaFile parser that will read from the given _io_ stream.
|
66
|
+
#
|
67
|
+
def initialize( io )
|
68
|
+
raise ArgumentError, "expecting an IO stream" unless io.respond_to? :gets
|
69
|
+
@io = io
|
70
|
+
@meta_count = 0
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns the entire contents of the IO stream exluding any meta-data
|
74
|
+
# found at the beginning of the stream.
|
75
|
+
#
|
76
|
+
def read
|
77
|
+
count = meta_end
|
78
|
+
@io.seek 0
|
79
|
+
count.times {@io.gets} unless count.nil?
|
80
|
+
@io.read
|
81
|
+
end
|
82
|
+
|
83
|
+
# Reads in each meta-data section and yields it to the given block. The
|
84
|
+
# first meta-data section is yielded "as is", but subsequent meta-data
|
85
|
+
# sections are merged with this first section and then yielded. This
|
86
|
+
# allows the user to define common items in the first meta-data section
|
87
|
+
# and only include items that are different in the subsequent sections.
|
88
|
+
#
|
89
|
+
# Example:
|
90
|
+
#
|
91
|
+
# ---
|
92
|
+
# title: First Title
|
93
|
+
# author: me
|
94
|
+
# directory: foo/bar/baz
|
95
|
+
# ---
|
96
|
+
# title: Second Title
|
97
|
+
# author: you
|
98
|
+
# ---
|
99
|
+
# title: Third Title
|
100
|
+
# author: them
|
101
|
+
# ---
|
102
|
+
#
|
103
|
+
# and parsing the meta-data above yields ...
|
104
|
+
#
|
105
|
+
# meta_file.each do |hash|
|
106
|
+
# pp hash
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# the following output
|
110
|
+
#
|
111
|
+
# { 'title' => 'First Title',
|
112
|
+
# 'author' => 'me',
|
113
|
+
# 'directory' => 'foo/bar/baz' }
|
114
|
+
#
|
115
|
+
# { 'title' => 'Second Title',
|
116
|
+
# 'author' => 'you',
|
117
|
+
# 'directory' => 'foo/bar/baz' }
|
118
|
+
#
|
119
|
+
# { 'title' => 'Third Title',
|
120
|
+
# 'author' => 'them',
|
121
|
+
# 'directory' => 'foo/bar/baz' }
|
122
|
+
#
|
123
|
+
# Even though the "directory" item only appears in the first meta-data
|
124
|
+
# block, it is copied to all the subsequent blocks.
|
125
|
+
#
|
126
|
+
def each
|
127
|
+
return unless meta_data?
|
128
|
+
|
129
|
+
first, count = nil, 0
|
130
|
+
@io.seek 0
|
131
|
+
|
132
|
+
buffer = @io.gets
|
133
|
+
while count < @meta_count
|
134
|
+
while (line = @io.gets) !~ META_SEP
|
135
|
+
buffer << line
|
136
|
+
end
|
137
|
+
|
138
|
+
h = YAML.load(buffer)
|
139
|
+
raise Error, ERR_MSG unless h.instance_of?(Hash)
|
140
|
+
|
141
|
+
if first then h = first.merge(h)
|
142
|
+
else first = h.dup end
|
143
|
+
|
144
|
+
buffer = line
|
145
|
+
count += 1
|
146
|
+
|
147
|
+
yield h
|
148
|
+
end
|
149
|
+
rescue ArgumentError => err
|
150
|
+
msg = ERR_MSG.dup << "\n\t-- " << err.message
|
151
|
+
raise Error, msg
|
152
|
+
end
|
153
|
+
|
154
|
+
# Returns the meta-data defined at the top of the file. Returns +nil+ if
|
155
|
+
# no meta-data is defined. The meta-data is returned as Ruby objects
|
156
|
+
#
|
157
|
+
# Meta-data is stored in YAML format between two YAML separators "---" on
|
158
|
+
# their own lines.
|
159
|
+
#
|
160
|
+
def meta_data
|
161
|
+
return if meta_end.nil?
|
162
|
+
|
163
|
+
@io.seek 0
|
164
|
+
return YAML.load(@io)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns true if the IO stream contains meta-data. Returns false if the
|
168
|
+
# IO stream does not contain meta-data.
|
169
|
+
#
|
170
|
+
def meta_data?
|
171
|
+
meta_end.nil? ? false : true
|
172
|
+
end
|
173
|
+
|
174
|
+
# Returns the number of meta-data blocks at the top of the file.
|
175
|
+
#
|
176
|
+
def meta_count
|
177
|
+
meta_end
|
178
|
+
@meta_count
|
179
|
+
end
|
180
|
+
|
181
|
+
# Returns the position in the IO stream where the meta-data ends and the
|
182
|
+
# regular data begins. If there is no meta-data in the stream, returns +nil+.
|
183
|
+
#
|
184
|
+
def meta_end
|
185
|
+
return @meta_end if defined? @meta_end
|
186
|
+
@meta_end = nil
|
187
|
+
|
188
|
+
@io.seek 0
|
189
|
+
line = @io.read(4)
|
190
|
+
return unless META_SEP =~ line
|
191
|
+
|
192
|
+
@io.seek 0
|
193
|
+
@io.gets
|
194
|
+
pos, count = nil, 1
|
195
|
+
|
196
|
+
while line = @io.gets
|
197
|
+
count += 1
|
198
|
+
if META_SEP =~ line
|
199
|
+
pos = count
|
200
|
+
@meta_count += 1
|
201
|
+
end
|
202
|
+
end
|
203
|
+
return if pos.nil?
|
204
|
+
|
205
|
+
@meta_end = pos
|
206
|
+
end
|
207
|
+
|
208
|
+
end # class MetaFile
|
209
|
+
end # module Webby::Resources
|
210
|
+
|
211
|
+
# EOF
|