docjs 0.2 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ require_relative '../code_object/converter'
3
3
 
4
4
  module Parser
5
5
 
6
- # Together with {Parser::Coment} it acts as an **Interface** between {Parser} and {CodeObject}.
6
+ # Together with {Parser::Comment} it acts as an **Interface** between {Parser} and {CodeObject}.
7
7
  # Parser::Comment creates instances of Tokenline, which are then analysed by
8
8
  # {Token::Container#process_token}
9
9
  #
@@ -2,8 +2,13 @@ require_relative 'comment'
2
2
  require_relative 'exceptions'
3
3
 
4
4
  module Parser
5
+
6
+ # Creates an instance of {Parser::Comment}, then parses the content and adds the contained doc-
7
+ # and tokenlines to it.
8
+ #
9
+ # @see Comment
5
10
  class CommentParser < StringScanner
6
-
11
+
7
12
  def initialize(input)
8
13
  super(input)
9
14
  @comment = Comment.new(input)
@@ -18,8 +23,7 @@ module Parser
18
23
  #
19
24
  # All other lines are interpreted as doclines
20
25
  #
21
- # @return [Parser::Comment] Creates an instance of {Parser::Comment} and attaches all find doc-
22
- # and tokenlines to it.
26
+ # @return [Parser::Comment] Attaches all found doc- and tokenlines to the instance of comment
23
27
  def parse
24
28
  # we don't want the linebreak of the comment start in our first docline
25
29
  # i.e. ignore '/**\n'
@@ -51,7 +55,7 @@ module Parser
51
55
  end
52
56
  end
53
57
 
54
- # Parses tokens, if the line begins with an @
58
+ # Parses tokens, if the line begins with an `@`
55
59
  # @token_one some other text etc.
56
60
  #
57
61
  # The parser does the following to detect multiline tokens like:
@@ -1,6 +1,10 @@
1
1
  module Parser
2
2
 
3
- # is included by {CodeObject::Base} and {Parser::Comment}
3
+ # Is included by {CodeObject::Base} and {Parser::Comment} and stores Metainformation like
4
+ #
5
+ # - **filepath** of the JavaScript-File, where the comment is extracted from
6
+ # - **source** of the JavaScript-Scope, which begins just after the comment ends.
7
+ # - **line_start** - Linenumber of the first scope-line
4
8
  module MetaContainer
5
9
 
6
10
  attr_reader :filepath, :source, :line_start
@@ -1,10 +1,8 @@
1
1
  require 'strscan'
2
2
  require_relative 'comment_parser'
3
3
 
4
- #
5
- # ![Parser Overview](../uml/Parser.svg)
6
- #
7
- #
4
+ # @see Parser::Parser
5
+ # @see Parser::CommentParser
8
6
  module Parser
9
7
 
10
8
  NO_BR = /((?!\n)\s)/
@@ -53,7 +51,35 @@ module Parser
53
51
  D_STRING => D_STRING,
54
52
  REGEXP_START => REGEXP_END
55
53
  }
56
-
54
+
55
+ # ![Parser Overview](../img/md_parse_js.png)
56
+ #
57
+ # Turns the incoming javascript-source into a stream of {Parser::Comment comments}. Those comments
58
+ # contain the parsed doclines, which are simply all lines found in the comment and all tokenlines.
59
+ #
60
+ # A tokenline starts with a token like `@token` and can span over multiple lines, if it is intended
61
+ # by two spaces.
62
+ #
63
+ # The comment-scope (i.e. the javascript-language-scope beginning in the next line) will be preserved
64
+ # as `source` of the comment as well.
65
+ #
66
+ # For example it extracts to Comments from the following source
67
+ #
68
+ # /**
69
+ # * @object Person
70
+ # */
71
+ # var Person = {}
72
+ #
73
+ # /**
74
+ # * Some documentation here, and there
75
+ # *
76
+ # * @object Person.config
77
+ # */
78
+ # Person.config = {};
79
+ #
80
+ # #=> [#<Parser::Comment tokenlines=1 doclines=0>, #<Parser::Comment tokenlines=1 doclines=2>]
81
+ #
82
+ # @see Parser::CommentParser
57
83
  class Parser
58
84
 
59
85
  attr_reader :filepath, :offset
@@ -78,9 +104,10 @@ module Parser
78
104
  end
79
105
 
80
106
 
81
- # Recursivly parses the {#initialize given input} and thereby ignores strings.
107
+ # Recursivly parses the {#initialize given input} and thereby ignores strings and regular-
108
+ # expressions.
82
109
  #
83
- # @todo Rewrite to use skip_intelligent_until
110
+ # @todo Rewrite to use {StringScanner#intelligent_skip_until}
84
111
  # @return [Array<Parser::Comment>] the parsed comment-stream
85
112
  def parse()
86
113
  @scanner.skip /\s/
@@ -108,6 +135,7 @@ module Parser
108
135
  end
109
136
  end
110
137
 
138
+ # Reads the contents of `path`, creates a new `Parser` and starts parsing all at once
111
139
  def self.parse_file(path)
112
140
  stream = File.read path
113
141
  Parser.new(stream, :filepath => path).parse
@@ -236,8 +264,6 @@ class StringScanner
236
264
 
237
265
  raise end_of_string_error(pattern) if self.matched.nil?
238
266
 
239
- return if found.match pattern
240
-
241
267
  Parser::NON_CODE_PATTERNS.each do |start_pattern, end_pattern|
242
268
  if found.match start_pattern
243
269
  self.skip_escaping_until end_pattern
@@ -259,7 +285,7 @@ class StringScanner
259
285
 
260
286
  raise end_of_string_error(pattern) if self.matched.nil?
261
287
 
262
- if self.matched.match /\\/
288
+ if self.matched.match /\\/
263
289
  self.getch
264
290
  skip_escaping_until(pattern)
265
291
  end
@@ -3,22 +3,52 @@ require_relative 'dom/dom'
3
3
  require_relative 'generator/generator'
4
4
  require_relative 'document/document'
5
5
 
6
- module Processor
7
-
8
- # @group Combined Stages
6
+ # @note The prerequisites for Processor to work is that {Logger} and {Configs} are prepared and all
7
+ # other components are already required. (Like the {Parser::Parser} and the {Dom}). For further
8
+ # information about how to set up the system, see {#setup_application}.
9
+ #
10
+ # The Processor is a component, which is essential for {DocJs} to fullfil it's tasks. While {DocJs}
11
+ # serves as commandline-interface (CLI), the Processor is the heartpiece of DocJs and it's methods are
12
+ # triggered directly by DocJs after having everything set up correctly.
13
+ #
14
+ # The Processing is divided into the following stages:
15
+ module Processor
9
16
 
10
- def self.process_and_render
11
- process_files_to_dom
12
- perform_all_tasks
13
- end
14
17
 
15
- def self.process_files_to_dom(files = nil)
16
- process_comments parse_files(files)
17
- end
18
+ # @group Stage #1 - Document Processing
19
+
20
+ # For each specified Markdown-Document a new instance of {Document::Document} is created and filled
21
+ # with it's contents. Afterwards the document-nodes are added as children to `Dom.docs`.
22
+ #
23
+ # ![Document Processing](img/md_process_documents.png)
24
+ #
25
+ def self.prepare_documents
26
+ # underscores will be replaced with whitespaces as title
27
+ Configs.docs.each do |doc|
28
+
29
+ doc_path = File.expand_path(doc, Configs.wdir)
30
+ Logger.debug "Working with Document #{doc_path}"
31
+
32
+ contents = File.read(doc_path)
33
+
34
+ # Those documents get registered in a special {Dom::Node} Dom.docs
35
+ document = Document::Document.new(doc_path, contents)
36
+ Dom.docs.add_node(document.path, document)
37
+
38
+ # The docs can be accessed via Dom later on
39
+ end
40
+ end
41
+
18
42
 
19
- # @group Stage #1 - FileProcessor
43
+ # @group Stage #2a - File Processing
20
44
 
21
- # Parsing Files and creating comment stream
45
+ # Process JavaScript files, whose filenames are stored in `Configs.files` (After having them
46
+ # provided as commandline-options or in a `docjs.yml`-file)
47
+ #
48
+ # Parses each JavaScript file and collects the found comments. After parsing everything all comments
49
+ # are returned as an Array.
50
+ #
51
+ # [ *.js Files ] --(parses)--> [ Comments ]
22
52
  def self.parse_files(files = nil)
23
53
  files ||= Configs.files
24
54
 
@@ -35,45 +65,47 @@ module Processor
35
65
  return comments
36
66
  end
37
67
 
38
- # @group Stage #2 - CommentProcessor
68
+
69
+ # @group Stage #2b - Comment Processing
39
70
 
40
71
  # Processing comment-stream and convert to {CodeObject CodeObjects}
41
- # This stage also adds the CodeObjects to Dom.
72
+ # This stage also adds the CodeObjects to {Dom}.
73
+ #
74
+ # [ Comments ] --(converts to)--> [ CodeObject ] --(add to)--> [ Dom ]
42
75
  def self.process_comments(comments)
43
76
 
44
77
  comments = [comments] unless comments.is_a? Array
45
78
 
46
79
  comments.each do |comment|
47
- code_object = comment.to_code_object # convert to code_object
80
+ code_object = comment.to_code_object # convert to code_object
48
81
  Logger.debug "Adding to Dom: #{code_object}"
49
- Dom.add_node(code_object.path, code_object) unless code_object.nil? # add to dom
82
+ Dom.add_node(code_object.path, code_object) unless code_object.nil? # add to dom
50
83
  end
51
- end
52
-
84
+ end
53
85
 
54
- # @group Stage #3 - TemplateProcessor
86
+ # @group Stage #3 - Template Processing
55
87
 
56
- def self.perform_all_tasks
88
+ # Searches for all Generator-Classes, instantiates them and calls {Generator::Generator#perform}
89
+ # to trigger the content-generation.
90
+ #
91
+ # [ Generators ] --(uses)--> [ Dom ]
92
+ # |
93
+ # ---(generates)--> [ HTML-Output ]
94
+ def self.start_generators
57
95
  Generator::Generator.all.each { |task| task.new.perform }
58
96
  end
97
+
98
+
99
+ # @group Combined Stages
59
100
 
60
- # @group Stage #4 - Document Processor
61
-
62
- def self.prepare_documents
63
- # underscores will be replaced with whitespaces as title
64
- Configs.docs.each do |doc|
65
-
66
- doc_path = File.expand_path(doc, Configs.wdir)
67
- Logger.debug "Working with Document #{doc_path}"
68
-
69
- contents = File.read(doc_path)
70
-
71
- # Those documents get registered in a special {Dom::Node} Dom.docs
72
- document = Document::Document.new(doc_path, contents)
73
- Dom.docs.add_node(document.path, document)
74
-
75
- # The docs can be accessed via Dom later on
76
- end
101
+ # Combines Stages {.parse_files #2a}, {.process_comments #2b} and {.start_generators #3}
102
+ def self.process_and_render
103
+ process_files_to_dom
104
+ start_generators
105
+ end
106
+
107
+ # Combines Stage {.parse_files #2a} and {.process_comments #2b}
108
+ def self.process_files_to_dom(files = nil)
109
+ process_comments parse_files(files)
77
110
  end
78
-
79
111
  end
@@ -1,6 +1,31 @@
1
1
  require 'erb'
2
2
  require 'fileutils'
3
3
 
4
+ # The Renderer is the heart-piece of each {Generator::Generator}, but can also be used without them.
5
+ # It uses ERB-Templates, which are being rendered with a binding to the Renderer-instance.
6
+ #
7
+ # It's only method {#render} can be used in multiple ways, which are explained {#render here}.
8
+ # The Renderer is automatically been set up by the Generator, but to understand how it works we
9
+ # may setup it ourselves like:
10
+ #
11
+ # my_renderer = Renderer.new 'my/template/path', 'layout/application'
12
+ # my_renderer.render 'test', :to_file => 'output.html'
13
+ #
14
+ # This will render the template `my/template/path/test.html.erb` in the layout
15
+ # `my/template/path/layout/application.html.erb` and saved to `output.html`.
16
+ #
17
+ # Most of the time, as with Generators, the renderer will be extended and used like:
18
+ #
19
+ # class MyRenderer < Renderer
20
+ #
21
+ # def initialize
22
+ # super('my/template/path', 'layout/application')
23
+ # end
24
+ #
25
+ # def index
26
+ # render 'test', :to_file => 'output.html'
27
+ # end
28
+ # end
4
29
  class Renderer
5
30
 
6
31
  def initialize(default_path, layout)
@@ -8,7 +33,81 @@ class Renderer
8
33
  @_layout = layout
9
34
  end
10
35
 
11
- # Pretty much inspired by Ruby on Rails
36
+ # @overload render(template, *opts)
37
+ # Options **opts**:
38
+ #
39
+ # - :layout (String) Default is specified in constructor. For example `'json'` or `'application'`
40
+ # - :to_file (String) Optional file-path to save the output to.
41
+ #
42
+ # @param [String, Symbol] template Template-file **without** file-extension. (Like `index` => `index.html.erb`)
43
+ # @param [Hash] opts
44
+ # @return [String, nil] the rendered output
45
+ #
46
+ #
47
+ # @overload render(:partial => template, :collection => [...])
48
+ # For each item of `collection`, the partial will be rendered once. The output consists of all
49
+ # those concatenated render-passes.
50
+ # The value of each item will be bound to a local-variable called like the partial, without leading
51
+ # _. (i.e. if partial-name = "_test.html.erb" the variable is called `test`
52
+ #
53
+ # Options **opts**:
54
+ #
55
+ # - :template (String, Symbol) Template-file **without** file-extension. (Like `index` => `index.html.erb`)
56
+ # - :collection (Array)
57
+ #
58
+ # @param [Hash] opts
59
+ # @return [String] the rendered output
60
+ #
61
+ #
62
+ # @overload render(:partial => template, :locals => {...})
63
+ # Each key of `locals` will be set to it's value in the local-binding of the partial.
64
+ #
65
+ # Options **opts**:
66
+ #
67
+ # - :template (String, Symbol) Template-file **without** file-extension. (Like `index` => `index.html.erb`)
68
+ # - :locals (Hash) Hash of variables, which will be available via local-variables in the partial-binding
69
+ #
70
+ # @param [Hash] opts
71
+ # @return [String] the rendered output
72
+ #
73
+ #
74
+ # @example simple rendering
75
+ # render 'test', :layout => nil #=> returns a string, containing the rendered template 'test.html.erb'
76
+ #
77
+ # @example rendering within a layout
78
+ # # layout/app.html.erb
79
+ # <html>
80
+ # <%= yield %>
81
+ # </html>
82
+ #
83
+ # # MyCustomRenderer < Renderer
84
+ # render 'test', :layout => 'layout/app' #=> renders 'test.html.erb' within 'app.html.erb'
85
+ #
86
+ # @example rendering a partial with collections
87
+ # # _item.html.erb
88
+ # <li><%= item %></li>
89
+ #
90
+ # # my_view.html.erb
91
+ # <ul>
92
+ # <%= render :partial => 'item', :collection => ["Foo", "Bar", "Baz"]
93
+ # </ul>
94
+ #
95
+ # #=> <ul><li>Foo</li><li>Bar</li><li>Baz</li></ul>
96
+ #
97
+ # @example setting local-variables within a partial
98
+ # # _item.html.erb
99
+ # <strong><%= foo %></strong> <em><%= bar %></em>
100
+ #
101
+ # # my_view.html.erb
102
+ # <%= render :partial => 'item', :locals => { :foo => "Hello", :bar => "World" } %>
103
+ #
104
+ # #=> <strong>Hello</strong> <em>World</em>
105
+ #
106
+ # @example rendering to file
107
+ # render 'my_test', :to_file => "test_output.html"
108
+ #
109
+ # @note Pretty much inspired by Ruby on Rails
110
+ # @see http://guides.rubyonrails.org/layouts_and_rendering.html
12
111
  def render(opt = nil, extra_options = {})
13
112
 
14
113
  # Prepare Options
@@ -1,3 +1,5 @@
1
+ # Extension of Thor to merge options from configuration-file and command line
2
+ # @see https://github.com/wycats/thor/wiki
1
3
  class Thor
2
4
 
3
5
  protected
@@ -1,7 +1,9 @@
1
1
  require_relative 'exceptions'
2
2
 
3
3
  module Token
4
-
4
+
5
+ # Each {CodeObject} serves as Token::Container. This module encapsulates all required methods
6
+ # to {#process_token convert Tokenlines to Tokens}, {#add_token add Tokens} and {#token query the stored tokens}.
5
7
  module Container
6
8
 
7
9
  def initialize
@@ -45,12 +47,14 @@ module Token
45
47
  @tokens[tokenid] << token
46
48
  end
47
49
 
48
- # @param [Parser::Tokenline] tokenline consisting of :token and :content
50
+ # tries to find matching tokenklass for token i.e. Token::Token::ParamToken for :param
49
51
  # then calls matching tokenhandler (if exists) with data in `this`-context
50
- # @todo only raise error, if config is set to whiny
52
+ #
53
+ # @param [Parser::Tokenline] tokenline consisting of :token and :content
54
+ #
55
+ # @todo only throw NoTokenHandler, if this really is the problem
51
56
  def process_token(tokenline)
52
-
53
- # try to find matching tokenklass for token i.e. Token::Token::ParamToken for :param
57
+
54
58
  begin
55
59
  camelcased = tokenline.token.to_s.capitalize.gsub(/_\w/){|w| w[1].capitalize}
56
60
  tokenklass = Token.const_get "#{camelcased}Token"
@@ -6,9 +6,7 @@ require_relative 'token'
6
6
  # The {CodeObject::Converter converter} starts the {Parser::Tokenline tokenline}-processing, by
7
7
  # calling the mixed-in function {Token::Container#process_token}.
8
8
  #
9
- # ![Token UML](../uml/Tokens.svg)
10
- #
11
- # The illustration above shows the **two modules** included in {Token}:
9
+ # There are **two modules** included in {Token}:
12
10
  #
13
11
  # 1. {Token::Handler}, which can be used to register new token-handlers.
14
12
  # 2. {Token::Container}, which is included in {CodeObject::Base} to add
@@ -12,6 +12,8 @@ module Token
12
12
  # :template => :foo,
13
13
  # :description => "Description"
14
14
  # })
15
+ #
16
+ # (That's basically everything, that is done internally while registering a Token)
15
17
  class Token
16
18
 
17
19
  attr_reader :name, :content, :types, :children