jsduck 5.0.0.beta01 → 5.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.travis.yml +1 -0
  2. data/README.md +6 -32
  3. data/Rakefile +5 -5
  4. data/bin/jsduck +0 -1
  5. data/js-classes/String.js +3 -5
  6. data/jsduck.gemspec +3 -2
  7. data/lib/jsduck/aggregator.rb +1 -3
  8. data/lib/jsduck/app.rb +2 -2
  9. data/lib/jsduck/categories/file.rb +0 -6
  10. data/lib/jsduck/class.rb +1 -2
  11. data/lib/jsduck/doc/parser.rb +12 -5
  12. data/lib/jsduck/doc/scanner.rb +6 -0
  13. data/lib/jsduck/doc/standard_tag_parser.rb +10 -5
  14. data/lib/jsduck/doc/subproperties.rb +9 -2
  15. data/lib/jsduck/docs_code_comparer.rb +20 -7
  16. data/lib/jsduck/exporter/app.rb +18 -13
  17. data/lib/jsduck/exporter/full.rb +18 -21
  18. data/lib/jsduck/format/doc.rb +0 -1
  19. data/lib/jsduck/format/html_stack.rb +1 -2
  20. data/lib/jsduck/format/subproperties.rb +2 -2
  21. data/lib/jsduck/inline/auto_link.rb +1 -1
  22. data/lib/jsduck/inline/img.rb +1 -1
  23. data/lib/jsduck/inline/link.rb +4 -6
  24. data/lib/jsduck/inline/video.rb +1 -2
  25. data/lib/jsduck/js/ast.rb +1 -1
  26. data/lib/jsduck/js/esprima.rb +24 -9
  27. data/lib/jsduck/logger.rb +50 -12
  28. data/lib/jsduck/members_index.rb +1 -2
  29. data/lib/jsduck/merger.rb +20 -2
  30. data/lib/jsduck/options.rb +125 -24
  31. data/lib/jsduck/process/accessors.rb +21 -8
  32. data/lib/jsduck/process/enums.rb +2 -3
  33. data/lib/jsduck/process/ext4_events.rb +2 -1
  34. data/lib/jsduck/process/global_members.rb +1 -2
  35. data/lib/jsduck/process/importer.rb +2 -6
  36. data/lib/jsduck/process/inherit_class.rb +58 -0
  37. data/lib/jsduck/process/inherit_doc.rb +6 -175
  38. data/lib/jsduck/process/inherit_members.rb +257 -0
  39. data/lib/jsduck/process/lint.rb +18 -7
  40. data/lib/jsduck/process/overrides.rb +1 -2
  41. data/lib/jsduck/render/class.rb +1 -1
  42. data/lib/jsduck/tag/alias.rb +2 -1
  43. data/lib/jsduck/tag/alternate_class_names.rb +1 -0
  44. data/lib/jsduck/tag/aside.rb +3 -3
  45. data/lib/jsduck/tag/author.rb +18 -3
  46. data/lib/jsduck/tag/autodetected.rb +21 -0
  47. data/lib/jsduck/tag/boolean_tag.rb +1 -1
  48. data/lib/jsduck/tag/cfg.rb +7 -3
  49. data/lib/jsduck/tag/class.rb +1 -1
  50. data/lib/jsduck/tag/class_list_tag.rb +1 -1
  51. data/lib/jsduck/tag/constructor.rb +1 -1
  52. data/lib/jsduck/tag/css_var.rb +1 -1
  53. data/lib/jsduck/tag/default.rb +1 -1
  54. data/lib/jsduck/tag/deprecated_tag.rb +1 -1
  55. data/lib/jsduck/tag/docauthor.rb +2 -0
  56. data/lib/jsduck/tag/enum.rb +2 -2
  57. data/lib/jsduck/tag/event.rb +1 -1
  58. data/lib/jsduck/tag/extends.rb +1 -1
  59. data/lib/jsduck/tag/ftype.rb +2 -1
  60. data/lib/jsduck/tag/inheritdoc.rb +1 -1
  61. data/lib/jsduck/tag/localdoc.rb +33 -0
  62. data/lib/jsduck/tag/markdown.rb +1 -1
  63. data/lib/jsduck/tag/member.rb +1 -1
  64. data/lib/jsduck/tag/method.rb +1 -1
  65. data/lib/jsduck/tag/mixins.rb +1 -0
  66. data/lib/jsduck/tag/override.rb +1 -1
  67. data/lib/jsduck/tag/param.rb +16 -5
  68. data/lib/jsduck/tag/preventable.rb +1 -1
  69. data/lib/jsduck/tag/property.rb +7 -3
  70. data/lib/jsduck/tag/ptype.rb +2 -1
  71. data/lib/jsduck/tag/requires.rb +1 -0
  72. data/lib/jsduck/tag/return.rb +2 -1
  73. data/lib/jsduck/tag/since.rb +1 -5
  74. data/lib/jsduck/tag/tag.rb +21 -12
  75. data/lib/jsduck/tag/throws.rb +2 -1
  76. data/lib/jsduck/tag/type.rb +2 -2
  77. data/lib/jsduck/tag/uses.rb +1 -0
  78. data/lib/jsduck/tag/xtype.rb +2 -1
  79. data/lib/jsduck/tag_loader.rb +26 -15
  80. data/lib/jsduck/tag_registry.rb +20 -11
  81. data/lib/jsduck/web/css.rb +22 -0
  82. data/lib/jsduck/web/data.rb +50 -0
  83. data/lib/jsduck/web/icons.rb +31 -0
  84. data/lib/jsduck/web/index_html.rb +88 -0
  85. data/lib/jsduck/web/search.rb +148 -0
  86. data/lib/jsduck/{source/writer.rb → web/source.rb} +2 -2
  87. data/lib/jsduck/web/template.rb +52 -0
  88. data/lib/jsduck/web/writer.rb +84 -0
  89. metadata +513 -488
  90. data/lib/jsduck/app_data.rb +0 -41
  91. data/lib/jsduck/icons.rb +0 -29
  92. data/lib/jsduck/index_html.rb +0 -84
  93. data/lib/jsduck/search_data.rb +0 -146
  94. data/lib/jsduck/template_dir.rb +0 -50
  95. data/lib/jsduck/web_writer.rb +0 -87
@@ -3,6 +3,17 @@ require 'jsduck/logger'
3
3
  module JsDuck
4
4
  module Process
5
5
 
6
+ # Expands accessors.
7
+ #
8
+ # Looks up configs with @accessor tag (or configs defined inside
9
+ # config: {} or eventedConfig: {} block).
10
+ #
11
+ # For such config "foo" it generates:
12
+ #
13
+ # - getter "getFoo"
14
+ # - setter "setFoo"
15
+ # - event "foochange" (when tagged with @evented)
16
+ #
6
17
  class Accessors
7
18
  def initialize(classes)
8
19
  @classes = classes
@@ -13,6 +24,8 @@ module JsDuck
13
24
  @classes.each_value {|cls| process(cls) }
14
25
  end
15
26
 
27
+ private
28
+
16
29
  # Given a class, generates accessor methods to configs with
17
30
  # @accessor tag. Modifies the class by adding these methods.
18
31
  # When class already contains a getter or setter, the method is
@@ -113,15 +126,15 @@ module JsDuck
113
126
  }, cfg)
114
127
  end
115
128
 
129
+ # Copy over from @cfg all the fields that aren't already present.
130
+ # Except :type and :default which don't make sense for methods and events.
116
131
  def add_shared(hash, cfg)
117
- hash.merge!({
118
- :owner => cfg[:owner],
119
- :files => cfg[:files],
120
- :private => cfg[:private],
121
- :protected => cfg[:protected],
122
- :autodetected => cfg[:autodetected],
123
- :hide => cfg[:hide],
124
- })
132
+ ignored_fields = [:type, :default, :accessor, :evented]
133
+
134
+ cfg.each_pair do |key, value|
135
+ hash[key] = value unless ignored_fields.include?(key) || hash[key]
136
+ end
137
+ hash
125
138
  end
126
139
 
127
140
  def upcase_first(str)
@@ -60,8 +60,7 @@ module JsDuck
60
60
  if m[:tagname] == :property
61
61
  false
62
62
  else
63
- f = m[:files][0]
64
- Logger.warn(:enum, "Enums can only contain properties, #{m[:tagname]} found instead.", f[:filename], f[:linenr])
63
+ Logger.warn(:enum, "Enums can only contain properties, #{m[:tagname]} found instead.", m[:files][0])
65
64
  true
66
65
  end
67
66
  end
@@ -71,7 +70,7 @@ module JsDuck
71
70
  # values default to being public.
72
71
  def strip_inheritdoc(cls)
73
72
  cls[:members].each do |p|
74
- p[:inheritdoc] = nil if p[:autodetected]
73
+ p[:inheritdoc] = nil if p[:autodetected] && p[:autodetected][:tagname]
75
74
  end
76
75
  end
77
76
 
@@ -34,7 +34,8 @@ module JsDuck
34
34
  :tagname => :params,
35
35
  :name => "eOpts",
36
36
  :type => "Object",
37
- :doc => "The options object passed to {@link Ext.util.Observable#addListener}."
37
+ :doc => "The options object passed to {@link Ext.util.Observable#addListener}.",
38
+ :ext4_auto_param => true,
38
39
  }
39
40
 
40
41
  end
@@ -21,8 +21,7 @@ module JsDuck
21
21
  @classes_hash["global"][:members].each do |m|
22
22
  type = m[:tagname].to_s
23
23
  name = m[:name]
24
- file = m[:files][0]
25
- Logger.warn(:global, "Global #{type}: #{name}", file[:filename], file[:linenr])
24
+ Logger.warn(:global, "Global #{type}: #{name}", m[:files][0])
26
25
  end
27
26
 
28
27
  # Throw away the "global" class when --ignore-global option used
@@ -42,12 +42,8 @@ module JsDuck
42
42
  # creates index of all class members
43
43
  def members_id_index(json)
44
44
  index = {}
45
- ["members", "statics"].each do |group_name|
46
- json[group_name].each_pair do |tagname, members|
47
- members.each do |m|
48
- index[m["id"]] = true
49
- end
50
- end
45
+ json["members"].each do |m|
46
+ index[m["id"]] = true
51
47
  end
52
48
  index
53
49
  end
@@ -0,0 +1,58 @@
1
+ require 'jsduck/logger'
2
+
3
+ module JsDuck
4
+ module Process
5
+
6
+ # Deals with inheriting class documentation.
7
+ class InheritClass
8
+ def initialize(relations)
9
+ @relations = relations
10
+ end
11
+
12
+ # Inherits docs for class.
13
+ #
14
+ # For class we only inherit the value of :doc field.
15
+ #
16
+ # When the class we're inheriting from also has @inheritdoc tag,
17
+ # we first recursively resolve the inheritance of that class and
18
+ # only afterwards inherit to the current class.
19
+ def resolve(cls)
20
+ return unless cls[:inheritdoc]
21
+
22
+ parent = find_parent(cls)
23
+ if parent && parent[:inheritdoc]
24
+ resolve(parent)
25
+ end
26
+
27
+ if parent
28
+ cls[:doc] = parent[:doc] if cls[:doc].empty?
29
+ end
30
+
31
+ cls[:inheritdoc] = nil
32
+ end
33
+
34
+ private
35
+
36
+ def find_parent(cls)
37
+ if cls[:inheritdoc][:cls]
38
+ # @inheritdoc MyClass
39
+ parent = @relations[cls[:inheritdoc][:cls]]
40
+ return warn("class not found", cls) unless parent
41
+ else
42
+ # @inheritdoc
43
+ parent = cls.parent
44
+ return warn("parent class not found", cls) unless parent
45
+ end
46
+
47
+ return parent
48
+ end
49
+
50
+ def warn(msg, cls)
51
+ Logger.warn(:inheritdoc, "@inheritdoc #{cls[:inheritdoc][:cls]} - #{msg}", cls[:files][0])
52
+ return nil
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+ end
@@ -1,5 +1,7 @@
1
1
  require 'jsduck/logger'
2
2
  require 'jsduck/class'
3
+ require 'jsduck/process/inherit_class'
4
+ require 'jsduck/process/inherit_members'
3
5
 
4
6
  module JsDuck
5
7
  module Process
@@ -8,189 +10,18 @@ module JsDuck
8
10
  class InheritDoc
9
11
  def initialize(relations)
10
12
  @relations = relations
13
+ @inherit_class = InheritClass.new(@relations)
14
+ @inherit_members = InheritMembers.new(@relations)
11
15
  end
12
16
 
13
17
  # Performs all inheriting
14
18
  def process_all!
15
19
  @relations.each do |cls|
16
- resolve_class(cls) if cls[:inheritdoc]
17
-
18
- new_cfgs = []
19
- cls.all_local_members.each do |member|
20
- if member[:inheritdoc]
21
- resolve(member, new_cfgs)
22
- end
23
- end
24
- move_cfgs(cls, new_cfgs) if new_cfgs.length > 0
25
- end
26
- end
27
-
28
- private
29
-
30
- # Copy over doc/params/return from parent member.
31
- def resolve(m, new_cfgs)
32
- parent = find_parent(m)
33
-
34
- if m[:inheritdoc] && parent
35
- m[:doc] = (m[:doc] + "\n\n" + parent[:doc]).strip
36
- m[:params] = parent[:params] if parent[:params]
37
- m[:return] = parent[:return] if parent[:return]
38
- m[:type] = parent[:type] if parent[:type]
39
-
40
- if m[:autodetected]
41
- m[:deprecated] = parent[:deprecated] if parent[:deprecated] && !m[:deprecated]
42
- end
43
-
44
- # remember properties that have changed to configs
45
- if m[:autodetected] && m[:tagname] != parent[:tagname]
46
- new_cfgs << m
47
- end
48
- end
49
-
50
- resolve_visibility(m, parent)
51
- end
52
-
53
- # Changes given properties into configs within class
54
- def move_cfgs(cls, members)
55
- members.each do |m|
56
- m[:tagname] = :cfg
57
- end
58
- # Ask class to update its internal caches for these members
59
- cls.update_members!(members)
60
- end
61
-
62
- # For auto-detected members/classes (which have @private == :inherit)
63
- # Use the visibility from parent class (defaulting to private when no parent).
64
- def resolve_visibility(m, parent)
65
- if m[:autodetected] && !JsDuck::Class.constructor?(m)
66
- if !parent || parent[:private]
67
- m[:private] = true
68
- end
69
-
70
- m[:protected] = true if parent && parent[:protected]
71
- end
72
- end
73
-
74
- # Finds parent member of the given member. When @inheritdoc names
75
- # a member to inherit from, finds that member instead.
76
- #
77
- # If the parent also has @inheritdoc, continues recursively.
78
- def find_parent(m)
79
-
80
- inherit = m[:inheritdoc] || {}
81
- if inherit[:cls]
82
- # @inheritdoc MyClass#member
83
- parent_cls = @relations[m[:inheritdoc][:cls]]
84
- return warn("class not found", m) unless parent_cls
85
-
86
- parent = lookup_member(parent_cls, m)
87
- return warn("member not found", m) unless parent
88
-
89
- elsif inherit[:member]
90
- # @inheritdoc #member
91
- parent = lookup_member(@relations[m[:owner]], m)
92
- return warn("member not found", m) unless parent
93
-
94
- else
95
- # @inheritdoc
96
- parent_cls = @relations[m[:owner]].parent
97
- mixins = @relations[m[:owner]].mixins
98
-
99
- # Warn when no parent or mixins at all
100
- if !parent_cls && mixins.length == 0
101
- warn("parent class not found", m) unless m[:autodetected]
102
- return nil
103
- end
104
-
105
- # First check for the member in all mixins, because members
106
- # from mixins override those from parent class. Looking first
107
- # from mixins is probably a bit slower, but it's the correct
108
- # order to do things.
109
- if mixins.length > 0
110
- parent = mixins.map {|mix| lookup_member(mix, m) }.compact.first
111
- end
112
-
113
- # When not found, try looking from parent class
114
- if !parent && parent_cls
115
- parent = lookup_member(parent_cls, m)
116
- end
117
-
118
- # Only when both parent and mixins fail, throw warning
119
- if !parent
120
- warn("parent member not found", m) unless m[:autodetected]
121
- return nil
122
- end
123
- end
124
-
125
- return parent[:inheritdoc] ? find_parent(parent) : parent
126
- end
127
-
128
- def lookup_member(cls, m)
129
- inherit = m[:inheritdoc] || {}
130
- name = inherit[:member] || m[:name]
131
- tagname = inherit[:type] || m[:tagname]
132
- static = inherit[:static] || m[:static]
133
-
134
- if m[:autodetected]
135
- # Auto-detected properties can override either a property or a
136
- # config. So look for both types.
137
- if tagname == :property
138
- cfg = cls.find_members(:name => name, :tagname => :cfg, :static => static || false)[0]
139
- prop = cls.find_members(:name => name, :tagname => :property, :static => static || false)[0]
140
-
141
- if cfg && prop
142
- prop
143
- elsif cfg
144
- cfg
145
- elsif prop
146
- prop
147
- else
148
- nil
149
- end
150
-
151
- else
152
- # Unless the auto-detected member is detected as static,
153
- # look only at instance members.
154
- cls.find_members(:name => name, :tagname => tagname, :static => static || false)[0]
155
- end
156
- else
157
- cls.find_members(:name => name, :tagname => tagname, :static => static)[0]
20
+ @inherit_class.resolve(cls)
21
+ @inherit_members.resolve(cls)
158
22
  end
159
23
  end
160
24
 
161
- # Copy over doc from parent class.
162
- def resolve_class(cls)
163
- parent = find_class_parent(cls)
164
-
165
- if parent
166
- cls[:doc] = (cls[:doc] + "\n\n" + parent[:doc]).strip
167
- end
168
- end
169
-
170
- def find_class_parent(cls)
171
- if cls[:inheritdoc][:cls]
172
- # @inheritdoc MyClass
173
- parent = @relations[cls[:inheritdoc][:cls]]
174
- return warn("class not found", cls) unless parent
175
- else
176
- # @inheritdoc
177
- parent = cls.parent
178
- return warn("parent class not found", cls) unless parent
179
- end
180
-
181
- return parent[:inheritdoc] ? find_class_parent(parent) : parent
182
- end
183
-
184
- def warn(msg, item)
185
- context = item[:files][0]
186
- i_member = item[:inheritdoc][:member]
187
-
188
- msg = "@inheritdoc #{item[:inheritdoc][:cls]}"+ (i_member ? "#" + i_member : "") + " - " + msg
189
- Logger.warn(:inheritdoc, msg, context[:filename], context[:linenr])
190
-
191
- return nil
192
- end
193
-
194
25
  end
195
26
 
196
27
  end
@@ -0,0 +1,257 @@
1
+ require 'jsduck/logger'
2
+ require 'jsduck/class'
3
+
4
+ module JsDuck
5
+ module Process
6
+
7
+ # Deals with inheriting member documentation.
8
+ class InheritMembers
9
+ def initialize(relations)
10
+ @relations = relations
11
+ end
12
+
13
+ # Inherits docs for all members in class.
14
+ #
15
+ # In case of members with explicit @inheritdoc tags we inherit
16
+ # the following fields when they're not empty in current member:
17
+ #
18
+ # - :doc
19
+ # - :params
20
+ # - :return
21
+ # - :throws
22
+ #
23
+ # In case of auto-detected members that inherit from a public
24
+ # member in parent class, we inherit all fields that aren't
25
+ # present in current member, plus the :type field.
26
+ #
27
+ # Auto-detected members inheriting from other private
28
+ # auto-detected members follow the same rules of inheritance as
29
+ # members with explicit @inheritdoc.
30
+ #
31
+ # Additionally auto-detected properties get turned into configs
32
+ # when a public configs with same name is detected in parent
33
+ # class.
34
+ #
35
+ def resolve(cls)
36
+ new_cfgs = []
37
+
38
+ cls.all_local_members.each do |member|
39
+ if member[:inheritdoc]
40
+ resolve_member(cls, member, new_cfgs)
41
+ end
42
+ end
43
+
44
+ move_cfgs(cls, new_cfgs) if new_cfgs.length > 0
45
+ end
46
+
47
+ private
48
+
49
+ def resolve_member(cls, m, new_cfgs)
50
+ parent = find_parent(m)
51
+ if parent && parent[:inheritdoc]
52
+ resolve_parent(cls, parent)
53
+ end
54
+
55
+ if m[:inheritdoc] && parent
56
+ if autodetected?(m) && !parent[:private]
57
+ auto_inherit(m, parent)
58
+ else
59
+ inherit(m, parent)
60
+ end
61
+
62
+ # remember properties that have changed to configs
63
+ if autodetected?(m) && m[:tagname] != parent[:tagname]
64
+ new_cfgs << m
65
+ end
66
+ end
67
+
68
+ resolve_visibility(m, parent)
69
+
70
+ m[:inheritdoc] = nil
71
+ end
72
+
73
+ def resolve_parent(cls, parent)
74
+ new_cfgs = []
75
+ resolve_member(cls, parent, new_cfgs)
76
+ move_cfgs(cls, new_cfgs) if new_cfgs.length > 0
77
+ end
78
+
79
+ def inherit(m, parent)
80
+ m[:doc] = parent[:doc] if m[:doc].empty?
81
+
82
+ m[:params] = parent[:params] if inherit_params?(m, parent)
83
+ m[:return] = parent[:return] unless m[:return]
84
+ m[:throws] = parent[:throws] unless m[:throws] && m[:throws].length > 0
85
+
86
+ # Don't inherit type from parent when:
87
+ # - member itself has type and it's not auto-detected
88
+ # - or the type in parent is auto-detected.
89
+ unless m[:type] && m[:type] != "Object" && !auto?(m, :type) || auto?(parent, :type)
90
+ m[:type] = parent[:type]
91
+ end
92
+ end
93
+
94
+ def inherit_params?(m, parent)
95
+ # ignore the auto-inserted param of Ext4-style events
96
+ params = (m[:params] || []).reject {|p| p[:ext4_auto_param] }
97
+
98
+ if params.length > 0 && !auto?(m, :params)
99
+ # member itself has params and these are not auto-detected
100
+ false
101
+ elsif auto?(parent, :params)
102
+ # Params in parent are auto-detected.
103
+ false
104
+ else
105
+ true
106
+ end
107
+ end
108
+
109
+ def auto_inherit(m, parent)
110
+ m[:doc] = parent[:doc] if m[:doc].empty?
111
+
112
+ parent.each_pair do |key, value|
113
+ if key == :type || !m[key]
114
+ m[key] = value
115
+ end
116
+ end
117
+ end
118
+
119
+ # True when specific field of member has been auto-detected
120
+ def auto?(m, key)
121
+ m[:autodetected] && m[:autodetected][key]
122
+ end
123
+
124
+ # Changes given properties into configs within class
125
+ def move_cfgs(cls, members)
126
+ members.each do |m|
127
+ m[:tagname] = :cfg
128
+ end
129
+ # Ask class to update its internal caches for these members
130
+ cls.update_members!(members)
131
+ end
132
+
133
+ # For auto-detected members/classes (which have @private == :inherit)
134
+ # Use the visibility from parent class (defaulting to private when no parent).
135
+ def resolve_visibility(m, parent)
136
+ if autodetected?(m) && !JsDuck::Class.constructor?(m)
137
+ if !parent || parent[:private]
138
+ m[:private] = true
139
+ end
140
+
141
+ m[:protected] = true if parent && parent[:protected]
142
+ end
143
+ end
144
+
145
+ # Finds parent member of the given member. When @inheritdoc names
146
+ # a member to inherit from, finds that member instead.
147
+ #
148
+ # If the parent also has @inheritdoc, continues recursively.
149
+ def find_parent(m)
150
+
151
+ inherit = m[:inheritdoc] || {}
152
+ if inherit[:cls]
153
+ # @inheritdoc MyClass#member
154
+ parent_cls = @relations[m[:inheritdoc][:cls]]
155
+ return warn("class not found", m) unless parent_cls
156
+
157
+ parent = lookup_member(parent_cls, m)
158
+ return warn("member not found", m) unless parent
159
+
160
+ elsif inherit[:member]
161
+ # @inheritdoc #member
162
+ parent = lookup_member(@relations[m[:owner]], m)
163
+ return warn("member not found", m) unless parent
164
+
165
+ else
166
+ # @inheritdoc
167
+ parent_cls = @relations[m[:owner]].parent
168
+ mixins = @relations[m[:owner]].mixins
169
+
170
+ # Warn when no parent or mixins at all
171
+ if !parent_cls && mixins.length == 0
172
+ warn("parent class not found", m) unless autodetected?(m)
173
+ return nil
174
+ end
175
+
176
+ # First check for the member in all mixins, because members
177
+ # from mixins override those from parent class. Looking first
178
+ # from mixins is probably a bit slower, but it's the correct
179
+ # order to do things.
180
+ if mixins.length > 0
181
+ parent = mixins.map {|mix| lookup_member(mix, m) }.compact.first
182
+ end
183
+
184
+ # When not found, try looking from parent class
185
+ if !parent && parent_cls
186
+ parent = lookup_member(parent_cls, m)
187
+ end
188
+
189
+ # Only when both parent and mixins fail, throw warning
190
+ if !parent
191
+ warn("parent member not found", m) unless autodetected?(m)
192
+ return nil
193
+ end
194
+ end
195
+
196
+ return parent
197
+ end
198
+
199
+ def lookup_member(cls, m)
200
+ inherit = m[:inheritdoc] || {}
201
+ name = inherit[:member] || m[:name]
202
+ tagname = inherit[:type] || m[:tagname]
203
+ # When not explicitly inheriting from static member
204
+ # and the member itself is not static,
205
+ # inherit from instance member.
206
+ static = inherit[:static] || m[:static] || false
207
+
208
+ if autodetected?(m)
209
+ # Auto-detected properties can override either a property or a
210
+ # config. So look for both types.
211
+ if tagname == :property
212
+ cfg = cls.find_members(:name => name, :tagname => :cfg, :static => static)[0]
213
+ prop = cls.find_members(:name => name, :tagname => :property, :static => static)[0]
214
+
215
+ if cfg && prop
216
+ prop
217
+ elsif cfg
218
+ cfg
219
+ elsif prop
220
+ prop
221
+ else
222
+ nil
223
+ end
224
+
225
+ else
226
+ cls.find_members(:name => name, :tagname => tagname, :static => static)[0]
227
+ end
228
+ else
229
+ m = cls.find_members(:name => name, :tagname => tagname, :static => static)[0]
230
+ # When member was not found with explicit staticality and
231
+ # the @inheritdoc tag contained no explicit "static", then
232
+ # look for both static and instance members.
233
+ if !m && !inherit[:static]
234
+ m = cls.find_members(:name => name, :tagname => tagname, :static => nil)[0]
235
+ end
236
+ m
237
+ end
238
+ end
239
+
240
+ # True when the entire member was auto-detected
241
+ def autodetected?(m)
242
+ m[:autodetected] && m[:autodetected][:tagname]
243
+ end
244
+
245
+ def warn(msg, m)
246
+ inh_member = m[:inheritdoc][:member]
247
+ inh_target = (m[:inheritdoc][:cls] || "") + (inh_member ? "#" + inh_member : "")
248
+
249
+ Logger.warn(:inheritdoc, "@inheritdoc #{inh_target} - #{msg}", m[:files][0])
250
+
251
+ return nil
252
+ end
253
+
254
+ end
255
+
256
+ end
257
+ end