mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Merge rdoc-6.0.0.beta3.
* It version introduced did you mean? feature for ri command: https://github.com/ruby/rdoc/pull/533 * Removed obbsoleted ruby_token.rbb. [Bug #13990][ruby-core:83180] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60146 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
4e1fe5357e
commit
db6c51ec4f
21 changed files with 208 additions and 564 deletions
|
@ -65,7 +65,7 @@ module RDoc
|
|||
##
|
||||
# RDoc version you are using
|
||||
|
||||
VERSION = '6.0.0.beta2'
|
||||
VERSION = '6.0.0.beta3'
|
||||
|
||||
##
|
||||
# Method visibilities
|
||||
|
|
|
@ -276,8 +276,7 @@ class RDoc::AnyMethod < RDoc::MethodAttr
|
|||
# &block
|
||||
params.sub!(/,?\s*&\w+/, '')
|
||||
|
||||
block = @block_params.gsub(/\s*\#.*/, '')
|
||||
block = block.tr("\n", " ").squeeze(" ")
|
||||
block = @block_params.tr("\n", " ").squeeze(" ")
|
||||
if block[0] == ?(
|
||||
block.sub!(/^\(/, '').sub!(/\)/, '')
|
||||
end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<footer id="validator-badges" role="contentinfo">
|
||||
<p><a href="http://validator.w3.org/check/referer">Validate</a>
|
||||
<p>Generated by <a href="https://rdoc.github.io/rdoc">RDoc</a> <%= RDoc::VERSION %>.
|
||||
<p><a href="https://validator.w3.org/check/referer">Validate</a>
|
||||
<p>Generated by <a href="https://ruby.github.io/rdoc/">RDoc</a> <%= RDoc::VERSION %>.
|
||||
<p>Based on <a href="http://deveiate.org/projects/Darkfish-RDoc/">Darkfish</a> by <a href="http://deveiate.org">Michael Granger</a>.
|
||||
</footer>
|
||||
|
|
|
@ -114,7 +114,7 @@
|
|||
<% else %>
|
||||
<div class="method-heading">
|
||||
<span class="method-name"><%= h method.name %></span><span
|
||||
class="method-args"><%= method.param_seq %></span>
|
||||
class="method-args"><%= h method.param_seq %></span>
|
||||
<% if method.token_stream then %>
|
||||
<span class="method-click-advice">click to toggle source</span>
|
||||
<% end %>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: false
|
||||
##
|
||||
# This module provides i18n realated features.
|
||||
# This module provides i18n related features.
|
||||
|
||||
module RDoc::I18n
|
||||
|
||||
|
|
|
@ -15280,7 +15280,7 @@ class RDoc::Markdown
|
|||
self.pos = _save
|
||||
break
|
||||
end
|
||||
@result = begin;
|
||||
@result = begin;
|
||||
ref = [:inline, @note_order.length]
|
||||
@footnotes[ref] = paragraph a
|
||||
|
||||
|
@ -15424,7 +15424,7 @@ class RDoc::Markdown
|
|||
return _tmp
|
||||
end
|
||||
|
||||
# CodeFence = &{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format verbatim }
|
||||
# CodeFence = &{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!"`" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim }
|
||||
def _CodeFence
|
||||
|
||||
_save = self.pos
|
||||
|
@ -15666,7 +15666,7 @@ class RDoc::Markdown
|
|||
break
|
||||
end
|
||||
@result = begin; verbatim = RDoc::Markup::Verbatim.new text
|
||||
verbatim.format = format.intern if format
|
||||
verbatim.format = format.intern if format.instance_of?(String)
|
||||
verbatim
|
||||
; end
|
||||
_tmp = true
|
||||
|
@ -16115,7 +16115,7 @@ class RDoc::Markdown
|
|||
Rules[:_InlineNote] = rule_info("InlineNote", "&{ notes? } \"^[\" @StartList:a (!\"]\" Inline:l { a << l })+ \"]\" { ref = [:inline, @note_order.length] @footnotes[ref] = paragraph a note_for ref }")
|
||||
Rules[:_Notes] = rule_info("Notes", "(Note | SkipBlock)*")
|
||||
Rules[:_RawNoteBlock] = rule_info("RawNoteBlock", "@StartList:a (!@BlankLine OptionallyIndentedLine:l { a << l })+ < @BlankLine* > { a << text } { a }")
|
||||
Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format verbatim }")
|
||||
Rules[:_CodeFence] = rule_info("CodeFence", "&{ github? } Ticks3 (@Sp StrChunk:format)? Spnl < ((!\"`\" Nonspacechar)+ | !Ticks3 /`+/ | Spacechar | @Newline)+ > Ticks3 @Sp @Newline* { verbatim = RDoc::Markup::Verbatim.new text verbatim.format = format.intern if format.instance_of?(String) verbatim }")
|
||||
Rules[:_DefinitionList] = rule_info("DefinitionList", "&{ definition_lists? } DefinitionListItem+:list { RDoc::Markup::List.new :NOTE, *list.flatten }")
|
||||
Rules[:_DefinitionListItem] = rule_info("DefinitionListItem", "DefinitionListLabel+:label DefinitionListDefinition+:defns { list_items = [] list_items << RDoc::Markup::ListItem.new(label, defns.shift) list_items.concat defns.map { |defn| RDoc::Markup::ListItem.new nil, defn } unless list_items.empty? list_items }")
|
||||
Rules[:_DefinitionListLabel] = rule_info("DefinitionListLabel", "StrChunk:label @Sp @Newline { label }")
|
||||
|
|
|
@ -377,7 +377,7 @@
|
|||
#
|
||||
# Example links:
|
||||
#
|
||||
# https://github.com/rdoc/rdoc
|
||||
# https://github.com/ruby/rdoc
|
||||
# mailto:user@example.com
|
||||
# {RDoc Documentation}[http://rdoc.rubyforge.org]
|
||||
# {RDoc Markup}[rdoc-ref:RDoc::Markup]
|
||||
|
@ -764,7 +764,7 @@ Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} #{RUBY_RELEASE_DATE}
|
|||
|
||||
Please file a bug report with the above information at:
|
||||
|
||||
https://github.com/rdoc/rdoc/issues
|
||||
https://github.com/ruby/rdoc/issues
|
||||
|
||||
EOF
|
||||
raise
|
||||
|
|
|
@ -206,7 +206,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
|
|||
result = RDoc::TokenStream.to_html tokens
|
||||
result = result + "\n" unless "\n" == result[-1]
|
||||
result
|
||||
rescue RDoc::RubyLex::Error
|
||||
rescue
|
||||
CGI.escapeHTML text
|
||||
end
|
||||
else
|
||||
|
|
|
@ -87,31 +87,6 @@ class RDoc::Parser
|
|||
not s.valid_encoding?
|
||||
end
|
||||
|
||||
##
|
||||
# Processes common directives for CodeObjects for the C and Ruby parsers.
|
||||
#
|
||||
# Applies +directive+'s +value+ to +code_object+, if appropriate
|
||||
|
||||
def self.process_directive code_object, directive, value
|
||||
warn "RDoc::Parser::process_directive is deprecated and wil be removed in RDoc 4. Use RDoc::Markup::PreProcess#handle_directive instead" if $-w
|
||||
|
||||
case directive
|
||||
when 'nodoc' then
|
||||
code_object.document_self = nil # notify nodoc
|
||||
code_object.document_children = value.downcase != 'all'
|
||||
when 'doc' then
|
||||
code_object.document_self = true
|
||||
code_object.force_documentation = true
|
||||
when 'yield', 'yields' then
|
||||
# remove parameter &block
|
||||
code_object.params.sub!(/,?\s*&\w+/, '') if code_object.params
|
||||
|
||||
code_object.block_params = value
|
||||
when 'arg', 'args' then
|
||||
code_object.params = value
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Checks if +file+ is a zip file in disguise. Signatures from
|
||||
# http://www.garykessler.net/library/file_sigs.html
|
||||
|
|
|
@ -376,7 +376,11 @@ class RDoc::Parser::Ruby < RDoc::Parser
|
|||
unless :on_const == name_t[:kind] || :on_ident == name_t[:kind]
|
||||
raise RDoc::Error, "Invalid class or module definition: #{given_name}"
|
||||
end
|
||||
given_name << '::' << name_t[:text]
|
||||
if prev_container == container and !ignore_constants
|
||||
given_name = name_t[:text]
|
||||
else
|
||||
given_name << '::' << name_t[:text]
|
||||
end
|
||||
end
|
||||
|
||||
skip_tkspace false
|
||||
|
@ -872,21 +876,17 @@ class RDoc::Parser::Ruby < RDoc::Parser
|
|||
|
||||
return unless name =~ /^\w+$/
|
||||
|
||||
eq_tk = get_tk
|
||||
|
||||
if :on_op == eq_tk[:kind] && '::' == eq_tk[:text] then
|
||||
unget_tk eq_tk
|
||||
if :on_op == peek_tk[:kind] && '::' == peek_tk[:text] then
|
||||
unget_tk tk
|
||||
|
||||
container, name_t, = get_class_or_module container, ignore_constants
|
||||
|
||||
name = name_t[:text]
|
||||
|
||||
eq_tk = get_tk
|
||||
end
|
||||
|
||||
is_array_or_hash = false
|
||||
if eq_tk && :on_lbracket == eq_tk[:kind]
|
||||
if peek_tk && :on_lbracket == peek_tk[:kind]
|
||||
get_tk
|
||||
nest = 1
|
||||
while bracket_tk = get_tk
|
||||
case bracket_tk[:kind]
|
||||
|
@ -898,14 +898,13 @@ class RDoc::Parser::Ruby < RDoc::Parser
|
|||
end
|
||||
end
|
||||
skip_tkspace false
|
||||
eq_tk = get_tk
|
||||
is_array_or_hash = true
|
||||
end
|
||||
|
||||
unless eq_tk && :on_op == eq_tk[:kind] && '=' == eq_tk[:text] then
|
||||
unget_tk eq_tk
|
||||
unless peek_tk && :on_op == peek_tk[:kind] && '=' == peek_tk[:text] then
|
||||
return false
|
||||
end
|
||||
get_tk
|
||||
|
||||
value = ''
|
||||
con = RDoc::Constant.new name, value, comment
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -47,13 +47,24 @@ class RDoc::RI::Driver
|
|||
|
||||
class NotFoundError < Error
|
||||
|
||||
def initialize(klass, suggestions = nil) # :nodoc:
|
||||
@klass = klass
|
||||
@suggestions = suggestions
|
||||
end
|
||||
|
||||
##
|
||||
# Name that wasn't found
|
||||
|
||||
alias name message
|
||||
def name
|
||||
@klass
|
||||
end
|
||||
|
||||
def message # :nodoc:
|
||||
"Nothing known about #{super}"
|
||||
str = "Nothing known about #{@klass}"
|
||||
if @suggestions and !@suggestions.empty?
|
||||
str += "\nDid you mean? #{@suggestions.join("\n ")}"
|
||||
end
|
||||
str
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -917,13 +928,38 @@ or the PAGER environment variable.
|
|||
display out
|
||||
end
|
||||
|
||||
def check_did_you_mean # :nodoc:
|
||||
if defined? DidYouMean::SpellChecker
|
||||
true
|
||||
else
|
||||
begin
|
||||
require 'did_you_mean'
|
||||
if defined? DidYouMean::SpellChecker
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
rescue LoadError
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Expands abbreviated klass +klass+ into a fully-qualified class. "Zl::Da"
|
||||
# will be expanded to Zlib::DataError.
|
||||
|
||||
def expand_class klass
|
||||
ary = classes.keys.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z"))
|
||||
raise NotFoundError, klass if ary.length != 1 && ary.first != klass
|
||||
class_names = classes.keys
|
||||
ary = class_names.grep(Regexp.new("\\A#{klass.gsub(/(?=::|\z)/, '[^:]*')}\\z"))
|
||||
if ary.length != 1 && ary.first != klass
|
||||
if check_did_you_mean
|
||||
suggestions = DidYouMean::SpellChecker.new(dictionary: class_names).correct(klass)
|
||||
raise NotFoundError.new(klass, suggestions)
|
||||
else
|
||||
raise NotFoundError, klass
|
||||
end
|
||||
end
|
||||
ary.first
|
||||
end
|
||||
|
||||
|
@ -1235,7 +1271,21 @@ or the PAGER environment variable.
|
|||
def lookup_method name
|
||||
found = load_methods_matching name
|
||||
|
||||
raise NotFoundError, name if found.empty?
|
||||
if found.empty?
|
||||
if check_did_you_mean
|
||||
methods = []
|
||||
_, _, method_name = parse_name name
|
||||
find_methods name do |store, klass, ancestor, types, method|
|
||||
methods.push(*store.class_methods[klass]) if [:class, :both].include? types
|
||||
methods.push(*store.instance_methods[klass]) if [:instance, :both].include? types
|
||||
end
|
||||
methods = methods.uniq
|
||||
suggestions = DidYouMean::SpellChecker.new(dictionary: methods).correct(method_name)
|
||||
raise NotFoundError.new(name, suggestions)
|
||||
else
|
||||
raise NotFoundError, name
|
||||
end
|
||||
end
|
||||
|
||||
filter_methods found, name
|
||||
end
|
||||
|
|
|
@ -1,470 +0,0 @@
|
|||
# frozen_string_literal: false
|
||||
#--
|
||||
# irb/ruby-token.rb - ruby tokens
|
||||
# $Release Version: 0.9.5$
|
||||
# $Revision: 11708 $
|
||||
# $Date: 2007-02-12 15:01:19 -0800 (Mon, 12 Feb 2007) $
|
||||
# by Keiju ISHITSUKA(keiju@ruby-lang.org)
|
||||
#++
|
||||
# Definitions of all tokens involved in the lexical analysis.
|
||||
#
|
||||
# This class is not documented because it is so deep in the internals.
|
||||
|
||||
module RDoc::RubyToken
|
||||
# :stopdoc:
|
||||
|
||||
EXPR_BEG = :EXPR_BEG
|
||||
EXPR_MID = :EXPR_MID
|
||||
EXPR_END = :EXPR_END
|
||||
EXPR_ARG = :EXPR_ARG
|
||||
EXPR_FNAME = :EXPR_FNAME
|
||||
EXPR_DOT = :EXPR_DOT
|
||||
EXPR_CLASS = :EXPR_CLASS
|
||||
|
||||
# for ruby 1.4X
|
||||
if !defined?(Symbol)
|
||||
Symbol = Integer
|
||||
end
|
||||
|
||||
def set_token_position(seek, line, char)
|
||||
@prev_seek = seek
|
||||
@prev_line_no = line
|
||||
@prev_char_no = char
|
||||
end
|
||||
|
||||
class Token
|
||||
def initialize(seek, line_no, char_no, text = nil)
|
||||
@seek = seek
|
||||
@line_no = line_no
|
||||
@char_no = char_no
|
||||
@text = text
|
||||
end
|
||||
|
||||
attr_reader :seek
|
||||
attr_reader :line_no
|
||||
attr_reader :char_no
|
||||
|
||||
attr_accessor :text
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
other.line_no == @line_no and
|
||||
other.char_no == @char_no and
|
||||
other.text == @text
|
||||
end
|
||||
|
||||
##
|
||||
# Because we're used in contexts that expect to return a token, we set the
|
||||
# text string and then return ourselves
|
||||
|
||||
def set_text(text)
|
||||
@text = text
|
||||
self
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
klass = self.class.name.split('::').last
|
||||
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @text]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TkNode < Token
|
||||
def initialize(seek, line_no, char_no, node = nil)
|
||||
super seek, line_no, char_no
|
||||
@node = node
|
||||
end
|
||||
|
||||
attr_reader:node
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
other.line_no == @line_no and
|
||||
other.char_no == @char_no and
|
||||
other.node == @node
|
||||
end
|
||||
|
||||
def set_text text
|
||||
@node = text
|
||||
self
|
||||
end
|
||||
|
||||
alias text node
|
||||
|
||||
def inspect # :nodoc:
|
||||
klass = self.class.name.split('::').last
|
||||
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @node]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TkId < Token
|
||||
def initialize(seek, line_no, char_no, name)
|
||||
super(seek, line_no, char_no)
|
||||
@name = name
|
||||
end
|
||||
attr_reader:name
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
other.line_no == @line_no and
|
||||
other.char_no == @char_no and
|
||||
other.name == @name
|
||||
end
|
||||
|
||||
def set_text text
|
||||
@name = text
|
||||
self
|
||||
end
|
||||
|
||||
alias text name
|
||||
|
||||
def inspect # :nodoc:
|
||||
klass = self.class.name.split('::').last
|
||||
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TkKW < TkId
|
||||
end
|
||||
|
||||
class TkVal < Token
|
||||
def initialize(seek, line_no, char_no, value = nil)
|
||||
super(seek, line_no, char_no)
|
||||
@value = value
|
||||
end
|
||||
attr_accessor :value
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
other.line_no == @line_no and
|
||||
other.char_no == @char_no and
|
||||
other.value == @value
|
||||
end
|
||||
|
||||
def set_text text
|
||||
@value = text
|
||||
self
|
||||
end
|
||||
|
||||
alias text value
|
||||
|
||||
def inspect # :nodoc:
|
||||
klass = self.class.name.split('::').last
|
||||
"{%s %s, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @value]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TkOp < Token
|
||||
def initialize(seek, line_no, char_no, name = nil)
|
||||
super seek, line_no, char_no
|
||||
@name = name
|
||||
end
|
||||
|
||||
attr_accessor :name
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
other.line_no == @line_no and
|
||||
other.char_no == @char_no and
|
||||
other.name == @name
|
||||
end
|
||||
|
||||
def set_text text
|
||||
@name = text
|
||||
self
|
||||
end
|
||||
|
||||
alias text name
|
||||
|
||||
def inspect # :nodoc:
|
||||
klass = self.class.name.split('::').last
|
||||
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TkOPASGN < TkOp
|
||||
def initialize(seek, line_no, char_no, op)
|
||||
super(seek, line_no, char_no)
|
||||
op = TkReading2Token[op][0] unless op.kind_of?(Symbol)
|
||||
@op = op
|
||||
@text = nil
|
||||
end
|
||||
|
||||
attr_reader:op
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
other.line_no == @line_no and
|
||||
other.char_no == @char_no and
|
||||
other.op == @op
|
||||
end
|
||||
|
||||
def text
|
||||
@text ||= "#{TkToken2Reading[op]}="
|
||||
end
|
||||
|
||||
def inspect # :nodoc:
|
||||
klass = self.class.name.split('::').last
|
||||
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @op]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TkUnknownChar < Token
|
||||
def initialize(seek, line_no, char_no, name)
|
||||
super(seek, line_no, char_no)
|
||||
@name = name
|
||||
end
|
||||
attr_reader:name
|
||||
|
||||
def ==(other)
|
||||
self.class == other.class and
|
||||
other.line_no == @line_no and
|
||||
other.char_no == @char_no and
|
||||
other.name == @name
|
||||
end
|
||||
|
||||
def set_text text
|
||||
@name = text
|
||||
self
|
||||
end
|
||||
|
||||
alias text name
|
||||
|
||||
def inspect # :nodoc:
|
||||
klass = self.class.name.split('::').last
|
||||
"{%s %d, %d:%d %p}" % [klass, @seek, @line_no, @char_no, @name]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TkError < Token
|
||||
end
|
||||
|
||||
def Token(token, value = nil)
|
||||
value ||= TkToken2Reading[token]
|
||||
|
||||
case token
|
||||
when String
|
||||
if (tk = TkReading2Token[token]).nil?
|
||||
IRB.fail TkReading2TokenNoKey, token
|
||||
end
|
||||
|
||||
tk = Token(tk[0], value)
|
||||
|
||||
if tk.kind_of?(TkOp) then
|
||||
tk.name = token
|
||||
end
|
||||
when Symbol
|
||||
if (tk = TkSymbol2Token[token]).nil?
|
||||
IRB.fail TkSymbol2TokenNoKey, token
|
||||
end
|
||||
|
||||
tk = Token(tk[0], value)
|
||||
else
|
||||
if token.instance_method(:initialize).arity == 3 then
|
||||
tk = token.new(@prev_seek, @prev_line_no, @prev_char_no)
|
||||
tk.set_text value
|
||||
else
|
||||
tk = token.new(@prev_seek, @prev_line_no, @prev_char_no, value)
|
||||
end
|
||||
end
|
||||
|
||||
tk
|
||||
end
|
||||
|
||||
TokenDefinitions = [
|
||||
[:TkCLASS, TkKW, "class", :EXPR_CLASS],
|
||||
[:TkMODULE, TkKW, "module", :EXPR_BEG],
|
||||
[:TkDEF, TkKW, "def", :EXPR_FNAME],
|
||||
[:TkUNDEF, TkKW, "undef", :EXPR_FNAME],
|
||||
[:TkBEGIN, TkKW, "begin", :EXPR_BEG],
|
||||
[:TkRESCUE, TkKW, "rescue", :EXPR_MID],
|
||||
[:TkENSURE, TkKW, "ensure", :EXPR_BEG],
|
||||
[:TkEND, TkKW, "end", :EXPR_END],
|
||||
[:TkIF, TkKW, "if", :EXPR_BEG, :TkIF_MOD],
|
||||
[:TkUNLESS, TkKW, "unless", :EXPR_BEG, :TkUNLESS_MOD],
|
||||
[:TkTHEN, TkKW, "then", :EXPR_BEG],
|
||||
[:TkELSIF, TkKW, "elsif", :EXPR_BEG],
|
||||
[:TkELSE, TkKW, "else", :EXPR_BEG],
|
||||
[:TkCASE, TkKW, "case", :EXPR_BEG],
|
||||
[:TkWHEN, TkKW, "when", :EXPR_BEG],
|
||||
[:TkWHILE, TkKW, "while", :EXPR_BEG, :TkWHILE_MOD],
|
||||
[:TkUNTIL, TkKW, "until", :EXPR_BEG, :TkUNTIL_MOD],
|
||||
[:TkFOR, TkKW, "for", :EXPR_BEG],
|
||||
[:TkBREAK, TkKW, "break", :EXPR_MID],
|
||||
[:TkNEXT, TkKW, "next", :EXPR_END],
|
||||
[:TkREDO, TkKW, "redo", :EXPR_END],
|
||||
[:TkRETRY, TkKW, "retry", :EXPR_END],
|
||||
[:TkIN, TkKW, "in", :EXPR_BEG],
|
||||
[:TkDO, TkKW, "do", :EXPR_BEG],
|
||||
[:TkRETURN, TkKW, "return", :EXPR_MID],
|
||||
[:TkYIELD, TkKW, "yield", :EXPR_ARG],
|
||||
[:TkSUPER, TkKW, "super", :EXPR_ARG],
|
||||
[:TkSELF, TkKW, "self", :EXPR_END],
|
||||
[:TkNIL, TkKW, "nil", :EXPR_END],
|
||||
[:TkTRUE, TkKW, "true", :EXPR_END],
|
||||
[:TkFALSE, TkKW, "false", :EXPR_END],
|
||||
[:TkAND, TkKW, "and", :EXPR_BEG],
|
||||
[:TkOR, TkKW, "or", :EXPR_BEG],
|
||||
[:TkNOT, TkKW, "not", :EXPR_BEG],
|
||||
[:TkIF_MOD, TkKW],
|
||||
[:TkUNLESS_MOD, TkKW],
|
||||
[:TkWHILE_MOD, TkKW],
|
||||
[:TkUNTIL_MOD, TkKW],
|
||||
[:TkALIAS, TkKW, "alias", :EXPR_FNAME],
|
||||
[:TkDEFINED, TkKW, "defined?", :EXPR_ARG],
|
||||
[:TklBEGIN, TkKW, "BEGIN", :EXPR_END],
|
||||
[:TklEND, TkKW, "END", :EXPR_END],
|
||||
[:Tk__LINE__, TkKW, "__LINE__", :EXPR_END],
|
||||
[:Tk__FILE__, TkKW, "__FILE__", :EXPR_END],
|
||||
[:Tk__ENCODING__,TkKW, "__ENCODING__", :EXPR_END],
|
||||
|
||||
[:TkIDENTIFIER, TkId],
|
||||
[:TkFID, TkId],
|
||||
[:TkGVAR, TkId],
|
||||
[:TkCVAR, TkId],
|
||||
[:TkIVAR, TkId],
|
||||
[:TkCONSTANT, TkId],
|
||||
[:TkHEREDOCBEG, TkId],
|
||||
[:TkHEREDOCEND, TkId],
|
||||
|
||||
[:TkINTEGER, TkVal],
|
||||
[:TkFLOAT, TkVal],
|
||||
[:TkRATIONAL, TkVal],
|
||||
[:TkIMAGINARY, TkVal],
|
||||
[:TkSTRING, TkVal],
|
||||
[:TkHEREDOC, TkVal],
|
||||
[:TkXSTRING, TkVal],
|
||||
[:TkREGEXP, TkVal],
|
||||
[:TkSYMBOL, TkVal],
|
||||
[:TkCHAR, TkVal],
|
||||
|
||||
[:TkDSTRING, TkNode],
|
||||
[:TkDXSTRING, TkNode],
|
||||
[:TkDREGEXP, TkNode],
|
||||
[:TkNTH_REF, TkNode],
|
||||
[:TkBACK_REF, TkNode],
|
||||
|
||||
[:TkUPLUS, TkOp, "+@"],
|
||||
[:TkUMINUS, TkOp, "-@"],
|
||||
[:TkPOW, TkOp, "**"],
|
||||
[:TkCMP, TkOp, "<=>"],
|
||||
[:TkEQ, TkOp, "=="],
|
||||
[:TkEQQ, TkOp, "==="],
|
||||
[:TkNEQ, TkOp, "!="],
|
||||
[:TkGEQ, TkOp, ">="],
|
||||
[:TkLEQ, TkOp, "<="],
|
||||
[:TkHASHROCKET, TkOp, "=>"],
|
||||
[:TkANDOP, TkOp, "&&"],
|
||||
[:TkOROP, TkOp, "||"],
|
||||
[:TkMATCH, TkOp, "=~"],
|
||||
[:TkNMATCH, TkOp, "!~"],
|
||||
[:TkDOT2, TkOp, ".."],
|
||||
[:TkDOT3, TkOp, "..."],
|
||||
[:TkAREF, TkOp, "[]"],
|
||||
[:TkASET, TkOp, "[]="],
|
||||
[:TkLSHFT, TkOp, "<<"],
|
||||
[:TkRSHFT, TkOp, ">>"],
|
||||
[:TkCOLON2, TkOp, '::'],
|
||||
[:TkCOLON3, TkOp, '::'],
|
||||
#[:OPASGN, TkOp], # +=, -= etc. #
|
||||
[:TkASSOC, TkOp, "=>"],
|
||||
[:TkLAMBDA, TkOp, "->"],
|
||||
[:TkQUESTION, TkOp, "?"], #?
|
||||
[:TkCOLON, TkOp, ":"], #:
|
||||
|
||||
[:TkfLPAREN, Token, "("], # func( #
|
||||
[:TkfLBRACK, Token, "["], # func[ #
|
||||
[:TkfLBRACE, Token, "{"], # func{ #
|
||||
[:TkSYMBEG, Token, ":"], # :SYMBOL
|
||||
|
||||
[:TkAMPER, TkOp, "&"],
|
||||
[:TkGT, TkOp, ">"],
|
||||
[:TkLT, TkOp, "<"],
|
||||
[:TkPLUS, TkOp, "+"],
|
||||
[:TkSTAR, TkOp, "*"],
|
||||
[:TkMINUS, TkOp, "-"],
|
||||
[:TkMULT, TkOp, "*"],
|
||||
[:TkDIV, TkOp, "/"],
|
||||
[:TkMOD, TkOp, "%"],
|
||||
[:TkBITOR, TkOp, "|"],
|
||||
[:TkBITXOR, TkOp, "^"],
|
||||
[:TkBITAND, TkOp, "&"],
|
||||
[:TkBITNOT, TkOp, "~"],
|
||||
[:TkNOTOP, TkOp, "!"],
|
||||
|
||||
[:TkBACKQUOTE, TkOp, "`"],
|
||||
|
||||
[:TkASSIGN, Token, "="],
|
||||
[:TkDOT, Token, "."],
|
||||
[:TkSAFENAV, Token, "&."],
|
||||
[:TkLPAREN, Token, "("], #(exp)
|
||||
[:TkLBRACK, Token, "["], #[arry]
|
||||
[:TkLBRACE, Token, "{"], #{hash}
|
||||
[:TkRPAREN, Token, ")"],
|
||||
[:TkRBRACK, Token, "]"],
|
||||
[:TkRBRACE, Token, "}"],
|
||||
[:TkCOMMA, Token, ","],
|
||||
[:TkSEMICOLON, Token, ";"],
|
||||
|
||||
[:TkCOMMENT, TkVal],
|
||||
[:TkSPACE, Token, " "],
|
||||
[:TkNL, Token, "\n"],
|
||||
[:TkEND_OF_SCRIPT],
|
||||
|
||||
[:TkBACKSLASH, TkUnknownChar, "\\"],
|
||||
[:TkAT, TkUnknownChar, "@"],
|
||||
[:TkDOLLAR, TkUnknownChar, "$"],
|
||||
]
|
||||
|
||||
# {reading => token_class}
|
||||
# {reading => [token_class, *opt]}
|
||||
TkReading2Token = {}
|
||||
TkToken2Reading = {}
|
||||
TkSymbol2Token = {}
|
||||
|
||||
def self.def_token(token_n, super_token = Token, reading = nil, *opts)
|
||||
token_n = token_n.id2name if token_n.kind_of?(Symbol)
|
||||
if const_defined?(token_n)
|
||||
IRB.fail AlreadyDefinedToken, token_n
|
||||
end
|
||||
token_c = eval("class #{token_n} < #{super_token}; end; #{token_n}")
|
||||
|
||||
if reading
|
||||
TkToken2Reading[token_c] = reading
|
||||
|
||||
return if TkReading2Token[reading]
|
||||
|
||||
if opts.empty?
|
||||
TkReading2Token[reading] = [token_c]
|
||||
else
|
||||
TkReading2Token[reading] = [token_c].concat(opts)
|
||||
end
|
||||
end
|
||||
TkSymbol2Token[token_n.intern] = token_c
|
||||
end
|
||||
|
||||
for defs in TokenDefinitions
|
||||
def_token(*defs)
|
||||
end
|
||||
|
||||
def_token :TkRD_COMMENT, TkCOMMENT
|
||||
|
||||
NEWLINE_TOKEN = TkNL.new 0, 0, 0, "\n"
|
||||
|
||||
class TkSYMBOL
|
||||
|
||||
def to_sym
|
||||
@sym ||= text[1..-1].intern
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# :startdoc:
|
||||
end
|
||||
|
|
@ -217,7 +217,7 @@ exception:
|
|||
<pre>#{ERB::Util.html_escape exception.message}</pre>
|
||||
|
||||
<p>Please report this to the
|
||||
<a href="https://github.com/rdoc/rdoc/issues">RDoc issues tracker</a>. Please
|
||||
<a href="https://github.com/ruby/rdoc/issues">RDoc issues tracker</a>. Please
|
||||
include the RDoc version, the URI above and exception class, message and
|
||||
backtrace. If you're viewing a gem's documentation, include the gem name and
|
||||
version. If you're viewing Ruby's documentation, include the version of ruby.
|
||||
|
|
|
@ -10,21 +10,8 @@ module RDoc::TokenStream
|
|||
|
||||
##
|
||||
# Converts +token_stream+ to HTML wrapping various tokens with
|
||||
# <tt><span></tt> elements. The following tokens types are wrapped in spans
|
||||
# with the given class names:
|
||||
#
|
||||
# TkCONSTANT :: 'ruby-constant'
|
||||
# TkKW :: 'ruby-keyword'
|
||||
# TkIVAR :: 'ruby-ivar'
|
||||
# TkOp :: 'ruby-operator'
|
||||
# TkId :: 'ruby-identifier'
|
||||
# TkNode :: 'ruby-node'
|
||||
# TkCOMMENT :: 'ruby-comment'
|
||||
# TkREGEXP :: 'ruby-regexp'
|
||||
# TkSTRING :: 'ruby-string'
|
||||
# TkVal :: 'ruby-value'
|
||||
#
|
||||
# Other token types are not wrapped in spans.
|
||||
# <tt><span></tt> elements. Some tokens types are wrapped in spans
|
||||
# with the given class names. Other token types are not wrapped in spans.
|
||||
|
||||
def self.to_html token_stream
|
||||
token_stream.map do |t|
|
||||
|
|
|
@ -89,6 +89,15 @@ method(a, b) { |c, d| ... }
|
|||
assert_equal '', @c2_a.markup_code
|
||||
end
|
||||
|
||||
def test_markup_code_with_variable_expansion
|
||||
m = RDoc::AnyMethod.new nil, 'method'
|
||||
m.parent = @c1
|
||||
m.block_params = '"Hello, #{world}", yield_arg'
|
||||
m.params = 'a'
|
||||
|
||||
assert_equal '(a) { |"Hello, #{world}", yield_arg| ... }', m.param_seq
|
||||
end
|
||||
|
||||
def test_marshal_dump
|
||||
@store.path = Dir.tmpdir
|
||||
top_level = @store.add_file 'file.rb'
|
||||
|
|
|
@ -43,10 +43,13 @@ class TestRDocGeneratorDarkfish < RDoc::TestCase
|
|||
|
||||
@meth = RDoc::AnyMethod.new nil, 'method'
|
||||
@meth_bang = RDoc::AnyMethod.new nil, 'method!'
|
||||
@meth_with_html_tag_yield = RDoc::AnyMethod.new nil, 'method_with_html_tag_yield'
|
||||
@meth_with_html_tag_yield.block_params = '%<<script>alert("atui")</script>>, yield_arg'
|
||||
@attr = RDoc::Attr.new nil, 'attr', 'RW', ''
|
||||
|
||||
@klass.add_method @meth
|
||||
@klass.add_method @meth_bang
|
||||
@klass.add_method @meth_with_html_tag_yield
|
||||
@klass.add_attribute @attr
|
||||
|
||||
@ignored = @top_level.add_class RDoc::NormalClass, 'Ignored'
|
||||
|
@ -167,7 +170,7 @@ class TestRDocGeneratorDarkfish < RDoc::TestCase
|
|||
assert_equal [@klass_alias, @ignored, @klass, @object],
|
||||
@g.classes.sort_by { |klass| klass.full_name }
|
||||
assert_equal [@top_level], @g.files
|
||||
assert_equal [@meth, @meth, @meth_bang, @meth_bang], @g.methods
|
||||
assert_equal [@meth, @meth, @meth_bang, @meth_bang, @meth_with_html_tag_yield, @meth_with_html_tag_yield], @g.methods
|
||||
assert_equal [@klass_alias, @klass, @object], @g.modsort
|
||||
end
|
||||
|
||||
|
@ -199,6 +202,23 @@ class TestRDocGeneratorDarkfish < RDoc::TestCase
|
|||
assert_same template, @g.send(:template_for, partial)
|
||||
end
|
||||
|
||||
def test_generated_method_with_html_tag_yield
|
||||
top_level = @store.add_file 'file.rb'
|
||||
top_level.add_class @klass.class, @klass.name
|
||||
|
||||
@g.generate
|
||||
|
||||
path = File.join @tmpdir, 'A.html'
|
||||
|
||||
f = open(path)
|
||||
internal_file = f.read
|
||||
method_name_index = internal_file.index('<span class="method-name">method_with_html_tag_yield</span>')
|
||||
last_of_method_name_index = method_name_index + internal_file[method_name_index..-1].index('<div class="method-description">') - 1
|
||||
method_name = internal_file[method_name_index..last_of_method_name_index]
|
||||
|
||||
assert_includes method_name, '{ |%<<script>alert("atui")</script>>, yield_arg| ... }'
|
||||
end
|
||||
|
||||
##
|
||||
# Asserts that +filename+ has a link count greater than 1 if hard links to
|
||||
# @tmpdir are supported.
|
||||
|
|
|
@ -973,6 +973,14 @@ and an extra note.[^2]
|
|||
assert_equal '<b>_emphasis_</b>', @parser.strong('_emphasis_')
|
||||
end
|
||||
|
||||
def test_code_fence_with_unintended_array
|
||||
doc = parse '```<ruby>```'
|
||||
|
||||
expected = doc(verb('<ruby>'))
|
||||
|
||||
assert_equal expected, doc
|
||||
end
|
||||
|
||||
def parse text
|
||||
@parser.parse text
|
||||
end
|
||||
|
|
|
@ -494,9 +494,9 @@ be guessed, raises an error if +name+ couldn't be guessed.
|
|||
rdoc = <<-RDOC
|
||||
= \RDoc - Ruby Documentation System
|
||||
|
||||
* {RDoc Project Page}[https://github.com/rdoc/rdoc/]
|
||||
* {RDoc Documentation}[https://rdoc.github.io/rdoc]
|
||||
* {RDoc Bug Tracker}[https://github.com/rdoc/rdoc/issues]
|
||||
* {RDoc Project Page}[https://github.com/ruby/rdoc]
|
||||
* {RDoc Documentation}[https://ruby.github.io/rdoc]
|
||||
* {RDoc Bug Tracker}[https://github.com/ruby/rdoc/issues]
|
||||
|
||||
== DESCRIPTION:
|
||||
|
||||
|
|
|
@ -778,12 +778,13 @@ end
|
|||
|
||||
def test_parse_class_lower_name_warning
|
||||
@options.verbosity = 2
|
||||
out, err = capture_io do
|
||||
stds = capture_io do
|
||||
util_parser "class foo\nend"
|
||||
tk = @parser.get_tk
|
||||
@parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
|
||||
end
|
||||
assert_match /Expected class name or '<<'\. Got/, err
|
||||
err = stds[1]
|
||||
assert_match(/Expected class name or '<<'\. Got/, err)
|
||||
end
|
||||
|
||||
def test_parse_multi_ghost_methods
|
||||
|
@ -1359,6 +1360,52 @@ A::B::C = 1
|
|||
assert_equal 'comment', c.comment
|
||||
end
|
||||
|
||||
def test_parse_class_the_same_of_outside
|
||||
util_parser <<-RUBY
|
||||
module A
|
||||
class A::B
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
@parser.scan
|
||||
|
||||
assert_includes @store.modules_hash, 'A'
|
||||
module_a = @store.find_module_named 'A'
|
||||
refute_empty module_a.classes_hash
|
||||
assert_includes module_a.classes_hash, 'B'
|
||||
refute_includes module_a.classes_hash, 'A'
|
||||
end
|
||||
|
||||
def test_parse_constant_the_same_of_outside
|
||||
util_parser <<-RUBY
|
||||
module A
|
||||
class B
|
||||
class C
|
||||
end
|
||||
end
|
||||
|
||||
def self.foo
|
||||
A::B::C
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
expected = <<EXPECTED
|
||||
<span class="ruby-keyword">def</span> <span class="ruby-keyword">self</span>.<span class="ruby-identifier">foo</span>
|
||||
<span class="ruby-constant">A</span><span class="ruby-operator">::</span><span class="ruby-constant">B</span><span class="ruby-operator">::</span><span class="ruby-constant">C</span>
|
||||
<span class="ruby-keyword">end</span>
|
||||
EXPECTED
|
||||
expected = expected.rstrip
|
||||
|
||||
@parser.scan
|
||||
|
||||
module_a = @store.find_module_named 'A'
|
||||
foo = module_a.method_list.first
|
||||
markup_code = foo.markup_code.sub(/^.*\n/, '')
|
||||
assert_equal expected, markup_code
|
||||
end
|
||||
|
||||
def test_parse_constant_with_bracket
|
||||
util_parser <<-RUBY
|
||||
class Klass
|
||||
|
@ -1379,8 +1426,6 @@ end
|
|||
klass = @store.find_class_named 'Klass'
|
||||
klass2 = @store.find_class_named 'Klass2'
|
||||
klass3 = @store.find_class_named 'Klass3'
|
||||
constant = klass2.find_module_named 'CONSTANT'
|
||||
constant2 = klass3.find_module_named 'CONSTANT_2'
|
||||
assert_equal klass, klass2.constants.first.is_alias_for
|
||||
refute_equal klass, klass3.constants.first.is_alias_for
|
||||
assert_nil klass3.find_module_named 'CONSTANT_2'
|
||||
|
@ -2561,14 +2606,14 @@ class Foo
|
|||
end
|
||||
RUBY
|
||||
|
||||
expected = <<EXPTECTED
|
||||
expected = <<EXPECTED
|
||||
<span class="ruby-keyword">def</span> <span class="ruby-identifier">blah</span>()
|
||||
<span class="ruby-keyword">for</span> <span class="ruby-identifier">i</span> <span class="ruby-keyword">in</span> (<span class="ruby-identifier">k</span>)<span class="ruby-operator">...</span><span class="ruby-identifier">n</span> <span class="ruby-keyword">do</span>
|
||||
<span class="ruby-keyword">end</span>
|
||||
<span class="ruby-keyword">for</span> <span class="ruby-identifier">i</span> <span class="ruby-keyword">in</span> (<span class="ruby-identifier">k</span>)<span class="ruby-operator">...</span><span class="ruby-identifier">n</span>
|
||||
<span class="ruby-keyword">end</span>
|
||||
<span class="ruby-keyword">end</span>
|
||||
EXPTECTED
|
||||
EXPECTED
|
||||
expected = expected.rstrip
|
||||
|
||||
@parser.scan
|
||||
|
@ -2578,7 +2623,7 @@ EXPTECTED
|
|||
|
||||
blah = foo.method_list.first
|
||||
markup_code = blah.markup_code.sub(/^.*\n/, '')
|
||||
assert_equal markup_code, expected
|
||||
assert_equal expected, markup_code
|
||||
end
|
||||
|
||||
def test_parse_statements_postfix_if_after_heredocbeg
|
||||
|
@ -2592,12 +2637,12 @@ class Foo
|
|||
end
|
||||
RUBY
|
||||
|
||||
expected = <<EXPTECTED
|
||||
expected = <<EXPECTED
|
||||
<span class="ruby-keyword">def</span> <span class="ruby-identifier">blah</span>()
|
||||
<span class="ruby-identifier"><<-EOM</span> <span class="ruby-keyword">if</span> <span class="ruby-keyword">true</span>
|
||||
<span class="ruby-value"></span><span class="ruby-identifier"> EOM</span>
|
||||
<span class="ruby-keyword">end</span>
|
||||
EXPTECTED
|
||||
EXPECTED
|
||||
expected = expected.rstrip
|
||||
|
||||
@parser.scan
|
||||
|
@ -2617,9 +2662,9 @@ class Foo
|
|||
end
|
||||
RUBY
|
||||
|
||||
expected = <<EXPTECTED
|
||||
expected = <<EXPECTED
|
||||
<span class="ruby-keyword">def</span> <span class="ruby-identifier">blah</span>() <span class="ruby-regexp">/bar/</span> <span class="ruby-keyword">end</span>
|
||||
EXPTECTED
|
||||
EXPECTED
|
||||
expected = expected.rstrip
|
||||
|
||||
@parser.scan
|
||||
|
@ -2647,14 +2692,14 @@ class Foo
|
|||
end
|
||||
RUBY
|
||||
|
||||
expected = <<EXPTECTED
|
||||
expected = <<EXPECTED
|
||||
<p>doc
|
||||
|
||||
<pre class="ruby"><span class="ruby-comment">=begin
|
||||
test embdoc
|
||||
=end</span>
|
||||
</pre>
|
||||
EXPTECTED
|
||||
EXPECTED
|
||||
|
||||
@parser.scan
|
||||
|
||||
|
@ -2663,7 +2708,7 @@ EXPTECTED
|
|||
|
||||
blah = foo.method_list.first
|
||||
markup_comment = blah.search_record[6]
|
||||
assert_equal markup_comment, expected
|
||||
assert_equal expected, markup_comment
|
||||
end
|
||||
|
||||
def test_parse_require_dynamic_string
|
||||
|
@ -3639,7 +3684,7 @@ end
|
|||
@parser.scan
|
||||
|
||||
c = @store.find_class_named 'C'
|
||||
const_a, const_b, const_c, const_d = c.constants.sort_by(&:name)
|
||||
const_a, const_b, const_c = c.constants.sort_by(&:name)
|
||||
|
||||
assert_equal 'CONST_A', const_a.name
|
||||
assert_equal :public, const_a.visibility
|
||||
|
|
|
@ -969,6 +969,27 @@ Foo::Bar#bother
|
|||
assert_equal 'nonexistent', e.name
|
||||
end
|
||||
|
||||
def test_did_you_mean
|
||||
skip 'skip test with did_you_men' unless defined? DidYouMean::SpellChecker
|
||||
|
||||
util_ancestors_store
|
||||
|
||||
e = assert_raises RDoc::RI::Driver::NotFoundError do
|
||||
@driver.lookup_method 'Foo.i_methdo'
|
||||
end
|
||||
assert_equal "Nothing known about Foo.i_methdo\nDid you mean? i_method", e.message
|
||||
|
||||
e = assert_raises RDoc::RI::Driver::NotFoundError do
|
||||
@driver.lookup_method 'Foo#i_methdo'
|
||||
end
|
||||
assert_equal "Nothing known about Foo#i_methdo\nDid you mean? i_method", e.message
|
||||
|
||||
e = assert_raises RDoc::RI::Driver::NotFoundError do
|
||||
@driver.lookup_method 'Foo::i_methdo'
|
||||
end
|
||||
assert_equal "Nothing known about Foo::i_methdo\nDid you mean? c_method", e.message
|
||||
end
|
||||
|
||||
def test_formatter
|
||||
tty = Object.new
|
||||
def tty.tty?() true; end
|
||||
|
|
Loading…
Reference in a new issue