docjs 0.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.
Files changed (109) hide show
  1. data/CONCEPT.md +80 -0
  2. data/DOCUMENTATION.md +41 -0
  3. data/LICENSE.md +19 -0
  4. data/README.md +19 -0
  5. data/RENDERING.md +8 -0
  6. data/bin/docjs +190 -0
  7. data/docjs.gemspec +32 -0
  8. data/lib/boot.rb +34 -0
  9. data/lib/code_object/base.rb +48 -0
  10. data/lib/code_object/converter.rb +48 -0
  11. data/lib/code_object/exceptions.rb +5 -0
  12. data/lib/code_object/function.rb +84 -0
  13. data/lib/code_object/object.rb +18 -0
  14. data/lib/code_object/type.rb +43 -0
  15. data/lib/configs.rb +53 -0
  16. data/lib/document/document.rb +25 -0
  17. data/lib/dom/dom.rb +188 -0
  18. data/lib/dom/exceptions.rb +12 -0
  19. data/lib/dom/no_doc.rb +26 -0
  20. data/lib/dom/node.rb +415 -0
  21. data/lib/helper/helper.rb +120 -0
  22. data/lib/helper/linker.rb +130 -0
  23. data/lib/logger.rb +49 -0
  24. data/lib/parser/comment.rb +69 -0
  25. data/lib/parser/comment_parser.rb +90 -0
  26. data/lib/parser/exceptions.rb +6 -0
  27. data/lib/parser/meta_container.rb +20 -0
  28. data/lib/parser/parser.rb +269 -0
  29. data/lib/processor.rb +123 -0
  30. data/lib/renderer.rb +108 -0
  31. data/lib/tasks/render_task.rb +112 -0
  32. data/lib/thor.rb +27 -0
  33. data/lib/token/container.rb +84 -0
  34. data/lib/token/exceptions.rb +6 -0
  35. data/lib/token/handler.rb +242 -0
  36. data/lib/token/token.rb +46 -0
  37. data/templates/application.rb +14 -0
  38. data/templates/helpers/template.rb +66 -0
  39. data/templates/resources/css/.sass-cache/98c121fba905284c2c8ca6220fe3c590e5c9ec19/application.scssc +0 -0
  40. data/templates/resources/css/application.css +836 -0
  41. data/templates/resources/img/arrow_down.png +0 -0
  42. data/templates/resources/img/arrow_right.png +0 -0
  43. data/templates/resources/img/arrow_up.png +0 -0
  44. data/templates/resources/img/bullet_toggle_minus.png +0 -0
  45. data/templates/resources/img/bullet_toggle_plus.png +0 -0
  46. data/templates/resources/img/constructor.png +0 -0
  47. data/templates/resources/img/function.png +0 -0
  48. data/templates/resources/img/object.png +0 -0
  49. data/templates/resources/img/page.png +0 -0
  50. data/templates/resources/img/prototype.png +0 -0
  51. data/templates/resources/img/tag.png +0 -0
  52. data/templates/resources/js/application.js +318 -0
  53. data/templates/resources/js/jcore.js +129 -0
  54. data/templates/resources/js/jquery.cookie.js +92 -0
  55. data/templates/resources/js/jquery.js +16 -0
  56. data/templates/resources/js/jquery.tooltip.js +77 -0
  57. data/templates/resources/js/jquery.treeview.js +238 -0
  58. data/templates/resources/scss/_footer.scss +10 -0
  59. data/templates/resources/scss/_header.scss +184 -0
  60. data/templates/resources/scss/_helpers.scss +91 -0
  61. data/templates/resources/scss/_print.scss +20 -0
  62. data/templates/resources/scss/_resets.scss +132 -0
  63. data/templates/resources/scss/_tooltip.scss +26 -0
  64. data/templates/resources/scss/application.scss +442 -0
  65. data/templates/tasks/api_index_task.rb +26 -0
  66. data/templates/tasks/docs_task.rb +33 -0
  67. data/templates/tasks/json_data_task.rb +55 -0
  68. data/templates/tasks/typed_task.rb +54 -0
  69. data/templates/tokens/tokens.rb +22 -0
  70. data/templates/types/prototype.rb +20 -0
  71. data/templates/views/api_index.html.erb +21 -0
  72. data/templates/views/doc_page.html.erb +11 -0
  73. data/templates/views/function/_detail.html.erb +8 -0
  74. data/templates/views/function/index.html.erb +53 -0
  75. data/templates/views/index.html.erb +0 -0
  76. data/templates/views/layout/application.html.erb +73 -0
  77. data/templates/views/layout/json.html.erb +3 -0
  78. data/templates/views/object/index.html.erb +63 -0
  79. data/templates/views/tokens/_default.html.erb +11 -0
  80. data/templates/views/tokens/_default_token.html.erb +19 -0
  81. data/templates/views/tokens/_example.html.erb +2 -0
  82. data/templates/views/tokens/_examples.html.erb +1 -0
  83. data/test/code_object/converter.rb +78 -0
  84. data/test/code_object/prototype.rb +70 -0
  85. data/test/configs.rb +65 -0
  86. data/test/docs/README.CONCEPT.md +83 -0
  87. data/test/docs/README.md +14 -0
  88. data/test/dom/dom.absolute_nodes.rb +40 -0
  89. data/test/dom/dom.rb +72 -0
  90. data/test/dom/node.rb +53 -0
  91. data/test/integration/converter.rb +72 -0
  92. data/test/integration/parser_factory.rb +28 -0
  93. data/test/interactive.rb +7 -0
  94. data/test/js-files/absolute.js +11 -0
  95. data/test/js-files/comments_in_strings.js +31 -0
  96. data/test/js-files/core-doc-relative.js +77 -0
  97. data/test/js-files/core-doc.js +145 -0
  98. data/test/js-files/nested.js +34 -0
  99. data/test/js-files/nested_with_strings.js +35 -0
  100. data/test/js-files/prototype.js +33 -0
  101. data/test/js-files/simple.js +17 -0
  102. data/test/js-files/tokens.js +32 -0
  103. data/test/parser/comments_in_strings.rb +51 -0
  104. data/test/parser/intelligent_skip_until.rb +110 -0
  105. data/test/parser/parser.rb +273 -0
  106. data/test/rspec_helper.rb +23 -0
  107. data/test/token/handler.rb +136 -0
  108. data/test/token/tokens.rb +52 -0
  109. metadata +184 -0
@@ -0,0 +1,120 @@
1
+ # ../data.img#1800236:1
2
+ require 'pathname'
3
+ require 'rdiscount'
4
+
5
+ require_relative 'linker'
6
+
7
+ # The Helpers are 'mixed' into your {Tasks::RenderTask} and therefore can be used in all
8
+ # template-views.
9
+ # If you are searching for a method and don't know, where it may be implemented i suggest the
10
+ # following inheritence chain as your search-strategy:
11
+ #
12
+ # Helper::IncludedHelpers → Tasks::YourTask → Tasks::RenderTask → Renderer
13
+ #
14
+ # Somewhere at that chain you will find your desired function.
15
+ module Helper
16
+
17
+ # The Helper-methods in this module are globally used one and should not depend on the template
18
+ # you are using. You will find many html-helpers around here.
19
+ module Helper
20
+
21
+ include Linker
22
+
23
+ def tag(sym, content = "", attrs = {})
24
+
25
+ # @todo FIXME
26
+ if block_given?
27
+ _erbout << "<#{sym.to_s} #{attributize(content)}>"
28
+ content = yield
29
+ _erbout << "</#{sym.to_s}>"
30
+ else
31
+ "<#{sym.to_s} #{attributize(attrs)}>#{content}</#{sym.to_s}>"
32
+ end
33
+ end
34
+
35
+ def truncate(string, num = 150)
36
+ if string.length > num
37
+ string[0..num] + " &hellip;"
38
+ else
39
+ string
40
+ end
41
+ end
42
+
43
+ def style(*args)
44
+ html = ""
45
+ args.each do |path|
46
+ html += tag :link, "", :rel => 'stylesheet', :href => to_relative('css/'+path+'.css')
47
+ end
48
+ return html
49
+ end
50
+
51
+ def script(*args)
52
+ html = ""
53
+ args.each do |path|
54
+ html += tag :script, "", :src => to_relative('js/'+path+'.js')
55
+ end
56
+ return html
57
+ end
58
+
59
+ def code(source)
60
+ # find minimal intendation
61
+ intendation = source.lines.map {|line| line.match(/(^\s+)/) && line.match(/(^\s+)/).captures.first.size || 0 }.min
62
+
63
+ # @todo there has to be a better way for that
64
+ tag :code, source.lines.map { |line| line[intendation .. line.size] }.join(""), :class => 'block'
65
+ end
66
+
67
+ def to_html(markdown_text, *markdown_opts)
68
+ replace_links RDiscount.new(markdown_text, *markdown_opts).to_html
69
+ end
70
+
71
+ def toc(markdown_text)
72
+ RDiscount.new(markdown_text, :generate_toc).toc_content
73
+ end
74
+
75
+ def to_relative(path)
76
+
77
+ path = Pathname.new(path)
78
+ base = Pathname.new(@current_path)
79
+
80
+ # for example /home/jsdoc/css/style.css
81
+ # current: /home/jsdoc/output/Foo/Bar.html
82
+ if not path.absolute?
83
+ # resolve to Configs.output
84
+ path = Pathname.new(Configs.output) + path
85
+ end
86
+
87
+ Logger.debug "Relative path '#{path}' from '#{base}'"
88
+ path.relative_path_from(base).to_s
89
+ end
90
+
91
+ def render_tokens(opts = {})
92
+
93
+ code_object = opts[:of] or raise Exception.new("Parameter :of (CodeObject) required")
94
+ area = opts[:in] or raise Exception.new("Parameter :in (Area) required")
95
+
96
+ rendered = ""
97
+
98
+ token_groups = code_object.tokens.values.each do |tokens|
99
+
100
+ # tokens is an array of Token::Token
101
+ if not tokens.empty? and tokens.first.area == area
102
+
103
+ template = tokens.first.template.to_s
104
+
105
+ # overwriting default template with specified option[:template] if existant
106
+ template = opts[:template].to_s if opts[:template] and template == 'default'
107
+
108
+ rendered += render :partial => "tokens/#{template}", :locals => { :tokens => tokens }
109
+ end
110
+ end
111
+
112
+ rendered
113
+ end
114
+
115
+ def attributize(hash)
116
+ hash.map{|k,v| "#{k}=\"#{v}\""}.join ' '
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,130 @@
1
+ module Helper
2
+
3
+ # This Helper contains all needed functionality to link to an object, on-page-element or some
4
+ # other urls
5
+ module Linker
6
+
7
+ FILE = /^file\:(\S+)/
8
+ EXTERNAL = /^((?:http|ftp|https|ssh):\/\/\S+)/
9
+ MAIL = /^(mailto\:\S+)/
10
+ HASH = /^#\S*/
11
+ DOCUMENTATION = /^doc\:([^\s#]+)(#\S+)?/
12
+
13
+ # @note link_to - first argument can be
14
+ # "file:some/path/to_a.file"
15
+ # "Code.object.path"
16
+ # ".relative.code_object.path"
17
+ # "http://external.address.com"
18
+ # instance_of_code_object
19
+ #
20
+ def link_to(target, text = nil, args = {})
21
+
22
+ Logger.debug "Trying to link #{target}"
23
+
24
+ link = if target.is_a? Document::Document
25
+
26
+ text = target.name if text.nil?
27
+ to_relative path_to target
28
+
29
+ elsif target.is_a? CodeObject::Base
30
+
31
+ if text.nil? and target.parent == context and context != Dom.root
32
+ text = ".#{target.name}"
33
+ text += "()" if target.is_a? CodeObject::Function
34
+ elsif text.nil?
35
+ text = target.qualified_name
36
+ end
37
+
38
+ to_relative path_to target
39
+
40
+ elsif target.match EXTERNAL or target.match MAIL or target.match HASH
41
+ target
42
+
43
+ elsif target.match FILE
44
+ to_relative target.match(FILE).captures.first
45
+
46
+ elsif target.match DOCUMENTATION
47
+ Logger.debug target + " matched DOCUMENTATION"
48
+
49
+ doc_name, hash = target.match(DOCUMENTATION).captures
50
+ obj = Dom.docs.find doc_name
51
+ text ||= obj.name
52
+
53
+ # find relative path to our object and reattach hash to path
54
+ to_relative(path_to obj) + (hash || "") unless obj.nil?
55
+
56
+ else
57
+ # use context dependent resolving functionality as specified in {Tasks::RenderTask}
58
+ obj = resolve target
59
+ to_relative path_to obj unless obj.nil?
60
+ end
61
+
62
+ text ||= target
63
+
64
+ if link.nil?
65
+ Logger.warn "Could not resolve link to '#{target}'"
66
+ return text
67
+ end
68
+
69
+ tag :a, text, :href => link
70
+ end
71
+
72
+ def relative_link(path, text)
73
+ tag :a, text, :href => to_relative(path)
74
+ end
75
+
76
+ # Returns the relative path (from dom) to this node
77
+ # The Node can be either a {CodeObject::Base CodeObject} or a {Document::Document Document}.
78
+ #
79
+ # @param [CodeObject::Base, Document::Document] object
80
+ #
81
+ # @example
82
+ # Dom[:Foo][:bar].file_path #=> Foo/bar
83
+ #
84
+ def path_to(object, args = {})
85
+
86
+ return "" if object.nil?
87
+ format = args[:format] || :html
88
+ path = object.parents.push(object).map{|p| p.name}.join('/') + ".#{format.to_s}"
89
+
90
+ # object can be either a CodeObject or a Document
91
+ # maybe source this one out later on in Configs.some_path
92
+ if object.is_a? CodeObject::Base
93
+ "api/" + path
94
+ elsif object.is_a? Document::Document
95
+ "docs/" + path
96
+ else
97
+ Logger.warn "Could not resolve link to '#{object}'"
98
+ object.to_s
99
+ end
100
+ end
101
+
102
+ # (see https://github.com/lsegal/yard/blob/master/lib/yard/templates/helpers/html_helper.rb)
103
+ def replace_links(text)
104
+ code_tags = 0
105
+ text.gsub(/<(\/)?(pre|code|tt)|(\\)?\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=[\W<]|.+<\/|$)/m) do |str|
106
+ closed, tag, escape, name, title, match = $1, $2, $3, $4, $5, $&
107
+ if tag
108
+ code_tags += (closed ? -1 : 1)
109
+ next str
110
+ end
111
+ next str unless code_tags == 0
112
+
113
+ next(match[1..-1]) if escape
114
+
115
+ next(match) if name[0,1] == '|'
116
+
117
+ link_to(name, title)
118
+ end
119
+ end
120
+
121
+ def link_on_page(object)
122
+ if object.is_a? CodeObject::Function
123
+ link_to "#method-#{object.name}", ".#{object.name}()"
124
+ else
125
+ link_to "#object-#{object.name}", ".#{object.name}"
126
+ end
127
+ end
128
+ end
129
+
130
+ end
@@ -0,0 +1,49 @@
1
+ require 'thor/base'
2
+
3
+ # The logger is using colorizing-functionality from Thor's shell
4
+ module Logger
5
+
6
+ LogLevel = Struct.new :numeric, :prefix, :color
7
+
8
+ LEVEL = {
9
+ :debug => LogLevel.new(0, "DEBUG ", :white),
10
+ :info => LogLevel.new(1, "INFO ", :blue),
11
+ :warn => LogLevel.new(2, "WARN ", :yellow),
12
+ :error => LogLevel.new(3, "ERROR ", :red),
13
+ :system => LogLevel.new(10, "", :black)
14
+ }
15
+
16
+ def self.setup(args = {})
17
+
18
+ @@shell = Thor::Base.shell.new
19
+ @@logfile = args[:file]
20
+ @@level = LEVEL[args[:level] || :info]
21
+
22
+ # write start sequence
23
+ log LEVEL[:info], ["\n\n== #{Time.now} #{'='*50}"]
24
+ end
25
+
26
+ def self.method_missing(name, *args)
27
+ level = LEVEL[name.to_sym]
28
+ raise NoMethodError.new(name.to_s) if level.nil?
29
+
30
+ log(level, args)
31
+ end
32
+
33
+ protected
34
+
35
+ def self.log(level, msg)
36
+ return if level.numeric < @@level.numeric
37
+
38
+ msg = msg.join "\n"
39
+
40
+ unless @@logfile.nil?
41
+ File.open(@@logfile, "a") do |f|
42
+ f.write "#{level.prefix} #{msg}\n"
43
+ end
44
+ end
45
+
46
+ @@shell.say @@shell.set_color(level.prefix, level.color, true) + msg
47
+ end
48
+
49
+ end
@@ -0,0 +1,69 @@
1
+ # ../data.img#1781829:1
2
+ require_relative 'meta_container'
3
+ require_relative '../code_object/converter'
4
+
5
+ module Parser
6
+
7
+ # Together with {Parser::Coment} it acts as an **Interface** between {Parser}
8
+ # and {CodeObject}. Parser::Comment creates instances of Tokenline, which are
9
+ # then analysed by {Token::Container#process_token}
10
+ #
11
+ # @see Parser::Comment
12
+ # @see Parser::CommentParser
13
+ Tokenline = Struct.new :token, :content
14
+
15
+ # Comment contains all **tokenlines** and **doclines**, which are created by the
16
+ # {Parser::Parser parser}. The tokenlines are stored as {Tokenline}. Because
17
+ # of this Comment and Tokenline act as **Interface** for {CodeObject::Base}.
18
+ #
19
+ # The tokens will further be processed by {Token::Container}, which
20
+ # is mixed in to CodeObject::Base).
21
+ #
22
+ # @example creating of an comment
23
+ # c = Parser::Comment.new "the original string of the comment, with all tokens and doclines"
24
+ # c.add_tokenline :param "[String] first_parameter this is the description for param1"
25
+ # c.add_docline "Some documentation of the comment"
26
+ #
27
+ # @example access of comment-data
28
+ # c.tokenlines.first.token #=> :param
29
+ # c.tokenlines.first.content #=> "[String] first_parameter this is the description for param1"
30
+ # c.doclines #=> ["Some documentation of the comment"]
31
+ class Comment
32
+
33
+ include MetaContainer
34
+ include CodeObject::Converter
35
+
36
+ attr_reader :tokenlines, :doclines, :children
37
+
38
+ def initialize(comment_text = "")
39
+ @original_comment = comment_text
40
+
41
+ @tokenlines, @doclines, @children = [], [], []
42
+ end
43
+
44
+ # @param [String, Symbol] tokenname
45
+ # @param [String] content
46
+ def add_tokenline(tokenname, content = "")
47
+ @tokenlines << Tokenline.new(tokenname.to_sym, content)
48
+ end
49
+
50
+ # @param [String] docline
51
+ def add_docline(docline)
52
+ @doclines << docline
53
+ end
54
+
55
+ # @param [Array<Comment>] comments
56
+ def add_children(comments)
57
+ @children += comments
58
+ end
59
+
60
+ def has_tokens?
61
+ not @tokenlines.empty?
62
+ end
63
+
64
+ def to_s
65
+ "#<Parser::Comment tokenlines=#{@tokenlines.length} doclines=#{@doclines.length}>"
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,90 @@
1
+ # ../data.img#1799299:1
2
+ require_relative 'comment'
3
+ require_relative 'exceptions'
4
+
5
+ module Parser
6
+ class CommentParser < StringScanner
7
+
8
+ def initialize(input)
9
+ super(input)
10
+ @comment = Comment.new(input)
11
+ end
12
+
13
+ # All lines, that start with a `@-symbol` will be processed as tokenline
14
+ # if the next line after a token starts with two spaces, it will be
15
+ # interpreted as continuation of the preceding token.
16
+ #
17
+ # @example multiline token
18
+ # @multiline_token this is a multi_line token, it won't
19
+ # stop if i intend the next line with two spaces, like " "
20
+ #
21
+ # All other lines are interpreted as doclines
22
+ #
23
+ # @return [Parser::Comment] Creates an instance of {Parser::Comment} and
24
+ # attaches all find doc- and tokenlines to it.
25
+ def parse
26
+ # we don't want the linebreak of the comment start in our first docline
27
+ # i.e. ignore '/**\n'
28
+ self.skip LINE_END
29
+
30
+ while not eos? do
31
+ parse_comment_line
32
+ end
33
+ return @comment
34
+ end
35
+
36
+ protected
37
+
38
+ # skips leading spaces with asterisk aka {Parser::LINE_START LINE_START}
39
+ # then checks for {Parser::TOKENLINE_START @-symbol} to parse a token
40
+ def parse_comment_line
41
+ self.skip LINE_START
42
+
43
+ if self.check TOKENLINE_START
44
+ tokenline = parse_token
45
+ matches = tokenline.match(TOKENLINE)
46
+
47
+ raise NotValidTokenline.new("Not valid:'#{tokenline}'") if matches.nil?
48
+
49
+ name, content = matches.captures
50
+ @comment.add_tokenline(name, content)
51
+ else
52
+ @comment.add_docline parse_doc
53
+ end
54
+ end
55
+
56
+ # Parses tokens, if the line begins with an @
57
+ # @token_one some other text etc.
58
+ #
59
+ # The parser does the following to detect multiline tokens like:
60
+ # @token_two some text, and some more
61
+ # and even some more.
62
+ #
63
+ # 1. Scan til the first linebreak (or end of string, if it reaches it first)
64
+ # 2. Check if next line starts with two spaces, skip them
65
+ # 3. Parse recursivly til the next line does not start with two spaces
66
+ #
67
+ # @see StringScanner.scan_until_ahead to see another example
68
+ # of the positive lookahead
69
+ def parse_token
70
+
71
+ # scan until the first linebreak, but don't include it in the `content`
72
+ # content = self.scan_until_or_end(/(?=(#{LINE_END}))/)
73
+ # so just skip it
74
+ # self.skip LINE_END
75
+ content = self.scan_until_or_end LINE_END
76
+
77
+ # skip the first two spaces and parse line recursivly
78
+ unless self.skip(/#{LINE_START}#{NO_BR}{2}/).nil?
79
+ content + parse_token
80
+ else
81
+ content
82
+ end
83
+ end
84
+
85
+ def parse_doc
86
+ self.scan_until_or_end(LINE_END)
87
+ end
88
+
89
+ end
90
+ end