Class: JsDuck::Class

Inherits:
Object
  • Object
show all
Defined in:
lib/jsduck/class.rb

Overview

Encapsulates class documentation and provides some commonly needed methods on it. Otherwise it acts like Hash, providing the [] method.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(doc, class_exists = true) ⇒ Class

Creates JSDuck class.

Pass true as second parameter to create a placeholder class.



19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/jsduck/class.rb', line 19

def initialize(doc, class_exists=true)
  @doc = doc

  # Wrap classname into custom string class that allows
  # differenciating between existing and missing classes.
  @doc[:name] = ClassNameString.new(@doc[:name], class_exists)

  @doc[:members] = [] if !@doc[:members]

  @members_index = MembersIndex.new(self)

  @relations = nil
end

Instance Attribute Details

#members_indexObject

Used only by MembersIndex class itself to access the MembersIndex instances of parents and mixins.



14
15
16
# File 'lib/jsduck/class.rb', line 14

def members_index
  @members_index
end

#relationsObject

Returns the value of attribute relations.



10
11
12
# File 'lib/jsduck/class.rb', line 10

def relations
  @relations
end

Class Method Details

.constructor?(member) ⇒ Boolean

True if the given member is a constructor method

Returns:

  • (Boolean)


207
208
209
# File 'lib/jsduck/class.rb', line 207

def self.constructor?(member)
  member[:tagname] == :method && member[:name] == "constructor"
end

.member_id(m) ⇒ Object

Generates member :id from member hash



200
201
202
203
204
# File 'lib/jsduck/class.rb', line 200

def self.member_id(m)
  # Sanitize $ and / in member names with something safer
  name = m[:name].gsub(/\$/, 'S-').gsub(/\//,'-')
  "#{m[:static] ? 'static-' : ''}#{m[:tagname]}-#{name}"
end

Instance Method Details

#[](key) ⇒ Object

Accessor to internal hash



60
61
62
# File 'lib/jsduck/class.rb', line 60

def [](key)
  @doc[key]
end

#[]=(key, value) ⇒ Object

Assignment to internal hash keys



65
66
67
# File 'lib/jsduck/class.rb', line 65

def []=(key, value)
  @doc[key] = value
end

#all_local_membersObject

Returns all local members of class



193
194
195
# File 'lib/jsduck/class.rb', line 193

def all_local_members
  @doc[:members]
end

#deps(type) ⇒ Object

Returns an array of class instances this class directly depends on. Possible types are:

  • :mixins

  • :implements

  • :requires

  • :uses



107
108
109
# File 'lib/jsduck/class.rb', line 107

def deps(type)
  @doc[type] ? @doc[type].collect {|classname| lookup(classname) } : []
end

#find_members(query = {}) ⇒ Object

Returns list of members filtered by a query. Searches both local and inherited members.

The query hash can contain the following fields:

  • :name : String - the name of the member to find.

  • :tagname : Symbol - the member type to look for.

  • :static : Boolean - true to only return static members,

    false to only return instance members.
    When nil or unspecified, both static
    and instance members are returned.
    
  • :local : Boolean - true to only return non-inherited members.

When called without arguments all members are returned.

When nothing found, an empty array is returned.



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/jsduck/class.rb', line 160

def find_members(query={})
  if query[:name]
    ms = @members_index.global_by_name[query[:name]] || []
    ms = ms.find_all {|m| m[:owner] == @doc[:name]} if query[:local]
  elsif query[:local]
    ms = @members_index.all_local
  else
    ms = @members_index.all_global
  end

  if query[:tagname]
    ms = ms.find_all {|m| m[:tagname] == query[:tagname] }
  end

  if query[:static] == true
    ms = ms.find_all {|m| m[:static] }
  elsif query[:static] == false
    ms = ms.reject {|m| m[:static] }
  end

  ms
end

#implementsObject

Returns all interfaces that either this class or it’s ancestors implement.



90
91
92
# File 'lib/jsduck/class.rb', line 90

def implements
  deps(:implements).concat(parent_deps(:implements))
end

#inherits_from?(class_name) ⇒ Boolean

Returns true when this class inherits from the specified class. Also returns true when the class itself is the one we are asking about.

Returns:

  • (Boolean)


137
138
139
# File 'lib/jsduck/class.rb', line 137

def inherits_from?(class_name)
  return @doc[:name] == class_name || (parent ? parent.inherits_from?(class_name) : false)
end

#internal_docObject

Returns the internal doc object.



34
35
36
# File 'lib/jsduck/class.rb', line 34

def internal_doc
  @doc
end

#internal_doc=(doc) ⇒ Object

Sets the internal doc object.

The doc object is processed in parallel and then assigned back through this method. But because of parallel processing the assigned doc object will not be just a modified old @doc but a completely new. If we were to just assign to @doc the #find_members caches would still point to old @doc members resulting in mysterious errors further along…



46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/jsduck/class.rb', line 46

def internal_doc=(doc)
  @doc.merge!(doc) do |key, oldval, newval|
    if key == :members
      oldval.zip(newval) do |ms|
        ms[0].merge!(ms[1])
      end
      oldval
    else
      newval
    end
  end
end

#lookup(classname) ⇒ Object

Looks up class object by name When not found, prints warning message.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/jsduck/class.rb', line 118

def lookup(classname)
  if @relations[classname]
    @relations[classname]
  elsif @relations.ignore?(classname) || classname =~ /\*/
    # Ignore explicitly ignored classes and classnames with
    # wildcards in them.  We could expand the wildcard, but that
    # can result in a very long list of classes, like when
    # somebody requires 'Ext.form.*', so for now we do the
    # simplest thing and ignore it.
    Class.new({:name => classname}, false)
  else
    Logger.warn(:extend, "Class #{classname} not found", @doc[:files][0])
    # Create placeholder class
    Class.new({:name => classname}, false)
  end
end

#mixinsObject

Returns all direct mixins of this class. Same as #deps(:mixins).



85
86
87
# File 'lib/jsduck/class.rb', line 85

def mixins
  deps(:mixins)
end

#parentObject

Returns instance of parent class, or nil if there is none



70
71
72
# File 'lib/jsduck/class.rb', line 70

def parent
  @doc[:extends] ? lookup(@doc[:extends]) : nil
end

#parent_deps(type) ⇒ Object

Same ase #deps, but pulls out the dependencies from all parent classes.



112
113
114
# File 'lib/jsduck/class.rb', line 112

def parent_deps(type)
  parent ? parent.deps(type) + parent.parent_deps(type) : []
end

#refresh_member_ids!Object

This must be called whenever member hashes are changed. It updates the :id fields of members and clears the caches.



185
186
187
188
189
190
# File 'lib/jsduck/class.rb', line 185

def refresh_member_ids!
  @doc[:members].each do |m|
    m[:id] = Class.member_id(m)
  end
  @members_index.invalidate!
end

#self_implementsObject

Returns all interfaces that this class implements.



95
96
97
# File 'lib/jsduck/class.rb', line 95

def self_implements
  deps(:implements)
end

#superclassesObject

Returns array of ancestor classes. Example result when asking ancestors of MyPanel might be:

[Ext.util.Observable, Ext.Component, Ext.Panel]


79
80
81
82
# File 'lib/jsduck/class.rb', line 79

def superclasses
  p = parent
  p ? p.superclasses + [p]  : []
end