webby 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/webby/file.rb CHANGED
@@ -1,4 +1,4 @@
1
- # $Id: file.rb 2 2007-08-20 17:55:30Z tim_pease $
1
+ # $Id: file.rb 46 2007-11-27 03:31:29Z tim_pease $
2
2
 
3
3
  require 'yaml'
4
4
 
@@ -40,7 +40,7 @@ class File < ::File
40
40
  fd = new name, 'r'
41
41
  fd.read *args
42
42
  ensure
43
- fd.close
43
+ fd.close unless fd.nil?
44
44
  end
45
45
 
46
46
  # call-seq:
@@ -54,7 +54,7 @@ class File < ::File
54
54
  fd = new name, 'r'
55
55
  fd.readlines sep
56
56
  ensure
57
- fd.close
57
+ fd.close unless fd.nil?
58
58
  end
59
59
 
60
60
  # call-seq:
@@ -67,7 +67,7 @@ class File < ::File
67
67
  fd = new name, 'r'
68
68
  fd.meta_data
69
69
  ensure
70
- fd.close
70
+ fd.close unless fd.nil?
71
71
  end
72
72
  end
73
73
 
@@ -140,7 +140,7 @@ class File < ::File
140
140
  seek 0, IO::SEEK_END
141
141
  end
142
142
 
143
- %w(getc gets read read_nonblock readbytes readchar readline readlines readpartial scanf sysread).each do |m|
143
+ %w(getc gets read read_nonblock readbytes readchar readline readlines readpartial scanf).each do |m|
144
144
  self.class_eval <<-CODE
145
145
  def #{m}(*a)
146
146
  skip_meta_data
@@ -169,17 +169,14 @@ class File < ::File
169
169
  cur = tell
170
170
 
171
171
  seek 0
172
- line = readline
172
+ line = gets
173
173
  return unless META_SEP =~ line
174
174
 
175
- loop do
176
- line = readline
175
+ while line = gets
177
176
  break if META_SEP =~ line
178
177
  end
179
- return tell
180
-
181
- rescue EOFError
182
- return
178
+ return if line.nil?
179
+ tell
183
180
 
184
181
  ensure
185
182
  seek cur
data/lib/webby/main.rb CHANGED
@@ -1,4 +1,4 @@
1
- # $Id: main.rb 20 2007-08-28 23:24:14Z tim_pease $
1
+ # $Id: main.rb 35 2007-09-25 23:31:03Z tim_pease $
2
2
 
3
3
  require 'fileutils'
4
4
  require 'find'
@@ -34,6 +34,15 @@ class Main
34
34
  else m.create_site end
35
35
  end
36
36
 
37
+ # call-seq:
38
+ # Main.new
39
+ #
40
+ # Create a new Main webby object for building websites.
41
+ #
42
+ def initialize
43
+ @log = Logging::Logger[self]
44
+ end
45
+
37
46
  # call-seq:
38
47
  # parse( args ) => nil
39
48
  #
@@ -142,8 +151,7 @@ class Main
142
151
  # Prints a "creating _msg_" to the screen.
143
152
  #
144
153
  def creating( msg )
145
- print "creating "
146
- puts msg
154
+ @log.info "creating #{msg}"
147
155
  end
148
156
 
149
157
  # call-seq:
@@ -152,8 +160,7 @@ class Main
152
160
  # Prints a "updating _msg_" to the screen.
153
161
  #
154
162
  def updating( msg )
155
- print "updating "
156
- puts msg
163
+ @log.info "updating #{msg}"
157
164
  end
158
165
 
159
166
  # call-seq:
@@ -162,8 +169,7 @@ class Main
162
169
  # Prints an abort _msg_ to the screen and then exits the Ruby interpreter.
163
170
  #
164
171
  def abort( msg )
165
- puts msg
166
- puts "Aborting!"
172
+ @log.fatal msg
167
173
  exit 1
168
174
  end
169
175
 
@@ -1,56 +1,140 @@
1
- # $Id: pages_db.rb 18 2007-08-28 15:48:17Z tim_pease $
1
+ # $Id: pages_db.rb 46 2007-11-27 03:31:29Z tim_pease $
2
2
 
3
3
  module Webby
4
4
 
5
- #
5
+ # A rudimentary "database" for holding resource objects and finding them.
6
+ # The database is held in a Ruby hash keyed by the directories in the
7
+ # content folder.
6
8
  #
7
9
  class PagesDB
8
- include Enumerable
9
10
 
10
11
  # call-seq:
11
12
  # PagesDB.new
12
13
  #
14
+ # Create a new pages database object. This is used to store resources and
15
+ # to find them by their attributes.
16
+ #
13
17
  def initialize
14
18
  @db = Hash.new {|h,k| h[k] = []}
15
19
  end
16
20
 
17
21
  # call-seq:
18
- # add( resource )
22
+ # add( resource ) => resource
23
+ #
24
+ # Add the given _resource_ to the database. It will not be added a second
25
+ # time if it already exists in the database.
19
26
  #
20
27
  def add( page )
21
- @db[page.dir] << page
22
- self
28
+ ary = @db[page.dir]
29
+
30
+ # make sure we don't duplicate pages
31
+ ary.delete page if ary.include? page
32
+ ary << page
33
+
34
+ page
23
35
  end
24
36
  alias :<< :add
25
37
 
26
38
  # call-seq:
27
- # clear
39
+ # clear => self
40
+ #
41
+ # Removes all resources from the database.
28
42
  #
29
43
  def clear
30
44
  @db.clear
45
+ self
31
46
  end
32
47
 
33
48
  # call-seq:
34
49
  # each {|resource| block}
35
50
  #
51
+ # Iterate over each resource in the database and pass it to the given
52
+ # block.
53
+ #
36
54
  def each( &b )
37
55
  keys = @db.keys.sort
38
56
  keys.each do |k|
39
57
  @db[k].sort.each(&b)
40
58
  end
59
+ self
41
60
  end
42
61
 
43
62
  # call-seq:
44
- # find_by_name( name )
63
+ # find( opts = {} ) => resource or nil
64
+ # find( opts = {} ) {|resource| block} => resource or nil
65
+ #
66
+ # Find a specific resource in the database. A resource can be found using
67
+ # any combination of attributes by passing them in as options to the
68
+ # +find+ method. This will used simple equality comparison to find the
69
+ # resource.
70
+ #
71
+ # For more complex finders, a block should be supplied. The usage
72
+ # follows that of of the Enumerable#find method. The method will return
73
+ # the first resource for which the block returns true.
74
+ #
75
+ # If the :all option is given as true, then all resources that match the
76
+ # finder criteria will be returned in an array. If none are found, an
77
+ # empty array will be returned.
78
+ #
79
+ # Options include:
80
+ #
81
+ # :all => true
82
+ # :in_directory => 'directory'
45
83
  #
46
- def find_by_name( name )
47
- self.find {|page| page.filename == name}
84
+ # Examples:
85
+ #
86
+ # # find the "index" resource in the "foo/bar" directory
87
+ # pages_db.find( :filename => 'index', :in_directory => 'foo/bar' )
88
+ #
89
+ # # find all resources named "widgets" whose color is "blue"
90
+ # pages_db.find( :name => 'widgets', :color => 'blue', :all => true )
91
+ #
92
+ # # find all resources created in the past week
93
+ # pages_db.find( :all => true ) do |resource|
94
+ # resource.created_at > Time.now - (7 * 24 * 3600)
95
+ # end
96
+ #
97
+ def find( opts = {}, &block )
98
+ find_all = if opts.has_key?(:all) then opts.delete(:all)
99
+ else false end
100
+
101
+ dir = if opts.has_key?(:in_directory) then opts.delete(:in_directory)
102
+ else nil end
103
+ if dir && !@db.has_key?(dir)
104
+ raise RuntimeError, "unknown directory '#{dir}'"
105
+ end
106
+
107
+ block ||= lambda do |page|
108
+ found = true
109
+ opts.each do |key, value|
110
+ found &&= page.__send__(key.to_sym) == value
111
+ break if not found
112
+ end
113
+ found
114
+ end
115
+
116
+ ary = []
117
+ search = dir ? @db[dir] : self
118
+ search.each do |page|
119
+ if block.call(page)
120
+ ary << page
121
+ break unless find_all
122
+ end
123
+ end
124
+
125
+ return ary if find_all
126
+ return ary.first
48
127
  end
49
128
 
50
129
  # call-seq:
51
130
  # siblings( page, opts = {} ) => array
52
131
  #
132
+ # Returns an array of resources that are siblings of the given _page_
133
+ # resource. A sibling is any resource that is in the same directory as the
134
+ # _page_.
135
+ #
53
136
  # Options include:
137
+ #
54
138
  # :sorty_by => 'attribute'
55
139
  # :reverse => true
56
140
  #
@@ -60,7 +144,7 @@ class PagesDB
60
144
  return ary unless opts.has_key? :sort_by
61
145
 
62
146
  m = opts[:sort_by]
63
- ary.sort! {|a,b| a.send(m) <=> b.send(m)}
147
+ ary.sort! {|a,b| a.__send__(m) <=> b.__send__(m)}
64
148
  ary.reverse! if opts[:reverse]
65
149
  ary
66
150
  end
@@ -68,7 +152,12 @@ class PagesDB
68
152
  # call-seq:
69
153
  # children( page, opts = {} ) => array
70
154
  #
155
+ # Returns an array of resources that are children of the given _page_
156
+ # resource. A child is any resource that exists in a subdirectory of the
157
+ # page's directory.
158
+ #
71
159
  # Options include:
160
+ #
72
161
  # :sorty_by => 'attribute'
73
162
  # :reverse => true
74
163
  #
@@ -82,7 +171,7 @@ class PagesDB
82
171
  return ary unless opts.has_key? :sort_by
83
172
 
84
173
  m = opts[:sort_by]
85
- ary.sort! {|a,b| a.send(m) <=> b.send(m)}
174
+ ary.sort! {|a,b| a.__send__(m) <=> b.__send__(m)}
86
175
  ary.reverse! if opts[:reverse]
87
176
  ary
88
177
  end
@@ -1,8 +1,10 @@
1
- # $Id: renderer.rb 27 2007-09-18 18:09:25Z tim_pease $
1
+ # $Id: renderer.rb 46 2007-11-27 03:31:29Z tim_pease $
2
2
 
3
3
  require 'erb'
4
4
  try_require 'bluecloth'
5
5
  try_require 'redcloth'
6
+ try_require 'haml'
7
+ try_require 'sass'
6
8
 
7
9
  module Webby
8
10
 
@@ -11,7 +13,7 @@ module Webby
11
13
  #
12
14
  # A page is filtered based on the settings of the 'filter' option in the
13
15
  # 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 filer.
16
+ # a filter, then the page will be run through the RedCloth markup filter.
15
17
  # More than one filter can be used on a page; they will be run in the
16
18
  # order specified in the meta-data.
17
19
  #
@@ -21,6 +23,24 @@ module Webby
21
23
  class Renderer
22
24
  include ERB::Util
23
25
 
26
+ # call-seq:
27
+ # Renderer.write( page )
28
+ #
29
+ # Render the given _page_ and write the resulting output to the page's
30
+ # destination. If the _page_ uses pagination, then multiple destination
31
+ # files will be created -- one for each paginated data set in the page.
32
+ #
33
+ def self.write( page )
34
+ renderer = self.new(page)
35
+
36
+ loop {
37
+ ::File.open(page.destination, 'w') do |fd|
38
+ fd.write renderer.layout_page
39
+ end
40
+ break unless renderer.next_page
41
+ }
42
+ end
43
+
24
44
  # call-seq:
25
45
  # Renderer.new( page )
26
46
  #
@@ -37,6 +57,8 @@ class Renderer
37
57
  @page = page
38
58
  @pages = Resource.pages
39
59
  @content = nil
60
+
61
+ @log = Logging::Logger[self]
40
62
  end
41
63
 
42
64
  # call-seq:
@@ -50,10 +72,10 @@ class Renderer
50
72
  def layout_page
51
73
  layouts = Resource.layouts
52
74
  obj = @page
53
- str = @page.render
75
+ str = @page.render(self)
54
76
 
55
77
  loop do
56
- lyt = layouts.find_by_name obj.layout
78
+ lyt = layouts.find :filename => obj.layout
57
79
  break if lyt.nil?
58
80
 
59
81
  @content, str = str, ::Webby::File.read(lyt.path)
@@ -84,6 +106,49 @@ class Renderer
84
106
  str
85
107
  end
86
108
 
109
+ # call-seq:
110
+ # paginate( items, per_page ) {|item| block}
111
+ #
112
+ # Iterate the given _block_ for each item selected from the _items_ array
113
+ # using the given number of items _per_page_. The first time the page is
114
+ # rendered, the items passed to the block are selected using the range
115
+ # (0...per_page). The next rendering selects (per_page...2*per_page). This
116
+ # continues until all _items_ have been paginated.
117
+ #
118
+ # Calling this method creates a <code>@pager</code> object that can be
119
+ # accessed from the _page_. The <code>@pager</code> contains information
120
+ # about the next page, the current page number, the previous page, and the
121
+ # number of items in the current page.
122
+ #
123
+ def paginate( items, count, &block )
124
+ @pager ||= Paginator.new(items.length, count, @page) do |offset, per_page|
125
+ items[offset,per_page]
126
+ end.first
127
+
128
+ @pager.each &block
129
+ end
130
+
131
+ # call-seq:
132
+ # next_page => true or false
133
+ #
134
+ # Returns +true+ if there is a next page to render. Returns +false+ if
135
+ # there is no next page or if pagination has not been configured for the
136
+ # current page.
137
+ #
138
+ def next_page
139
+ return false unless defined? @pager and @pager
140
+
141
+ # go to the next page; break out if there is no next page
142
+ if @pager.next?
143
+ @pager = @pager.next
144
+ else
145
+ @page.number = nil
146
+ return false
147
+ end
148
+
149
+ true
150
+ end
151
+
87
152
  # Render text via ERB using the built in ERB library.
88
153
  #
89
154
  def erb_filter( str )
@@ -96,7 +161,7 @@ class Renderer
96
161
  def markdown_filter( str )
97
162
  BlueCloth.new(str).to_html
98
163
  rescue NameError
99
- $stderr.puts 'ERROR: markdown filter failed (BlueCloth not installed?)'
164
+ @log.error 'markdown filter failed (BlueCloth not installed?)'
100
165
  exit
101
166
  end
102
167
 
@@ -105,7 +170,7 @@ class Renderer
105
170
  def textile_filter( str )
106
171
  RedCloth.new(str).to_html
107
172
  rescue NameError
108
- $stderr.puts 'ERROR: textile filter failed (RedCloth not installed?)'
173
+ @log.error 'textile filter failed (RedCloth not installed?)'
109
174
  exit
110
175
  end
111
176
 
@@ -114,7 +179,29 @@ class Renderer
114
179
  def coderay_filter( str )
115
180
  CodeRayFilter.new(str).to_html
116
181
  rescue NameError
117
- $stderr.puts "ERROR: coderay filter failed (CodeRay not installed?)"
182
+ @log.error 'coderay filter failed (CodeRay not installed?)'
183
+ exit
184
+ end
185
+
186
+ # Render text via the Haml library
187
+ #
188
+ def haml_filter( str )
189
+ opts = @page.haml_options || {}
190
+ opts[:locals] ||= {}
191
+ opts[:locals].merge!({:page => @page, :pages => @pages})
192
+ Haml::Engine.new(str, opts).to_html
193
+ rescue NameError
194
+ @log.error 'haml filter failed (Haml not installed?)'
195
+ exit
196
+ end
197
+
198
+ # Render text via the Sass library (part of Haml)
199
+ #
200
+ def sass_filter( str )
201
+ opts = @page.sass_options || {}
202
+ Sass::Engine.new(str, opts).render
203
+ rescue NameError
204
+ @log.error 'sass filter failed (Haml not installed?)'
118
205
  exit
119
206
  end
120
207