jsduck 5.3.4 → 6.0.0beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/bin/jsduck +3 -3
  4. data/lib/jsduck/app.rb +1 -1
  5. data/lib/jsduck/assets.rb +3 -3
  6. data/lib/jsduck/base_type.rb +2 -2
  7. data/lib/jsduck/batch_processor.rb +3 -1
  8. data/lib/jsduck/categories/file.rb +2 -2
  9. data/lib/jsduck/class_doc_expander.rb +1 -1
  10. data/lib/jsduck/css/parser.rb +59 -90
  11. data/lib/jsduck/css/type.rb +55 -0
  12. data/lib/jsduck/doc/parser.rb +1 -1
  13. data/lib/jsduck/doc/scanner.rb +2 -2
  14. data/lib/jsduck/doc/subproperties.rb +1 -1
  15. data/lib/jsduck/export_writer.rb +4 -4
  16. data/lib/jsduck/exporter/app.rb +2 -1
  17. data/lib/jsduck/exporter/full.rb +5 -3
  18. data/lib/jsduck/external_classes.rb +337 -5
  19. data/lib/jsduck/format/class.rb +3 -3
  20. data/lib/jsduck/format/doc.rb +6 -5
  21. data/lib/jsduck/format/subproperties.rb +1 -1
  22. data/lib/jsduck/guide_toc.rb +45 -27
  23. data/lib/jsduck/guide_toc_entry.rb +54 -0
  24. data/lib/jsduck/guides.rb +9 -5
  25. data/lib/jsduck/img/dir.rb +1 -1
  26. data/lib/jsduck/inline/example.rb +3 -1
  27. data/lib/jsduck/inline/img.rb +3 -3
  28. data/lib/jsduck/inline/link.rb +2 -2
  29. data/lib/jsduck/inline/link_renderer.rb +3 -2
  30. data/lib/jsduck/inline/video.rb +2 -1
  31. data/lib/jsduck/js/class.rb +6 -11
  32. data/lib/jsduck/js/ext_define.rb +46 -0
  33. data/lib/jsduck/js/ext_patterns.rb +7 -2
  34. data/lib/jsduck/js/rkelly_adapter.rb +16 -2
  35. data/lib/jsduck/logger.rb +40 -25
  36. data/lib/jsduck/member_registry.rb +41 -0
  37. data/lib/jsduck/news.rb +18 -5
  38. data/lib/jsduck/options/config.rb +35 -0
  39. data/lib/jsduck/options/helpful_parser.rb +111 -0
  40. data/lib/jsduck/options/input_files.rb +60 -0
  41. data/lib/jsduck/options/jsb.rb +25 -0
  42. data/lib/jsduck/{options.rb → options/parser.rb} +436 -484
  43. data/lib/jsduck/options/processor.rb +47 -0
  44. data/lib/jsduck/options/record.rb +51 -0
  45. data/lib/jsduck/output_dir.rb +4 -4
  46. data/lib/jsduck/parser.rb +5 -5
  47. data/lib/jsduck/process/components.rb +19 -0
  48. data/lib/jsduck/process/ext4_events.rb +4 -2
  49. data/lib/jsduck/process/importer.rb +5 -2
  50. data/lib/jsduck/process/inherit_members.rb +2 -0
  51. data/lib/jsduck/process/lint.rb +3 -3
  52. data/lib/jsduck/process/no_doc.rb +1 -1
  53. data/lib/jsduck/process/overrides.rb +4 -3
  54. data/lib/jsduck/process/versions.rb +86 -51
  55. data/lib/jsduck/render/class.rb +3 -2
  56. data/lib/jsduck/render/subproperties.rb +18 -0
  57. data/lib/jsduck/render/tags.rb +13 -1
  58. data/lib/jsduck/source/file.rb +2 -2
  59. data/lib/jsduck/tag/class.rb +6 -0
  60. data/lib/jsduck/tag/component.rb +19 -0
  61. data/lib/jsduck/tag/css_mixin.rb +10 -0
  62. data/lib/jsduck/tag/deprecated.rb +1 -1
  63. data/{template-min/resources/images/class-m.png → lib/jsduck/tag/icons/class-large.png} +0 -0
  64. data/lib/jsduck/tag/icons/class-redirect.png +0 -0
  65. data/lib/jsduck/tag/icons/class.png +0 -0
  66. data/{template-min/resources/images/component-m.png → lib/jsduck/tag/icons/component-large.png} +0 -0
  67. data/lib/jsduck/tag/icons/component-redirect.png +0 -0
  68. data/lib/jsduck/tag/icons/component.png +0 -0
  69. data/{template-min/resources/images/singleton-m.png → lib/jsduck/tag/icons/singleton-large.png} +0 -0
  70. data/lib/jsduck/tag/icons/singleton-redirect.png +0 -0
  71. data/lib/jsduck/tag/icons/singleton.png +0 -0
  72. data/lib/jsduck/tag/inheritdoc.rb +2 -2
  73. data/lib/jsduck/tag/new.rb +13 -0
  74. data/lib/jsduck/tag/since.rb +2 -2
  75. data/lib/jsduck/tag/singleton.rb +13 -0
  76. data/lib/jsduck/tag/tag.rb +19 -0
  77. data/lib/jsduck/tag_registry.rb +20 -81
  78. data/lib/jsduck/util/io.rb +5 -0
  79. data/lib/jsduck/util/json.rb +3 -3
  80. data/lib/jsduck/util/null_object.rb +14 -1
  81. data/lib/jsduck/util/parallel.rb +7 -3
  82. data/lib/jsduck/version.rb +1 -1
  83. data/lib/jsduck/warning/registry.rb +4 -2
  84. data/lib/jsduck/warning/tag.rb +57 -0
  85. data/lib/jsduck/web/class_icons.rb +76 -0
  86. data/lib/jsduck/web/css.rb +12 -1
  87. data/lib/jsduck/web/data.rb +4 -3
  88. data/lib/jsduck/web/index_html.rb +26 -10
  89. data/lib/jsduck/web/member_icons.rb +3 -3
  90. data/lib/jsduck/web/search.rb +4 -4
  91. data/lib/jsduck/web/source.rb +1 -1
  92. data/lib/jsduck/web/template.rb +6 -6
  93. data/lib/jsduck/web/tree.rb +22 -0
  94. data/lib/jsduck/web/writer.rb +11 -9
  95. data/template-min/app-0f524ddd276c4019a11a6128932a9c96.js +1 -0
  96. data/template-min/index-template.html +1 -1
  97. data/template-min/print-template.html +1 -1
  98. data/template-min/resources/css/{app-4689d2a5522dcd3c9e9923ca59c33f27.css → app-de670120f43fdad3091a0cc2c10daadb.css} +1 -1
  99. data/template-min/resources/images/icons.xcf +0 -0
  100. data/template-min/template.html +2 -2
  101. metadata +46 -13
  102. data/lib/jsduck/css/lexer.rb +0 -203
  103. data/lib/jsduck/option_parser.rb +0 -109
  104. data/lib/jsduck/web/icons.rb +0 -31
  105. data/template-min/app-0c945a27f43452df695771ddb60b3d14.js +0 -1
@@ -0,0 +1,47 @@
1
+ require 'jsduck/options/parser'
2
+ require 'jsduck/options/input_files'
3
+ require 'jsduck/logger'
4
+ require 'jsduck/util/json'
5
+ require 'jsduck/util/io'
6
+ require 'jsduck/util/parallel'
7
+ require 'jsduck/tag_registry'
8
+ require 'jsduck/js/ext_patterns'
9
+
10
+ module JsDuck
11
+ module Options
12
+
13
+ # A facade for all the command line options processing.
14
+ class Processor
15
+ # Takes a list of command line options, parses it to an
16
+ # Options::Record object, validates the options, applies it to
17
+ # various singleton classes and returns the Options::Record.
18
+ def self.process(args)
19
+ # HACK! First establish warnings defaults.
20
+ Logger.configure_defaults
21
+
22
+ opts = Options::Parser.new.parse(args)
23
+
24
+ # Expand list of input files
25
+ Options::InputFiles.new(opts).expand!
26
+
27
+ # Validate the options.
28
+ # Exit program when there's an error.
29
+ if err = opts.validate!
30
+ Array(err).each {|line| Logger.fatal(line) }
31
+ exit(1)
32
+ end
33
+
34
+ # Configure various objects with these options
35
+ Logger.configure(opts)
36
+ Util::Parallel.configure(opts)
37
+ TagRegistry.configure(opts)
38
+ Js::ExtPatterns.configure(opts)
39
+ Util::Json.configure(opts)
40
+ Util::IO.configure(opts)
41
+
42
+ opts
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,51 @@
1
+ module JsDuck
2
+ module Options
3
+
4
+ # Stores values of command line options.
5
+ #
6
+ # All options are initially defined with an #attribute method, which
7
+ # ensures that accessing an unexisting option will result in an
8
+ # error.
9
+ class Record
10
+ def initialize
11
+ @validators = {}
12
+ end
13
+
14
+ # Defines accessor for an option,
15
+ # and assigns a default value for it.
16
+ def attribute(name, default=nil)
17
+ instance_variable_set("@#{name}", default)
18
+ # Use `send` to invoke private attr_accessor method. As we only
19
+ # expect a single OptionsRecord to exist for the lifetime of the
20
+ # app, it should be safe to define a method on a class.
21
+ self.class.send(:attr_accessor, name)
22
+ end
23
+
24
+ # Defines a validator function that gets run after all the
25
+ # options have been parsed. When validation fails, the function
26
+ # should return an error message string (or an array of string
27
+ # for multi-line error message) otherwise nil, to signify
28
+ # success.
29
+ def validator(name, &block)
30
+ @validators[name] = block
31
+ end
32
+
33
+ # Runs all the validators. Returns an error message string from
34
+ # the first failed validation or nil when everything is OK.
35
+ #
36
+ # Alternatively runs just one validator by name. Used in testing.
37
+ def validate!(name=nil)
38
+ validators = name ? [@validators[name]] : @validators.values
39
+
40
+ validators.each do |block|
41
+ if err = block.call()
42
+ return err
43
+ end
44
+ end
45
+ return nil
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+ end
@@ -11,18 +11,18 @@ module JsDuck
11
11
  def self.clean(opts)
12
12
  if opts.cache && cache_dir_needs_preserving(opts)
13
13
  # Remove all files inside <output-dir> except .cache/
14
- Dir[opts.output_dir + "/*"].each do |file|
14
+ Dir[opts.output + "/*"].each do |file|
15
15
  FileUtils.rm_rf(file) unless file =~ /\/.cache\z/
16
16
  end
17
17
  else
18
18
  # Remove and recreate the entire <output-dir>
19
- FileUtils.rm_rf(opts.output_dir)
20
- FileUtils.mkdir(opts.output_dir)
19
+ FileUtils.rm_rf(opts.output)
20
+ FileUtils.mkdir(opts.output)
21
21
  end
22
22
  end
23
23
 
24
24
  def self.cache_dir_needs_preserving(opts)
25
- opts.cache_dir == opts.output_dir + "/.cache" && File.exists?(opts.cache_dir)
25
+ opts.cache_dir == opts.output + "/.cache" && File.exists?(opts.cache_dir)
26
26
  end
27
27
 
28
28
  end
@@ -9,7 +9,7 @@ require 'jsduck/base_type'
9
9
  require 'jsduck/class_doc_expander'
10
10
 
11
11
  module JsDuck
12
- # Performs the actual parsing of CSS or JS source.
12
+ # Performs the actual parsing of SCSS or JS source.
13
13
  #
14
14
  # This is the class that brings together all the different steps of
15
15
  # parsing the source.
@@ -27,7 +27,7 @@ module JsDuck
27
27
  def parse(contents, filename="", options={})
28
28
  @doc_processor.filename = @filename = filename
29
29
 
30
- parse_js_or_css(contents, filename, options).map do |docset|
30
+ parse_js_or_scss(contents, filename, options).map do |docset|
31
31
  expand(docset)
32
32
  end.flatten.map do |docset|
33
33
  merge(docset)
@@ -36,9 +36,9 @@ module JsDuck
36
36
 
37
37
  private
38
38
 
39
- # Parses the file depending on filename as JS or CSS
40
- def parse_js_or_css(contents, filename, options)
41
- if filename =~ /\.s?css$/
39
+ # Parses the file depending on filename as JS or SCSS
40
+ def parse_js_or_scss(contents, filename, options)
41
+ if filename =~ /\.scss$/
42
42
  docs = Css::Parser.new(contents, options).parse
43
43
  else
44
44
  docs = Js::Parser.new(contents, options).parse
@@ -0,0 +1,19 @@
1
+ module JsDuck
2
+ module Process
3
+
4
+ # Auto-detects classes inheriting from Ext.Component, and marks
5
+ # them as :component.
6
+ class Components
7
+ def initialize(relations)
8
+ @relations = relations
9
+ end
10
+
11
+ def process_all!
12
+ @relations.each do |cls|
13
+ cls[:component] = true if cls.inherits_from?("Ext.Component")
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -1,3 +1,5 @@
1
+ require 'ostruct'
2
+
1
3
  module JsDuck
2
4
  module Process
3
5
 
@@ -7,13 +9,13 @@ module JsDuck
7
9
  # But only does so when :ext4_events option is set to true or the
8
10
  # code itself is detected as being writted in Ext4 style.
9
11
  class Ext4Events
10
- def initialize(classes, opts={})
12
+ def initialize(classes, opts=OpenStruct.new)
11
13
  @classes = classes
12
14
  @opts = opts
13
15
  end
14
16
 
15
17
  def process_all!
16
- if @opts[:ext4_events] == true || (@opts[:ext4_events] == nil && ext4_style_code?)
18
+ if @opts.ext4_events == true || (@opts.ext4_events == nil && ext4_style_code?)
17
19
  @classes.each_value {|cls| process(cls) }
18
20
  end
19
21
  end
@@ -23,7 +23,10 @@ module JsDuck
23
23
  private
24
24
 
25
25
  def current_version
26
- Util::NullObject.new(:[] => Util::NullObject.new(:[] => true))
26
+ JsDuck::Util::NullObject.new(
27
+ :[] => JsDuck::Util::NullObject.new( # class
28
+ :[] => JsDuck::Util::NullObject.new( # member
29
+ :length => 1.0 / 0))) # params count == Infinity
27
30
  end
28
31
 
29
32
  # Reads in data from all .json files in directory
@@ -61,7 +64,7 @@ module JsDuck
61
64
  def members_id_index(json)
62
65
  index = {}
63
66
  json["members"].each do |m|
64
- index[m["id"]] = true
67
+ index[m["id"]] = m["params"] ? m["params"].map {|p| p["name"] } : true
65
68
  end
66
69
  index
67
70
  end
@@ -19,6 +19,7 @@ module JsDuck
19
19
  # - :params
20
20
  # - :return
21
21
  # - :throws
22
+ # - :properties
22
23
  #
23
24
  # In case of auto-detected members that inherit from a public
24
25
  # member in parent class, we inherit all fields that aren't
@@ -82,6 +83,7 @@ module JsDuck
82
83
  m[:params] = parent[:params] if inherit_params?(m, parent)
83
84
  m[:return] = parent[:return] unless m[:return]
84
85
  m[:throws] = parent[:throws] unless m[:throws] && m[:throws].length > 0
86
+ m[:properties] = parent[:properties] unless m[:properties] && m[:properties].length > 0
85
87
 
86
88
  # Don't inherit type from parent when:
87
89
  # - member itself has type and it's not auto-detected
@@ -27,7 +27,7 @@ module JsDuck
27
27
  if !member[:name] || member[:name] == ""
28
28
  warn(:name_missing, "Unnamed #{member[:tagname]}", member)
29
29
  end
30
- (member[:params] || []).each do |p|
30
+ Array(member[:params]).each do |p|
31
31
  if !p[:name] || p[:name] == ""
32
32
  warn(:name_missing, "Unnamed parameter", member)
33
33
  end
@@ -40,7 +40,7 @@ module JsDuck
40
40
  each_member do |member|
41
41
  if member[:tagname] == :method
42
42
  optional_found = false
43
- member[:params].each do |p|
43
+ Array(member[:params]).each do |p|
44
44
  if optional_found && !p[:optional]
45
45
  warn(:req_after_opt, "Optional param followed by regular param #{p[:name]}", member)
46
46
  end
@@ -54,7 +54,7 @@ module JsDuck
54
54
  def warn_duplicate_params
55
55
  each_member do |member|
56
56
  params = {}
57
- (member[:params] || []).each do |p|
57
+ Array(member[:params]).each do |p|
58
58
  if params[p[:name]]
59
59
  warn(:dup_param, "Duplicate parameter name #{p[:name]}", member)
60
60
  end
@@ -41,7 +41,7 @@ module JsDuck
41
41
  def warn(type, msg, owner)
42
42
  visibility = owner[:private] ? :private : (owner[:protected] ? :protected : :public)
43
43
 
44
- Logger.warn_nodoc(type, visibility, msg, owner[:files][0])
44
+ Logger.warn(:nodoc, msg, owner[:files][0], [type, visibility])
45
45
  end
46
46
 
47
47
  end
@@ -1,17 +1,18 @@
1
1
  require 'jsduck/logger'
2
+ require 'ostruct'
2
3
 
3
4
  module JsDuck
4
5
  module Process
5
6
 
6
7
  class Overrides
7
- def initialize(classes_hash, opts = {:external_classes => []})
8
+ def initialize(classes_hash, opts = OpenStruct.new(:external => []))
8
9
  @classes_hash = classes_hash
9
10
  @opts = opts
10
11
  end
11
12
 
12
13
  # Applies all override classes to target classes, then deletes
13
14
  # the overrides themselves from classes hash and adds the names
14
- # of all the processed overrides to external_classes list in
15
+ # of all the processed overrides to external classes list in
15
16
  # options object.
16
17
  def process_all!
17
18
  overrides = []
@@ -28,7 +29,7 @@ module JsDuck
28
29
  @classes_hash.delete(cls[:name])
29
30
  end
30
31
 
31
- @opts[:external_classes] += overrides.map {|c| c[:name] }
32
+ @opts.external += overrides.map {|c| c[:name] }
32
33
  end
33
34
 
34
35
  private
@@ -1,5 +1,5 @@
1
1
  require 'jsduck/process/importer'
2
- require 'jsduck/tag_registry'
2
+ require 'ostruct'
3
3
 
4
4
  module JsDuck
5
5
  module Process
@@ -7,76 +7,65 @@ module JsDuck
7
7
  # Generates @since and @new tags by importing JSDuck exports of
8
8
  # older versions of the same project and looking in which version
9
9
  # a class or method first appeared.
10
- #
11
- # Additionally here the tooltip text for @new tag gets injected.
12
10
  class Versions
13
- def initialize(relations, opts={}, importer=nil)
11
+ def initialize(relations, opts=OpenStruct.new, importer=Process::Importer.new)
14
12
  @relations = relations
15
13
  @opts = opts
16
- # Allow different importer to be injected for testing
17
- @importer = importer || Process::Importer.new
14
+ @importer = importer
18
15
  end
19
16
 
20
17
  # Loads in exported docs and generates @since and @new tags.
21
18
  def process_all!
22
- init_new_tag_tooltip!
23
-
24
- if @opts[:imports].length > 0
25
- generate_since_tags(@importer.import(@opts[:imports]))
19
+ if @opts.import.length > 0
20
+ @versions = @importer.import(@opts.import)
21
+ add_since_tags
26
22
  end
27
23
  end
28
24
 
29
25
  private
30
26
 
31
- # Initializes the tooltip text for the signature of @new tag.
32
- def init_new_tag_tooltip!
33
- signature = TagRegistry.get_by_name(:new).signature
34
- if @opts[:new_since]
35
- signature[:tooltip] = "New since #{@opts[:new_since]}"
36
- elsif @opts[:imports].length > 0
37
- signature[:tooltip] = "New since #{@opts[:imports].last[:version]}"
38
- end
39
- end
27
+ # classes...
40
28
 
41
29
  # Using the imported versions data, adds @since tags to all
42
- # classes/members.
43
- def generate_since_tags(versions)
44
- new_versions = build_new_versions_map(versions)
45
-
30
+ # classes/members/params.
31
+ def add_since_tags
46
32
  @relations.each do |cls|
47
- v = cls[:since] || class_since(versions, cls)
33
+ v = cls[:since] || class_since(cls)
48
34
  cls[:since] = v
49
- cls[:new] = true if new_versions[v]
35
+ cls[:new] = true if is_new?(v)
50
36
 
51
- cls.all_local_members.each do |m|
52
- v = m[:since] || member_since(versions, cls, m)
53
- m[:since] = v
54
- m[:new] = true if new_versions[v]
55
- end
37
+ add_members_since_tags(cls)
56
38
  end
57
39
  end
58
40
 
59
- # Generates a lookup table of versions that we are going to label
60
- # with @new tags. By default we use the latest version, otherwise
61
- # use all versions since the latest.
62
- def build_new_versions_map(versions)
63
- new_versions = {}
64
-
65
- if @opts[:new_since]
66
- versions.map {|v| v[:version] }.each do |v|
67
- if v == @opts[:new_since] || !new_versions.empty?
68
- new_versions[v] = true
69
- end
41
+ # Returns name of the version since which the class is available
42
+ def class_since(cls)
43
+ @versions.each do |ver|
44
+ return ver[:version] if ver[:classes][cls[:name]]
45
+ cls[:alternateClassNames].each do |name|
46
+ return ver[:version] if ver[:classes][name]
70
47
  end
71
- else
72
- new_versions[versions.last[:version]] = true
73
48
  end
49
+ end
74
50
 
75
- new_versions
51
+ # members...
52
+
53
+ def add_members_since_tags(cls)
54
+ cls.all_local_members.each do |m|
55
+ # Remember the initial explicit @since tag value
56
+ # to disable params processing when it's present.
57
+ explicit_since = m[:since]
58
+
59
+ v = m[:since] || member_since(cls, m)
60
+ m[:since] = v
61
+ m[:new] = true if is_new?(v)
62
+
63
+ add_params_since_tags(cls, m, v) unless explicit_since
64
+ end
76
65
  end
77
66
 
78
- def member_since(versions, cls, m)
79
- versions.each do |ver|
67
+ def member_since(cls, m)
68
+ @versions.each do |ver|
80
69
  c = ver[:classes][cls[:name]]
81
70
  return ver[:version] if c && c[m[:id]]
82
71
  cls[:alternateClassNames].each do |name|
@@ -86,14 +75,60 @@ module JsDuck
86
75
  end
87
76
  end
88
77
 
89
- # Returns name of the version since which the class is available
90
- def class_since(versions, cls)
91
- versions.each do |ver|
92
- return ver[:version] if ver[:classes][cls[:name]]
78
+ # params...
79
+
80
+ def add_params_since_tags(cls, member, member_version)
81
+ Array(member[:params]).each_with_index do |p, i|
82
+ v = param_since(cls, member, i)
83
+ if v != member_version
84
+ p[:since] = v
85
+ p[:new] = true if is_new?(v)
86
+ end
87
+ end
88
+ end
89
+
90
+ def param_since(cls, m, i)
91
+ @versions.each do |ver|
92
+ c = ver[:classes][cls[:name]]
93
+ return ver[:version] if c && has_param?(c[m[:id]], i)
93
94
  cls[:alternateClassNames].each do |name|
94
- return ver[:version] if ver[:classes][name]
95
+ c = ver[:classes][name]
96
+ return ver[:version] if c && has_param?(c[m[:id]], i)
97
+ end
98
+ end
99
+ end
100
+
101
+ # Because parameters can be renamed between versions, only
102
+ # consider parameter count.
103
+ def has_param?(member, param_index)
104
+ member && member.respond_to?(:length) && member.length > param_index
105
+ end
106
+
107
+ # helpers...
108
+
109
+ # Should items introduced in given version be marked as new?
110
+ def is_new?(version_nr)
111
+ @new_versions = new_versions_map unless @new_versions
112
+ @new_versions[version_nr]
113
+ end
114
+
115
+ # Generates a lookup table of versions that we are going to label
116
+ # with @new tags. By default we use the latest version, otherwise
117
+ # use all versions since the latest.
118
+ def new_versions_map
119
+ new_versions = {}
120
+
121
+ if @opts.new_since
122
+ @versions.map {|v| v[:version] }.each do |v|
123
+ if v == @opts.new_since || !new_versions.empty?
124
+ new_versions[v] = true
125
+ end
95
126
  end
127
+ else
128
+ new_versions[@versions.last[:version]] = true
96
129
  end
130
+
131
+ new_versions
97
132
  end
98
133
 
99
134
  end