jsduck 5.0.0.beta01 → 5.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.travis.yml +1 -0
  2. data/README.md +6 -32
  3. data/Rakefile +5 -5
  4. data/bin/jsduck +0 -1
  5. data/js-classes/String.js +3 -5
  6. data/jsduck.gemspec +3 -2
  7. data/lib/jsduck/aggregator.rb +1 -3
  8. data/lib/jsduck/app.rb +2 -2
  9. data/lib/jsduck/categories/file.rb +0 -6
  10. data/lib/jsduck/class.rb +1 -2
  11. data/lib/jsduck/doc/parser.rb +12 -5
  12. data/lib/jsduck/doc/scanner.rb +6 -0
  13. data/lib/jsduck/doc/standard_tag_parser.rb +10 -5
  14. data/lib/jsduck/doc/subproperties.rb +9 -2
  15. data/lib/jsduck/docs_code_comparer.rb +20 -7
  16. data/lib/jsduck/exporter/app.rb +18 -13
  17. data/lib/jsduck/exporter/full.rb +18 -21
  18. data/lib/jsduck/format/doc.rb +0 -1
  19. data/lib/jsduck/format/html_stack.rb +1 -2
  20. data/lib/jsduck/format/subproperties.rb +2 -2
  21. data/lib/jsduck/inline/auto_link.rb +1 -1
  22. data/lib/jsduck/inline/img.rb +1 -1
  23. data/lib/jsduck/inline/link.rb +4 -6
  24. data/lib/jsduck/inline/video.rb +1 -2
  25. data/lib/jsduck/js/ast.rb +1 -1
  26. data/lib/jsduck/js/esprima.rb +24 -9
  27. data/lib/jsduck/logger.rb +50 -12
  28. data/lib/jsduck/members_index.rb +1 -2
  29. data/lib/jsduck/merger.rb +20 -2
  30. data/lib/jsduck/options.rb +125 -24
  31. data/lib/jsduck/process/accessors.rb +21 -8
  32. data/lib/jsduck/process/enums.rb +2 -3
  33. data/lib/jsduck/process/ext4_events.rb +2 -1
  34. data/lib/jsduck/process/global_members.rb +1 -2
  35. data/lib/jsduck/process/importer.rb +2 -6
  36. data/lib/jsduck/process/inherit_class.rb +58 -0
  37. data/lib/jsduck/process/inherit_doc.rb +6 -175
  38. data/lib/jsduck/process/inherit_members.rb +257 -0
  39. data/lib/jsduck/process/lint.rb +18 -7
  40. data/lib/jsduck/process/overrides.rb +1 -2
  41. data/lib/jsduck/render/class.rb +1 -1
  42. data/lib/jsduck/tag/alias.rb +2 -1
  43. data/lib/jsduck/tag/alternate_class_names.rb +1 -0
  44. data/lib/jsduck/tag/aside.rb +3 -3
  45. data/lib/jsduck/tag/author.rb +18 -3
  46. data/lib/jsduck/tag/autodetected.rb +21 -0
  47. data/lib/jsduck/tag/boolean_tag.rb +1 -1
  48. data/lib/jsduck/tag/cfg.rb +7 -3
  49. data/lib/jsduck/tag/class.rb +1 -1
  50. data/lib/jsduck/tag/class_list_tag.rb +1 -1
  51. data/lib/jsduck/tag/constructor.rb +1 -1
  52. data/lib/jsduck/tag/css_var.rb +1 -1
  53. data/lib/jsduck/tag/default.rb +1 -1
  54. data/lib/jsduck/tag/deprecated_tag.rb +1 -1
  55. data/lib/jsduck/tag/docauthor.rb +2 -0
  56. data/lib/jsduck/tag/enum.rb +2 -2
  57. data/lib/jsduck/tag/event.rb +1 -1
  58. data/lib/jsduck/tag/extends.rb +1 -1
  59. data/lib/jsduck/tag/ftype.rb +2 -1
  60. data/lib/jsduck/tag/inheritdoc.rb +1 -1
  61. data/lib/jsduck/tag/localdoc.rb +33 -0
  62. data/lib/jsduck/tag/markdown.rb +1 -1
  63. data/lib/jsduck/tag/member.rb +1 -1
  64. data/lib/jsduck/tag/method.rb +1 -1
  65. data/lib/jsduck/tag/mixins.rb +1 -0
  66. data/lib/jsduck/tag/override.rb +1 -1
  67. data/lib/jsduck/tag/param.rb +16 -5
  68. data/lib/jsduck/tag/preventable.rb +1 -1
  69. data/lib/jsduck/tag/property.rb +7 -3
  70. data/lib/jsduck/tag/ptype.rb +2 -1
  71. data/lib/jsduck/tag/requires.rb +1 -0
  72. data/lib/jsduck/tag/return.rb +2 -1
  73. data/lib/jsduck/tag/since.rb +1 -5
  74. data/lib/jsduck/tag/tag.rb +21 -12
  75. data/lib/jsduck/tag/throws.rb +2 -1
  76. data/lib/jsduck/tag/type.rb +2 -2
  77. data/lib/jsduck/tag/uses.rb +1 -0
  78. data/lib/jsduck/tag/xtype.rb +2 -1
  79. data/lib/jsduck/tag_loader.rb +26 -15
  80. data/lib/jsduck/tag_registry.rb +20 -11
  81. data/lib/jsduck/web/css.rb +22 -0
  82. data/lib/jsduck/web/data.rb +50 -0
  83. data/lib/jsduck/web/icons.rb +31 -0
  84. data/lib/jsduck/web/index_html.rb +88 -0
  85. data/lib/jsduck/web/search.rb +148 -0
  86. data/lib/jsduck/{source/writer.rb → web/source.rb} +2 -2
  87. data/lib/jsduck/web/template.rb +52 -0
  88. data/lib/jsduck/web/writer.rb +84 -0
  89. metadata +513 -488
  90. data/lib/jsduck/app_data.rb +0 -41
  91. data/lib/jsduck/icons.rb +0 -29
  92. data/lib/jsduck/index_html.rb +0 -84
  93. data/lib/jsduck/search_data.rb +0 -146
  94. data/lib/jsduck/template_dir.rb +0 -50
  95. data/lib/jsduck/web_writer.rb +0 -87
@@ -16,7 +16,7 @@ module JsDuck::Tag
16
16
 
17
17
  # @preventable is optionally followed by some method name, but we
18
18
  # don't document it.
19
- def parse_doc(p)
19
+ def parse_doc(p, pos)
20
20
  p.match(/.*$/)
21
21
  {:tagname => :preventable}
22
22
  end
@@ -6,6 +6,7 @@ module JsDuck::Tag
6
6
  def initialize
7
7
  @pattern = "property"
8
8
  @tagname = :property
9
+ @repeatable = true
9
10
  @member_type = {
10
11
  :name => :property,
11
12
  :category => :property_like,
@@ -19,7 +20,7 @@ module JsDuck::Tag
19
20
  end
20
21
 
21
22
  # @property {Type} [name=default] ...
22
- def parse_doc(p)
23
+ def parse_doc(p, pos)
23
24
  tag = p.standard_tag({:tagname => :property, :type => true, :name => true})
24
25
  tag[:doc] = :multiline
25
26
  tag
@@ -27,13 +28,16 @@ module JsDuck::Tag
27
28
 
28
29
  def process_doc(h, tags, pos)
29
30
  p = tags[0]
30
- h[:name] = p[:name]
31
31
  # Type might also come from @type, don't overwrite it with nil.
32
32
  h[:type] = p[:type] if p[:type]
33
33
  h[:default] = p[:default]
34
- h[:properties] = JsDuck::Doc::Subproperties.nest(tags, pos)[0][:properties]
34
+
35
35
  # Documentation after the first @property is part of the top-level docs.
36
36
  h[:doc] += p[:doc]
37
+
38
+ nested = JsDuck::Doc::Subproperties.nest(tags, pos)[0]
39
+ h[:properties] = nested[:properties]
40
+ h[:name] = nested[:name]
37
41
  end
38
42
  end
39
43
  end
@@ -4,10 +4,11 @@ module JsDuck::Tag
4
4
  class Ptype < Xtype
5
5
  def initialize
6
6
  @pattern = "ptype"
7
+ @repeatable = true
7
8
  end
8
9
 
9
10
  # @ptype name
10
- def parse_doc(p)
11
+ def parse_doc(p, pos)
11
12
  {
12
13
  :tagname => :aliases,
13
14
  :name => parse_alias_shorthand(p, "plugin")
@@ -5,6 +5,7 @@ module JsDuck::Tag
5
5
  def initialize
6
6
  @pattern = "requires"
7
7
  @tagname = :requires
8
+ @repeatable = true
8
9
  @ext_define_pattern = "requires"
9
10
  @ext_define_default = {:requires => []}
10
11
  end
@@ -7,11 +7,12 @@ module JsDuck::Tag
7
7
  def initialize
8
8
  @pattern = ["return", "returns"]
9
9
  @tagname = :return
10
+ @repeatable = true
10
11
  @html_position = POS_RETURN
11
12
  end
12
13
 
13
14
  # @return {Type} return.name ...
14
- def parse_doc(p)
15
+ def parse_doc(p, pos)
15
16
  tag = p.standard_tag({:tagname => :return, :type => true})
16
17
  tag[:name] = subproperty_name(p)
17
18
  tag[:doc] = :multiline
@@ -9,7 +9,7 @@ module JsDuck::Tag
9
9
  @html_position = POS_SINCE
10
10
  end
11
11
 
12
- def parse_doc(p)
12
+ def parse_doc(p, pos)
13
13
  {
14
14
  :tagname => :since,
15
15
  :version => p.match(/.*$/).strip,
@@ -17,10 +17,6 @@ module JsDuck::Tag
17
17
  end
18
18
 
19
19
  def process_doc(h, tags, pos)
20
- if tags.length > 1
21
- JsDuck::Logger.warn(nil, "Only one @since tag allowed per class/member.")
22
- end
23
-
24
20
  h[:since] = tags[0][:version]
25
21
  end
26
22
 
@@ -6,6 +6,11 @@ module JsDuck::Tag
6
6
  # For example: "cfg"
7
7
  attr_reader :pattern
8
8
 
9
+ # Set to true to allow the tag to occour multiple times within one
10
+ # doc-comment. By default a tag can only appear once and when
11
+ # it's detected several times a warning will be generated.
12
+ attr_reader :repeatable
13
+
9
14
  # Called by DocParser when the @tag is reached to do the parsing
10
15
  # from that point forward. Gets passed an instance of DocScanner.
11
16
  #
@@ -23,7 +28,10 @@ module JsDuck::Tag
23
28
  # the documentation following this tag will get added to the :doc
24
29
  # field of the tag and will later be accessible in #process_doc
25
30
  # method.
26
- def parse_doc(p)
31
+ #
32
+ # Also a hash with position information {:filename, :linenr} is
33
+ # passed in.
34
+ def parse_doc(scanner, position)
27
35
  end
28
36
 
29
37
  # Defines the symbol under which the tag data is stored in final
@@ -163,17 +171,18 @@ module JsDuck::Tag
163
171
  POS_ASIDE = 1
164
172
  POS_PRIVATE = 2
165
173
  POS_DOC = 3
166
- POS_DEFAULT = 4
167
- POS_SINCE = 5
168
- POS_DEPRECATED = 6
169
- POS_ENUM = 7
170
- POS_TEMPLATE = 8
171
- POS_PREVENTABLE = 9
172
- POS_PARAM = 10
173
- POS_SUBPROPERTIES = 11
174
- POS_RETURN = 12
175
- POS_THROWS = 13
176
- POS_OVERRIDES = 14
174
+ POS_LOCALDOC = 4
175
+ POS_DEFAULT = 5
176
+ POS_SINCE = 6
177
+ POS_DEPRECATED = 7
178
+ POS_ENUM = 8
179
+ POS_TEMPLATE = 9
180
+ POS_PREVENTABLE = 10
181
+ POS_PARAM = 11
182
+ POS_SUBPROPERTIES = 12
183
+ POS_RETURN = 13
184
+ POS_THROWS = 14
185
+ POS_OVERRIDES = 15
177
186
 
178
187
  # Called before #to_html to allow rendering of Markdown content.
179
188
  # For this an instance of DocFormatter is passed in, on which one
@@ -6,11 +6,12 @@ module JsDuck::Tag
6
6
  def initialize
7
7
  @pattern = "throws"
8
8
  @tagname = :throws
9
+ @repeatable = true
9
10
  @html_position = POS_THROWS
10
11
  end
11
12
 
12
13
  # @throws {Type} ...
13
- def parse_doc(p)
14
+ def parse_doc(p, pos)
14
15
  tag = p.standard_tag({:tagname => :throws, :type => true})
15
16
  tag[:doc] = :multiline
16
17
  tag
@@ -18,7 +18,7 @@ module JsDuck::Tag
18
18
  # The presence of @type implies that we are dealing with property.
19
19
  # ext-doc allows type name to be either inside curly braces or
20
20
  # without them at all.
21
- def parse_doc(p)
21
+ def parse_doc(p, pos)
22
22
  tag = p.standard_tag({:tagname => :type, :type => true})
23
23
  tag[:type] = curlyless_type(p) unless tag[:type]
24
24
  tag
@@ -34,7 +34,7 @@ module JsDuck::Tag
34
34
 
35
35
  # Do the merging of :type field
36
36
  def merge(h, docs, code)
37
- h[:type] = JsDuck::DocsCodeComparer.merge_if_matches(:type, docs, code)
37
+ JsDuck::DocsCodeComparer.merge_if_matches(h, :type, docs, code)
38
38
  if h[:type] == nil
39
39
  h[:type] = code[:tagname] == :method ? "Function" : "Object"
40
40
  end
@@ -5,6 +5,7 @@ module JsDuck::Tag
5
5
  def initialize
6
6
  @pattern = "uses"
7
7
  @tagname = :uses
8
+ @repeatable = true
8
9
  @ext_define_pattern = "uses"
9
10
  @ext_define_default = {:uses => []}
10
11
  end
@@ -6,10 +6,11 @@ module JsDuck::Tag
6
6
  def initialize
7
7
  @pattern = "xtype"
8
8
  @ext_define_pattern = "xtype"
9
+ @repeatable = true
9
10
  end
10
11
 
11
12
  # @xtype name
12
- def parse_doc(p)
13
+ def parse_doc(p, pos)
13
14
  {
14
15
  :tagname => :aliases,
15
16
  :name => parse_alias_shorthand(p, "widget")
@@ -2,35 +2,46 @@ require "jsduck/tag/tag"
2
2
 
3
3
  module JsDuck
4
4
 
5
+ # Loads Tag classes from the builtin tags/ dir and optionally also
6
+ # from additional paths.
5
7
  class TagLoader
6
- def initialize
7
- @already_loaded = {}
8
+ def initialize(extra_paths=[])
9
+ @paths = [File.dirname(__FILE__) + "/tag"]
10
+ @paths += extra_paths
8
11
  end
9
12
 
10
- # Loads tag classes from given dir or single file.
13
+ # Loads Tag classes from all supplied paths.
11
14
  #
12
15
  # Returns the tag classes that got loaded, sorted alphabetically
13
- # by class name. This ensures attributes in member signatures are
14
- # always rendered in the same order.
15
- def load_from(path)
16
+ # by class name.
17
+ def load_all
18
+ @paths.each {|path| load(path) }
19
+ tag_classes
20
+ end
21
+
22
+ private
23
+
24
+ # Loads tag classes from given dir or single file.
25
+ def load(path)
16
26
  if File.directory?(path)
17
- Dir[path+"/**/*.rb"].each {|file| require(file) }
27
+ Dir[path+"/**/*.rb"].each do |file|
28
+ # Ruby 1.8 doesn't understand that "jsduck/tag/tag" and
29
+ # "./lib/jsduck/tag/tag.rb" refer to the same file. So
30
+ # explicitly avoid loading this file (as it's required on
31
+ # top already) to prevent warnings of constants getting
32
+ # defined multiple times.
33
+ require(file) unless file =~ /jsduck\/tag\/tag\.rb$/
34
+ end
18
35
  else
19
36
  require(path)
20
37
  end
21
-
22
- tag_classes
23
38
  end
24
39
 
25
- private
26
-
27
40
  def tag_classes
28
41
  classes = JsDuck::Tag::Tag.descendants
29
- # exclude already loaded classes
30
- classes.reject! {|cls| @already_loaded[cls.name] }
31
- # remember these classes as loaded
32
- classes.each {|cls| @already_loaded[cls.name] = true }
33
42
  # sort by classname
43
+ # This ensures attributes in member signatures are
44
+ # always rendered in the same order.
34
45
  classes.sort {|a, b| a.name <=> b.name }
35
46
  end
36
47
 
@@ -1,13 +1,28 @@
1
1
  require "jsduck/tag_loader"
2
- require "jsduck/util/singleton"
3
2
 
4
3
  module JsDuck
5
4
 
6
5
  # Access to builtin @tags
7
6
  class TagRegistry
8
- include Util::Singleton
7
+ # Access to the singleton instance (only used internally)
8
+ def self.instance
9
+ @instance = TagRegistry.new unless @instance
10
+ @instance
11
+ end
12
+
13
+ # Reconfigures the registry with additional load paths.
14
+ # Used in Options class.
15
+ def self.reconfigure(load_paths)
16
+ @instance = TagRegistry.new(load_paths)
17
+ end
9
18
 
10
- def initialize
19
+ # Redirect calls from TagRegistry.method to TagRegistry.instance.method,
20
+ # making it behave like other Singleton classes.
21
+ def self.method_missing(meth, *args, &block)
22
+ self.instance.send(meth, *args, &block)
23
+ end
24
+
25
+ def initialize(load_paths=[])
11
26
  @patterns = {}
12
27
  @ext_define_patterns = {}
13
28
  @ext_define_defaults = {}
@@ -19,13 +34,7 @@ module JsDuck
19
34
  @member_types = []
20
35
  @css = []
21
36
 
22
- @loader = TagLoader.new
23
- load_from(File.dirname(__FILE__) + "/tag")
24
- end
25
-
26
- # Loads and instantiates tags from the given file or dir.
27
- def load_from(path)
28
- instantiate_tags(@loader.load_from(path))
37
+ instantiate_tags(TagLoader.new(load_paths).load_all)
29
38
  end
30
39
 
31
40
  # Instantiates all descendants of JsDuck::Tag::Tag
@@ -171,7 +180,7 @@ module JsDuck
171
180
  expand_merger(:member)
172
181
  expand_merger(:method_like)
173
182
  expand_merger(:property_like)
174
- @mergers_expanded
183
+ @mergers_expanded = true
175
184
  end
176
185
 
177
186
  def expand_merger(type_name)
@@ -0,0 +1,22 @@
1
+ require 'jsduck/tag_registry'
2
+ require 'jsduck/util/md5'
3
+
4
+ module JsDuck
5
+ module Web
6
+
7
+ # Writes the CSS gathered from Tag classes and --css option into given file.
8
+ # Then Renames the file so it contains an MD5 hash inside it,
9
+ # returning the resulting fingerprinted name.
10
+ class Css
11
+ def initialize(opts)
12
+ @opts = opts
13
+ end
14
+
15
+ def write(filename)
16
+ File.open(filename, 'w') {|f| f.write(TagRegistry.css + @opts.css) }
17
+ Util::MD5.rename(filename)
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,50 @@
1
+ require 'jsduck/util/json'
2
+ require 'jsduck/util/md5'
3
+ require 'jsduck/web/icons'
4
+ require 'jsduck/web/search'
5
+ require 'jsduck/tag_registry'
6
+
7
+ module JsDuck
8
+ module Web
9
+
10
+ # Creates big JS file with data for Docs app.
11
+ class Data
12
+ def initialize(relations, assets, opts)
13
+ @relations = relations
14
+ @assets = assets
15
+ @opts = opts
16
+ end
17
+
18
+ # Writes classes, guides, videos, and search data to one big .js file.
19
+ # Then Renames the file so it contains an MD5 hash inside it,
20
+ # returning the resulting fingerprinted name.
21
+ def write(filename)
22
+ js = "Docs = " + Util::Json.generate({
23
+ :data => {
24
+ :classes => Web::Icons.new.create(@relations.classes),
25
+ :guides => @assets.guides.to_array,
26
+ :videos => @assets.videos.to_array,
27
+ :examples => @assets.examples.to_array,
28
+ :search => Web::Search.new.create(@relations.classes, @assets),
29
+ :tests => @opts.tests,
30
+ :signatures => TagRegistry.signatures,
31
+ :memberTypes => TagRegistry.member_types,
32
+ :localStorageDb => @opts.local_storage_db,
33
+ :showPrintButton => @opts.seo,
34
+ :touchExamplesUi => @opts.touch_examples_ui,
35
+ :source => @opts.source,
36
+ :commentsUrl => @opts.comments_url,
37
+ :commentsDomain => @opts.comments_domain,
38
+ :message => @opts.message,
39
+ }
40
+ }) + ";\n"
41
+
42
+ File.open(filename, 'w') {|f| f.write(js) }
43
+
44
+ Util::MD5.rename(filename)
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ module JsDuck
2
+ module Web
3
+
4
+ # Creates an array of small hashes documenting name, parent class
5
+ # and icon of a class.
6
+ class Icons
7
+ def create(classes)
8
+ classes.map do |cls|
9
+ {
10
+ :name => cls[:name],
11
+ :extends => cls[:extends],
12
+ :private => cls[:private],
13
+ :icon => Web::Icons::class_icon(cls),
14
+ }
15
+ end
16
+ end
17
+
18
+ # Returns CSS class name for an icon of class
19
+ def self.class_icon(cls)
20
+ if cls[:singleton]
21
+ "icon-singleton"
22
+ elsif cls.inherits_from?("Ext.Component")
23
+ "icon-component"
24
+ else
25
+ "icon-class"
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,88 @@
1
+ require 'jsduck/logger'
2
+ require 'jsduck/util/io'
3
+ require 'jsduck/tag_registry'
4
+ require 'fileutils'
5
+
6
+ module JsDuck
7
+ module Web
8
+
9
+ # Deals with creation of main HTML or PHP files.
10
+ class IndexHtml
11
+ def initialize(assets, opts, paths={})
12
+ @assets = assets
13
+ @opts = opts
14
+ @paths = paths
15
+ end
16
+
17
+ # In normal mode creates index.html.
18
+ #
19
+ # When --seo enabled, creates index.php, template.html and print-template.html.
20
+ def write
21
+ if @opts.seo
22
+ FileUtils.cp(@opts.template_dir+"/index.php", @opts.output_dir+"/index.php")
23
+ create_template_html(@opts.template_dir+"/template.html", @opts.output_dir+"/template.html")
24
+ create_print_template_html(@opts.template_dir+"/print-template.html", @opts.output_dir+"/print-template.html")
25
+ create_index_template_html(@opts.template_dir+"/index-template.html", @opts.output_dir+"/index-template.html")
26
+ else
27
+ create_template_html(@opts.template_dir+"/template.html", @opts.output_dir+"/index.html")
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def create_template_html(in_file, out_file)
34
+ write_template(in_file, out_file, {
35
+ "{title}" => @opts.title,
36
+ "{mobile_redirect}" => @opts.seo ? include_script(@opts.template_dir+"/mobile-redirect.js") : "",
37
+ "{header}" => @opts.header,
38
+ "{footer}" => "<div id='footer-content' style='display: none'>#{@opts.footer}</div>",
39
+ "{extjs_path}" => @opts.extjs_path,
40
+ "{data_path}" => File.basename(@paths[:data]),
41
+ "{css_path}" => File.basename(@paths[:css]),
42
+ "{welcome}" => @assets.welcome.to_html("display:none"),
43
+ "{categories}" => @assets.categories.to_html("display:none"),
44
+ "{guides}" => @assets.guides.to_html("display:none"),
45
+ "{head_html}" => @opts.head_html,
46
+ "{body_html}" => @opts.body_html,
47
+ })
48
+ end
49
+
50
+ def create_print_template_html(in_file, out_file)
51
+ write_template(in_file, out_file, {
52
+ "{title}" => @opts.title,
53
+ "{header}" => @opts.header,
54
+ "{css_path}" => File.basename(@paths[:css]),
55
+ })
56
+ end
57
+
58
+ def create_index_template_html(in_file, out_file)
59
+ categories = @assets.categories.to_html
60
+ guides = @assets.guides.to_html
61
+
62
+ write_template(in_file, out_file, {
63
+ "{title}" => @opts.title,
64
+ "{header}" => @opts.header,
65
+ "{categories}" => categories ? "<h1>API Documentation</h1> #{categories}" : "",
66
+ "{guides}" => guides ? "<h1>Guides</h1> #{guides}" : "",
67
+ "{css_path}" => File.basename(@paths[:css]),
68
+ })
69
+ end
70
+
71
+ def include_script(filename)
72
+ "<script type='text/javascript'>\n" + Util::IO.read(filename) + "\n</script>"
73
+ end
74
+
75
+ # Opens in_file, replaces {keys} inside it, writes to out_file
76
+ def write_template(in_file, out_file, replacements)
77
+ Logger.log("Writing", out_file)
78
+ html = Util::IO.read(in_file)
79
+ html.gsub!(/\{\w+\}/) do |key|
80
+ replacements[key] ? replacements[key] : key
81
+ end
82
+ File.open(out_file, 'w') {|f| f.write(html) }
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+ end