yard 0.4.0 → 0.5.0

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 (121) hide show
  1. data/ChangeLog +585 -1
  2. data/README.md +10 -2
  3. data/benchmarks/yri_cache.rb +19 -0
  4. data/bin/yri +1 -26
  5. data/docs/WhatsNew.md +99 -0
  6. data/lib/rubygems_plugin.rb +2 -0
  7. data/lib/yard.rb +2 -2
  8. data/lib/yard/autoload.rb +9 -4
  9. data/lib/yard/cli/base.rb +26 -0
  10. data/lib/yard/cli/yard_graph.rb +2 -9
  11. data/lib/yard/cli/yardoc.rb +93 -33
  12. data/lib/yard/cli/yri.rb +128 -0
  13. data/lib/yard/code_objects/base.rb +16 -5
  14. data/lib/yard/code_objects/class_object.rb +11 -4
  15. data/lib/yard/code_objects/method_object.rb +11 -1
  16. data/lib/yard/code_objects/proxy.rb +5 -2
  17. data/lib/yard/code_objects/root_object.rb +1 -0
  18. data/lib/yard/core_ext/file.rb +1 -1
  19. data/lib/yard/core_ext/hash.rb +15 -0
  20. data/lib/yard/core_ext/module.rb +2 -2
  21. data/lib/yard/core_ext/string.rb +66 -0
  22. data/lib/yard/core_ext/symbol_hash.rb +1 -1
  23. data/lib/yard/docstring.rb +5 -5
  24. data/lib/yard/handlers/base.rb +10 -4
  25. data/lib/yard/handlers/processor.rb +3 -4
  26. data/lib/yard/handlers/ruby/attribute_handler.rb +3 -2
  27. data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +2 -2
  28. data/lib/yard/handlers/ruby/legacy/method_handler.rb +7 -1
  29. data/lib/yard/handlers/ruby/method_handler.rb +7 -1
  30. data/lib/yard/logging.rb +11 -1
  31. data/lib/yard/parser/c_parser.rb +407 -0
  32. data/lib/yard/parser/ruby/ast_node.rb +2 -2
  33. data/lib/yard/parser/ruby/legacy/ruby_lex.rb +3 -4
  34. data/lib/yard/parser/source_parser.rb +18 -7
  35. data/lib/yard/rake/yardoc_task.rb +1 -1
  36. data/lib/yard/registry.rb +83 -29
  37. data/lib/yard/registry_store.rb +213 -0
  38. data/lib/yard/serializers/base.rb +1 -1
  39. data/lib/yard/serializers/yardoc_serializer.rb +113 -0
  40. data/lib/yard/tags/library.rb +4 -0
  41. data/lib/yard/tags/overload_tag.rb +16 -5
  42. data/lib/yard/tags/tag.rb +1 -2
  43. data/lib/yard/templates/engine.rb +3 -3
  44. data/lib/yard/templates/helpers/html_helper.rb +50 -16
  45. data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +1 -3
  46. data/lib/yard/templates/helpers/html_syntax_highlight_helper18.rb +1 -3
  47. data/lib/yard/templates/helpers/method_helper.rb +11 -4
  48. data/lib/yard/templates/helpers/text_helper.rb +24 -2
  49. data/lib/yard/verifier.rb +3 -3
  50. data/spec/cli/yardoc_spec.rb +33 -6
  51. data/spec/cli/yri_spec.rb +30 -0
  52. data/spec/code_objects/base_spec.rb +7 -0
  53. data/spec/code_objects/class_object_spec.rb +6 -1
  54. data/spec/code_objects/method_object_spec.rb +25 -0
  55. data/spec/core_ext/hash_spec.rb +10 -0
  56. data/spec/core_ext/module_spec.rb +1 -1
  57. data/spec/core_ext/string_spec.rb +50 -12
  58. data/spec/handlers/attribute_handler_spec.rb +4 -0
  59. data/spec/handlers/examples/method_handler_001.rb.txt +9 -0
  60. data/spec/handlers/method_handler_spec.rb +22 -4
  61. data/spec/parser/c_parser_spec.rb +22 -0
  62. data/spec/parser/examples/array.c.txt +3887 -0
  63. data/spec/parser/source_parser_spec.rb +29 -7
  64. data/spec/registry_spec.rb +93 -72
  65. data/spec/registry_store_spec.rb +184 -0
  66. data/spec/serializers/file_system_serializer_spec.rb +96 -75
  67. data/spec/spec_helper.rb +2 -2
  68. data/spec/tags/overload_tag_spec.rb +18 -0
  69. data/spec/templates/examples/class001.html +32 -30
  70. data/spec/templates/examples/method001.html +4 -1
  71. data/spec/templates/examples/method002.html +7 -2
  72. data/spec/templates/examples/method002.txt +1 -1
  73. data/spec/templates/examples/method003.html +30 -8
  74. data/spec/templates/examples/method003.txt +4 -4
  75. data/spec/templates/examples/method004.html +44 -0
  76. data/spec/templates/examples/method004.txt +10 -0
  77. data/spec/templates/examples/method005.html +99 -0
  78. data/spec/templates/examples/method005.txt +33 -0
  79. data/spec/templates/examples/module001.dot +1 -1
  80. data/spec/templates/examples/module001.html +391 -37
  81. data/spec/templates/examples/module001.txt +1 -1
  82. data/spec/templates/helpers/base_helper_spec.rb +2 -2
  83. data/spec/templates/helpers/html_helper_spec.rb +83 -0
  84. data/spec/templates/helpers/method_helper_spec.rb +47 -0
  85. data/spec/templates/helpers/shared_signature_examples.rb +102 -0
  86. data/spec/templates/helpers/text_helper_spec.rb +31 -0
  87. data/spec/templates/method_spec.rb +43 -18
  88. data/spec/templates/module_spec.rb +22 -1
  89. data/spec/templates/spec_helper.rb +10 -1
  90. data/spec/yard_spec.rb +4 -3
  91. data/templates/default/class/html/constructor_details.erb +1 -1
  92. data/templates/default/docstring/html/returns_void.erb +1 -0
  93. data/templates/default/docstring/setup.rb +9 -4
  94. data/templates/default/docstring/text/returns_void.erb +1 -0
  95. data/templates/default/fulldoc/html/css/style.css +4 -2
  96. data/templates/default/fulldoc/html/full_list.erb +2 -2
  97. data/templates/default/fulldoc/html/js/app.js +1 -1
  98. data/templates/default/fulldoc/html/setup.rb +14 -6
  99. data/templates/default/layout/dot/setup.rb +1 -1
  100. data/templates/default/layout/html/breadcrumb.erb +2 -2
  101. data/templates/default/layout/html/index.erb +2 -2
  102. data/templates/default/layout/html/setup.rb +5 -5
  103. data/templates/default/method/html/header.erb +6 -4
  104. data/templates/default/method_details/html/method_signature.erb +2 -1
  105. data/templates/default/method_details/html/source.erb +1 -1
  106. data/templates/default/method_details/setup.rb +2 -1
  107. data/templates/default/method_details/text/setup.rb +1 -1
  108. data/templates/default/module/html/attribute_details.erb +4 -4
  109. data/templates/default/module/html/attribute_summary.erb +3 -3
  110. data/templates/default/module/html/box_info.erb +2 -2
  111. data/templates/default/module/html/defines.erb +1 -1
  112. data/templates/default/module/html/inherited_constants.erb +1 -1
  113. data/templates/default/module/html/inherited_methods.erb +1 -1
  114. data/templates/default/module/html/item_summary.erb +13 -4
  115. data/templates/default/module/html/method_details_list.erb +5 -4
  116. data/templates/default/module/html/method_summary.erb +5 -4
  117. data/templates/default/module/html/methodmissing.erb +1 -1
  118. data/templates/default/module/setup.rb +14 -5
  119. data/templates/default/tags/html/overload.erb +3 -2
  120. data/templates/default/tags/setup.rb +4 -0
  121. metadata +23 -2
@@ -261,7 +261,7 @@ module YARD
261
261
  #
262
262
  # @yield each descendent node in order
263
263
  # @yieldparam [AstNode] self, or a child/descendent node
264
- # @return [nil]
264
+ # @return [void]
265
265
  def traverse
266
266
  nodes = [self]
267
267
  nodes.each.with_index do |node, index|
@@ -273,7 +273,7 @@ module YARD
273
273
  private
274
274
 
275
275
  # Resets line information
276
- # @return [nil]
276
+ # @return [void]
277
277
  def reset_line_info
278
278
  if size == 0
279
279
  self.line_range = @fallback_line
@@ -14,7 +14,6 @@ module YARD
14
14
 
15
15
  class Token
16
16
  NO_TEXT = "??".freeze
17
- attr :text
18
17
 
19
18
  def initialize(line_no, char_no)
20
19
  @line_no = line_no
@@ -457,9 +456,9 @@ module YARD
457
456
  @exception_on_syntax_error = true
458
457
  end
459
458
 
460
- attr :skip_space, true
461
- attr :read_auto_clean_up, true
462
- attr :exception_on_syntax_error, true
459
+ attr_accessor :skip_space
460
+ attr_accessor :read_auto_clean_up
461
+ attr_accessor :exception_on_syntax_error
463
462
 
464
463
  attr :indent
465
464
 
@@ -32,11 +32,12 @@ module YARD
32
32
  #
33
33
  # @return [Symbol] the parser type
34
34
  attr_accessor :parser_type
35
+ undef parser_type=
35
36
 
36
37
  # Sets the parser and makes sure it's a valid type
37
38
  #
38
39
  # @param [Symbol] value the new parser type
39
- # @return [nil]
40
+ # @return [void]
40
41
  def parser_type=(value)
41
42
  @parser_type = validated_parser_type(value)
42
43
  end
@@ -48,9 +49,12 @@ module YARD
48
49
  # @param [Fixnum] level the logger level to use during parsing. See
49
50
  # {YARD::Logger}
50
51
  # @return the parser object that was used to parse the source.
51
- def parse(paths = "lib/**/*.rb", level = log.level)
52
+ def parse(paths = ["lib/**/*.rb", "ext/**/*.c"], level = log.level)
52
53
  log.debug("Parsing #{paths} with `#{parser_type}` parser")
53
- files = [paths].flatten.map {|p| p.include?("*") ? Dir[p] : p }.flatten
54
+ files = [paths].flatten.
55
+ map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c}" : p }.
56
+ map {|p| p.include?("*") ? Dir[p] : p }.flatten.
57
+ reject {|p| !File.file?(p) }
54
58
 
55
59
  log.enter_level(level) do
56
60
  parse_in_order(*files.uniq)
@@ -91,7 +95,7 @@ module YARD
91
95
  # that can continue processing the file.
92
96
  #
93
97
  # @param [Array<String>] files a list of files to queue for parsing
94
- # @return [nil]
98
+ # @return [void]
95
99
  def parse_in_order(*files)
96
100
  files = files.sort_by {|x| x.length if x }
97
101
  while file = files.shift
@@ -134,12 +138,18 @@ module YARD
134
138
  # use the class methods {parse} and {parse_string}.
135
139
  #
136
140
  # @param [String, #read, Object] content the source file to parse
137
- # @return the parser object used to parse the source
141
+ # @return [Object, nil] the parser object used to parse the source
138
142
  def parse(content = __FILE__)
139
143
  case content
140
144
  when String
141
145
  @file = content
142
146
  content = IO.read(content)
147
+ checksum = Registry.checksum_for(content)
148
+ if Registry.checksums[file] == checksum
149
+ log.info "File '#{file}' hasn't changed, skipping..."
150
+ return
151
+ end
152
+ Registry.checksums[@file] = checksum
143
153
  self.parser_type = parser_type_for_filename(file)
144
154
  else
145
155
  content = content.read if content.respond_to? :read
@@ -174,8 +184,9 @@ module YARD
174
184
  private
175
185
 
176
186
  # Runs a {Handlers::Processor} object to post process the parsed statements.
177
- # @return [nil]
187
+ # @return [void]
178
188
  def post_process
189
+ return unless @parser.respond_to? :enumerator
179
190
  post = Handlers::Processor.new(@file, @load_order_errors, @parser_type)
180
191
  post.process(@parser.enumerator)
181
192
  end
@@ -204,7 +215,7 @@ module YARD
204
215
  def parse_statements(content)
205
216
  case parser_type
206
217
  when :c
207
- raise NotImplementedError, "no support for C/C++ files"
218
+ CParser.new(content, file).parse
208
219
  when :ruby18
209
220
  Ruby::Legacy::StatementList.new(content)
210
221
  when :ruby
@@ -54,7 +54,7 @@ module YARD
54
54
  protected
55
55
 
56
56
  # Defines the rake task
57
- # @return [nil]
57
+ # @return [void]
58
58
  def define
59
59
  desc "Generate YARD Documentation"
60
60
  task(name) do
data/lib/yard/registry.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'singleton'
2
- require 'find'
2
+ require 'fileutils'
3
+ require 'digest/sha1'
3
4
 
4
5
  module YARD
5
6
  # The +Registry+ is the centralized data store for all {CodeObjects} created
@@ -16,6 +17,7 @@ module YARD
16
17
  # delegated to the instance.
17
18
  class Registry
18
19
  DEFAULT_YARDOC_FILE = ".yardoc"
20
+ LOCAL_YARDOC_INDEX = File.expand_path('~/.yard/gem_index')
19
21
 
20
22
  include Singleton
21
23
 
@@ -28,11 +30,57 @@ module YARD
28
30
  attr_reader :objects
29
31
 
30
32
  # Clears the registry and cache
31
- # @return [nil]
33
+ # @return [void]
32
34
  def clear
33
35
  instance.clear
34
36
  objects.clear
35
37
  end
38
+
39
+ # Returns the .yardoc file associated with a gem.
40
+ #
41
+ # @param [String] gem the name of the gem to search for
42
+ # @param [String] ver_require an optional Gem version requirement
43
+ # @param [Boolean] for_writing whether or not the method should search
44
+ # for writable locations
45
+ # @return [String] if +for_writing+ is set to +true+, returns the best
46
+ # location suitable to write the .yardoc file. Otherwise, the first
47
+ # existing location associated with the gem's .yardoc file.
48
+ # @return [nil] if +for_writing+ is set to false and no yardoc file
49
+ # is found, returns nil.
50
+ def yardoc_file_for_gem(gem, ver_require = ">= 0", for_writing = false)
51
+ spec = Gem.source_index.find_name(gem, ver_require).first
52
+
53
+ if for_writing
54
+ global_yardoc_file(spec, for_writing) ||
55
+ local_yardoc_file(spec, for_writing)
56
+ else
57
+ local_yardoc_file(spec, for_writing) ||
58
+ global_yardoc_file(spec, for_writing)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def global_yardoc_file(spec, for_writing = false)
65
+ path = spec.full_gem_path
66
+ yfile = File.join(path, DEFAULT_YARDOC_FILE)
67
+ if for_writing && File.writable?(path)
68
+ return yfile
69
+ elsif !for_writing && File.exist?(yfile)
70
+ return yfile
71
+ end
72
+ end
73
+
74
+ def local_yardoc_file(spec, for_writing = false)
75
+ path = Registry::LOCAL_YARDOC_INDEX
76
+ FileUtils.mkdir_p(path) if for_writing
77
+ path = File.join(path, "#{spec.full_name}.yardoc")
78
+ if for_writing
79
+ path
80
+ else
81
+ File.exist?(path) ? path : nil
82
+ end
83
+ end
36
84
  end
37
85
 
38
86
  # Gets/sets the yardoc filename
@@ -42,7 +90,9 @@ module YARD
42
90
 
43
91
  # The assumed types of a list of paths
44
92
  # @return [{String => Symbol}] a set of unresolved paths and their assumed type
45
- attr_reader :proxy_types
93
+ def proxy_types
94
+ @store.proxy_types
95
+ end
46
96
 
47
97
  # Loads the registry and/or parses a list of files
48
98
  #
@@ -64,9 +114,9 @@ module YARD
64
114
  if File.exists?(yardoc_file) && !reload
65
115
  load_yardoc
66
116
  else
67
- size = namespace.size
117
+ size = @store.keys.size
68
118
  YARD.parse(files)
69
- save if namespace.size > size
119
+ save if @store.keys.size > size
70
120
  end
71
121
  true
72
122
  elsif files.is_a?(String)
@@ -80,21 +130,30 @@ module YARD
80
130
  # Loads a yardoc file directly
81
131
  #
82
132
  # @param [String] file the yardoc file to load.
83
- # @return [nil]
133
+ # @return [void]
84
134
  def load_yardoc(file = yardoc_file)
85
- return false unless File.exists?(file)
86
- ns, pt = *Marshal.load(IO.read(file))
87
- namespace.update(ns)
88
- proxy_types.update(pt)
135
+ clear
136
+ @store.load(file)
89
137
  end
90
138
 
91
139
  # Saves the registry to +file+
92
140
  #
93
141
  # @param [String] file the yardoc file to save to
94
142
  # @return [Boolean] true if the file was saved
95
- def save(file = yardoc_file)
96
- File.open(file, "wb") {|f| Marshal.dump([@namespace, @proxy_types], f) }
97
- true
143
+ def save(merge = false, file = yardoc_file)
144
+ @store.save(merge, file)
145
+ end
146
+
147
+ def checksums
148
+ @store.checksums
149
+ end
150
+
151
+ def checksum_for(data)
152
+ Digest::SHA1.hexdigest(data)
153
+ end
154
+
155
+ def delete_from_disk
156
+ @store.destroy
98
157
  end
99
158
 
100
159
  # Returns all objects in the registry that match one of the types provided
@@ -110,7 +169,7 @@ module YARD
110
169
  # @return [Array<CodeObjects::Base>] the list of objects found
111
170
  # @see CodeObjects::Base#type
112
171
  def all(*types)
113
- namespace.values.select do |obj|
172
+ @store.values.select do |obj|
114
173
  if types.empty?
115
174
  obj != root
116
175
  else
@@ -123,9 +182,10 @@ module YARD
123
182
  end
124
183
 
125
184
  # Returns the paths of all of the objects in the registry.
185
+ # @param [Boolean] reload whether to load entire database
126
186
  # @return [Array<String>] all of the paths in the registry.
127
- def paths
128
- namespace.keys.map {|k| k.to_s }
187
+ def paths(reload = true)
188
+ @store.keys(reload).map {|k| k.to_s }
129
189
  end
130
190
 
131
191
  # Returns the object at a specific path.
@@ -133,27 +193,25 @@ module YARD
133
193
  # returns the {#root} object.
134
194
  # @return [CodeObjects::Base] the object at path
135
195
  # @return [nil] if no object is found
136
- def at(path) path.to_s.empty? ? root : namespace[path] end
196
+ def at(path) @store[path] end
137
197
  alias_method :[], :at
138
198
 
139
199
  # The root namespace object.
140
200
  # @return [CodeObjects::RootObject] the root object in the namespace
141
- def root; namespace[:root] end
201
+ def root; @store[:root] end
142
202
 
143
203
  # Deletes an object from the registry
144
204
  # @param [CodeObjects::Base] object the object to remove
145
- # @return [nil]
205
+ # @return [void]
146
206
  def delete(object)
147
- namespace.delete(object.path)
207
+ @store.delete(object.path)
148
208
  self.class.objects.delete(object.path)
149
209
  end
150
210
 
151
211
  # Clears the registry
152
- # @return [nil]
212
+ # @return [void]
153
213
  def clear
154
- @namespace = SymbolHash.new
155
- @namespace[:root] = CodeObjects::RootObject.new(nil, :root)
156
- @proxy_types = {}
214
+ @store = RegistryStore.new
157
215
  end
158
216
 
159
217
  # Creates the Registry
@@ -170,7 +228,7 @@ module YARD
170
228
  def register(object)
171
229
  self.class.objects[object.path] = object
172
230
  return if object.is_a?(CodeObjects::Proxy)
173
- namespace[object.path] = object
231
+ @store[object.path] = object
174
232
  end
175
233
 
176
234
  # Attempts to find an object by name starting at +namespace+, performing
@@ -246,10 +304,6 @@ module YARD
246
304
  end
247
305
 
248
306
  private
249
-
250
- # The internal namespace hash
251
- # @return [Hash{String => CodeObjects::Base}] the path/object hash
252
- attr_accessor :namespace
253
307
 
254
308
  # Attempts to resolve a name in a namespace
255
309
  #
@@ -0,0 +1,213 @@
1
+ require 'fileutils'
2
+
3
+ module YARD
4
+ # The data store for the {Registry}.
5
+ #
6
+ # @see Registry
7
+ # @see Serializers::YardocSerializer
8
+ class RegistryStore
9
+ attr_reader :proxy_types, :file, :checksums
10
+
11
+ def initialize
12
+ @file = nil
13
+ @checksums = {}
14
+ @store = { :root => CodeObjects::RootObject.new(nil, :root) }
15
+ @proxy_types = {}
16
+ @loaded_objects = 0
17
+ @available_objects = 0
18
+ end
19
+
20
+ # Gets a {CodeObjects::Base} from the store
21
+ #
22
+ # @param [String, Symbol] key the path name of the object to look for.
23
+ # If it is empty or :root, returns the {#root} object.
24
+ # @return [CodeObjects::Base, nil] a code object or nil if none is found
25
+ def get(key)
26
+ key = :root if key == ''
27
+ key = key.to_sym
28
+ return @store[key] if @store[key]
29
+ return nil if @loaded_objects >= @available_objects
30
+
31
+ # check disk
32
+ if obj = @serializer.deserialize(key)
33
+ @loaded_objects += 1
34
+ put(key, obj)
35
+ end
36
+ end
37
+
38
+ # Associates an object with a path
39
+ # @param [String, Symbol] key the path name (:root or '' for root object)
40
+ # @param [CodeObjects::Base] value the object to store
41
+ # @return [CodeObjects::Base] returns +value+
42
+ def put(key, value)
43
+ if key == ''
44
+ @store[:root] = value
45
+ else
46
+ @store[key.to_sym] = value
47
+ end
48
+ end
49
+
50
+ alias [] get
51
+ alias []= put
52
+
53
+ def delete(key) @store.delete(key.to_sym) end
54
+
55
+ # Gets all path names from the store. Loads the entire database
56
+ # if +reload+ is +true+
57
+ #
58
+ # @param [Boolean] reload if false, does not load the entire database
59
+ # before a lookup.
60
+ # @return [Array<Symbol>] the path names of all the code objects
61
+ def keys(reload = true) load_all if reload; @store.keys end
62
+
63
+ # Gets all code objects from the store. Loads the entire database
64
+ # if +reload+ is +true+
65
+ #
66
+ # @param [Boolean] reload if false, does not load the entire database
67
+ # before a lookup.
68
+ # @return [Array<CodeObjects::Base>] all the code objects
69
+ def values(reload = true) load_all if reload; @store.values end
70
+
71
+ # @return [CodeObjects::RootObject] the root object
72
+ def root; @store[:root] end
73
+
74
+ # @param [String, nil] file the name of the yardoc db to load
75
+ # @return [Boolean] whether the database was loaded
76
+ def load(file = nil)
77
+ @file = file
78
+ @store = {}
79
+ @proxy_types = {}
80
+ @serializer = Serializers::YardocSerializer.new(@file)
81
+ load_yardoc
82
+ end
83
+
84
+ # Saves the database to disk
85
+ # @param [Boolean] merge if true, merges the data in memory with the
86
+ # data on disk, otherwise the data on disk is deleted.
87
+ # @param [String, nil] file if supplied, the name of the file to save to
88
+ # @return [Boolean] whether the database was saved
89
+ def save(merge = true, file = nil)
90
+ if file && file != @file
91
+ @file = file
92
+ @serializer = Serializers::YardocSerializer.new(@file)
93
+ end
94
+ destroy unless merge
95
+ values(false).each do |object|
96
+ @serializer.serialize(object)
97
+ end
98
+ write_proxy_types
99
+ write_checksums
100
+ true
101
+ end
102
+
103
+ # Deletes the .yardoc database on disk
104
+ #
105
+ # @param [Boolean] force if force is not set to true, the file/directory
106
+ # will only be removed if it ends with .yardoc. This helps with
107
+ # cases where the directory might have been named incorrectly.
108
+ # @return [Boolean] true if the .yardoc database was deleted, false
109
+ # otherwise.
110
+ def destroy(force = false)
111
+ if (!force && file =~ /\.yardoc$/) || force
112
+ if File.file?(@file)
113
+ # Handle silent upgrade of old .yardoc format
114
+ File.unlink(@file)
115
+ elsif File.directory?(@file)
116
+ FileUtils.rm_rf(@file)
117
+ end
118
+ true
119
+ else
120
+ false
121
+ end
122
+ end
123
+
124
+ protected
125
+
126
+ def objects_path
127
+ @serializer.objects_path
128
+ end
129
+
130
+ def proxy_types_path
131
+ @serializer.proxy_types_path
132
+ end
133
+
134
+ def checksums_path
135
+ @serializer.checksums_path
136
+ end
137
+
138
+ def load_yardoc
139
+ return false unless @file
140
+ if File.directory?(@file) # new format
141
+ Registry.objects.replace({})
142
+ @loaded_objects = 0
143
+ @available_objects = all_disk_objects.size
144
+ load_proxy_types
145
+ load_checksums
146
+ load_root
147
+ true
148
+ elsif File.file?(@file) # old format
149
+ load_yardoc_old
150
+ true
151
+ else
152
+ false
153
+ end
154
+ end
155
+
156
+ def load_yardoc_old
157
+ @store, @proxy_types = *Marshal.load(File.read(@file))
158
+ end
159
+
160
+ private
161
+
162
+ def load_proxy_types
163
+ return unless File.file?(proxy_types_path)
164
+ @proxy_types = Marshal.load(File.read(proxy_types_path))
165
+ end
166
+
167
+ def load_checksums
168
+ return unless File.file?(checksums_path)
169
+ lines = File.readlines(checksums_path).map do |line|
170
+ line.strip.split(/\s+/)
171
+ end
172
+ @checksums = Hash[lines]
173
+ end
174
+
175
+ def load_root
176
+ if root = @serializer.deserialize('root')
177
+ @store[:root] = root
178
+ end
179
+ end
180
+
181
+ def load_all
182
+ return unless @file
183
+ return if @loaded_objects >= @available_objects
184
+ log.debug "Loading entire database: #{@file} ..."
185
+ objects = []
186
+
187
+ all_disk_objects.sort_by {|x| x.size }.each do |path|
188
+ if obj = @serializer.deserialize(path, true)
189
+ objects << obj
190
+ end
191
+ end
192
+ objects.each do |obj|
193
+ put(obj.path, obj)
194
+ end
195
+ @loaded_objects += objects.size
196
+ log.debug "Loaded database (file='#{@file}' count=#{objects.size} total=#{@available_objects})"
197
+ end
198
+
199
+ def all_disk_objects
200
+ Dir.glob(File.join(objects_path, '**/*')).select {|f| File.file?(f) }
201
+ end
202
+
203
+ def write_proxy_types
204
+ File.open(proxy_types_path, 'wb') {|f| f.write(Marshal.dump(@proxy_types)) }
205
+ end
206
+
207
+ def write_checksums
208
+ File.open(checksums_path, 'w') do |f|
209
+ @checksums.each {|k, v| f.puts("#{k} #{v}") }
210
+ end
211
+ end
212
+ end
213
+ end