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,152 @@
1
+ require 'hpricot'
2
+ require 'open-uri'
3
+
4
+ module Webby
5
+
6
+ # The Webby LinkValidator class is used to validate the hyperlinks of all
7
+ # the HTML files in the output directory. By default, only links to other
8
+ # pages in the output directory are checked. However, setting the
9
+ # :external flag to +true+ will cause hyperlinks to external web sites to
10
+ # be validated as well.
11
+ #
12
+ class LinkValidator
13
+
14
+ # A lazy man's method that will instantiate a new link validator and run
15
+ # the validations.
16
+ #
17
+ def self.validate( opts = {} )
18
+ new(opts).validate
19
+ end
20
+
21
+ attr_accessor :validate_externals
22
+
23
+ # call-seq:
24
+ # LinkValidator.new( opts = {} )
25
+ #
26
+ # Creates a new LinkValidator object. The only supported option is the
27
+ # :external flag. When set to +true+, the link validator will also check
28
+ # out links to external websites. This is done by opening a connection to
29
+ # the remote site and pulling down the page specified in the hyperlink.
30
+ # Use with caution.
31
+ #
32
+ def initialize( opts = {} )
33
+ @log = Logging::Logger[self]
34
+
35
+ glob = ::File.join(::Webby.site.output_dir, '**', '*.html')
36
+ @files = Dir.glob(glob).sort
37
+ @attr_rgxp = %r/\[@(\w+)\]$/o
38
+
39
+ @validate_externals = opts.getopt(:external, false)
40
+ @valid_uris = ::Webby.site.valid_uris.flatten
41
+ @invalid_uris = []
42
+ end
43
+
44
+ # Iterate over all the HTML files in the output directory and validate the
45
+ # hyperlinks.
46
+ #
47
+ def validate
48
+ @files.each {|fn| check_file fn}
49
+ end
50
+
51
+ # Check the given file (identified by its filename {fn for short here}) by
52
+ # iterating through all the configured xpaths and validating that those
53
+ # hyperlinks ae valid.
54
+ #
55
+ def check_file( fn )
56
+ @log.info "validating #{fn}"
57
+
58
+ dir = ::File.dirname(fn)
59
+ @doc = Hpricot(::File.read(fn))
60
+
61
+ ::Webby.site.xpaths.each do |xpath|
62
+ @attr_name = nil
63
+
64
+ @doc.search(xpath).each do |element|
65
+ @attr_name ||= @attr_rgxp.match(xpath)[1]
66
+ uri = URI.parse(element.get_attribute(@attr_name))
67
+ validate_uri(uri, dir)
68
+ end
69
+ end
70
+ @doc = @attr_name = nil
71
+ end
72
+
73
+ # Validate the the page the _uri_ refers to actually exists. The directory
74
+ # of the current page being processed is needed in order to resolve
75
+ # relative paths.
76
+ #
77
+ # If the _uri_ is a relative path, then the output directory is searched
78
+ # for the appropriate page. If the _uri_ is an absolute path, then the
79
+ # remote server is contacted and the page requested from the server. This
80
+ # will only take place if the LinkValidator was created with the :external
81
+ # flag set to true.
82
+ #
83
+ def validate_uri( uri, dir )
84
+ # for relative URIs, we can see if the file exists in the output folder
85
+ if uri.relative?
86
+ return validate_anchor(uri, @doc) if uri.path.empty?
87
+
88
+ path = if uri.path =~ %r/^\//
89
+ ::File.join(::Webby.site.output_dir, uri.path)
90
+ else
91
+ ::File.join(dir, uri.path)
92
+ end
93
+ path = ::File.join(path, 'index.html') if ::File.extname(path).empty?
94
+
95
+ uri_str = path.dup
96
+ (uri_str << '#' << uri.fragment) if uri.fragment
97
+ return if @valid_uris.include? uri_str
98
+
99
+ if test ?f, path
100
+ valid = if uri.fragment
101
+ validate_anchor(uri, Hpricot(::File.read(path)))
102
+ else true end
103
+ @valid_uris << uri_str if valid
104
+ else
105
+ @log.error "invalid URI '#{uri.to_s}'"
106
+ end
107
+
108
+ # if the URI responds to the open mehod, then try to access the URI
109
+ elsif uri.respond_to? :open
110
+ return unless @validate_externals
111
+ return if @valid_uris.include? uri.to_s
112
+
113
+ if @invalid_uris.include? uri.to_s
114
+ @log.error "could not open URI '#{uri.to_s}'"
115
+ return
116
+ end
117
+
118
+ begin
119
+ uri.open {|_| nil}
120
+ @valid_uris << uri.to_s
121
+ rescue Exception
122
+ @log.error "could not open URI '#{uri.to_s}'"
123
+ @invalid_uris << uri.to_s
124
+ end
125
+
126
+ # otherwise, post a warning that the URI could not be validated
127
+ else
128
+ return if @valid_uris.include? uri.to_s
129
+ @log.warn "could not validate URI '#{uri.to_s}'"
130
+ end
131
+ end
132
+
133
+ # Validate that the anchor fragment of the URI exists in the given
134
+ # document. The document is an Hpricot document object.
135
+ #
136
+ # Returns +true+ if the anchor exists in the document and +false+ if it
137
+ # does not.
138
+ #
139
+ def validate_anchor( uri, doc )
140
+ return false if uri.fragment.nil?
141
+
142
+ anchor = '#' + uri.fragment
143
+ if doc.at(anchor).nil?
144
+ @log.error "invalid URI '#{uri.to_s}'"
145
+ false
146
+ else true end
147
+ end
148
+
149
+ end # class LinkValidator
150
+ end # module Webby
151
+
152
+ # EOF
@@ -0,0 +1,379 @@
1
+ # Equivalent to a header guard in C/C++
2
+ # Used to prevent the spec helper from being loaded more than once
3
+ unless defined? ::Webby::Renderer
4
+
5
+ require 'erb'
6
+
7
+ module Webby
8
+
9
+ # The Webby::Renderer is used to _filter_ and _layout_ the text found in the
10
+ # resource page files in the content directory.
11
+ #
12
+ # A page is filtered based on the settings of the 'filter' option in the
13
+ # page's meta-data information. For example, if 'textile' is specified as
14
+ # a filter, then the page will be run through the RedCloth markup filter.
15
+ # More than one filter can be used on a page; they will be run in the
16
+ # order specified in the meta-data.
17
+ #
18
+ # A page is rendered into a layout specified by the 'layout' option in the
19
+ # page's meta-data information.
20
+ #
21
+ class Renderer
22
+ include ERB::Util
23
+
24
+ # :stopdoc:
25
+ @@stack = []
26
+ # :startdoc:
27
+
28
+ # call-seq:
29
+ # Renderer.write( page )
30
+ #
31
+ # Render the given _page_ and write the resulting output to the page's
32
+ # destination. If the _page_ uses pagination, then multiple destination
33
+ # files will be created -- one for each paginated data set in the page.
34
+ #
35
+ def self.write( page )
36
+ renderer = self.new(page)
37
+
38
+ loop {
39
+ ::File.open(page.destination, 'w') do |fd|
40
+ fd.write(renderer._layout_page)
41
+ end
42
+ break unless renderer._next_page
43
+ }
44
+ end
45
+
46
+ # call-seq:
47
+ # Renderer.new( page )
48
+ #
49
+ # Create a new renderer for the given _page_. The renderer will apply the
50
+ # desired filters to the _page_ (from the page's meta-data) and then
51
+ # render the filtered page into the desired layout.
52
+ #
53
+ def initialize( page )
54
+ unless page.instance_of? Resources::Page
55
+ raise ArgumentError,
56
+ "only page resources can be rendered '#{page.path}'"
57
+ end
58
+
59
+ @page = page
60
+ @pages = Resources.pages
61
+ @partials = Resources.partials
62
+ @content = nil
63
+ @config = ::Webby.site
64
+
65
+ @_bindings = []
66
+ @_content_for = {}
67
+ @log = Logging::Logger[self]
68
+ end
69
+
70
+ # call-seq:
71
+ # render( resource = nil, opts = {} ) => string
72
+ #
73
+ # Render the given resource (a page or a partial) and return the results
74
+ # as a string. If a resource is not given, then the options hash should
75
+ # contain the name of a partial to render (:partial => 'name').
76
+ #
77
+ # When a partial name is given, the partial is found by looking in the
78
+ # directory of the current page being rendered. Otherwise, the full path
79
+ # to the partial can be given.
80
+ #
81
+ # If a :guard option is given as true, then the resulting string will be
82
+ # protected from processing by subsequent filters. Currently this only
83
+ # protects against the textile filter.
84
+ #
85
+ # When rendering partials, local variables can be passed to the partial by
86
+ # setting them in hash passed as the :locals option.
87
+ #
88
+ # ==== Options
89
+ # :partial<String>::
90
+ # The partial to render
91
+ # :locals<Hash>::
92
+ # Locals values to define when rendering a partial
93
+ # :guard<Boolean>::
94
+ # Prevents the resulting string from being processed by subsequent
95
+ # filters (only textile for now)
96
+ #
97
+ # ==== Returns
98
+ # A string that is the rendered page or partial.
99
+ #
100
+ # ==== Examples
101
+ # # render the partial "foo" using the given local variables
102
+ # render( :partial => "foo", :locals => {:bar => "value for bar"} )
103
+ #
104
+ # # find another page and render it into this page and protect the
105
+ # # resulting contents from further filters
106
+ # page = @pages.find( :title => "Chicken Coop" )
107
+ # render( page, :guard => true )
108
+ #
109
+ # # find a partial and render it using the given local variables
110
+ # partial = @partials.find( :filename => "foo", :in_directory => "/path" )
111
+ # render( partial, :locals => {:baz => "baztastic"} )
112
+ #
113
+ def render( *args )
114
+ opts = Hash === args.last ? args.pop : {}
115
+ resource = args.first
116
+ resource = _find_partial(opts[:partial]) if resource.nil?
117
+
118
+ str = case resource
119
+ when Resources::Page
120
+ ::Webby::Renderer.new(resource)._render_page
121
+ when Resources::Partial
122
+ _render_partial(resource, opts)
123
+ else
124
+ raise ::Webby::Error, "expecting a page or a partial but got '#{resource.class.name}'"
125
+ end
126
+
127
+ str = _guard(str) if opts[:guard]
128
+ str
129
+ end
130
+
131
+ # call-seq:
132
+ # render_page => string
133
+ #
134
+ # This method is being deprecated. It is being made internal to the
135
+ # framework and really shouldn't be used anymore.
136
+ #
137
+ def render_page
138
+ Webby.deprecated "render_page", "this method is being made internal to the framework"
139
+ _render_page
140
+ end
141
+
142
+ # call-seq:
143
+ # render_partial( partial, :locals => {} ) => string
144
+ #
145
+ # This method is being deprecated. Please use the +render+ method instead.
146
+ #
147
+ def render_partial( part, opts = {} )
148
+ Webby.deprecated "render_partial", "it is being replaced by the Renderer#render() method"
149
+ opts[:partial] = part
150
+ render opts
151
+ end
152
+
153
+ # call-seq:
154
+ # paginate( items, per_page ) {|item| block}
155
+ #
156
+ # Iterate the given _block_ for each item selected from the _items_ array
157
+ # using the given number of items _per_page_. The first time the page is
158
+ # rendered, the items passed to the block are selected using the range
159
+ # (0...per_page). The next rendering selects (per_page...2*per_page). This
160
+ # continues until all _items_ have been paginated.
161
+ #
162
+ # Calling this method creates a <code>@pager</code> object that can be
163
+ # accessed from the page. The <code>@pager</code> contains information
164
+ # about the next page, the current page number, the previous page, and the
165
+ # number of items in the current page.
166
+ #
167
+ def paginate( items, count, &block )
168
+ @pager ||= Paginator.new(items.length, count, @page) do |offset, per_page|
169
+ items[offset,per_page]
170
+ end.first
171
+
172
+ @pager.each(&block)
173
+ end
174
+
175
+ # call-seq:
176
+ # get_binding => binding
177
+ #
178
+ # Returns the current binding for the renderer.
179
+ #
180
+ def get_binding
181
+ @_bindings.last
182
+ end
183
+
184
+ # call-seq:
185
+ # _render_page => string
186
+ #
187
+ # Apply the desired filters to the page. The filters to apply are
188
+ # determined from the page's meta-data.
189
+ #
190
+ def _render_page
191
+ _track_rendering(@page.path) {
192
+ Filters.process(self, @page, ::Webby::Resources::File.read(@page.path))
193
+ }
194
+ end
195
+
196
+ # call-seq:
197
+ # _render_partial( partial, :locals => {} ) => string
198
+ #
199
+ # Render the given _partial_ into the current page. The :locals are a hash
200
+ # of key / value pairs that will be set as local variables in the scope of
201
+ # the partial when it is rendered.
202
+ #
203
+ def _render_partial( part, opts = {} )
204
+ _track_rendering(part.path) {
205
+ _configure_locals(opts[:locals])
206
+ Filters.process(self, part, ::Webby::Resources::File.read(part.path))
207
+ }
208
+ end
209
+
210
+ # call-seq:
211
+ # _layout_page => string
212
+ #
213
+ # Apply the desired filters to the page and then render the filtered page
214
+ # into the desired layout. The filters to apply to the page are determined
215
+ # from the page's meta-data. The layout to use is also determined from the
216
+ # page's meta-data.
217
+ #
218
+ def _layout_page
219
+ @content = _render_page
220
+
221
+ _track_rendering(@page.path) {
222
+ _render_layout_for(@page)
223
+ }
224
+ raise ::Webby::Error, "rendering stack corrupted" unless @@stack.empty?
225
+
226
+ @content
227
+ rescue ::Webby::Error => err
228
+ @log.error "while rendering page '#{@page.path}'"
229
+ @log.error err.message
230
+ rescue => err
231
+ @log.error "while rendering page '#{@page.path}'"
232
+ @log.fatal err
233
+ exit 1
234
+ ensure
235
+ @content = nil
236
+ @@stack.clear
237
+ end
238
+
239
+ # call-seq:
240
+ # _render_layout_for( resource )
241
+ #
242
+ # Render the layout for the given resource. If the resource does not have
243
+ # a layout, then this method returns immediately.
244
+ #
245
+ def _render_layout_for( res )
246
+ return unless res.layout
247
+ lyt = Resources.find_layout(res.layout)
248
+ return if lyt.nil?
249
+
250
+ _track_rendering(lyt.path) {
251
+ @content = Filters.process(
252
+ self, lyt, ::Webby::Resources::File.read(lyt.path))
253
+ _render_layout_for(lyt)
254
+ }
255
+ end
256
+
257
+ # call-seq:
258
+ # _next_page => true or false
259
+ #
260
+ # Returns +true+ if there is a next page to render. Returns +false+ if
261
+ # there is no next page or if pagination has not been configured for the
262
+ # current page.
263
+ #
264
+ def _next_page
265
+ return false unless defined? @pager and @pager
266
+
267
+ # go to the next page; break out if there is no next page
268
+ if @pager.next?
269
+ @pager = @pager.next
270
+ @_content_for.clear
271
+ @_bindings.clear
272
+ else
273
+ @page.number = nil
274
+ return false
275
+ end
276
+
277
+ true
278
+ end
279
+
280
+ # call-seq:
281
+ # _track_rendering( path ) {block}
282
+ #
283
+ # Keep track of the page rendering for the given _path_. The _block_ is
284
+ # where the the page will be rendered.
285
+ #
286
+ # This method keeps a stack of the current pages being rendeered. It looks
287
+ # for duplicates in the stack -- an indication of a rendering loop. When a
288
+ # rendering loop is detected, an error is raised.
289
+ #
290
+ # This method returns whatever is returned from the _block_.
291
+ #
292
+ def _track_rendering( path )
293
+ loop_error = @@stack.include? path
294
+ @@stack << path
295
+ @_bindings << _binding
296
+
297
+ if loop_error
298
+ msg = "rendering loop detected for '#{path}'\n"
299
+ msg << " current rendering stack\n\t"
300
+ msg << @@stack.join("\n\t")
301
+ raise ::Webby::Error, msg
302
+ end
303
+
304
+ yield
305
+ ensure
306
+ @@stack.pop if path == @@stack.last
307
+ @_bindings.pop
308
+ end
309
+
310
+ # call-seq:
311
+ # _configure_locals( locals )
312
+ #
313
+ # Configure local variables in the scope of the current binding returned
314
+ # by the +get_binding+ method. The _locals_ should be given as a hash of
315
+ # name / value pairs.
316
+ #
317
+ def _configure_locals( locals )
318
+ return if locals.nil?
319
+
320
+ locals.each do |k,v|
321
+ Thread.current[:value] = v
322
+ definition = "#{k} = Thread.current[:value]"
323
+ eval(definition, get_binding)
324
+ end
325
+ end
326
+
327
+ # Attempts to locate a partial by name. If only the partial name is given,
328
+ # then the current directory of the page being rendered is searched for
329
+ # the partial. If a full path is given, then the partial is searched for
330
+ # in that directory.
331
+ #
332
+ # Raies a Webby::Error if the partial could not be found.
333
+ #
334
+ def _find_partial( part )
335
+ case part
336
+ when String
337
+ part_dir = ::File.dirname(part)
338
+ part_dir = @page.dir if part_dir == '.'
339
+
340
+ part_fn = ::File.basename(part)
341
+ part_fn = '_' + part_fn unless part_fn =~ %r/^_/
342
+
343
+ p = Resources.partials.find(
344
+ :filename => part_fn, :in_directory => part_dir ) rescue nil
345
+ raise ::Webby::Error, "could not find partial '#{part}'" if p.nil?
346
+ p
347
+ when ::Webby::Resources::Partial
348
+ part
349
+ else raise ::Webby::Error, "expecting a partial or a partial name" end
350
+ end
351
+
352
+ # This method will put filter guards around the given input string. This
353
+ # will protect the string from being processed by any remaining filters
354
+ # (specifically the textile filter).
355
+ #
356
+ # The string is returned unchanged if there are no remaining filters to
357
+ # guard against.
358
+ #
359
+ def _guard( str )
360
+ return str unless @_cursor
361
+
362
+ if @_cursor.remaining_filters.include? 'textile'
363
+ str = "<notextile>\n%s\n</notextile>" % str
364
+ end
365
+ str
366
+ end
367
+
368
+ # Returns the binding in the scope of this Renderer object.
369
+ #
370
+ def _binding() binding end
371
+
372
+ end # class Renderer
373
+ end # module Webby
374
+
375
+ Webby.require_all_libs_relative_to(__FILE__, 'stelan')
376
+
377
+ end # unless defined?
378
+
379
+ # EOF