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.
Files changed (229) hide show
  1. data/History.txt +206 -0
  2. data/Manifest.txt +228 -0
  3. data/README.txt +92 -0
  4. data/Rakefile +49 -0
  5. data/bin/webby +41 -0
  6. data/bin/webby-gen +41 -0
  7. data/examples/blog/Sitefile +7 -0
  8. data/examples/blog/tasks/blog.rake +72 -0
  9. data/examples/blog/templates/atom_feed.erb +40 -0
  10. data/examples/blog/templates/blog/month.erb +22 -0
  11. data/examples/blog/templates/blog/post.erb +16 -0
  12. data/examples/blog/templates/blog/year.erb +22 -0
  13. data/examples/presentation/Sitefile +10 -0
  14. data/examples/presentation/content/css/uv/twilight.css +137 -0
  15. data/examples/presentation/content/presentation/_sample_code.txt +10 -0
  16. data/examples/presentation/content/presentation/index.txt +63 -0
  17. data/examples/presentation/content/presentation/s5/blank.gif +0 -0
  18. data/examples/presentation/content/presentation/s5/bodybg.gif +0 -0
  19. data/examples/presentation/content/presentation/s5/framing.css +23 -0
  20. data/examples/presentation/content/presentation/s5/iepngfix.htc +42 -0
  21. data/examples/presentation/content/presentation/s5/opera.css +7 -0
  22. data/examples/presentation/content/presentation/s5/outline.css +15 -0
  23. data/examples/presentation/content/presentation/s5/pretty.css +86 -0
  24. data/examples/presentation/content/presentation/s5/print.css +25 -0
  25. data/examples/presentation/content/presentation/s5/s5-core.css +9 -0
  26. data/examples/presentation/content/presentation/s5/slides.css +3 -0
  27. data/examples/presentation/content/presentation/s5/slides.js +553 -0
  28. data/examples/presentation/layouts/presentation.txt +43 -0
  29. data/examples/presentation/templates/_code_partial.erb +13 -0
  30. data/examples/presentation/templates/presentation.erb +40 -0
  31. data/examples/tumblog/Sitefile +9 -0
  32. data/examples/tumblog/content/css/tumblog.css +308 -0
  33. data/examples/tumblog/content/images/tumblog/permalink.gif +0 -0
  34. data/examples/tumblog/content/images/tumblog/rss.gif +0 -0
  35. data/examples/tumblog/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
  36. data/examples/tumblog/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
  37. data/examples/tumblog/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
  38. data/examples/tumblog/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
  39. data/examples/tumblog/content/tumblog/200807/up-a-tree/index.txt +13 -0
  40. data/examples/tumblog/content/tumblog/index.txt +37 -0
  41. data/examples/tumblog/content/tumblog/rss.txt +37 -0
  42. data/examples/tumblog/layouts/tumblog/default.txt +44 -0
  43. data/examples/tumblog/layouts/tumblog/post.txt +15 -0
  44. data/examples/tumblog/lib/tumblog_helper.rb +32 -0
  45. data/examples/tumblog/tasks/tumblog.rake +30 -0
  46. data/examples/tumblog/templates/atom_feed.erb +40 -0
  47. data/examples/tumblog/templates/tumblog/conversation.erb +12 -0
  48. data/examples/tumblog/templates/tumblog/link.erb +10 -0
  49. data/examples/tumblog/templates/tumblog/photo.erb +13 -0
  50. data/examples/tumblog/templates/tumblog/post.erb +12 -0
  51. data/examples/tumblog/templates/tumblog/quote.erb +11 -0
  52. data/examples/webby/Sitefile +19 -0
  53. data/examples/webby/content/communicate/index.txt +28 -0
  54. data/examples/webby/content/css/background.gif +0 -0
  55. data/examples/webby/content/css/blueprint/print.css +76 -0
  56. data/examples/webby/content/css/blueprint/screen.css +696 -0
  57. data/examples/webby/content/css/coderay.css +96 -0
  58. data/examples/webby/content/css/site.css +196 -0
  59. data/examples/webby/content/css/uv/twilight.css +137 -0
  60. data/examples/webby/content/index.txt +37 -0
  61. data/examples/webby/content/learn/index.txt +28 -0
  62. data/examples/webby/content/reference/index.txt +204 -0
  63. data/examples/webby/content/release-notes/index.txt +21 -0
  64. data/examples/webby/content/release-notes/rel-0-9-0/index.txt +74 -0
  65. data/examples/webby/content/release-notes/rel-0-9-1/index.txt +93 -0
  66. data/examples/webby/content/release-notes/rel-0-9-2/index.txt +14 -0
  67. data/examples/webby/content/release-notes/rel-0-9-3/index.txt +49 -0
  68. data/examples/webby/content/robots.txt +6 -0
  69. data/examples/webby/content/script/jquery.corner.js +152 -0
  70. data/examples/webby/content/script/jquery.js +31 -0
  71. data/examples/webby/content/sitemap.txt +31 -0
  72. data/examples/webby/content/tips_and_tricks/index.txt +97 -0
  73. data/examples/webby/content/tutorial/index.txt +135 -0
  74. data/examples/webby/content/user-manual/index.txt +419 -0
  75. data/examples/webby/layouts/default.txt +49 -0
  76. data/examples/webby/templates/page.erb +10 -0
  77. data/examples/website/Sitefile +7 -0
  78. data/examples/website/content/css/blueprint/License.txt +21 -0
  79. data/examples/website/content/css/blueprint/Readme.txt +100 -0
  80. data/examples/website/content/css/blueprint/compressed/print.css +76 -0
  81. data/examples/website/content/css/blueprint/compressed/screen.css +696 -0
  82. data/examples/website/content/css/blueprint/lib/forms.css +45 -0
  83. data/examples/website/content/css/blueprint/lib/grid.css +193 -0
  84. data/examples/website/content/css/blueprint/lib/grid.png +0 -0
  85. data/examples/website/content/css/blueprint/lib/ie.css +30 -0
  86. data/examples/website/content/css/blueprint/lib/reset.css +39 -0
  87. data/examples/website/content/css/blueprint/lib/typography.css +116 -0
  88. data/examples/website/content/css/blueprint/plugins/buttons/Readme +31 -0
  89. data/examples/website/content/css/blueprint/plugins/buttons/buttons.css +97 -0
  90. data/examples/website/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
  91. data/examples/website/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
  92. data/examples/website/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
  93. data/examples/website/content/css/blueprint/plugins/css-classes/Readme +14 -0
  94. data/examples/website/content/css/blueprint/plugins/css-classes/css-classes.css +24 -0
  95. data/examples/website/content/css/blueprint/plugins/fancy-type/Readme +22 -0
  96. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +5 -0
  97. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type.css +74 -0
  98. data/examples/website/content/css/blueprint/print.css +68 -0
  99. data/examples/website/content/css/blueprint/screen.css +22 -0
  100. data/examples/website/content/css/coderay.css +111 -0
  101. data/examples/website/content/css/site.css +67 -0
  102. data/examples/website/content/index.txt +19 -0
  103. data/examples/website/layouts/default.txt +58 -0
  104. data/examples/website/lib/breadcrumbs.rb +28 -0
  105. data/examples/website/templates/_partial.erb +10 -0
  106. data/examples/website/templates/page.erb +18 -0
  107. data/lib/webby.rb +221 -0
  108. data/lib/webby/apps.rb +12 -0
  109. data/lib/webby/apps/generator.rb +276 -0
  110. data/lib/webby/apps/main.rb +255 -0
  111. data/lib/webby/auto_builder.rb +157 -0
  112. data/lib/webby/builder.rb +180 -0
  113. data/lib/webby/core_ext/enumerable.rb +11 -0
  114. data/lib/webby/core_ext/hash.rb +28 -0
  115. data/lib/webby/core_ext/kernel.rb +26 -0
  116. data/lib/webby/core_ext/string.rb +163 -0
  117. data/lib/webby/core_ext/time.rb +9 -0
  118. data/lib/webby/filters.rb +83 -0
  119. data/lib/webby/filters/basepath.rb +97 -0
  120. data/lib/webby/filters/erb.rb +9 -0
  121. data/lib/webby/filters/haml.rb +18 -0
  122. data/lib/webby/filters/markdown.rb +16 -0
  123. data/lib/webby/filters/outline.rb +309 -0
  124. data/lib/webby/filters/sass.rb +17 -0
  125. data/lib/webby/filters/slides.rb +56 -0
  126. data/lib/webby/filters/textile.rb +16 -0
  127. data/lib/webby/filters/tidy.rb +76 -0
  128. data/lib/webby/filters/wiki_words.rb +14 -0
  129. data/lib/webby/helpers.rb +30 -0
  130. data/lib/webby/helpers/capture_helper.rb +141 -0
  131. data/lib/webby/helpers/coderay_helper.rb +69 -0
  132. data/lib/webby/helpers/graphviz_helper.rb +136 -0
  133. data/lib/webby/helpers/tag_helper.rb +65 -0
  134. data/lib/webby/helpers/tex_img_helper.rb +133 -0
  135. data/lib/webby/helpers/ultraviolet_helper.rb +63 -0
  136. data/lib/webby/helpers/url_helper.rb +241 -0
  137. data/lib/webby/journal.rb +126 -0
  138. data/lib/webby/link_validator.rb +152 -0
  139. data/lib/webby/renderer.rb +386 -0
  140. data/lib/webby/resources.rb +136 -0
  141. data/lib/webby/resources/db.rb +251 -0
  142. data/lib/webby/resources/layout.rb +54 -0
  143. data/lib/webby/resources/meta_file.rb +211 -0
  144. data/lib/webby/resources/page.rb +81 -0
  145. data/lib/webby/resources/partial.rb +85 -0
  146. data/lib/webby/resources/resource.rb +201 -0
  147. data/lib/webby/resources/static.rb +36 -0
  148. data/lib/webby/stelan/mktemp.rb +135 -0
  149. data/lib/webby/stelan/paginator.rb +165 -0
  150. data/lib/webby/stelan/spawner.rb +339 -0
  151. data/lib/webby/tasks/build.rake +27 -0
  152. data/lib/webby/tasks/create.rake +22 -0
  153. data/lib/webby/tasks/deploy.rake +22 -0
  154. data/lib/webby/tasks/growl.rake +16 -0
  155. data/lib/webby/tasks/validate.rake +19 -0
  156. data/spec/core_ext/hash_spec.rb +47 -0
  157. data/spec/core_ext/string_spec.rb +110 -0
  158. data/spec/core_ext/time_spec.rb +19 -0
  159. data/spec/data/hooligans/bad_meta_data_1.txt +34 -0
  160. data/spec/data/hooligans/bad_meta_data_2.txt +34 -0
  161. data/spec/data/outline/basic.out +81 -0
  162. data/spec/data/outline/basic.txt +25 -0
  163. data/spec/data/outline/no_clobber.out +86 -0
  164. data/spec/data/outline/numbering.out +81 -0
  165. data/spec/data/outline/numbering_only.out +21 -0
  166. data/spec/data/outline/toc_range_1.out +66 -0
  167. data/spec/data/outline/toc_range_2.out +55 -0
  168. data/spec/data/outline/toc_style.out +81 -0
  169. data/spec/data/site/Sitefile +9 -0
  170. data/spec/data/site/content/_partial.txt +10 -0
  171. data/spec/data/site/content/css/coderay.css +111 -0
  172. data/spec/data/site/content/css/site.css +67 -0
  173. data/spec/data/site/content/css/tumblog.css +308 -0
  174. data/spec/data/site/content/images/tumblog/permalink.gif +0 -0
  175. data/spec/data/site/content/images/tumblog/rss.gif +0 -0
  176. data/spec/data/site/content/index.txt +19 -0
  177. data/spec/data/site/content/photos.txt +21 -0
  178. data/spec/data/site/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
  179. data/spec/data/site/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
  180. data/spec/data/site/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
  181. data/spec/data/site/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
  182. data/spec/data/site/content/tumblog/200807/up-a-tree/index.txt +13 -0
  183. data/spec/data/site/content/tumblog/index.txt +37 -0
  184. data/spec/data/site/content/tumblog/rss.txt +37 -0
  185. data/spec/data/site/layouts/default.txt +58 -0
  186. data/spec/data/site/layouts/tumblog/default.txt +44 -0
  187. data/spec/data/site/layouts/tumblog/post.txt +15 -0
  188. data/spec/data/site/lib/breadcrumbs.rb +28 -0
  189. data/spec/data/site/lib/tumblog_helper.rb +32 -0
  190. data/spec/data/site/tasks/tumblog.rake +30 -0
  191. data/spec/data/site/templates/_partial.erb +10 -0
  192. data/spec/data/site/templates/atom_feed.erb +40 -0
  193. data/spec/data/site/templates/page.erb +18 -0
  194. data/spec/data/site/templates/presentation.erb +40 -0
  195. data/spec/data/site/templates/tumblog/conversation.erb +12 -0
  196. data/spec/data/site/templates/tumblog/link.erb +10 -0
  197. data/spec/data/site/templates/tumblog/photo.erb +13 -0
  198. data/spec/data/site/templates/tumblog/post.erb +12 -0
  199. data/spec/data/site/templates/tumblog/quote.erb +11 -0
  200. data/spec/spec.opts +1 -0
  201. data/spec/spec_helper.rb +51 -0
  202. data/spec/webby/apps/generator_spec.rb +116 -0
  203. data/spec/webby/apps/main_spec.rb +88 -0
  204. data/spec/webby/filters/basepath_spec.rb +167 -0
  205. data/spec/webby/filters/outline_spec.rb +92 -0
  206. data/spec/webby/filters/textile_spec.rb +20 -0
  207. data/spec/webby/helpers/capture_helper_spec.rb +56 -0
  208. data/spec/webby/renderer_spec.rb +139 -0
  209. data/spec/webby/resources/db_spec.rb +250 -0
  210. data/spec/webby/resources/layout_spec.rb +83 -0
  211. data/spec/webby/resources/meta_file_spec.rb +171 -0
  212. data/spec/webby/resources/page_spec.rb +111 -0
  213. data/spec/webby/resources/partial_spec.rb +58 -0
  214. data/spec/webby/resources/resource_spec.rb +219 -0
  215. data/spec/webby/resources/static_spec.rb +49 -0
  216. data/spec/webby/resources_spec.rb +69 -0
  217. data/tasks/ann.rake +81 -0
  218. data/tasks/bones.rake +21 -0
  219. data/tasks/gem.rake +187 -0
  220. data/tasks/git.rake +41 -0
  221. data/tasks/manifest.rake +48 -0
  222. data/tasks/notes.rake +28 -0
  223. data/tasks/post_load.rake +39 -0
  224. data/tasks/rdoc.rake +51 -0
  225. data/tasks/rubyforge.rake +55 -0
  226. data/tasks/setup.rb +268 -0
  227. data/tasks/spec.rake +55 -0
  228. data/tasks/website.rake +38 -0
  229. 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