TwP-webby 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/History.txt +176 -0
  2. data/Manifest.txt +173 -0
  3. data/README.txt +92 -0
  4. data/Rakefile +50 -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/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/rel-0-9-0/index.txt +73 -0
  64. data/examples/webby/content/robots.txt +6 -0
  65. data/examples/webby/content/script/jquery.corner.js +152 -0
  66. data/examples/webby/content/script/jquery.js +31 -0
  67. data/examples/webby/content/sitemap.txt +31 -0
  68. data/examples/webby/content/tips_and_tricks/index.txt +96 -0
  69. data/examples/webby/content/tutorial/index.txt +131 -0
  70. data/examples/webby/content/user-manual/index.txt +419 -0
  71. data/examples/webby/layouts/default.txt +49 -0
  72. data/examples/webby/templates/page.erb +10 -0
  73. data/examples/website/Sitefile +7 -0
  74. data/examples/website/content/css/blueprint/License.txt +21 -0
  75. data/examples/website/content/css/blueprint/Readme.txt +100 -0
  76. data/examples/website/content/css/blueprint/compressed/print.css +76 -0
  77. data/examples/website/content/css/blueprint/compressed/screen.css +696 -0
  78. data/examples/website/content/css/blueprint/lib/forms.css +45 -0
  79. data/examples/website/content/css/blueprint/lib/grid.css +193 -0
  80. data/examples/website/content/css/blueprint/lib/grid.png +0 -0
  81. data/examples/website/content/css/blueprint/lib/ie.css +30 -0
  82. data/examples/website/content/css/blueprint/lib/reset.css +39 -0
  83. data/examples/website/content/css/blueprint/lib/typography.css +116 -0
  84. data/examples/website/content/css/blueprint/plugins/buttons/Readme +31 -0
  85. data/examples/website/content/css/blueprint/plugins/buttons/buttons.css +97 -0
  86. data/examples/website/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
  87. data/examples/website/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
  88. data/examples/website/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
  89. data/examples/website/content/css/blueprint/plugins/css-classes/Readme +14 -0
  90. data/examples/website/content/css/blueprint/plugins/css-classes/css-classes.css +24 -0
  91. data/examples/website/content/css/blueprint/plugins/fancy-type/Readme +22 -0
  92. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +5 -0
  93. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type.css +74 -0
  94. data/examples/website/content/css/blueprint/print.css +68 -0
  95. data/examples/website/content/css/blueprint/screen.css +22 -0
  96. data/examples/website/content/css/coderay.css +111 -0
  97. data/examples/website/content/css/site.css +67 -0
  98. data/examples/website/content/index.txt +19 -0
  99. data/examples/website/layouts/default.txt +58 -0
  100. data/examples/website/lib/breadcrumbs.rb +28 -0
  101. data/examples/website/templates/_partial.erb +10 -0
  102. data/examples/website/templates/page.erb +18 -0
  103. data/examples/website/templates/presentation.erb +40 -0
  104. data/lib/webby/apps/generator.rb +283 -0
  105. data/lib/webby/apps/main.rb +221 -0
  106. data/lib/webby/apps.rb +12 -0
  107. data/lib/webby/auto_builder.rb +83 -0
  108. data/lib/webby/builder.rb +183 -0
  109. data/lib/webby/core_ext/enumerable.rb +11 -0
  110. data/lib/webby/core_ext/hash.rb +28 -0
  111. data/lib/webby/core_ext/kernel.rb +21 -0
  112. data/lib/webby/core_ext/string.rb +163 -0
  113. data/lib/webby/core_ext/time.rb +9 -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 +309 -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/filters.rb +91 -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/helpers.rb +30 -0
  132. data/lib/webby/link_validator.rb +152 -0
  133. data/lib/webby/renderer.rb +379 -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/resources.rb +96 -0
  142. data/lib/webby/stelan/mktemp.rb +135 -0
  143. data/lib/webby/stelan/paginator.rb +150 -0
  144. data/lib/webby/stelan/spawner.rb +339 -0
  145. data/lib/webby/tasks/build.rake +27 -0
  146. data/lib/webby/tasks/create.rake +22 -0
  147. data/lib/webby/tasks/deploy.rake +22 -0
  148. data/lib/webby/tasks/growl.rake +15 -0
  149. data/lib/webby/tasks/heel.rake +28 -0
  150. data/lib/webby/tasks/validate.rake +19 -0
  151. data/lib/webby.rb +227 -0
  152. data/spec/core_ext/hash_spec.rb +47 -0
  153. data/spec/core_ext/string_spec.rb +110 -0
  154. data/spec/core_ext/time_spec.rb +19 -0
  155. data/spec/spec.opts +1 -0
  156. data/spec/spec_helper.rb +14 -0
  157. data/spec/webby/apps/generator_spec.rb +111 -0
  158. data/spec/webby/apps/main_spec.rb +75 -0
  159. data/spec/webby/helpers/capture_helper_spec.rb +56 -0
  160. data/spec/webby/resources/file_spec.rb +104 -0
  161. data/spec/webby/resources_spec.rb +17 -0
  162. data/tasks/ann.rake +81 -0
  163. data/tasks/bones.rake +21 -0
  164. data/tasks/gem.rake +126 -0
  165. data/tasks/git.rake +41 -0
  166. data/tasks/manifest.rake +49 -0
  167. data/tasks/notes.rake +28 -0
  168. data/tasks/post_load.rake +39 -0
  169. data/tasks/rdoc.rake +51 -0
  170. data/tasks/rubyforge.rake +57 -0
  171. data/tasks/setup.rb +268 -0
  172. data/tasks/spec.rake +55 -0
  173. data/tasks/website.rake +38 -0
  174. metadata +289 -0
@@ -0,0 +1,79 @@
1
+ require Webby.libpath(*%w[webby resources resource])
2
+
3
+ module Webby::Resources
4
+
5
+ # A Partial is a file in the content folder whose filename starts with an
6
+ # underscore "_" character. Partials contain text that can be included into
7
+ # other pages. Partials are not standalone pages, and they will never
8
+ # correspond directly to an output file.
9
+ #
10
+ # Partials can contain YAML meta-data at the top of the file. This
11
+ # information is only used to determine the filters to apply to the
12
+ # partial. If there is no meta-data, then the partial text is used "as is"
13
+ # without any processing by the Webby rendering engine.
14
+ #
15
+ class Partial < Resource
16
+
17
+ # call-seq:
18
+ # Partial.new( path )
19
+ #
20
+ # Creates a new Partial object given the full path to the partial file.
21
+ # Partial filenames start with an underscore (this is an enforced
22
+ # convention).
23
+ #
24
+ def initialize( fn )
25
+ super
26
+
27
+ @mdata = ::Webby::Resources::File.meta_data(@path)
28
+ @mdata ||= {}
29
+ @mdata.sanitize!
30
+ end
31
+
32
+ # call-seq:
33
+ # dirty? => true or false
34
+ #
35
+ # Returns +true+ if this resource is newer than its corresponding output
36
+ # product. The resource needs to be rendered (if a page or layout) or
37
+ # copied (if a static file) to the output directory.
38
+ #
39
+ def dirty?
40
+ return @mdata['dirty'] if @mdata.has_key? 'dirty'
41
+
42
+ # if the destination file does not exist, then we are dirty
43
+ return true unless test(?e, destination)
44
+
45
+ # if this file's mtime is larger than the destination file's
46
+ # mtime, then we are dirty
47
+ dirty = @mtime > ::File.mtime(destination)
48
+ return dirty if dirty
49
+
50
+ # if we got here, then we are not dirty
51
+ false
52
+ end
53
+
54
+ # call-seq:
55
+ # destination => string
56
+ #
57
+ # The output file destination for the partial. This is the ".cairn" file in
58
+ # the output folder. It is used to determine if the partial is newer than
59
+ # the build products.
60
+ #
61
+ def destination
62
+ ::Webby.cairn
63
+ end
64
+
65
+ alias :extension :ext
66
+
67
+ # call-seq:
68
+ # url => nil
69
+ #
70
+ # Partials do not have a URL. This method will alwasy return +nil+.
71
+ #
72
+ def url
73
+ nil
74
+ end
75
+
76
+ end # class Partial
77
+ end # module Webby::Resources
78
+
79
+ # EOF
@@ -0,0 +1,160 @@
1
+ unless defined? Webby::Resources::Resource
2
+
3
+ module Webby::Resources
4
+
5
+ # A Webby::Resource is any file that can be found in the content directory
6
+ # or in the layout directory. This class contains information about the
7
+ # resources available to Webby.
8
+ #
9
+ class Resource
10
+
11
+ instance_methods.each do |m|
12
+ undef_method(m) unless m =~ %r/\A__|\?$/ ||
13
+ m == 'class'
14
+ end
15
+
16
+ # The full path to the resource file
17
+ attr_reader :path
18
+
19
+ # The directory of the resource excluding the content directory
20
+ attr_reader :dir
21
+
22
+ # The resource filename excluding path and extension
23
+ attr_reader :filename
24
+
25
+ # Extesion of the resource file
26
+ attr_reader :ext
27
+
28
+ # Resource file modification time
29
+ attr_reader :mtime
30
+
31
+ # call-seq:
32
+ # Resource.new( filename ) => resource
33
+ #
34
+ # Creates a new resource object given the _filename_.
35
+ #
36
+ def initialize( fn )
37
+ @path = fn
38
+ @dir = ::Webby::Resources::File.dirname(@path)
39
+ @filename = ::Webby::Resources::File.basename(@path)
40
+ @ext = ::Webby::Resources::File.extname(@path)
41
+ @mtime = ::File.mtime @path
42
+
43
+ @mdata = @@mdata ||= {}
44
+ end
45
+
46
+ # call-seq:
47
+ # equal?( other ) => true or false
48
+ #
49
+ # Returns +true+ if the path of this resource is equivalent to the path of
50
+ # the _other_ resource. Returns +false+ if this is not the case.
51
+ #
52
+ def equal?( other )
53
+ return false unless other.kind_of? ::Webby::Resources::Resource
54
+ @path == other.path
55
+ end
56
+ alias :== :equal?
57
+ alias :eql? :equal?
58
+
59
+ # call-seq:
60
+ # resource <=> other => -1, 0, +1, or nil
61
+ #
62
+ # Resource comparison operates on the full path of the resource objects
63
+ # and uses the standard String comparison operator. Returns +nil+ if
64
+ # _other_ is not a Resource instance.
65
+ #
66
+ def <=>( other )
67
+ return unless other.kind_of? ::Webby::Resources::Resource
68
+ @path <=> other.path
69
+ end
70
+
71
+ # call-seq:
72
+ # resource[key] => value or nil
73
+ #
74
+ # Returns the value associated with the given meta-data key. Key is
75
+ # converted into a string.
76
+ #
77
+ def []( key )
78
+ @mdata[key.to_s]
79
+ end
80
+
81
+ # call-seq:
82
+ # resource[key] = value
83
+ #
84
+ # Sets the given meta-data key to the value. Key is converted into a
85
+ # string.
86
+ #
87
+ def []=( key, value )
88
+ @mdata[key.to_s] = value
89
+ end
90
+
91
+ # call-seq:
92
+ # method_missing( symbol [, *args, &block] ) => result
93
+ #
94
+ # Invoked by Ruby when a message is sent to the resource that it cannot
95
+ # handle. The default behavior is to convert _symbol_ to a string and
96
+ # search for that string in the resource's meta-data. If found, the
97
+ # meta-data item is returned; otherwise, +nil+ is returned.
98
+ #
99
+ def method_missing( name, *a, &b )
100
+ @mdata[name.to_s]
101
+ end
102
+
103
+ # call-seq:
104
+ # dirty? => true or false
105
+ #
106
+ # Returns +true+ if this resource is newer than its corresponding output
107
+ # product. The resource needs to be rendered (if a page or layout) or
108
+ # copied (if a static file) to the output directory.
109
+ #
110
+ def dirty?
111
+ return @mdata['dirty'] if @mdata.has_key? 'dirty'
112
+
113
+ # if the destination file does not exist, then we are dirty
114
+ return true unless test(?e, destination)
115
+
116
+ # if this file's mtime is larger than the destination file's
117
+ # mtime, then we are dirty
118
+ dirty = @mtime > ::File.mtime(destination)
119
+ return dirty if dirty
120
+
121
+ # check to see if the layout is dirty, and if it is then we
122
+ # are dirty, too
123
+ if @mdata.has_key? 'layout'
124
+ lyt = ::Webby::Resources.find_layout(@mdata['layout'])
125
+ unless lyt.nil?
126
+ return true if lyt.dirty?
127
+ end
128
+ end
129
+
130
+ # if we got here, then we are not dirty
131
+ false
132
+ end
133
+
134
+ # call-seq
135
+ # url => string or nil
136
+ #
137
+ # Returns a string suitable for use as a URL linking to this page. Nil
138
+ # is returned for layouts.
139
+ #
140
+ def url
141
+ return @url if defined? @url and @url
142
+ @url = destination.sub(::Webby.site.output_dir, '')
143
+ end
144
+
145
+ # :stopdoc:
146
+ def destination
147
+ raise NotImplementedError
148
+ end
149
+
150
+ def extension
151
+ raise NotImplementedError
152
+ end
153
+ # :startdoc:
154
+
155
+ end # class Resource
156
+ end # module Webby::Resources
157
+
158
+ end # unless defined?
159
+
160
+ # EOF
@@ -0,0 +1,52 @@
1
+ require Webby.libpath(*%w[webby resources resource])
2
+
3
+ module Webby::Resources
4
+
5
+ # A Static resource is any file in the content folder that does not
6
+ # contain YAML meta-data at the top of the file and does not start with
7
+ # and underscore "_" character (those are partials). Static resources will
8
+ # be copied as-is from the content directory to the output directory.
9
+ #
10
+ class Static < Resource
11
+
12
+ # call-seq:
13
+ # render => string
14
+ #
15
+ # Returns the contents of the file.
16
+ #
17
+ def render
18
+ ::File.read(path)
19
+ end
20
+
21
+ # call-seq:
22
+ # dirty? => true or false
23
+ #
24
+ # Returns +true+ if this static file is newer than its corresponding output
25
+ # product. The static file needs to be copied to the output directory.
26
+ #
27
+ def dirty?
28
+ return true unless test(?e, destination)
29
+ @mtime > ::File.mtime(destination)
30
+ end
31
+
32
+ # call-seq:
33
+ # destination => string
34
+ #
35
+ # Returns the path in the output directory where the static file should
36
+ # be copied. This path is used to determine if the static file is dirty
37
+ # and in need of copying to the output file.
38
+ #
39
+ def destination
40
+ return @dest if defined? @dest and @dest
41
+
42
+ @dest = ::File.join(::Webby.site.output_dir, dir, filename)
43
+ @dest << '.' << @ext if @ext and !@ext.empty?
44
+ @dest
45
+ end
46
+
47
+ alias :extension :ext
48
+
49
+ end # class Layout
50
+ end # module Webby::Resources
51
+
52
+ # EOF
@@ -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,135 @@
1
+ # :stopdoc:
2
+ # Skeleton module for the 'mktemp' routine.
3
+ #
4
+ # Ideally, one would do this in their code to import the "mktemp" call
5
+ # directly into their current namespace:
6
+ #
7
+ # require 'mktemp'
8
+ # include MkTemp
9
+ # # do something with mktemp()
10
+ #
11
+ #
12
+ # It is recommended that you look at the documentation for the mktemp()
13
+ # call directly for specific usage.
14
+ #
15
+ #--
16
+ #
17
+ # The compilation of software known as mktemp.rb is distributed under the
18
+ # following terms:
19
+ # Copyright (C) 2005-2006 Erik Hollensbe. All rights reserved.
20
+ #
21
+ # Redistribution and use in source form, with or without
22
+ # modification, are permitted provided that the following conditions
23
+ # are met:
24
+ # 1. Redistributions of source code must retain the above copyright
25
+ # notice, this list of conditions and the following disclaimer.
26
+ #
27
+ # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
28
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30
+ # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
31
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33
+ # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35
+ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37
+ # SUCH DAMAGE.
38
+ #
39
+ #++
40
+
41
+ module Webby
42
+ module MkTemp
43
+ VALID_TMPNAM_CHARS = (?a..?z).to_a + (?A..?Z).to_a
44
+
45
+ #
46
+ # This routine just generates a temporary file similar to the
47
+ # routines from 'mktemp'. A trailing series of 'X' characters will
48
+ # be transformed into a randomly-generated set of alphanumeric
49
+ # characters.
50
+ #
51
+ # This routine performs no file testing, at all. It is not suitable
52
+ # for anything beyond that.
53
+ #
54
+
55
+ def tmpnam(filename)
56
+ m = filename.match(/(X*)$/)
57
+
58
+ retnam = filename.dup
59
+
60
+ if m[1]
61
+ mask = ""
62
+ m[1].length.times { mask += VALID_TMPNAM_CHARS[rand(52)].chr }
63
+ retnam.sub!(/(X*)$/, mask)
64
+ end
65
+
66
+ return retnam
67
+ end
68
+
69
+ module_function :tmpnam
70
+
71
+ #
72
+ # This routine works similarly to mkstemp(3) in that it gets a new
73
+ # file, and returns a file handle for that file. The mask parameter
74
+ # determines whether or not to process the filename as a mask by
75
+ # calling the tmpnam() routine in this module. This routine will
76
+ # continue until it finds a valid filename, which may not do what
77
+ # you expect.
78
+ #
79
+ # While all attempts have been made to keep this as secure as
80
+ # possible, due to a few problems with Ruby's file handling code, we
81
+ # are required to allow a few concessions. If a 0-length file is
82
+ # created before we attempt to create ours, we have no choice but to
83
+ # accept it. Do not rely on this code for any expected level of
84
+ # security, even though we have taken all the measures we can to
85
+ # handle that situation.
86
+ #
87
+
88
+ def mktemp(filename, mask=true)
89
+ fh = nil
90
+
91
+ begin
92
+ loop do
93
+ fn = mask ? tmpnam(filename) : filename
94
+
95
+ if File.exist? fn
96
+ fail "Unable to create a temporary filename" unless mask
97
+ next
98
+ end
99
+
100
+ fh = File.new(fn, "a", 0600)
101
+ fh.seek(0, IO::SEEK_END)
102
+ break if fh.pos == 0
103
+
104
+ fail "Unable to create a temporary filename" unless mask
105
+ fh.close
106
+ end
107
+ rescue Exception => e
108
+ # in the case that we hit a locked file...
109
+ fh.close if fh
110
+ raise e unless mask
111
+ end
112
+
113
+ return fh
114
+ end
115
+
116
+ module_function :mktemp
117
+
118
+ #
119
+ # Create a directory. If mask is true (default), it will use the
120
+ # random name generation rules from the tmpnam() call in this
121
+ # module.
122
+ #
123
+
124
+ def mktempdir(filename, mask=true)
125
+ fn = mask ? tmpnam(filename) : filename
126
+ Dir.mkdir(fn)
127
+ return fn
128
+ end
129
+
130
+ module_function :mktempdir
131
+ end # module MkTemp
132
+ end # module Webby
133
+
134
+ # :startdoc:
135
+ # EOF
@@ -0,0 +1,150 @@
1
+ # This code was originally written by Bruce Williams, and it is available
2
+ # as the Paginator gem. I've added a few helper methods and modifications so
3
+ # it plays a little more nicely with Webby. Specifically, a Webby::Resource
4
+ # can be given to the Page and used to generate links to the previous and
5
+ # next pages.
6
+ #
7
+ # Many thanks to Bruce Williams for letting me use his work. Drop him a note
8
+ # of praise scribbled on the back of a $100 bill. He'd appreciate it.
9
+
10
+ require 'forwardable'
11
+
12
+ module Webby
13
+ class Paginator
14
+
15
+ include Enumerable
16
+
17
+ class ArgumentError < ::ArgumentError; end
18
+ class MissingCountError < ArgumentError; end
19
+ class MissingSelectError < ArgumentError; end
20
+
21
+ attr_reader :per_page, :count, :resource
22
+
23
+ # Instantiate a new Paginator object
24
+ #
25
+ # Provide:
26
+ # * A total count of the number of objects to paginate
27
+ # * The number of objects in each page
28
+ # * A block that returns the array of items
29
+ # * The block is passed the item offset
30
+ # (and the number of items to show per page, for
31
+ # convenience, if the arity is 2)
32
+ def initialize(count, per_page, resource, &select)
33
+ @count, @per_page, @resource = count, per_page, resource
34
+ unless select
35
+ raise MissingSelectError, "Must provide block to select data for each page"
36
+ end
37
+ @select = select
38
+ end
39
+
40
+ # Total number of pages
41
+ def number_of_pages
42
+ (@count / @per_page).to_i + (@count % @per_page > 0 ? 1 : 0)
43
+ end
44
+
45
+ # First page object
46
+ def first
47
+ page 1
48
+ end
49
+
50
+ # Last page object
51
+ def last
52
+ page number_of_pages
53
+ end
54
+
55
+ def each
56
+ 1.upto(number_of_pages) do |number|
57
+ yield page(number)
58
+ end
59
+ end
60
+
61
+ # Retrieve page object by number
62
+ def page(number)
63
+ number = (n = number.to_i) > 0 ? n : 1
64
+ Page.new(self, number, lambda {
65
+ offset = (number - 1) * @per_page
66
+ args = [offset]
67
+ args << @per_page if @select.arity == 2
68
+ @select.call(*args)
69
+ })
70
+ end
71
+
72
+ # Page object
73
+ #
74
+ # Retrieves items for a page and provides metadata about the position
75
+ # of the page in the paginator
76
+ class Page
77
+
78
+ include Enumerable
79
+
80
+ attr_reader :number, :pager, :url
81
+
82
+ def initialize(pager, number, select) #:nodoc:
83
+ @pager, @number = pager, number
84
+ @offset = (number - 1) * pager.per_page
85
+ @select = select
86
+
87
+ @pager.resource.number = (number == 1 ? nil : number)
88
+ @url = @pager.resource.url
89
+ end
90
+
91
+ # Retrieve the items for this page
92
+ # * Caches
93
+ def items
94
+ @items ||= @select.call
95
+ end
96
+
97
+ # Checks to see if there's a page before this one
98
+ def prev?
99
+ @number > 1
100
+ end
101
+
102
+ # Get previous page (if possible)
103
+ def prev
104
+ @pager.page(@number - 1) if prev?
105
+ end
106
+
107
+ # Checks to see if there's a page after this one
108
+ def next?
109
+ @number < @pager.number_of_pages
110
+ end
111
+
112
+ # Get next page (if possible)
113
+ def next
114
+ @pager.page(@number + 1) if next?
115
+ end
116
+
117
+ # The "item number" of the first item on this page
118
+ def first_item_number
119
+ 1 + @offset
120
+ end
121
+
122
+ # The "item number" of the last item on this page
123
+ def last_item_number
124
+ if next?
125
+ @offset + @pager.per_page
126
+ else
127
+ @pager.count
128
+ end
129
+ end
130
+
131
+ def ==(other) #:nodoc:
132
+ @pager == other.pager && self.number == other.number
133
+ end
134
+
135
+ def each(&block)
136
+ items.each(&block)
137
+ end
138
+
139
+ def method_missing(meth, *args, &block) #:nodoc:
140
+ if @pager.respond_to?(meth)
141
+ @pager.__send__(meth, *args, &block)
142
+ else
143
+ super
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ end # class Paginator
150
+ end # module Webby