Class: Docter::Collection

Inherits:
Object
  • Object
show all
Includes:
HTML
Defined in:
lib/docter/server.rb,
lib/docter/collection.rb

Defined Under Namespace

Classes: ToCResource

Instance Method Summary collapse

Methods included from HTML

inner_text_from, regexp_attribute, regexp_element

Constructor Details

#initialize(title = nil) ⇒ Collection

Returns a new instance of Collection.



81
82
83
84
# File 'lib/docter/collection.rb', line 81

def initialize(title = nil)
  @title = title
  @sources = FileList[]
end

Instance Method Details

#dependenciesObject

:call-seq:

Returns a list of dependencies (resource files, the template file, etc). Useful when creating a Rake task based on this template.



286
287
288
289
# File 'lib/docter/collection.rb', line 286

def dependencies #:nodoc:
  files = @sources.map { |path| File.directory?(path) ? FileList[path, File.join(path, '**/*')] : path }.flatten +
    (@toc_resource ? [@toc_resource.filename] : [])
end

#exclude(*paths) ⇒ Object

:call-seq:

exclude(*paths) => self

Excludes files or directories from the collection.



148
149
150
151
# File 'lib/docter/collection.rb', line 148

def exclude(*paths)
  @sources.exclude *paths.flatten
  self
end

#file(path) ⇒ Object

:call-seq:

file(path) => filename

Returns the full path based on the relative path. For example:

collection.include('pages', 'LICENSE')
collection.find('index.textile') => 'pages/index.textile'
collection.find('LICENSE') => 'LICENSE'


195
196
197
198
199
200
201
202
203
204
205
# File 'lib/docter/collection.rb', line 195

def file(path)      
  @sources.inject(nil) do |found, file|
    break found if found
    if File.directory?(file)
      base = file + '/'
      FileList[File.join(file, '**/*')].find { |file| file.sub(base, '') == path }
    else
      file if File.basename(file) == path
    end
  end
end

#generate(template, to_dir, *args) ⇒ Object

:call-seq:

generate(template, to_dir, :all?)
generate(template, to_dir, pages)
generate(template, to_dir, page)
generate(template, to_dir, :one_page)

The first form generates all pages from the ToC into the destination directory. The :all argument is optional. In addition, it copies all other resource files to the destination directory.

The second form works the same way but only for the specified pages, and the third form for a single page. Neither copies any resource files.

The fourth form generates a single HTML document in the destination directory (index.html) with all pages from the ToC, and copies all resource files to the destination directory. It will typically use a different template than the first three forms.



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/docter/collection.rb', line 257

def generate(template, to_dir, *args)
  options = Hash === args.last ? args.pop : {}
  if args.empty? || args.first == :all
    generate template, to_dir, pages, options
    template.copy_resources to_dir
  elsif args.first == :one_page
    mkpath to_dir
    File.join(to_dir, 'index.html').tap do |filename|
      puts "Generating #{filename}" if verbose
      html = render(template, options)
      File.open(filename, 'w') { |file| file.write html }
    end
    template.copy_resources to_dir
  else
    mkpath to_dir
    args.flatten.each do |page|
      File.join(to_dir, page.path).tap do |filename|
        puts "Generating #{filename}" if verbose
        html = render(template, page, options)
        File.open(filename, 'w') { |file| file.write html }
      end
    end
  end
end

#include(*paths) ⇒ Object Also known as: add

:call-seq:

include(*paths) => self

Adds files and directories to the collection.



137
138
139
140
# File 'lib/docter/collection.rb', line 137

def include(*paths)
  @sources.include *paths.flatten
  self
end

#next(page) ⇒ Object



182
183
184
185
186
# File 'lib/docter/collection.rb', line 182

def next(page)
  pages = toc.map { |entry| page(entry.url) }.compact
  index = pages.index(page)
  pages[index + 1] if index
end

#page(path) ⇒ Object

:call-seq:

page(path) => Page

Returns a page based on its path.

For example:

collection.include('doc/pages')
collection.page('index.html')

Will return a page generated from ‘doc/pages/index.textile’.



162
163
164
# File 'lib/docter/collection.rb', line 162

def page(path)
  pages.find { |page| page.path == path }
end

#pagesObject

:call-seq:

pages => Pages

Returns all the pages in this collection/



170
171
172
173
174
# File 'lib/docter/collection.rb', line 170

def pages
  @pages = @sources.map { |path| File.directory?(path) ? FileList[File.join(path, '**/*')] : path }.flatten.
    inject(@pages || {}) { |pages, file| pages[file] ||= Page.new(file, :collection=>self) ; pages }
  @pages.values
end

#prev(page) ⇒ Object



176
177
178
179
180
# File 'lib/docter/collection.rb', line 176

def prev(page)
  pages = toc.map { |entry| page(entry.url) }.compact
  index = pages.index(page)
  pages[index - 1] if index && index > 0
end

#render(template, *args) ⇒ Object

:call-seq:

render(template, page, options?) => html
render(template, options?) => html

Render page or collection using the template.

The first form attempts to reload the page if modified and passes the page to the template context, returning a single HTML document generated from that page.

The second form attempts to reload all modified pages from the ToC, and passes all these pages to the template context, returning a single HTML document generates from pages as ordered by the ToC.



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/docter/collection.rb', line 219

def render(template, *args)
  options = Hash === args.last ? args.pop : {}
  template = Template.new(template) unless Template === template
  template.reload if template.modified?
  if page = args.shift
    page.reload if page.modified?
    template.render options.merge(:collection=>self, :page=>page, :one_page=>false)
  else
    pages = toc.map { |entry| page(entry.url) }.compact
    pages.each { |page| page.reload if page.modified? }
    html = template.render(options.merge(:collection=>self, :pages=>pages, :one_page=>true))

    url_map = pages.inject({}) { |map, page| map[page.path] = "##{page.id}" ; map }
    html.gsub(regexp_element('a')) do |link|
      link.gsub(regexp_attribute('href')) do |href|
        url = $3
        url = url_map[url] || url.gsub(/^(.*?)#(.*?)$/) { |path| url_map[$1] ? "##{$2}" : path }
        %{href="#{url}"}
      end
    end
  end
end

#serve(template, *args) ⇒ Object



100
101
102
103
104
105
# File 'lib/docter/server.rb', line 100

def serve(template, *args)
  options = Hash === args.last ? args.pop.clone : {}
  options[:port] = args.shift if Integer === args.first
  args.each { |arg| options[arg.to_sym] = true }
  Server.new(self, template, options).start
end

#titleObject

The collection title (HTML encoded).



87
88
89
90
91
92
# File 'lib/docter/collection.rb', line 87

def title
  @title || if @toc_resource
    @toc_resource.reload if @toc_resource.modified?
    @toc_resource.title
  end || ''
end

#tocObject

:call-seq:

toc => ToC

Returns the collection’s ToC.



98
99
100
101
102
103
104
105
# File 'lib/docter/collection.rb', line 98

def toc
  if @toc_resource
    @toc_resource.reload if @toc_resource.modified?
    @toc_resource.toc
  else
    @toc ||= pages.inject(ToC.new) { |toc, page| toc.add page.toc_entry ; toc }
  end
end

#toc=(toc) ⇒ Object

:call-seq:

toc = toc|filename|nil

Sets the ToC. You can provide an existing ToC, provide a ToC file name, or nil to create the default ToC from all pages in this collection.



122
123
124
125
126
127
128
129
130
131
# File 'lib/docter/collection.rb', line 122

def toc=(toc)
  case toc
  when String
    @toc_resource = ToCResource.new(self, toc)
  when ToCResource
    @toc_resource = toc
  when ToC, nil
    @toc = toc
  end
end

#using(toc) ⇒ Object

:call-seq:

using(toc) => self

Specifies the ToC to use. You can load an exiting ToC object, or specify a filename containing the ToC.



112
113
114
115
# File 'lib/docter/collection.rb', line 112

def using(toc)
  self.toc = toc
  self
end