# frozen_string_literal: true### Abstract class representing either a method or an attribute.classRDoc::MethodAttr<RDoc::CodeObjectincludeComparable### Name of this method/attribute.attr_accessor:name### public, protected, privateattr_accessor:visibility### Is this a singleton method/attribute?attr_accessor:singleton### Source file token streamattr_reader:text### Array of other names for this method/attributeattr_reader:aliases### The method/attribute we're aliasingattr_accessor:is_alias_for#--# The attributes below are for AnyMethod only.# They are left here for the time being to# allow ri to operate.# TODO modify ri to avoid calling these on attributes.#++### Parameters yielded by the called blockattr_reader:block_params### Parameters for this methodattr_accessor:params### Different ways to call this methodattr_accessor:call_seq### The call_seq or the param_seq with method name, if there is no call_seq.attr_reader:arglists### Pretty parameter list for this methodattr_reader:param_seq### Creates a new MethodAttr from token stream +text+ and method or attribute# name +name+.## Usually this is called by super from a subclass.definitializetext,namesuper()@text=text@name=name@aliases=[]@is_alias_for=nil@parent_name=nil@singleton=nil@visibility=:public@see=false@arglists=nil@block_params=nil@call_seq=nil@param_seq=nil@params=nilend### Resets cached data for the object so it can be rebuilt by accessor methodsdefinitialize_copyother# :nodoc:@full_name=nilenddefinitialize_visibility# :nodoc:super@see=nilend### Order by #singleton then #namedef<=>(other)returnunlessother.respond_to?(:singleton)&&other.respond_to?(:name)[@singleton?0:1,name_ord_range,name]<=>[other.singleton?0:1,other.name_ord_range,other.name]enddef==other# :nodoc:equal?(other)orself.class==other.classandfull_name==other.full_nameend### A method/attribute is documented if any of the following is true:# - it was marked with :nodoc:;# - it has a comment;# - it is an alias for a documented method;# - it has a +#see+ method that is documented.defdocumented?superor(is_alias_forandis_alias_for.documented?)or(seeandsee.documented?)end### A method/attribute to look at,# in particular if this method/attribute has no documentation.## It can be a method/attribute of the superclass or of an included module,# including the Kernel module, which is always appended to the included# modules.## Returns +nil+ if there is no such method/attribute.# The +#is_alias_for+ method/attribute, if any, is not included.## Templates may generate a "see also ..." if this method/attribute# has documentation, and "see ..." if it does not.defsee@see=find_seeif@see==false@seeend### Sets the store for this class or module and its contained code objects.defstore=storesuper@file=@store.add_file@file.full_nameif@fileenddeffind_see# :nodoc:returnnilifsingleton||is_alias_for# look for the methodother=find_method_or_attributenamereturnotherifother# if it is a setter, look for a getterreturnnilunlessname=~/[a-z_]=$/i# avoid == or ===returnfind_method_or_attributename[0..-2]enddeffind_method_or_attributename# :nodoc:returnnilunlessparent.respond_to?:ancestorssearched=parent.ancestorskernel=@store.modules_hash['Kernel']searched<<kernelifkernel&&parent!=kernel&&!searched.include?(kernel)searched.eachdo|ancestor|nextifString===ancestornextifparent==ancestorother=ancestor.find_method_named('#'+name)||ancestor.find_attribute_named(name)returnotherifotherendnilend### Abstract method. Contexts in their building phase call this# to register a new alias for this known method/attribute.## - creates a new AnyMethod/Attribute named <tt>an_alias.new_name</tt>;# - adds +self+ as an alias for the new method or attribute# - adds the method or attribute to #aliases# - adds the method or attribute to +context+.defadd_alias(an_alias,context)raiseNotImplementedErrorend### HTML fragment reference for this methoddefareftype=singleton?'c':'i'# % characters are not allowed in html names => dash instead"#{aref_prefix}-#{type}-#{html_name}"end### Prefix for +aref+, defined by subclasses.defaref_prefixraiseNotImplementedErrorend### Attempts to sanitize the content passed by the Ruby parser:# remove outer parentheses, etc.defblock_params=(value)# 'yield.to_s' or 'assert yield, msg'return@block_params=''ifvalue=~/^[\.,]/# remove trailing 'if/unless ...'return@block_params=''ifvalue=~/^(if|unless)\s/value=$1.stripifvalue=~/^(.+)\s(if|unless)\s/# outer parenthesesvalue=$1ifvalue=~/^\s*\((.*)\)\s*$/value=value.strip# proc/lambdareturn@block_params=$1ifvalue=~/^(proc|lambda)(\s*\{|\sdo)/# surrounding +...+ or [...]value=$1.stripifvalue=~/^\+(.*)\+$/value=$1.stripifvalue=~/^\[(.*)\]$/return@block_params=''ifvalue.empty?# global variablereturn@block_params='str'ifvalue=~/^\$[&0-9]$/# wipe out array/hash indicesvalue.gsub!(/(\w)\[[^\[]+\]/,'\1')# remove @ from class/instance variablesvalue.gsub!(/@@?([a-z0-9_]+)/,'\1')# method calls => method namevalue.gsub!(/([A-Z:a-z0-9_]+)\.([a-z0-9_]+)(\s*\(\s*[a-z0-9_.,\s]*\s*\)\s*)?/)docase$2when'to_s'then$1when'const_get'then'const'when'new'then$1.split('::').last.# ClassName => class_namegsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').downcaseelse$2endend# class prefixesvalue.gsub!(/[A-Za-z0-9_:]+::/,'')# simple expressionsvalue=$1ifvalue=~/^([a-z0-9_]+)\s*[-*+\/]/@block_params=value.stripend### HTML id-friendly method/attribute namedefhtml_namerequire'cgi/util'CGI.escape(@name.gsub('-','-2D')).gsub('%','-').sub(/^-/,'')end### Full method/attribute name including namespacedeffull_name@full_name||="#{parent_name}#{pretty_name}"enddefinspect# :nodoc:alias_for=@is_alias_for?" (alias for #{@is_alias_for.name})":nilvisibility=self.visibilityvisibility="forced #{visibility}"ifforce_documentation"#<%s:0x%x %s (%s)%s>"%[self.class,object_id,full_name,visibility,alias_for,]end### '::' for a class method/attribute, '#' for an instance method.defname_prefix@singleton?'::':'#'end### Name for output to HTML. For class methods the full name with a "." is# used like +SomeClass.method_name+. For instance methods the class name is# used if +context+ does not match the parent.## This is to help prevent people from using :: to call class methods.defoutput_namecontextreturn"#{name_prefix}#{@name}"ifcontext==parent"#{parent_name}#{@singleton?'.':'#'}#{@name}"end### Method/attribute name with class/instance indicatordefpretty_name"#{name_prefix}#{@name}"end### Type of method/attribute (class or instance)deftypesingleton?'class':'instance'end### Path to this method for use with HTML generator output.defpath"#{@parent.path}##{aref}"end### Name of our parent with special handling for un-marshaled methodsdefparent_name@parent_name||superenddefpretty_printq# :nodoc:alias_for=if@is_alias_for.respond_to?:namethen"alias for #{@is_alias_for.name}"elsifArray===@is_alias_forthen"alias for #{@is_alias_for.last}"endq.group2,"[#{self.class.name}#{full_name}#{visibility}","]"doifalias_forthenq.breakableq.textalias_forendiftextthenq.breakableq.text"text:"q.breakableq.pp@textendunlesscomment.empty?thenq.breakableq.text"comment:"q.breakableq.pp@commentendendend### Used by RDoc::Generator::JsonIndex to create a record for the search# engine.defsearch_record[@name,full_name,@name,@parent.full_name,path,params,snippet(@comment),]enddefto_s# :nodoc:if@is_alias_for"#{self.class.name}: #{full_name} -> #{is_alias_for}"else"#{self.class.name}: #{full_name}"endenddefname_ord_range# :nodoc:casename.ordwhen0..64# anything below "A"1when91..96# the symbols between "Z" and "a"2when123..126# 7-bit symbols above "z": "{", "|", "}", "~"3else# everythig else can be sorted as normal4endendend