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.
- data/CONCEPT.md +80 -0
- data/DOCUMENTATION.md +41 -0
- data/LICENSE.md +19 -0
- data/README.md +19 -0
- data/RENDERING.md +8 -0
- data/bin/docjs +190 -0
- data/docjs.gemspec +32 -0
- data/lib/boot.rb +34 -0
- data/lib/code_object/base.rb +48 -0
- data/lib/code_object/converter.rb +48 -0
- data/lib/code_object/exceptions.rb +5 -0
- data/lib/code_object/function.rb +84 -0
- data/lib/code_object/object.rb +18 -0
- data/lib/code_object/type.rb +43 -0
- data/lib/configs.rb +53 -0
- data/lib/document/document.rb +25 -0
- data/lib/dom/dom.rb +188 -0
- data/lib/dom/exceptions.rb +12 -0
- data/lib/dom/no_doc.rb +26 -0
- data/lib/dom/node.rb +415 -0
- data/lib/helper/helper.rb +120 -0
- data/lib/helper/linker.rb +130 -0
- data/lib/logger.rb +49 -0
- data/lib/parser/comment.rb +69 -0
- data/lib/parser/comment_parser.rb +90 -0
- data/lib/parser/exceptions.rb +6 -0
- data/lib/parser/meta_container.rb +20 -0
- data/lib/parser/parser.rb +269 -0
- data/lib/processor.rb +123 -0
- data/lib/renderer.rb +108 -0
- data/lib/tasks/render_task.rb +112 -0
- data/lib/thor.rb +27 -0
- data/lib/token/container.rb +84 -0
- data/lib/token/exceptions.rb +6 -0
- data/lib/token/handler.rb +242 -0
- data/lib/token/token.rb +46 -0
- data/templates/application.rb +14 -0
- data/templates/helpers/template.rb +66 -0
- data/templates/resources/css/.sass-cache/98c121fba905284c2c8ca6220fe3c590e5c9ec19/application.scssc +0 -0
- data/templates/resources/css/application.css +836 -0
- data/templates/resources/img/arrow_down.png +0 -0
- data/templates/resources/img/arrow_right.png +0 -0
- data/templates/resources/img/arrow_up.png +0 -0
- data/templates/resources/img/bullet_toggle_minus.png +0 -0
- data/templates/resources/img/bullet_toggle_plus.png +0 -0
- data/templates/resources/img/constructor.png +0 -0
- data/templates/resources/img/function.png +0 -0
- data/templates/resources/img/object.png +0 -0
- data/templates/resources/img/page.png +0 -0
- data/templates/resources/img/prototype.png +0 -0
- data/templates/resources/img/tag.png +0 -0
- data/templates/resources/js/application.js +318 -0
- data/templates/resources/js/jcore.js +129 -0
- data/templates/resources/js/jquery.cookie.js +92 -0
- data/templates/resources/js/jquery.js +16 -0
- data/templates/resources/js/jquery.tooltip.js +77 -0
- data/templates/resources/js/jquery.treeview.js +238 -0
- data/templates/resources/scss/_footer.scss +10 -0
- data/templates/resources/scss/_header.scss +184 -0
- data/templates/resources/scss/_helpers.scss +91 -0
- data/templates/resources/scss/_print.scss +20 -0
- data/templates/resources/scss/_resets.scss +132 -0
- data/templates/resources/scss/_tooltip.scss +26 -0
- data/templates/resources/scss/application.scss +442 -0
- data/templates/tasks/api_index_task.rb +26 -0
- data/templates/tasks/docs_task.rb +33 -0
- data/templates/tasks/json_data_task.rb +55 -0
- data/templates/tasks/typed_task.rb +54 -0
- data/templates/tokens/tokens.rb +22 -0
- data/templates/types/prototype.rb +20 -0
- data/templates/views/api_index.html.erb +21 -0
- data/templates/views/doc_page.html.erb +11 -0
- data/templates/views/function/_detail.html.erb +8 -0
- data/templates/views/function/index.html.erb +53 -0
- data/templates/views/index.html.erb +0 -0
- data/templates/views/layout/application.html.erb +73 -0
- data/templates/views/layout/json.html.erb +3 -0
- data/templates/views/object/index.html.erb +63 -0
- data/templates/views/tokens/_default.html.erb +11 -0
- data/templates/views/tokens/_default_token.html.erb +19 -0
- data/templates/views/tokens/_example.html.erb +2 -0
- data/templates/views/tokens/_examples.html.erb +1 -0
- data/test/code_object/converter.rb +78 -0
- data/test/code_object/prototype.rb +70 -0
- data/test/configs.rb +65 -0
- data/test/docs/README.CONCEPT.md +83 -0
- data/test/docs/README.md +14 -0
- data/test/dom/dom.absolute_nodes.rb +40 -0
- data/test/dom/dom.rb +72 -0
- data/test/dom/node.rb +53 -0
- data/test/integration/converter.rb +72 -0
- data/test/integration/parser_factory.rb +28 -0
- data/test/interactive.rb +7 -0
- data/test/js-files/absolute.js +11 -0
- data/test/js-files/comments_in_strings.js +31 -0
- data/test/js-files/core-doc-relative.js +77 -0
- data/test/js-files/core-doc.js +145 -0
- data/test/js-files/nested.js +34 -0
- data/test/js-files/nested_with_strings.js +35 -0
- data/test/js-files/prototype.js +33 -0
- data/test/js-files/simple.js +17 -0
- data/test/js-files/tokens.js +32 -0
- data/test/parser/comments_in_strings.rb +51 -0
- data/test/parser/intelligent_skip_until.rb +110 -0
- data/test/parser/parser.rb +273 -0
- data/test/rspec_helper.rb +23 -0
- data/test/token/handler.rb +136 -0
- data/test/token/tokens.rb +52 -0
- metadata +184 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative '../renderer'
|
2
|
+
require_relative '../dom/dom'
|
3
|
+
require_relative '../helper/helper'
|
4
|
+
|
5
|
+
module Tasks
|
6
|
+
|
7
|
+
class RenderTask < Renderer
|
8
|
+
|
9
|
+
include Helper::Helper
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super(Configs.templates + configs(:templates), configs(:layout))
|
13
|
+
|
14
|
+
# Set Global Context to Dom's root node
|
15
|
+
@_context = Dom.root
|
16
|
+
end
|
17
|
+
|
18
|
+
def perform
|
19
|
+
|
20
|
+
unless self.respond_to? configs(:start_method)
|
21
|
+
raise Exception, "#{self.class} needs to implement specified start-method '#{configs(:start_method)}'"
|
22
|
+
end
|
23
|
+
|
24
|
+
self.send configs(:start_method)
|
25
|
+
end
|
26
|
+
|
27
|
+
def context
|
28
|
+
@_context
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.description
|
32
|
+
configs(:description)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.use(helper_module)
|
36
|
+
self.include helper_module
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
# @group Task-Specification methods
|
42
|
+
|
43
|
+
def self.describe(desc)
|
44
|
+
self.set_config(:description, desc.to_s)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.layout(layout_view)
|
48
|
+
unless layout_view.nil?
|
49
|
+
self.set_config(:layout, 'layout/' + layout_view)
|
50
|
+
else
|
51
|
+
self.set_config(:layout, nil)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.templates(path_to_templates)
|
56
|
+
self.set_config(:templates, path_to_templates)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.start_method(method)
|
60
|
+
self.set_config(:start_method, method.to_sym)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# @group helper methods to make usage of class-variables work in **inheriting** classes
|
65
|
+
|
66
|
+
def self.configs(attribute)
|
67
|
+
|
68
|
+
key = "@@_configs_#{attribute.to_s}".to_sym
|
69
|
+
|
70
|
+
defaults = {:templates => '/views',
|
71
|
+
:layout => nil,
|
72
|
+
:description => 'No description given.',
|
73
|
+
:start_method => :perform_task }
|
74
|
+
|
75
|
+
if self.class_variable_defined? key
|
76
|
+
self.class_variable_get(key)
|
77
|
+
else
|
78
|
+
defaults[attribute.to_sym]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# the instance equivalent to get the class-variable of the **inheriting** class
|
83
|
+
def configs(*args)
|
84
|
+
self.class.configs(*args)
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.set_config(attribute, value)
|
88
|
+
key = "@@_configs_#{attribute.to_s}".to_sym
|
89
|
+
|
90
|
+
self.class_variable_set(key, value)
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# @group context manipulation and access methods
|
95
|
+
|
96
|
+
# maybe we can use this later on, while linking
|
97
|
+
def in_context(new_context, &block)
|
98
|
+
old_context = @_context
|
99
|
+
@_context = new_context
|
100
|
+
yield
|
101
|
+
@_context = old_context
|
102
|
+
end
|
103
|
+
|
104
|
+
def context
|
105
|
+
@_context
|
106
|
+
end
|
107
|
+
|
108
|
+
def resolve(nodename)
|
109
|
+
@_context.resolve nodename
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
data/lib/thor.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
class Thor
|
2
|
+
|
3
|
+
protected
|
4
|
+
|
5
|
+
# @param [Hash<Hash>] options
|
6
|
+
def self.set_options(options)
|
7
|
+
options.each {|name, hash| method_option(name, hash) }
|
8
|
+
end
|
9
|
+
|
10
|
+
# Types
|
11
|
+
# :boolean - is parsed as --option or --option=true
|
12
|
+
# :string - is parsed as --option=VALUE
|
13
|
+
# :numeric - is parsed as --option=N
|
14
|
+
# :array - is parsed as --option=one two three
|
15
|
+
# :hash - is parsed as --option=name:string age:integer
|
16
|
+
#
|
17
|
+
# @note options declared in a build.yml will override command-line ones
|
18
|
+
# @return [Hash] options
|
19
|
+
def merge_options(options, filename)
|
20
|
+
require 'yaml' # only load yaml if we are reading from file
|
21
|
+
configs = YAML.load_file(filename)
|
22
|
+
merged = {}
|
23
|
+
options.each { |name, value| merged[name.to_sym] = configs[name] || value }
|
24
|
+
merged
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# ../data.img#1811394:1
|
2
|
+
require_relative 'exceptions'
|
3
|
+
require_relative 'handler'
|
4
|
+
|
5
|
+
module Token
|
6
|
+
|
7
|
+
module Container
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
@tokens = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# provides access to tokens, through token identifier
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# obj.token :public
|
18
|
+
# #=> #<struct Token::Handler::Token content=nil>
|
19
|
+
#
|
20
|
+
# @param [String, Symbol] tokenname the tokenidentifier like :public
|
21
|
+
# @return [Token] the token with it's content
|
22
|
+
def token(tokenname)
|
23
|
+
@tokens[tokenname.to_sym]
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Hash<Symbol, Array<Token::Token>>] all tokens of this container
|
27
|
+
def tokens
|
28
|
+
@tokens
|
29
|
+
end
|
30
|
+
|
31
|
+
# @overload add_token(tokenid, token)
|
32
|
+
# @param [Symbol] tokenid
|
33
|
+
# @param [Token::Token] token
|
34
|
+
#
|
35
|
+
# @overload add_token(token)
|
36
|
+
# @param [Token::Token] token
|
37
|
+
def add_token(tokenid_or_token, token=nil)
|
38
|
+
|
39
|
+
unless token.nil?
|
40
|
+
tokenid = tokenid_or_token
|
41
|
+
else
|
42
|
+
tokenid = tokenid_or_token.token
|
43
|
+
token = tokenid_or_token
|
44
|
+
end
|
45
|
+
|
46
|
+
@tokens[tokenid] ||= []
|
47
|
+
@tokens[tokenid] << token
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param [Parser::Tokenline] tokenline consisting of :token and :content
|
51
|
+
# then calls matching tokenhandler (if exists) with data in `this`-context
|
52
|
+
# @todo only raise error, if config is set to whiny
|
53
|
+
def process_token(tokenline)
|
54
|
+
|
55
|
+
# try to find matching tokenklass for token i.e. Token::Token::ParamToken for :param
|
56
|
+
begin
|
57
|
+
tokenklass = Token.const_get "#{tokenline.token.capitalize.to_s}Token"
|
58
|
+
instance_exec(tokenklass, tokenline.content, &(tokenklass.handler))
|
59
|
+
rescue Exception => error
|
60
|
+
raise NoTokenHandler.new("No Tokenhandler for: @#{tokenline.token}
|
61
|
+
This is no big deal. You can add your custom tokenhandler for @#{tokenline.token} by adding the following line to your included ruby-file:
|
62
|
+
|
63
|
+
Token::Handler.register :#{tokenline.token} # optionally add a tokenhandler or target-area (See documentation for more infos)
|
64
|
+
|
65
|
+
After this using '@#{tokenline.token}' in your documentation is no problem...\n\n" + error.message)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Plural version of {#process_token}
|
70
|
+
#
|
71
|
+
# @param [Array<Parser::Tokenline>] tokenlines
|
72
|
+
def process_tokens(tokenlines)
|
73
|
+
tokenlines.each {|tokenline| process_token(tokenline) }
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def has_to_be_a(type)
|
79
|
+
raise WrongType.new("Not a valid Type: '#{type}'") unless self.is_a? type
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# ../data.img#1799432:1 && #1858562:1
|
2
|
+
require_relative 'token'
|
3
|
+
|
4
|
+
# This module contains all required mixins and modules to register customized
|
5
|
+
# tokens, that will be further processed and added to the {CodeObject::Base}.
|
6
|
+
#
|
7
|
+
# The {CodeObject::Converter converter} starts the {Parser::Tokenline tokenline}-processing, by calling
|
8
|
+
# the mixed-in function {Token::Container#process_token}.
|
9
|
+
#
|
10
|
+
# 
|
11
|
+
#
|
12
|
+
# The illustration above shows the **two modules** included in {Token}:
|
13
|
+
#
|
14
|
+
# 1. {Token::Handler}, which can be used to register new token-handlers.
|
15
|
+
# 2. {Token::Container}, which is included in {CodeObject::Base} to add
|
16
|
+
# individual token-{Token::Container#add_token container} and
|
17
|
+
# {Token::Container#process_token -processing} functionality to all CodeObjects.
|
18
|
+
#
|
19
|
+
module Token
|
20
|
+
|
21
|
+
# @note This module is **not** built to be used as a mixin! It should be seen as
|
22
|
+
# a **global singleton** instead.
|
23
|
+
#
|
24
|
+
# The {Token::Handler} is meant to be the global store for all Token-handlers.
|
25
|
+
# Token-handlers are needed to process incoming {Parser::Tokenline tokenlines}
|
26
|
+
# of each comment. The following sample, shows a comment including a token line:
|
27
|
+
#
|
28
|
+
# /**
|
29
|
+
# * @token this is a default tokenline
|
30
|
+
# */
|
31
|
+
#
|
32
|
+
# This Comment will be transformed by the {Parser::CommentParser} into a
|
33
|
+
# {Parser::Tokenline tokenline} like the following:
|
34
|
+
#
|
35
|
+
# puts my_tokenline
|
36
|
+
# #=> <struct Parser::Tokenline token="token", content="this is a default tokenline">
|
37
|
+
#
|
38
|
+
# After creating the right type of {CodeObject::Base CodeObjects} (either a
|
39
|
+
# {CodeObject::Object Object} or {CodeObject::Object Function}) the
|
40
|
+
# {CodeObject::Converter converter} will trigger the conversion to a 'real'
|
41
|
+
# {Token::Handler::Token token} by calling {Token::Container#process_token #process_token}
|
42
|
+
# on the CodeObject.
|
43
|
+
#
|
44
|
+
# code_object.process_token(my_tokenline)
|
45
|
+
# code_object.token(:token)
|
46
|
+
# #=> [#<struct Token::Handler::Token content="this is a default tokenline">]
|
47
|
+
#
|
48
|
+
# Tokens are always stored in an array to make multiple usage in one comment
|
49
|
+
# possible.
|
50
|
+
#
|
51
|
+
# @see .register
|
52
|
+
module Handler
|
53
|
+
|
54
|
+
ALL = /./m
|
55
|
+
NO_BR = /((?!\n)\s)/
|
56
|
+
IDENTIFIER = /(?:[^\s])*/
|
57
|
+
TYPELIST = /\[(?<types>#{IDENTIFIER}(?:,#{NO_BR}*#{IDENTIFIER})*)\]/
|
58
|
+
|
59
|
+
# Token with type and content
|
60
|
+
TOKEN_W_TYPE = /#{NO_BR}*#{TYPELIST}#{NO_BR}*(?<content>#{ALL}*)/
|
61
|
+
|
62
|
+
# Token with type, name and content
|
63
|
+
TOKEN_W_TYPE_NAME = /^#{NO_BR}*
|
64
|
+
#{TYPELIST}#{NO_BR}*
|
65
|
+
(?<name>#{IDENTIFIER})
|
66
|
+
#{NO_BR}*
|
67
|
+
(?<content>#{ALL}*)
|
68
|
+
/x
|
69
|
+
|
70
|
+
@@defaults = {
|
71
|
+
:text_only => ->(tokenklass, content) {
|
72
|
+
self.add_token tokenklass.new(:content => content)
|
73
|
+
},
|
74
|
+
|
75
|
+
:typed => ->(tokenklass, content) {
|
76
|
+
typestring, content = TOKEN_W_TYPE.match(content).captures
|
77
|
+
types = typestring.split /,\s*/
|
78
|
+
|
79
|
+
self.add_token tokenklass.new(:types => types, :content => content)
|
80
|
+
},
|
81
|
+
|
82
|
+
:typed_with_name => ->(tokenklass, content) {
|
83
|
+
typestring, name, content = TOKEN_W_TYPE_NAME.match(content).captures
|
84
|
+
types = typestring.split /,\s*/
|
85
|
+
|
86
|
+
self.add_token tokenklass.new(:name => name, :types => types, :content => content)
|
87
|
+
},
|
88
|
+
|
89
|
+
:named_multiline => ->(tokenklass, content) {
|
90
|
+
rows = content.split(/\n/)
|
91
|
+
|
92
|
+
# use first row as name
|
93
|
+
name = rows.shift.strip
|
94
|
+
content = rows.join("\n")
|
95
|
+
|
96
|
+
self.add_token tokenklass.new(:name => name, :content => content)
|
97
|
+
},
|
98
|
+
|
99
|
+
:noop => ->(tokenklass, content) {}
|
100
|
+
}
|
101
|
+
@@handlers = {}
|
102
|
+
|
103
|
+
# Attribute-Reader for all registered `@@handlers`
|
104
|
+
#
|
105
|
+
# @return [Hash<Symbol, Block>]
|
106
|
+
def self.handlers
|
107
|
+
@@handlers
|
108
|
+
end
|
109
|
+
|
110
|
+
# Registering a new Tokenhandler
|
111
|
+
# ==============================
|
112
|
+
# It is possible to register your own Tokenhandlers and therefore extend the
|
113
|
+
# capabilities of this documentation-program.
|
114
|
+
#
|
115
|
+
# There are different types of handlers which can be used:
|
116
|
+
#
|
117
|
+
# 1. Default-handler
|
118
|
+
# 2. A handler for Typed-Token
|
119
|
+
# 3. A handler for Named-Typed-Tokens
|
120
|
+
# 4. Your custom handler (see second overload)
|
121
|
+
#
|
122
|
+
#
|
123
|
+
# @overload self.register(tokenname, type=nil)
|
124
|
+
#
|
125
|
+
# The first three of the handlers above can be registered with this
|
126
|
+
# overload.
|
127
|
+
#
|
128
|
+
# The Default Handler
|
129
|
+
# -------------------
|
130
|
+
# The Default Header can be used for tokens like the one in the example above.
|
131
|
+
# Trying to add a token like `@token` without adding a handler, you may get
|
132
|
+
# an `exception` like:
|
133
|
+
#
|
134
|
+
# #=> Token::NoTokenHandler: No Tokenhandler for: token
|
135
|
+
# # from lib/token/container.rb:41:in process_token
|
136
|
+
#
|
137
|
+
# So we better register a handler for that token:
|
138
|
+
#
|
139
|
+
# Token::Handler.register :token
|
140
|
+
#
|
141
|
+
# As you can see **the second argument can be ommitted** to use a **default
|
142
|
+
# handler**. This default handler cannot parse typelists or tokennames, it
|
143
|
+
# only saves the content of the token to the struct {Token::Handler::Token Token}.
|
144
|
+
#
|
145
|
+
# This Default Handler is enough for tokens like `@todo` or `@note`. But for
|
146
|
+
# more complex Tokens we need some other handlers.
|
147
|
+
#
|
148
|
+
# Handler for Typed-Tokens
|
149
|
+
# ------------------------
|
150
|
+
# Typed tokens look like `@return [Foo, Bar] This is the description` - Additional
|
151
|
+
# to their **default content** they specify the possible Types.
|
152
|
+
#
|
153
|
+
# To register a typed-token, you only need to add a second argument:
|
154
|
+
#
|
155
|
+
# Token::Handler.register :return, :typed
|
156
|
+
#
|
157
|
+
# The {Token::Handler::TypedToken typed-token struct}, pretty much looks like
|
158
|
+
# the default one.
|
159
|
+
#
|
160
|
+
# #=> #<struct Token::Handler::TypedToken types=["Foo", "Bar"], content="This is the description\n">
|
161
|
+
#
|
162
|
+
# Handler for Typed-Named-Tokens
|
163
|
+
# ------------------------------
|
164
|
+
# They are much like **Typed-Token-Handlers**. They are needed for Tokenlines
|
165
|
+
# like `@param [String] my_param This is a param`. They are registered with
|
166
|
+
# `:typed_with_name` as the second argument:
|
167
|
+
#
|
168
|
+
# Token::Handler.register :param, :typed_with_name
|
169
|
+
#
|
170
|
+
# @param [String, Symbol] tokenname
|
171
|
+
# @param [:typed, :typed_with_name, nil] type
|
172
|
+
#
|
173
|
+
#
|
174
|
+
# @overload self.register(tokenname, &handler)
|
175
|
+
#
|
176
|
+
# Writing your own custom Token-Handler
|
177
|
+
# -------------------------------------
|
178
|
+
# By adding a block in the Tokenregistration you easily can build your own
|
179
|
+
# Tokenhandler:
|
180
|
+
#
|
181
|
+
# Token::Handler.register(:my_own) do |token_klass, stringcontent|
|
182
|
+
# # Do something with token_id and stringcontent
|
183
|
+
# # but don't forget to add the token like:
|
184
|
+
# self.add_token(token_klass.new(:content => stringcontent)
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# Because the token processing is done in the **context of the CodeObject** you
|
188
|
+
# can easily extend or manipulate the Objects.
|
189
|
+
#
|
190
|
+
# If you want to assure, that the object you are working on has a specific type
|
191
|
+
# (for example a Function) add the following line to your handler:
|
192
|
+
#
|
193
|
+
# has_to_be_a CodeObject::Function
|
194
|
+
#
|
195
|
+
# @param [String, Symbol] tokenname
|
196
|
+
# @yield [tokenklass, stringcontent] Your custom tokenhandler
|
197
|
+
#
|
198
|
+
def self.register(tokenname, options = {}, &handler)
|
199
|
+
|
200
|
+
tokenname = tokenname.to_sym
|
201
|
+
|
202
|
+
# search matching handler
|
203
|
+
if block_given?
|
204
|
+
# handler is already defined
|
205
|
+
elsif options[:handler] and @@defaults.include?(options[:handler])
|
206
|
+
handler = @@defaults[options[:handler]]
|
207
|
+
elsif options[:handler]
|
208
|
+
raise Exception, "#{type} has no registered Tokenhandler"
|
209
|
+
else
|
210
|
+
handler = @@defaults[:text_only]
|
211
|
+
end
|
212
|
+
|
213
|
+
# Dynamically create Class named TokennameToken
|
214
|
+
klass = Token.const_set "#{tokenname.to_s.capitalize}Token", Class.new(Token)
|
215
|
+
|
216
|
+
klass.process_options options.merge({
|
217
|
+
|
218
|
+
:token => tokenname,
|
219
|
+
:handler => handler
|
220
|
+
|
221
|
+
});
|
222
|
+
|
223
|
+
@@handlers[tokenname] = klass
|
224
|
+
end
|
225
|
+
|
226
|
+
# Remove a registered handler from the list
|
227
|
+
#
|
228
|
+
# @example
|
229
|
+
# Token::Handler.register :foo
|
230
|
+
# Token::Handler.unregister :foo
|
231
|
+
#
|
232
|
+
# @param [String, Symbol] tokenname
|
233
|
+
def self.unregister(tokenname)
|
234
|
+
@@handlers.delete(tokenname.to_sym)
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.add_default_handler(name, &block)
|
238
|
+
@@defaults[name] = block;
|
239
|
+
end
|
240
|
+
|
241
|
+
end
|
242
|
+
end
|