Class: DocuBot::Page

Inherits:
Object
  • Object
show all
Defined in:
lib/docubot/page.rb

Constant Summary collapse

AUTO_ID_ELEMENTS =
%w[ h1 h2 h3 h4 h5 h6 legend caption dt ].join(',')

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bundle, source_path, title = nil) ⇒ Page

Returns a new instance of Page.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/docubot/page.rb', line 19

def initialize( bundle, source_path, title=nil )
  puts "#{self.class}.new( #{source_path.inspect}, #{title.inspect}, #{type.inspect} )" if $DEBUG
  title ||= self.class.title( source_path )
  @bundle = bundle
  @file  = source_path
  if File.directory?( @file )
    @folder = @file
    @file   = Dir[ source_path/'index.*' ][0]
    # Directories without an index.* file now have nil @file

  else
    @folder = File.dirname( @file )
  end
  @type = File.extname( @file )[ 1..-1 ] if @file
  @meta = DocuBot::MetaSection.new( {'title'=>title}, @file )
  @raw  = @meta.__contents__
  @raw = nil if @raw && @raw.empty?

  create_nokodoc
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object



96
97
98
99
100
101
102
103
104
105
# File 'lib/docubot/page.rb', line 96

def method_missing( method, *args )
  key=method.to_s
  case key[-1..-1] # the last character of the method name

    when '?' then @meta.has_key?( key[0..-2] )
    when '!','=' then super
    else
      # warn "Unknown attribute #{key.inspect} asked for on #{@file || @folder}" unless @meta.has_key?( key )

      @meta[ key ]
  end
end

Instance Attribute Details

#bundleObject (readonly)

Returns the value of attribute bundle.



8
9
10
# File 'lib/docubot/page.rb', line 8

def bundle
  @bundle
end

#fileObject (readonly)

Returns the value of attribute file.



8
9
10
# File 'lib/docubot/page.rb', line 8

def file
  @file
end

#folderObject (readonly)

Returns the value of attribute folder.



8
9
10
# File 'lib/docubot/page.rb', line 8

def folder
  @folder
end

#metaObject (readonly)

Returns the value of attribute meta.



8
9
10
# File 'lib/docubot/page.rb', line 8

def meta
  @meta
end

#nokodocObject (readonly)

Returns the value of attribute nokodoc.



8
9
10
# File 'lib/docubot/page.rb', line 8

def nokodoc
  @nokodoc
end

#typeObject (readonly)

Returns the value of attribute type.



8
9
10
# File 'lib/docubot/page.rb', line 8

def type
  @type
end

Class Method Details

.title(source_path) ⇒ Object



10
11
12
13
14
15
16
17
# File 'lib/docubot/page.rb', line 10

def self.title( source_path )
  # File#basename might return the same string

  title = File.basename( source_path ).dup
  title.sub!(/\.[^.\s]+$/,'') unless File.directory?( source_path )
  title.gsub!( '_', ' ' )
  title.sub!( /^\d+\s+/, '' )
  title
end

Instance Method Details

#[](key) ⇒ Object



92
93
94
# File 'lib/docubot/page.rb', line 92

def []( key )
  @meta[key]
end

#auto_idObject

Add IDs to elements that don’t have them



57
58
59
60
61
62
63
64
65
66
67
# File 'lib/docubot/page.rb', line 57

def auto_id
  # ...but only if a toc entry might reference one, or requested.

  if @meta['auto-id'].as_boolean || @meta.toc.as_list.any?{ |toc| !toc['#'] }
    @nokodoc.css( AUTO_ID_ELEMENTS ).each do |node|
      next if node.has_attribute?('id')
      # Strip off the unwanted leading '#'

      node['id'] = DocuBot.id_from_text(node.inner_text)[1..-1]
    end
    dirty_doc
  end
end

#auto_sectionObject

Wrap siblings of headers in <div class=‘section’>



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/docubot/page.rb', line 70

def auto_section
  return if @meta['auto-section']==false
  
  #TODO: Make this a generic nokogiri call on any node (like body) where you can pass in a hierarchy of elements and a wrapper

  stack = []
  @nokodoc.children.each do |node|
    # non-matching nodes will get level of 0

    level = node.name[ /h([1-6])/i, 1 ].to_i
    level = 99 if level == 0

    stack.pop while (top=stack.last) && top[:level]>=level
    stack.last[:div].add_child( node ) if stack.last
    if level<99
      div = Nokogiri::XML::Node.new('div',@nokodoc)
      div.set_attribute( 'class', 'section' )
      node.add_next_sibling(div)
      stack << { :div=>div, :level=>level }
    end
  end
  dirty_doc
end

#childrenObject



133
134
135
# File 'lib/docubot/page.rb', line 133

def children
  @bundle.toc.children(html_path).map{ |node| node.page }.uniq.compact
end

#content_htmlObject



129
130
131
# File 'lib/docubot/page.rb', line 129

def content_html
  @content_html ||= nokodoc.to_html
end

#create_nokodocObject



39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/docubot/page.rb', line 39

def create_nokodoc
  # Directories with no index.* file will not have any @raw

  # Pages with metasection only will also not have any @raw

  html = if @raw && !@raw.empty?
    html = DocuBot::process_snippets( self, @raw )
    html = DocuBot::convert_to_html( self, html, @type )
  end
  @nokodoc = Nokogiri::HTML::DocumentFragment.parse(html || "")
  auto_id
  auto_section
  @nokodoc
end

#depthObject



141
142
143
# File 'lib/docubot/page.rb', line 141

def depth
  @depth ||= html_path.scan('/').length
end

#dirty_docObject

Call this after modifying the structure of the nokodoc for the page



118
119
120
# File 'lib/docubot/page.rb', line 118

def dirty_doc
  @content_html = nil
end

#dirty_sourceObject

Call this if the source generated by the converter would change THIS DESTROYS ANY CUSTOM CHANGES YOU HAVE MADE TO THE NOKODOC



113
114
115
# File 'lib/docubot/page.rb', line 113

def dirty_source
  @nokodoc = nil
end

#dirty_templateObject

Call this if the HTML generated by the page template needs to change e.g. for a glossary page.



124
125
126
127
# File 'lib/docubot/page.rb', line 124

def dirty_template
  # to_html doesn't cache anything at this point

  # so nothing needs to be done here

end

#html_pathObject



107
108
109
# File 'lib/docubot/page.rb', line 107

def html_path
  @html_path ||= @file ? @file.sub( /[^.]+$/, 'html' ) : ( @folder / 'index.html' )
end

#inspectObject



163
164
165
# File 'lib/docubot/page.rb', line 163

def inspect
  "<#{self.class} '#{self.title}' #{@file ? "@file=#{@file.inspect}" : "@folder=#{@folder.inspect}"}>"
end

#leaf?Boolean

Returns:

  • (Boolean)


137
138
139
# File 'lib/docubot/page.rb', line 137

def leaf?
  @leaf ||= !children.any?{ |page| page != self }
end

#rootObject



145
146
147
# File 'lib/docubot/page.rb', line 145

def root
  @root ||= "../" * depth
end

#to_htmlObject

TODO: cache this is people keep calling to_html and it’s a problem



150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/docubot/page.rb', line 150

def to_html
  @meta.template ||= leaf? ? 'page' : 'section'

  master_templates = DocuBot::TEMPLATE_DIR
  source_templates = @bundle.source / '_templates'
  tmpl = source_templates / "#{template}.haml"
  tmpl = master_templates / "#{template}.haml" unless File.exists?( tmpl )
  tmpl = master_templates / "page.haml"        unless File.exists?( tmpl )
  tmpl = IO.read( tmpl, encoding:'utf-8' )
  haml = Haml::Engine.new( tmpl, DocuBot::Writer::HAML_OPTIONS )
  haml.render( Object.new, :contents=>content_html, :page=>self, :global=>@bundle.global, :root=>root )
end