yard 0.5.5 → 0.5.6

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of yard might be problematic. Click here for more details.

Files changed (46) hide show
  1. data/ChangeLog +131 -0
  2. data/README.md +16 -12
  3. data/Rakefile +2 -1
  4. data/docs/GettingStarted.md +1 -107
  5. data/docs/Tags.md +250 -53
  6. data/docs/WhatsNew.md +13 -0
  7. data/lib/rubygems_plugin.rb +18 -17
  8. data/lib/yard.rb +1 -1
  9. data/lib/yard/autoload.rb +4 -0
  10. data/lib/yard/cli/yardoc.rb +5 -4
  11. data/lib/yard/cli/yri.rb +18 -3
  12. data/lib/yard/code_objects/base.rb +5 -4
  13. data/lib/yard/code_objects/class_object.rb +1 -1
  14. data/lib/yard/code_objects/constant_object.rb +1 -1
  15. data/lib/yard/code_objects/method_object.rb +3 -2
  16. data/lib/yard/code_objects/namespace_object.rb +3 -3
  17. data/lib/yard/code_objects/proxy.rb +4 -0
  18. data/lib/yard/docstring.rb +3 -2
  19. data/lib/yard/handlers/base.rb +1 -1
  20. data/lib/yard/handlers/ruby/class_condition_handler.rb +5 -1
  21. data/lib/yard/handlers/ruby/class_handler.rb +41 -1
  22. data/lib/yard/handlers/ruby/legacy/class_condition_handler.rb +5 -1
  23. data/lib/yard/handlers/ruby/legacy/class_handler.rb +44 -0
  24. data/lib/yard/handlers/ruby/struct_handler_methods.rb +128 -0
  25. data/lib/yard/parser/base.rb +55 -0
  26. data/lib/yard/parser/c_parser.rb +5 -1
  27. data/lib/yard/parser/ruby/ast_node.rb +4 -4
  28. data/lib/yard/parser/ruby/legacy/ruby_parser.rb +26 -0
  29. data/lib/yard/parser/ruby/legacy/statement_list.rb +0 -4
  30. data/lib/yard/parser/ruby/ruby_parser.rb +45 -2
  31. data/lib/yard/parser/source_parser.rb +69 -45
  32. data/lib/yard/serializers/file_system_serializer.rb +1 -1
  33. data/lib/yard/tags/default_factory.rb +1 -13
  34. data/lib/yard/tags/library.rb +3 -1
  35. data/lib/yard/templates/erb_cache.rb +5 -2
  36. data/lib/yard/templates/helpers/html_helper.rb +1 -0
  37. data/lib/yard/templates/template.rb +2 -1
  38. data/spec/cli/yardoc_spec.rb +6 -6
  39. data/spec/handlers/class_condition_handler_spec.rb +11 -0
  40. data/spec/handlers/class_handler_spec.rb +121 -0
  41. data/spec/handlers/examples/class_handler_001.rb.txt +19 -0
  42. data/spec/parser/base_spec.rb +25 -0
  43. data/spec/parser/source_parser_spec.rb +63 -0
  44. data/templates/default/layout/html/setup.rb +1 -1
  45. data/templates/default/tags/html/option.erb +1 -1
  46. metadata +21 -5
data/docs/WhatsNew.md CHANGED
@@ -170,6 +170,19 @@ You can now access the "Class List", "Method List" and "File List" with the
170
170
  'c', 'm' and 'f' keyboard shortcuts in the default HTML template, allowing
171
171
  for keyboard-only navigation around YARD documentation.
172
172
 
173
+ API for registering custom parsers (0.5.6)
174
+ ------------------------------------------
175
+
176
+ You can now register parsers for custom source languages by calling the
177
+ following method:
178
+
179
+ SourceParser.register_parser_type(:java, MyJavaParser, 'java')
180
+
181
+ The parser class MyJavaParser should be a subclass of {YARD::Parser::Base},
182
+ and the last argument is a set of extensions (string, array or regexp). You
183
+ can read more about registering parsers at the {YARD::Parser::SourceParser}
184
+ class documentation.
185
+
173
186
 
174
187
  What's New in 0.4.x?
175
188
  ====================
@@ -1,28 +1,28 @@
1
1
  require 'rubygems/specification'
2
2
  require 'rubygems/doc_manager'
3
3
 
4
- class Gem::Specification
5
- # has_rdoc should not be ignored!
6
- overwrite_accessor(:has_rdoc) { @has_rdoc }
7
- overwrite_accessor(:has_rdoc=) {|v| @has_rdoc = v }
4
+ unless defined? Gem::DocManager.load_yardoc
5
+ class Gem::Specification
6
+ # has_rdoc should not be ignored!
7
+ overwrite_accessor(:has_rdoc) { @has_rdoc }
8
+ overwrite_accessor(:has_rdoc=) {|v| @has_rdoc = v }
8
9
 
9
- def has_yardoc=(value)
10
- @has_rdoc = 'yard'
11
- end
10
+ def has_yardoc=(value)
11
+ @has_rdoc = 'yard'
12
+ end
12
13
 
13
- def has_yardoc
14
- @has_rdoc == 'yard'
15
- end
14
+ def has_yardoc
15
+ @has_rdoc == 'yard'
16
+ end
16
17
 
17
- undef has_rdoc?
18
- def has_rdoc?
19
- @has_rdoc && @has_rdoc != 'yard'
20
- end
18
+ undef has_rdoc?
19
+ def has_rdoc?
20
+ @has_rdoc && @has_rdoc != 'yard'
21
+ end
21
22
 
22
- alias has_yardoc? has_yardoc
23
- end
23
+ alias has_yardoc? has_yardoc
24
+ end
24
25
 
25
- unless defined? Gem::DocManager.load_yardoc
26
26
  class Gem::DocManager
27
27
  def self.load_yardoc
28
28
  require File.dirname(__FILE__) + '/yard'
@@ -76,6 +76,7 @@ unless defined? Gem::DocManager.load_yardoc
76
76
 
77
77
  def install_ri_yard
78
78
  install_ri_yard_orig if @spec.has_rdoc?
79
+ return if @spec.has_rdoc? == false
79
80
  return if @spec.has_yardoc?
80
81
 
81
82
  self.class.load_yardoc
data/lib/yard.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module YARD
2
- VERSION = "0.5.5"
2
+ VERSION = "0.5.6"
3
3
  ROOT = File.expand_path(File.dirname(__FILE__))
4
4
  TEMPLATE_ROOT = File.join(ROOT, '..', 'templates')
5
5
  CONFIG_DIR = File.expand_path('~/.yard')
data/lib/yard/autoload.rb CHANGED
@@ -82,6 +82,7 @@ module YARD
82
82
  autoload :MixinHandler, __p('handlers/ruby/mixin_handler')
83
83
  autoload :ModuleHandler, __p('handlers/ruby/module_handler')
84
84
  autoload :ProcessHandler, __p('handlers/ruby/process_handler')
85
+ autoload :StructHandlerMethods, __p('handlers/ruby/struct_handler_methods')
85
86
  autoload :VisibilityHandler, __p('handlers/ruby/visibility_handler')
86
87
  autoload :YieldHandler, __p('handlers/ruby/yield_handler')
87
88
  end
@@ -95,6 +96,8 @@ module YARD
95
96
  module Parser
96
97
  module Ruby # Ruby parsing components.
97
98
  module Legacy # Handles Ruby parsing in Ruby 1.8.
99
+ autoload :RipperParser, __p('parser/ruby/legacy/ruby_parser')
100
+ autoload :RubyParser, __p('parser/ruby/legacy/ruby_parser')
98
101
  autoload :RubyToken, __p('parser/ruby/legacy/ruby_lex')
99
102
  autoload :Statement, __p('parser/ruby/legacy/statement')
100
103
  autoload :StatementList, __p('parser/ruby/legacy/statement_list')
@@ -105,6 +108,7 @@ module YARD
105
108
  autoload :RubyParser, __p('parser/ruby/ruby_parser')
106
109
  end
107
110
 
111
+ autoload :Base, __p('parser/base')
108
112
  autoload :CParser, __p('parser/c_parser')
109
113
  autoload :ParserSyntaxError, __p('parser/source_parser')
110
114
  autoload :SourceParser, __p('parser/source_parser')
@@ -70,7 +70,8 @@ module YARD
70
70
  # @return [void]
71
71
  def run(*args)
72
72
  args += support_rdoc_document_file!
73
- optparse(*(yardopts + args))
73
+ optparse(*yardopts)
74
+ optparse(*args)
74
75
 
75
76
  if use_cache
76
77
  Registry.load
@@ -104,7 +105,7 @@ module YARD
104
105
  # Parses the .yardopts file for default yard options
105
106
  # @return [void]
106
107
  def yardopts
107
- IO.read(options_file).shell_split
108
+ File.read_binary(options_file).shell_split
108
109
  rescue Errno::ENOENT
109
110
  []
110
111
  end
@@ -325,7 +326,7 @@ module YARD
325
326
  end
326
327
 
327
328
  opts.on('--files FILE1,FILE2,...', 'Any extra comma separated static files to be included (eg. FAQ)') do |files|
328
- add_extra_files *files.split(",")
329
+ add_extra_files(*files.split(","))
329
330
  end
330
331
 
331
332
  opts.on('-m', '--markup MARKUP',
@@ -344,7 +345,7 @@ module YARD
344
345
  serialopts[:basepath] = dir
345
346
  end
346
347
 
347
- opts.on('--charset ENC', 'Character set to use for HTML output (default is utf-8)') do |encoding|
348
+ opts.on('--charset ENC', 'Character set to use for HTML output (default is system locale)') do |encoding|
348
349
  begin
349
350
  Encoding.default_external = encoding
350
351
  rescue ArgumentError => e
data/lib/yard/cli/yri.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'rbconfig'
2
+
1
3
  module YARD
2
4
  module CLI
3
5
  # A tool to view documentation in the console like `ri`
@@ -27,9 +29,16 @@ module YARD
27
29
  def run(*args)
28
30
  optparse(*args)
29
31
 
30
- @serializer ||= YARD::Serializers::ProcessSerializer.new('less')
32
+ if Config::CONFIG['host_os'] =~ /mingw|win32/
33
+ @serializer ||= YARD::Serializers::StdoutSerializer.new
34
+ else
35
+ @serializer ||= YARD::Serializers::ProcessSerializer.new('less')
36
+ end
31
37
 
32
- if object = find_object(@name)
38
+ if @name.nil? || @name.strip.empty?
39
+ print_usage
40
+ exit(1)
41
+ elsif object = find_object(@name)
33
42
  print_object(object)
34
43
  else
35
44
  STDERR.puts "No documentation for `#{@name}'"
@@ -39,6 +48,11 @@ module YARD
39
48
 
40
49
  protected
41
50
 
51
+ def print_usage
52
+ puts "Usage: yri [options] <Path to object>"
53
+ puts "See yri --help for more options."
54
+ end
55
+
42
56
  def cache_object(name, path)
43
57
  return if path == Registry.yardoc_file
44
58
  @cache[name] = path
@@ -112,7 +126,8 @@ module YARD
112
126
  # @param [Array<String>] args each tokenized argument
113
127
  def optparse(*args)
114
128
  opts = OptionParser.new
115
-
129
+ opts.banner = "Usage: yri [options] <Path to object>"
130
+ opts.separator "Example: yri String#gsub"
116
131
  opts.separator ""
117
132
  opts.separator "General Options:"
118
133
 
@@ -93,11 +93,11 @@ module YARD
93
93
  # The namespace the object is defined in. If the object is in the
94
94
  # top level namespace, this is {Registry#root}
95
95
  # @return [NamespaceObject] the namespace object
96
- attr_accessor :namespace
96
+ attr_reader :namespace
97
97
 
98
98
  # The source code associated with the object
99
99
  # @return [String, nil] source, if present, or nil
100
- attr_accessor :source
100
+ attr_reader :source
101
101
 
102
102
  # Language of the source code associated with the object. Defaults to
103
103
  # +:ruby+.
@@ -114,7 +114,7 @@ module YARD
114
114
 
115
115
  # The documentation string associated with the object
116
116
  # @return [Docstring] the documentation string
117
- attr_accessor :docstring
117
+ attr_reader :docstring
118
118
 
119
119
  # Marks whether or not the method is conditionally defined at runtime
120
120
  # @return [Boolean] true if the method is conditionally defined at runtime
@@ -194,6 +194,7 @@ module YARD
194
194
  @source_type = :ruby
195
195
  @tags = []
196
196
  @docstring = Docstring.new('', self)
197
+ @namespace = nil
197
198
  self.namespace = namespace
198
199
  yield(self) if block_given?
199
200
  end
@@ -262,7 +263,7 @@ module YARD
262
263
  def [](key)
263
264
  if respond_to?(key)
264
265
  send(key)
265
- else
266
+ elsif instance_variable_defined?("@#{key}")
266
267
  instance_variable_get("@#{key}")
267
268
  end
268
269
  end
@@ -2,7 +2,7 @@ module YARD::CodeObjects
2
2
  class ClassObject < NamespaceObject
3
3
  # The {ClassObject} that this class object inherits from in Ruby source.
4
4
  # @return [ClassObject] a class object that is the superclass of this one
5
- attr_accessor :superclass
5
+ attr_reader :superclass
6
6
 
7
7
  # Creates a new class object in +namespace+ with +name+
8
8
  #
@@ -4,7 +4,7 @@ module YARD::CodeObjects
4
4
  class ConstantObject < Base
5
5
  # The source code representing the constant's value
6
6
  # @return [String] the value the constant is set to
7
- attr_accessor :value
7
+ attr_reader :value
8
8
 
9
9
  def value=(value)
10
10
  @value = format_source(value)
@@ -4,12 +4,12 @@ module YARD::CodeObjects
4
4
  # The visibility of the method (+:public:+, +:protected+, +:private+)
5
5
  #
6
6
  # @return [Symbol] the method visibility
7
- attr_accessor :visibility
7
+ attr_reader :visibility
8
8
 
9
9
  # The scope of the method (+:class+ or +:instance+)
10
10
  #
11
11
  # @return [Symbol] the scope
12
- attr_accessor :scope
12
+ attr_reader :scope
13
13
 
14
14
  # Whether the object is explicitly defined in source or whether it was
15
15
  # inferred by a handler. For instance, attribute methods are generally
@@ -32,6 +32,7 @@ module YARD::CodeObjects
32
32
  # @param [String, Symbol] name the method name
33
33
  # @param [Symbol] scope +:instance+ or +:class+
34
34
  def initialize(namespace, name, scope = :instance)
35
+ @scope = nil
35
36
  self.visibility = :public
36
37
  self.scope = scope
37
38
  self.parameters = []
@@ -3,9 +3,9 @@ module YARD::CodeObjects
3
3
  # The two main Ruby objects that can act as namespaces are modules
4
4
  # ({ModuleObject}) and classes ({ClassObject}).
5
5
  class NamespaceObject < Base
6
- attr_reader :constants, :meths, :cvars, :mixins, :child
7
- attr_reader :class_attributes, :instance_attributes
8
- attr_reader :included_constants, :included_meths
6
+ attr_writer :constants, :cvars, :mixins, :child, :meths
7
+ attr_writer :class_attributes, :instance_attributes
8
+ attr_writer :included_constants, :included_meths
9
9
 
10
10
  # The list of objects defined in this namespace
11
11
  # @return [Array<Base>] a list of objects
@@ -38,10 +38,14 @@ module YARD
38
38
  @imethod = true if name.include? ISEP
39
39
  namespace = Proxy.new(namespace, $`) unless $`.empty?
40
40
  name = $1
41
+ else
42
+ @orignamespace, @origname, @imethod = nil, nil, nil
41
43
  end
42
44
 
43
45
  @name = name.to_sym
44
46
  @namespace = namespace
47
+ @obj = nil
48
+ @imethod ||= nil
45
49
 
46
50
  unless @namespace.is_a?(NamespaceObject) or @namespace.is_a?(Proxy)
47
51
  raise ArgumentError, "Invalid namespace object: #{namespace}"
@@ -23,7 +23,7 @@ module YARD
23
23
  attr_accessor :line_range
24
24
 
25
25
  # @return [String] the raw documentation (including raw tag text)
26
- attr_accessor :all
26
+ attr_reader :all
27
27
 
28
28
  # Matches a tag at the start of a comment line
29
29
  META_MATCH = /^@([a-z_]+)(?:\s+(.*))?$/i
@@ -40,6 +40,7 @@ module YARD
40
40
  # with.
41
41
  def initialize(content = '', object = nil)
42
42
  @object = object
43
+ @summary = nil
43
44
 
44
45
  self.all = content
45
46
  end
@@ -166,7 +167,7 @@ module YARD
166
167
  tag_factory = Tags::Library.instance
167
168
  tag_method = "#{tag_name}_tag"
168
169
  if tag_name && tag_factory.respond_to?(tag_method)
169
- add_tag *tag_factory.send(tag_method, tag_buf)
170
+ add_tag(*tag_factory.send(tag_method, tag_buf))
170
171
  else
171
172
  log.warn "Unknown tag @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "")
172
173
  end
@@ -201,7 +201,7 @@ module YARD
201
201
  end
202
202
 
203
203
  def namespace_only?
204
- @namespace_only ? true : false
204
+ (@namespace_only ||= false) ? true : false
205
205
  end
206
206
 
207
207
  # Generates a +process+ method, equivalent to +def process; ... end+.
@@ -43,7 +43,11 @@ class YARD::Handlers::Ruby::ClassConditionHandler < YARD::Handlers::Ruby::Base
43
43
  # *too* dangerous here since code is not actually executed.
44
44
  name = statement.condition[0].source
45
45
  obj = YARD::Registry.resolve(namespace, name, true)
46
- condition = true if obj || Object.instance_eval("defined? #{name}")
46
+ begin
47
+ condition = true if obj || Object.instance_eval("defined? #{name}")
48
+ rescue SyntaxError, NameError
49
+ condition = false
50
+ end
47
51
  when :var_ref
48
52
  var = statement.condition[0]
49
53
  if var == s(:kw, "true")
@@ -1,4 +1,5 @@
1
1
  class YARD::Handlers::Ruby::ClassHandler < YARD::Handlers::Ruby::Base
2
+ include YARD::Handlers::Ruby::StructHandlerMethods
2
3
  namespace_only
3
4
  handles :class, :sclass
4
5
 
@@ -6,12 +7,17 @@ class YARD::Handlers::Ruby::ClassHandler < YARD::Handlers::Ruby::Base
6
7
  if statement.type == :class
7
8
  classname = statement[0].source
8
9
  superclass = parse_superclass(statement[1])
10
+ if superclass == "Struct"
11
+ is_a_struct = true
12
+ superclass = struct_superclass_name(statement[1]) # refine the superclass if possible
13
+ create_struct_superclass(superclass, statement[1])
14
+ end
9
15
  undocsuper = statement[1] && superclass.nil?
10
-
11
16
  klass = register ClassObject.new(namespace, classname) do |o|
12
17
  o.superclass = superclass if superclass
13
18
  o.superclass.type = :class if o.superclass.is_a?(Proxy)
14
19
  end
20
+ parse_struct_superclass(klass, statement[1]) if is_a_struct
15
21
  parse_block(statement[2], namespace: klass)
16
22
 
17
23
  if undocsuper
@@ -48,6 +54,40 @@ class YARD::Handlers::Ruby::ClassHandler < YARD::Handlers::Ruby::Base
48
54
 
49
55
  private
50
56
 
57
+ # Extract the parameters from the Struct.new AST node, returning them as a list
58
+ # of strings
59
+ #
60
+ # @param [MethodCallNode] superclass the AST node for the Struct.new call
61
+ # @return [Array<String>] the member names to generate methods for
62
+ def extract_parameters(superclass)
63
+ members = superclass.parameters.select {|x| x && x.type == :symbol_literal}
64
+ members.map! {|x| x.source.strip[1..-1]}
65
+ members
66
+ end
67
+
68
+ def create_struct_superclass(superclass, superclass_def)
69
+ return if superclass == "Struct"
70
+ the_super = register ClassObject.new(P("Struct"), superclass[8..-1]) do |o|
71
+ o.superclass = "Struct"
72
+ end
73
+ parse_struct_superclass(the_super, superclass_def)
74
+ the_super
75
+ end
76
+
77
+ def struct_superclass_name(superclass)
78
+ first = superclass.parameters.first
79
+ if first.type == :string_literal && first[0].type == :string_content && first[0].size == 1
80
+ return "Struct::#{first[0][0][0]}"
81
+ end
82
+ "Struct"
83
+ end
84
+
85
+ def parse_struct_superclass(klass, superclass)
86
+ return unless superclass.parameters
87
+ members = extract_parameters(superclass)
88
+ create_attributes(klass, members)
89
+ end
90
+
51
91
  def parse_superclass(superclass)
52
92
  return nil unless superclass
53
93
 
@@ -43,7 +43,11 @@ class YARD::Handlers::Ruby::Legacy::ClassConditionHandler < YARD::Handlers::Ruby
43
43
  # *too* dangerous here since code is not actually executed.
44
44
  name = $1
45
45
  obj = YARD::Registry.resolve(namespace, name, true)
46
- condition = true if obj || Object.instance_eval("defined? #{name}")
46
+ begin
47
+ condition = true if obj || Object.instance_eval("defined? #{name}")
48
+ rescue SyntaxError, NameError
49
+ condition = false
50
+ end
47
51
  when "true"
48
52
  condition = true
49
53
  when "false"
@@ -1,16 +1,24 @@
1
1
  class YARD::Handlers::Ruby::Legacy::ClassHandler < YARD::Handlers::Ruby::Legacy::Base
2
+ include YARD::Handlers::Ruby::StructHandlerMethods
2
3
  handles TkCLASS
3
4
 
4
5
  process do
5
6
  if statement.tokens.to_s =~ /^class\s+(#{NAMESPACEMATCH})\s*(?:<\s*(.+)|\Z)/m
6
7
  classname = $1
8
+ superclass_def = $2
7
9
  superclass = parse_superclass($2)
10
+ if superclass == "Struct"
11
+ is_a_struct = true
12
+ superclass = struct_superclass_name(superclass_def)
13
+ create_struct_superclass(superclass, superclass_def)
14
+ end
8
15
  undocsuper = $2 && superclass.nil?
9
16
 
10
17
  klass = register ClassObject.new(namespace, classname) do |o|
11
18
  o.superclass = superclass if superclass
12
19
  o.superclass.type = :class if o.superclass.is_a?(Proxy)
13
20
  end
21
+ parse_struct_subclass(klass, superclass_def) if is_a_struct
14
22
  parse_block(:namespace => klass)
15
23
 
16
24
  if undocsuper
@@ -44,6 +52,42 @@ class YARD::Handlers::Ruby::Legacy::ClassHandler < YARD::Handlers::Ruby::Legacy:
44
52
 
45
53
  private
46
54
 
55
+ # Extracts the parameter list from the Struct.new declaration and returns it
56
+ # formatted as a list of member names. Expects the user will have used symbols
57
+ # to define the struct member names
58
+ #
59
+ # @param [String] superstring the string declaring the superclass
60
+ # @return [Array<String>] a list of member names
61
+ def extract_parameters(superstring)
62
+ paramstring = superstring.match(/\A(O?Struct)\.new\((.*?)\)/)[2]
63
+ paramstring.split(",").select {|x| x.strip[0,1] == ":"}.map {|x| x.strip[1..-1] } # the 1..-1 chops the leading :
64
+ end
65
+
66
+ def create_struct_superclass(superclass, superclass_def)
67
+ return if superclass == "Struct"
68
+ the_super = register ClassObject.new(P("Struct"), superclass[8..-1]) do |o|
69
+ o.superclass = "Struct"
70
+ end
71
+ parse_struct_subclass(the_super, superclass_def)
72
+ the_super
73
+ end
74
+
75
+ def struct_superclass_name(superclass)
76
+ paramstring = superclass.match(/\A(Struct)\.new\((.*?)\)/)[2].split(",")
77
+ first = paramstring.first.strip
78
+ if first[0,1] =~ /['"]/ && first[-1,1] =~ /['"]/ && first !~ /\#\{/
79
+ return "Struct::#{first[1..-2]}"
80
+ end
81
+ "Struct"
82
+ end
83
+
84
+ def parse_struct_subclass(klass, superclass_def)
85
+ # Bounce if there's no parens
86
+ return unless superclass_def =~ /O?Struct\.new\((.*?)\)/
87
+ members = extract_parameters(superclass_def)
88
+ create_attributes(klass, members)
89
+ end
90
+
47
91
  def parse_superclass(superclass)
48
92
  case superclass
49
93
  when /\A(#{NAMESPACEMATCH})(?:\s|\Z)/,