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.
@@ -11,9 +11,18 @@ require_relative 'code_object/base'
11
11
  require_relative 'dom/dom'
12
12
  require_relative 'processor'
13
13
 
14
+ # `#setup_application` is called during the initialization process of DocJs within {DocJs#docjs}
15
+ #
16
+ # ![Boot Activity Diagram](img/md_boot.svg)
17
+ #
18
+ # It is responsible to configure the two application-wide Singleton Objects {Logger} and {Configs}
19
+ # and fill {Configs} with the given commandline arguments.
20
+ #
21
+ # If the user is using it's own custom templates (see {file:CUSTOMIZE.md}) those templates will be
22
+ # included before the processing can begin.
14
23
  def setup_application(options = {})
15
24
 
16
- # initialize Logger
25
+ # Initialize Logger
17
26
  Logger.setup :logfile => (options[:logfile] && File.expand_path(options[:logfile], Dir.pwd)),
18
27
  :level => (options[:loglevel] || :info).to_sym
19
28
 
@@ -21,10 +30,11 @@ def setup_application(options = {})
21
30
 
22
31
  # Process option-values and store them in our Configs-object
23
32
  Configs.set :options => options, # Just store the options for now
33
+
34
+ # Set the paths
24
35
  :wdir => Dir.pwd, # The current working directory
25
36
  :output => File.absolute_path(options[:output]),
26
37
  :templates => File.absolute_path(options[:templates]),
27
- :includes => (options[:includes] && File.absolute_path(options[:includes])),
28
38
  :files => (options[:files] && options[:files].map {|path| Dir.glob(path) }.flatten),
29
39
  :docs => (options[:docs] && options[:docs].map {|path| Dir.glob(path) }.flatten)
30
40
 
@@ -3,10 +3,6 @@ require_relative '../token/handler'
3
3
  require_relative '../dom/dom'
4
4
  require_relative '../parser/meta_container'
5
5
 
6
- #
7
- # ![Code Object Overview](../uml/CodeObject.svg)
8
- #
9
- #
10
6
  module CodeObject
11
7
 
12
8
  class Base
@@ -2,8 +2,6 @@ require_relative 'exceptions'
2
2
 
3
3
  module CodeObject
4
4
 
5
- # here the dependencies to {Dom::Node} and {Parser::Comment} should be described
6
- #
7
5
  # Converts a comment to a code_object and therefor is included in {Parser::Comment}
8
6
  module Converter
9
7
 
@@ -11,7 +9,7 @@ module CodeObject
11
9
 
12
10
  def to_code_object
13
11
 
14
- # 1. Create a new CodeObject from Type-Token like @function CodeObject::Function
12
+ # 1. Create a new CodeObject from Type-Token like @function -> CodeObject::Function
15
13
  @code_object = find_type_for(@tokenlines) or return nil
16
14
 
17
15
  # join all documentation-contents and make them one text again
@@ -51,16 +49,17 @@ module CodeObject
51
49
 
52
50
  if types.size > 1
53
51
  raise CodeObject::MultipleTypeDeclarations.new, "Wrong number of TypeDeclarations: #{types}"
54
- elsif types.size == 0
52
+ elsif types.size == 1
53
+ type = types.first
54
+
55
+ # Get Class and instantiate it with content
56
+ klass = available_types[type.token]
57
+ return klass.new(type.content)
58
+
59
+ else
55
60
  # it's not possible to create instance
56
61
  return nil
57
- end
58
-
59
- type = types.first
60
-
61
- # Get Class and instantiate it with content
62
- klass = available_types[type.token]
63
- klass.new(type.content)
62
+ end
64
63
  end
65
64
  end
66
65
  end
@@ -1,3 +1,31 @@
1
+ # Systemwide Singleton, which can be used to store global configurations, like paths or some other
2
+ # settings
3
+ #
4
+ # @example Usage
5
+ # Configs.set :foo, 123
6
+ # Configs.foo #=> 123
7
+ #
8
+ # Configs.set :foo => 456, :bar => "Hello World"
9
+ # Configs.foo #=> 456
10
+ # Configs.bar #=> "Hello World"
11
+ #
12
+ # Configs.baz #=> nil
13
+ #
14
+ # @example List all configs
15
+ # Configs.attributes #=> { :foo => 456, :bar => "Hello World" }
16
+ #
17
+ # @example Real dump of Configs, after setting up DocJs
18
+ # Configs.attributes #=> [:root, :options, :wdir, :output, :templates, :files, :docs]
19
+ #
20
+ # Configs.root #=> #<Pathname:/path/to/application/root>
21
+ # Configs.options #=> {:files=>["test/js-files/core-doc.js"], :docs=>["test/docs/*.md"],
22
+ # # :output=>"out", :templates=>#<Pathname:/path/to/templates>,
23
+ # # :appname=>"Doc.js", :loglevel=>"debug"}
24
+ # Configs.wdir #=> "/path/to/working/directory"
25
+ # Configs.output #=> "/path/to/output/directory"
26
+ # Configs.templates #=> "/path/to/used/template/directory"
27
+ # Configs.files #=> ["test/js-files/core-doc.js"]
28
+ # Configs.docs #=> ["test/docs/README.md", "test/docs/README.CONCEPT.md"]
1
29
  module Configs
2
30
 
3
31
  def self.set(sym_or_hash, value = nil)
@@ -2,6 +2,27 @@ require_relative '../dom/dom'
2
2
 
3
3
  module Document
4
4
 
5
+ # Document is used to represent Markdown-Files (which should provied further help to your
6
+ # generated docs)
7
+ # Each given Markdown-File is converted in a {Document::Document} and then added to {Dom.docs}
8
+ # Like the {file:USE.md#Namespacing namespacing} in JavaScript-Comments there is a
9
+ # naming-convention for Markdown-files if you wish to store them in a tree-like structure.
10
+ #
11
+ # docs/README.md
12
+ # docs/README.CONCEPT.md
13
+ # docs/README.ARCHITECTURE.md
14
+ #
15
+ # will result in a tree:
16
+ #
17
+ # Dom.docs
18
+ # |
19
+ # README
20
+ # / \
21
+ # CONCEPT ARCHITECTURE
22
+ #
23
+ # @todo it would be much nicer, if a directory is provided in the CLI (like :docs => "/my/docs")
24
+ # that this tree-structure is reconstructed from the directory-structure. Naming files like
25
+ # `My.Awesome.File.md` is not that elegant.
5
26
  class Document
6
27
 
7
28
  include Dom::Node
@@ -11,10 +11,6 @@ require_relative 'exceptions'
11
11
  # 1. {Dom::NoDoc Not documented nodes} that contain other nodes
12
12
  # 2. {Dom::Node Documented nodes}, that contain other nodes
13
13
  # 3. Leafs of the tree, without children. (Those leafs have to be {Dom::Node documented nodes})
14
- #
15
- # The architecure of the Dom looks pretty much like this:
16
- #
17
- # ![Dom Architecture](../uml/Dom.svg)
18
14
  #
19
15
  # Take the following code-sample:
20
16
  #
@@ -82,11 +78,6 @@ require_relative 'exceptions'
82
78
  #
83
79
  # Dom.add_node != Dom.root.add_node
84
80
  #
85
- # For the example above the full UML-Graph, including the root-node, could look
86
- # like:
87
- #
88
- # ![dom tree sample](../uml/dom_tree_sample.svg)
89
- #
90
81
  # @example Adding some Nodes
91
82
  # o1 = CodeObject::Object.new "foo"
92
83
  # o2 = CodeObject::Object.new "poo"
@@ -4,9 +4,84 @@ require_relative '../helper/helper'
4
4
 
5
5
  module Generator
6
6
 
7
+ # If you already familiar with Ruby on Rails: Generators are pretty much like Controllers in Rails.
8
+ # That's like in Rails:
9
+ #
10
+ # - They use the existing data-model (The {Dom} in our case)
11
+ # - They start the rendering process in a view, by calling {Renderer#render render}.
12
+ # - If you want to make use of data in a view, you can store it in an instance-variable, like `@nodes`
13
+ # - Helpers are included in the generator, so you can utilize their messages in views
14
+ #
15
+ # The major difference between controllers in Rails and generators in DocJs is, that DocJs triggers
16
+ # all generators one after another and there is no real interaction between the views and the
17
+ # generator.
18
+ #
19
+ # In other words, after collecting all necessary informations about the JavaScript-Files and
20
+ # Markdown-Documents DocJs uses the Generators to create the final output.
21
+ #
22
+ # @example a simple generator
23
+ # module Generator
24
+ # class MyTestGenerator < Generator
25
+ # # For more information about those methods, see section Generator-Specification methods
26
+ # describe 'does awesome things'
27
+ # layout 'application'
28
+ # start_method :go
29
+ # templates '/views/special_ones'
30
+ #
31
+ # protected
32
+ #
33
+ # def go
34
+ # in_context Dom.root do
35
+ # @elements = []
36
+ # Dom.root.each_child do |child|
37
+ # @elements << child unless child.is_a? Dom::NoDoc
38
+ # end
39
+ #
40
+ # render 'my_view', :to_file => 'output_file.html'
41
+ # end
42
+ # end
43
+ # end
44
+ # end
45
+ #
46
+ # The following image should help you to get a general overview, how the components of DocJs interact:
47
+ #
48
+ # ![Render Flow](../img/md_render_flow.png)
49
+ #
50
+ # One may notice, that {Renderer} and {Generator::Generator} are not that separable, as shown in this
51
+ # image. In fact the concrete Generator (like {Generator::ApiIndexGenerator}) inherits from
52
+ # {Generator::Generator}, which in turn inherits from {Renderer}.
53
+ # So we've got an inheritence-chain like:
54
+ #
55
+ # Generator::ApiIndexGenerator < Generator::Generator < Renderer
56
+ #
57
+ # Helpers
58
+ # -------
59
+ # You can create your own helper functions, bundled in a custom helper-module. They automatically
60
+ # will be mixed in all Generators, as long as they match the following conditions:
61
+ #
62
+ # - Your module has to be a Submodule of Helper
63
+ # - Your code has to be included somewhere (i.e. `require 'my_helper'` in `application.rb`)
64
+ #
65
+ # For example your helper could look like:
66
+ #
67
+ # # TEMPLATE_PATH/helpers/my_helper.rb
68
+ # module Helper::MyHelper
69
+ # def my_greeter
70
+ # "Hello Woooorld"
71
+ # end
72
+ # end
73
+ #
74
+ # # TEMPLATE_PATH/application.rb
75
+ # require_relative 'helpers/my_helper'
76
+ #
77
+ # Then you could use them in your Generator or in your Views
78
+ #
79
+ # # TEMPLATE_PATH/views/template.html.erb
80
+ # <h1><%= my_greeter %></h1>
7
81
  class Generator < Renderer
8
82
 
9
83
  def initialize
84
+ # At this point we pass the configurations to our Parent `Renderer`
10
85
  super(Configs.templates + configs(:templates), configs(:layout))
11
86
 
12
87
  # include all Helpers
@@ -18,6 +93,90 @@ module Generator
18
93
  @_context = Dom.root
19
94
  end
20
95
 
96
+ # @group Generator-Specification methods
97
+
98
+ # This description is used in the cli-command `docjs generators` to list all generators and their
99
+ # descriptions
100
+ #
101
+ # @param [String] desc A short description of this generators task
102
+ def self.describe(desc)
103
+ self.set_config(:description, desc.to_s)
104
+ end
105
+
106
+ # Specifies which layout should be used to render in (Default is `nil`)
107
+ #
108
+ # @param [String] layout_view
109
+ def self.layout(layout_view)
110
+ unless layout_view.nil?
111
+ self.set_config(:layout, 'layout/' + layout_view)
112
+ else
113
+ self.set_config(:layout, nil)
114
+ end
115
+ end
116
+
117
+ # Which method should be invoked, if generator is executed (Default is `:index`)
118
+ #
119
+ # @param [String, Symbol] method
120
+ def self.start_method(method)
121
+ self.set_config(:start_method, method.to_sym)
122
+ end
123
+
124
+ # The path to your views (Default is `/views`)
125
+ #
126
+ # You can use this method, to specify a special template path, for example if you want to use
127
+ # a subdirectory of your views, without always having to provide the full path in all `render`-calls
128
+ #
129
+ # @note the layout-path is always relative to your specified path (i.e. `layout 'application'`
130
+ # and `templates 'my_custom'` will result in a required layout file with a path like
131
+ # `my_custom/layout/application.html.erb`
132
+ #
133
+ # @param [String] path_to_views Relative path from your scaffolded template-directory, but with
134
+ # a leading `/`, like `/views/classes`
135
+ def self.templates(path_to_views)
136
+ self.set_config(:templates, path_to_views)
137
+ end
138
+
139
+ # @note not neccesarily needed, because all Helpers are included by default
140
+ #
141
+ # Can be used to include a helper in a Generator
142
+ def self.use(helper_module)
143
+ include helper_module
144
+ end
145
+
146
+ # @group Context manipulation- and access-methods
147
+
148
+ # Modyfies the Dom-resolution-context {#context} to `new_context`, while in `&block`. After
149
+ # leaving the block, the context will be switched back.
150
+ #
151
+ # @param [Dom::Node] new_context The new context
152
+ # @yield block The block, in which the context is valid
153
+ def in_context(new_context, &block)
154
+ old_context = @_context
155
+ @_context = new_context
156
+ yield
157
+ @_context = old_context
158
+ end
159
+
160
+ # Retreives the current Dom-resolution-context, which can be specified by using {#in_context}
161
+ #
162
+ # @return [Dom::Node] the context, to which all relative nodes should be resolved
163
+ def context
164
+ @_context
165
+ end
166
+
167
+ # Resolves a nodename in the specified context, by using {Dom::Node#resolve} on it.
168
+ #
169
+ # @param [String] nodename
170
+ # @return [Dom::Node, nil]
171
+ # @see Dom::Node#resolve
172
+ def resolve(nodename)
173
+ @_context.resolve nodename
174
+ end
175
+
176
+ # @group System-Methods
177
+
178
+ # Calls always the specified `:start_method` on this Generator. (Default for :start_method is
179
+ # 'index')
21
180
  def perform
22
181
 
23
182
  unless self.respond_to? configs(:start_method)
@@ -27,19 +186,17 @@ module Generator
27
186
  self.send configs(:start_method)
28
187
  end
29
188
 
30
- def context
31
- @_context
32
- end
33
-
189
+ # Is used by {DocJs#generators} to provide a list of all generators and their descriptions
190
+ #
191
+ # @return [String] description, which has been previously entered using `.describe`
34
192
  def self.description
35
193
  configs(:description)
36
194
  end
37
195
 
38
- # not neccesarily needed, because all Helpers are included by default
39
- def self.use(helper_module)
40
- include helper_module
41
- end
42
-
196
+ # Returns all Generators, by finding all constants in the Generator-Module and filtering them
197
+ # for classes with parent {Generator::Generator}.
198
+ #
199
+ # @return [Array<Generator>]
43
200
  def self.all
44
201
  # Otherwise we don't get the global Generator-Module
45
202
  gen_module = Object.const_get(:Generator)
@@ -50,29 +207,6 @@ module Generator
50
207
 
51
208
  protected
52
209
 
53
- # @group Generator-Specification methods
54
-
55
- def self.describe(desc)
56
- self.set_config(:description, desc.to_s)
57
- end
58
-
59
- def self.layout(layout_view)
60
- unless layout_view.nil?
61
- self.set_config(:layout, 'layout/' + layout_view)
62
- else
63
- self.set_config(:layout, nil)
64
- end
65
- end
66
-
67
- def self.templates(path_to_templates)
68
- self.set_config(:templates, path_to_templates)
69
- end
70
-
71
- def self.start_method(method)
72
- self.set_config(:start_method, method.to_sym)
73
- end
74
-
75
-
76
210
  # @group helper methods to make usage of class-variables work in **inheriting** classes
77
211
 
78
212
  def self.configs(attribute)
@@ -82,14 +216,14 @@ module Generator
82
216
  defaults = {:templates => '/views',
83
217
  :layout => nil,
84
218
  :description => 'No description given.',
85
- :start_method => :perform_task }
219
+ :start_method => :index }
86
220
 
87
221
  if self.class_variable_defined? key
88
222
  self.class_variable_get(key)
89
223
  else
90
224
  defaults[attribute.to_sym]
91
225
  end
92
- end
226
+ end
93
227
 
94
228
  # the instance equivalent to get the class-variable of the **inheriting** class
95
229
  def configs(*args)
@@ -102,24 +236,5 @@ module Generator
102
236
  self.class_variable_set(key, value)
103
237
  end
104
238
 
105
-
106
- # @group context manipulation and access methods
107
-
108
- # maybe we can use this later on, while linking
109
- def in_context(new_context, &block)
110
- old_context = @_context
111
- @_context = new_context
112
- yield
113
- @_context = old_context
114
- end
115
-
116
- def context
117
- @_context
118
- end
119
-
120
- def resolve(nodename)
121
- @_context.resolve nodename
122
- end
123
-
124
239
  end
125
240
  end
@@ -103,6 +103,9 @@ module Helper
103
103
  # @param [Hash] opts
104
104
  # @option opts [Numeric] :firstline (1) The line-numeration will start with that number
105
105
  # @option opts [String] :class ("block") A optional css-class which can be added
106
+ #
107
+ # @see http://alexgorbatchev.com/SyntaxHighlighter
108
+ #
106
109
  # @return [String] the html-code-element
107
110
  def code(source, opts = {})
108
111