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.
Files changed (172) hide show
  1. data/History.txt +176 -0
  2. data/Manifest.txt +171 -0
  3. data/README.txt +92 -0
  4. data/Rakefile +54 -0
  5. data/bin/webby +8 -0
  6. data/bin/webby-gen +8 -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 +1 -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/css/background.gif +0 -0
  54. data/examples/webby/content/css/blueprint/print.css +76 -0
  55. data/examples/webby/content/css/blueprint/screen.css +696 -0
  56. data/examples/webby/content/css/coderay.css +96 -0
  57. data/examples/webby/content/css/site.css +184 -0
  58. data/examples/webby/content/css/uv/twilight.css +137 -0
  59. data/examples/webby/content/index.txt +37 -0
  60. data/examples/webby/content/manual/index.txt +430 -0
  61. data/examples/webby/content/reference/index.txt +202 -0
  62. data/examples/webby/content/release-notes/rel-0-9-0/index.txt +73 -0
  63. data/examples/webby/content/robots.txt +6 -0
  64. data/examples/webby/content/script/jquery.corner.js +152 -0
  65. data/examples/webby/content/script/jquery.js +31 -0
  66. data/examples/webby/content/sitemap.txt +31 -0
  67. data/examples/webby/content/tips_and_tricks/index.txt +96 -0
  68. data/examples/webby/content/tutorial/index.txt +131 -0
  69. data/examples/webby/layouts/default.txt +55 -0
  70. data/examples/webby/templates/page.erb +10 -0
  71. data/examples/website/Sitefile +7 -0
  72. data/examples/website/content/css/blueprint/License.txt +21 -0
  73. data/examples/website/content/css/blueprint/Readme.txt +100 -0
  74. data/examples/website/content/css/blueprint/compressed/print.css +76 -0
  75. data/examples/website/content/css/blueprint/compressed/screen.css +696 -0
  76. data/examples/website/content/css/blueprint/lib/forms.css +45 -0
  77. data/examples/website/content/css/blueprint/lib/grid.css +193 -0
  78. data/examples/website/content/css/blueprint/lib/grid.png +0 -0
  79. data/examples/website/content/css/blueprint/lib/ie.css +30 -0
  80. data/examples/website/content/css/blueprint/lib/reset.css +39 -0
  81. data/examples/website/content/css/blueprint/lib/typography.css +116 -0
  82. data/examples/website/content/css/blueprint/plugins/buttons/Readme +31 -0
  83. data/examples/website/content/css/blueprint/plugins/buttons/buttons.css +97 -0
  84. data/examples/website/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
  85. data/examples/website/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
  86. data/examples/website/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
  87. data/examples/website/content/css/blueprint/plugins/css-classes/Readme +14 -0
  88. data/examples/website/content/css/blueprint/plugins/css-classes/css-classes.css +24 -0
  89. data/examples/website/content/css/blueprint/plugins/fancy-type/Readme +22 -0
  90. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +5 -0
  91. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type.css +74 -0
  92. data/examples/website/content/css/blueprint/print.css +68 -0
  93. data/examples/website/content/css/blueprint/screen.css +22 -0
  94. data/examples/website/content/css/coderay.css +111 -0
  95. data/examples/website/content/css/site.css +67 -0
  96. data/examples/website/content/index.txt +19 -0
  97. data/examples/website/layouts/default.txt +58 -0
  98. data/examples/website/lib/breadcrumbs.rb +28 -0
  99. data/examples/website/templates/_partial.erb +10 -0
  100. data/examples/website/templates/page.erb +18 -0
  101. data/examples/website/templates/presentation.erb +40 -0
  102. data/lib/webby.rb +227 -0
  103. data/lib/webby/apps.rb +12 -0
  104. data/lib/webby/apps/generator.rb +283 -0
  105. data/lib/webby/apps/main.rb +221 -0
  106. data/lib/webby/auto_builder.rb +83 -0
  107. data/lib/webby/builder.rb +183 -0
  108. data/lib/webby/core_ext/enumerable.rb +11 -0
  109. data/lib/webby/core_ext/hash.rb +28 -0
  110. data/lib/webby/core_ext/kernel.rb +21 -0
  111. data/lib/webby/core_ext/string.rb +163 -0
  112. data/lib/webby/core_ext/time.rb +9 -0
  113. data/lib/webby/filters.rb +91 -0
  114. data/lib/webby/filters/basepath.rb +97 -0
  115. data/lib/webby/filters/erb.rb +9 -0
  116. data/lib/webby/filters/haml.rb +18 -0
  117. data/lib/webby/filters/markdown.rb +16 -0
  118. data/lib/webby/filters/outline.rb +308 -0
  119. data/lib/webby/filters/sass.rb +17 -0
  120. data/lib/webby/filters/slides.rb +56 -0
  121. data/lib/webby/filters/textile.rb +16 -0
  122. data/lib/webby/filters/tidy.rb +76 -0
  123. data/lib/webby/helpers.rb +30 -0
  124. data/lib/webby/helpers/capture_helper.rb +141 -0
  125. data/lib/webby/helpers/coderay_helper.rb +69 -0
  126. data/lib/webby/helpers/graphviz_helper.rb +136 -0
  127. data/lib/webby/helpers/tag_helper.rb +65 -0
  128. data/lib/webby/helpers/tex_img_helper.rb +133 -0
  129. data/lib/webby/helpers/ultraviolet_helper.rb +63 -0
  130. data/lib/webby/helpers/url_helper.rb +235 -0
  131. data/lib/webby/link_validator.rb +152 -0
  132. data/lib/webby/renderer.rb +379 -0
  133. data/lib/webby/resources.rb +96 -0
  134. data/lib/webby/resources/db.rb +251 -0
  135. data/lib/webby/resources/file.rb +221 -0
  136. data/lib/webby/resources/layout.rb +63 -0
  137. data/lib/webby/resources/page.rb +118 -0
  138. data/lib/webby/resources/partial.rb +79 -0
  139. data/lib/webby/resources/resource.rb +160 -0
  140. data/lib/webby/resources/static.rb +52 -0
  141. data/lib/webby/stelan/mktemp.rb +135 -0
  142. data/lib/webby/stelan/paginator.rb +150 -0
  143. data/lib/webby/stelan/spawner.rb +339 -0
  144. data/lib/webby/tasks/build.rake +27 -0
  145. data/lib/webby/tasks/create.rake +22 -0
  146. data/lib/webby/tasks/deploy.rake +22 -0
  147. data/lib/webby/tasks/growl.rake +15 -0
  148. data/lib/webby/tasks/heel.rake +28 -0
  149. data/lib/webby/tasks/validate.rake +19 -0
  150. data/spec/core_ext/hash_spec.rb +47 -0
  151. data/spec/core_ext/string_spec.rb +110 -0
  152. data/spec/core_ext/time_spec.rb +19 -0
  153. data/spec/spec.opts +1 -0
  154. data/spec/spec_helper.rb +14 -0
  155. data/spec/webby/apps/generator_spec.rb +111 -0
  156. data/spec/webby/apps/main_spec.rb +75 -0
  157. data/spec/webby/helpers/capture_helper_spec.rb +56 -0
  158. data/spec/webby/resources/file_spec.rb +104 -0
  159. data/spec/webby/resources_spec.rb +17 -0
  160. data/tasks/ann.rake +81 -0
  161. data/tasks/bones.rake +21 -0
  162. data/tasks/gem.rake +126 -0
  163. data/tasks/git.rake +41 -0
  164. data/tasks/manifest.rake +49 -0
  165. data/tasks/notes.rake +28 -0
  166. data/tasks/post_load.rake +39 -0
  167. data/tasks/rdoc.rake +51 -0
  168. data/tasks/rubyforge.rake +57 -0
  169. data/tasks/setup.rb +268 -0
  170. data/tasks/spec.rake +55 -0
  171. data/tasks/website.rake +38 -0
  172. 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