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,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,386 @@
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
+ FileUtils.mkdir_p ::File.dirname(page.destination)
40
+ journal.create_or_update(page)
41
+
42
+ ::File.open(page.destination, 'w') do |fd|
43
+ fd.write(renderer._layout_page)
44
+ end
45
+ break unless renderer._next_page
46
+ }
47
+ end
48
+
49
+ attr_reader :logger
50
+
51
+ # call-seq:
52
+ # Renderer.new( page )
53
+ #
54
+ # Create a new renderer for the given _page_. The renderer will apply the
55
+ # desired filters to the _page_ (from the page's meta-data) and then
56
+ # render the filtered page into the desired layout.
57
+ #
58
+ def initialize( page )
59
+ unless page.instance_of? Resources::Page
60
+ raise ArgumentError,
61
+ "only page resources can be rendered '#{page.path}'"
62
+ end
63
+
64
+ @page = page
65
+ @pages = Resources.pages
66
+ @partials = Resources.partials
67
+ @content = nil
68
+ @config = ::Webby.site
69
+
70
+ @_bindings = []
71
+ @_content_for = {}
72
+ @logger = Logging::Logger[self]
73
+ end
74
+
75
+ # call-seq:
76
+ # render( resource = nil, opts = {} ) => string
77
+ #
78
+ # Render the given resource (a page or a partial) and return the results
79
+ # as a string. If a resource is not given, then the options hash should
80
+ # contain the name of a partial to render (:partial => 'name').
81
+ #
82
+ # When a partial name is given, the partial is found by looking in the
83
+ # directory of the current page being rendered. Otherwise, the full path
84
+ # to the partial can be given.
85
+ #
86
+ # If a :guard option is given as true, then the resulting string will be
87
+ # protected from processing by subsequent filters. Currently this only
88
+ # protects against the textile filter.
89
+ #
90
+ # When rendering partials, local variables can be passed to the partial by
91
+ # setting them in hash passed as the :locals option.
92
+ #
93
+ # ==== Options
94
+ # :partial<String>::
95
+ # The partial to render
96
+ # :locals<Hash>::
97
+ # Locals values to define when rendering a partial
98
+ # :guard<Boolean>::
99
+ # Prevents the resulting string from being processed by subsequent
100
+ # filters (only textile for now)
101
+ #
102
+ # ==== Returns
103
+ # A string that is the rendered page or partial.
104
+ #
105
+ # ==== Examples
106
+ # # render the partial "foo" using the given local variables
107
+ # render( :partial => "foo", :locals => {:bar => "value for bar"} )
108
+ #
109
+ # # find another page and render it into this page and protect the
110
+ # # resulting contents from further filters
111
+ # page = @pages.find( :title => "Chicken Coop" )
112
+ # render( page, :guard => true )
113
+ #
114
+ # # find a partial and render it using the given local variables
115
+ # partial = @partials.find( :filename => "foo", :in_directory => "/path" )
116
+ # render( partial, :locals => {:baz => "baztastic"} )
117
+ #
118
+ def render( *args )
119
+ opts = Hash === args.last ? args.pop : {}
120
+ resource = args.first
121
+ resource = _find_partial(opts[:partial]) if resource.nil?
122
+
123
+ str = case resource
124
+ when Resources::Page
125
+ ::Webby::Renderer.new(resource)._render_page
126
+ when Resources::Partial
127
+ _render_partial(resource, opts)
128
+ when Resources::Static
129
+ resource._read
130
+ else
131
+ raise ::Webby::Error, "expecting a page or a partial but got '#{resource.class.name}'"
132
+ end
133
+
134
+ str = _guard(str) if opts[:guard]
135
+ str
136
+ end
137
+
138
+ # call-seq:
139
+ # render_page => string
140
+ #
141
+ # This method is being deprecated. It is being made internal to the
142
+ # framework and really shouldn't be used anymore.
143
+ #
144
+ def render_page
145
+ Webby.deprecated "render_page", "this method is being made internal to the framework"
146
+ _render_page
147
+ end
148
+
149
+ # call-seq:
150
+ # render_partial( partial, :locals => {} ) => string
151
+ #
152
+ # This method is being deprecated. Please use the +render+ method instead.
153
+ #
154
+ def render_partial( part, opts = {} )
155
+ Webby.deprecated "render_partial", "it is being replaced by the Renderer#render() method"
156
+ opts[:partial] = part
157
+ render opts
158
+ end
159
+
160
+ # call-seq:
161
+ # paginate( items, per_page ) {|item| block}
162
+ #
163
+ # Iterate the given _block_ for each item selected from the _items_ array
164
+ # using the given number of items _per_page_. The first time the page is
165
+ # rendered, the items passed to the block are selected using the range
166
+ # (0...per_page). The next rendering selects (per_page...2*per_page). This
167
+ # continues until all _items_ have been paginated.
168
+ #
169
+ # Calling this method creates a <code>@pager</code> object that can be
170
+ # accessed from the page. The <code>@pager</code> contains information
171
+ # about the next page, the current page number, the previous page, and the
172
+ # number of items in the current page.
173
+ #
174
+ def paginate( items, count, &block )
175
+ @pager ||= Paginator.new(items.length, count, @page) do |offset, per_page|
176
+ items[offset,per_page]
177
+ end.first
178
+
179
+ @pager.each(&block)
180
+ end
181
+
182
+ # call-seq:
183
+ # get_binding => binding
184
+ #
185
+ # Returns the current binding for the renderer.
186
+ #
187
+ def get_binding
188
+ @_bindings.last
189
+ end
190
+
191
+ # call-seq:
192
+ # _render_page => string
193
+ #
194
+ # Apply the desired filters to the page. The filters to apply are
195
+ # determined from the page's meta-data.
196
+ #
197
+ def _render_page
198
+ _track_rendering(@page.path) {
199
+ Filters.process(self, @page, @page._read)
200
+ }
201
+ end
202
+
203
+ # call-seq:
204
+ # _render_partial( partial, :locals => {} ) => string
205
+ #
206
+ # Render the given _partial_ into the current page. The :locals are a hash
207
+ # of key / value pairs that will be set as local variables in the scope of
208
+ # the partial when it is rendered.
209
+ #
210
+ def _render_partial( part, opts = {} )
211
+ _track_rendering(part.path) {
212
+ _configure_locals(opts[:locals])
213
+ Filters.process(self, part, part._read)
214
+ }
215
+ end
216
+
217
+ # call-seq:
218
+ # _layout_page => string
219
+ #
220
+ # Apply the desired filters to the page and then render the filtered page
221
+ # into the desired layout. The filters to apply to the page are determined
222
+ # from the page's meta-data. The layout to use is also determined from the
223
+ # page's meta-data.
224
+ #
225
+ def _layout_page
226
+ @content = _render_page
227
+
228
+ _track_rendering(@page.path) {
229
+ _render_layout_for(@page)
230
+ }
231
+ raise ::Webby::Error, "rendering stack corrupted" unless @@stack.empty?
232
+
233
+ @content
234
+ rescue ::Webby::Error => err
235
+ logger.error "while rendering page '#{@page.path}'"
236
+ logger.error err.message
237
+ rescue => err
238
+ logger.error "while rendering page '#{@page.path}'"
239
+ logger.fatal err
240
+ exit 1
241
+ ensure
242
+ @content = nil
243
+ @@stack.clear
244
+ end
245
+
246
+ # call-seq:
247
+ # _render_layout_for( resource )
248
+ #
249
+ # Render the layout for the given resource. If the resource does not have
250
+ # a layout, then this method returns immediately.
251
+ #
252
+ def _render_layout_for( res )
253
+ return unless res.layout
254
+ lyt = Resources.find_layout(res.layout)
255
+ return if lyt.nil?
256
+
257
+ _track_rendering(lyt.path) {
258
+ @content = Filters.process(self, lyt, lyt._read)
259
+ _render_layout_for(lyt)
260
+ }
261
+ end
262
+
263
+ # call-seq:
264
+ # _next_page => true or false
265
+ #
266
+ # Returns +true+ if there is a next page to render. Returns +false+ if
267
+ # there is no next page or if pagination has not been configured for the
268
+ # current page.
269
+ #
270
+ def _next_page
271
+ return false unless defined? @pager and @pager
272
+
273
+ # go to the next page; break out if there is no next page
274
+ if @pager.next?
275
+ @pager = @pager.next
276
+ @_content_for.clear
277
+ @_bindings.clear
278
+ else
279
+ @pager.pager.reset
280
+ @pager = nil
281
+ return false
282
+ end
283
+
284
+ true
285
+ end
286
+
287
+ # call-seq:
288
+ # _track_rendering( path ) {block}
289
+ #
290
+ # Keep track of the page rendering for the given _path_. The _block_ is
291
+ # where the the page will be rendered.
292
+ #
293
+ # This method keeps a stack of the current pages being rendeered. It looks
294
+ # for duplicates in the stack -- an indication of a rendering loop. When a
295
+ # rendering loop is detected, an error is raised.
296
+ #
297
+ # This method returns whatever is returned from the _block_.
298
+ #
299
+ def _track_rendering( path )
300
+ loop_error = @@stack.include? path
301
+ @@stack << path
302
+ @_bindings << _binding
303
+
304
+ if loop_error
305
+ msg = "rendering loop detected for '#{path}'\n"
306
+ msg << " current rendering stack\n\t"
307
+ msg << @@stack.join("\n\t")
308
+ raise ::Webby::Error, msg
309
+ end
310
+
311
+ yield
312
+ ensure
313
+ @@stack.pop if path == @@stack.last
314
+ @_bindings.pop
315
+ end
316
+
317
+ # call-seq:
318
+ # _configure_locals( locals )
319
+ #
320
+ # Configure local variables in the scope of the current binding returned
321
+ # by the +get_binding+ method. The _locals_ should be given as a hash of
322
+ # name / value pairs.
323
+ #
324
+ def _configure_locals( locals )
325
+ return if locals.nil?
326
+
327
+ locals.each do |k,v|
328
+ Thread.current[:value] = v
329
+ definition = "#{k} = Thread.current[:value]"
330
+ eval(definition, get_binding)
331
+ end
332
+ end
333
+
334
+ # Attempts to locate a partial by name. If only the partial name is given,
335
+ # then the current directory of the page being rendered is searched for
336
+ # the partial. If a full path is given, then the partial is searched for
337
+ # in that directory.
338
+ #
339
+ # Raies a Webby::Error if the partial could not be found.
340
+ #
341
+ def _find_partial( part )
342
+ case part
343
+ when String
344
+ part_dir = ::File.dirname(part)
345
+ part_dir = @page.dir if part_dir == '.'
346
+
347
+ part_fn = ::File.basename(part)
348
+ part_fn = '_' + part_fn unless part_fn =~ %r/^_/
349
+
350
+ p = Resources.partials.find(
351
+ :filename => part_fn, :in_directory => part_dir ) rescue nil
352
+ raise ::Webby::Error, "could not find partial '#{part}'" if p.nil?
353
+ p
354
+ when ::Webby::Resources::Partial
355
+ part
356
+ else raise ::Webby::Error, "expecting a partial or a partial name" end
357
+ end
358
+
359
+ # This method will put filter guards around the given input string. This
360
+ # will protect the string from being processed by any remaining filters
361
+ # (specifically the textile filter).
362
+ #
363
+ # The string is returned unchanged if there are no remaining filters to
364
+ # guard against.
365
+ #
366
+ def _guard( str )
367
+ return str unless @_cursor
368
+
369
+ if @_cursor.remaining_filters.include? 'textile'
370
+ str = "<notextile>\n%s\n</notextile>" % str
371
+ end
372
+ str
373
+ end
374
+
375
+ # Returns the binding in the scope of this Renderer object.
376
+ #
377
+ def _binding() binding end
378
+
379
+ end # class Renderer
380
+ end # module Webby
381
+
382
+ Webby.require_all_libs_relative_to(__FILE__, 'stelan')
383
+
384
+ end # unless defined?
385
+
386
+ # EOF