deep-cover 0.1.13 → 0.1.14

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef02156435418688aa0934036aa4273c3179468c
4
- data.tar.gz: ba37d24e7cbf1e34f0fbd0db4f3f2720527825f4
3
+ metadata.gz: e6de45ce3979398ef5abb25a8147848ad13fa370
4
+ data.tar.gz: 74dfa0b7b03271419f0b2c7094e124b447392c46
5
5
  SHA512:
6
- metadata.gz: 0c209ce060a984b41dc8e454fccebb6d9911a464a1b76de267ccdd326e567b9af9e427c42e66f75007b7fd81cdb27d4bc5b513772cf2d0d0e11c98a8d152a164
7
- data.tar.gz: 492ebdb2f56861e7b9d8d195cfdc2818568ff245e7e64c778d9062290785d420c31e43cb1cdcd2efbd204ef40141ba6e80d7d05e220250beba4bf88759b39a1d
6
+ metadata.gz: 2a455c059204f7eeb91f57ca3d4453a7a79021ece85e3228b4a312034dcaef7d022f0776dc9179bcb1dc44049971ba5248fcdc94badcacc6ab1c08bbd9da195e
7
+ data.tar.gz: 8c6ec4f7204c95968a329d1ae3896cf9c0e41c68973883add1beca6d1efdcdba353e09ff11dfa97651488a75e2cb4f6dd7cc70d5f23159b21efaba6e967233e4
data/Rakefile CHANGED
@@ -14,6 +14,7 @@ namespace :dev do
14
14
  if RUBY_VERSION >= '2.2.2' && (!defined?(RUBY_ENGINE) || RUBY_ENGINE != 'jruby')
15
15
  commands << 'bundle install --gemfile=spec/full_usage/rails51_project/Gemfile'
16
16
  end
17
+ commands << 'bundle install --gemfile=spec/cli_fixtures/simple_rails42_app/Gemfile'
17
18
 
18
19
  commands.each do |command|
19
20
  puts "Running: #{command}"
@@ -8,7 +8,8 @@ def gem_list
8
8
  rspec-support thread_safe rspec-core rspec-expectations rspec-mocks rspec mini_portile
9
9
  multi_json rspec-support rspec-expectations rspec-mocks mail nokogiri rack rspec unf
10
10
  json thread_safe rspec-core json rack-protection sdoc docile faraday multi_xml coderay
11
- mime-types net-scp multi_json turbolinks formatador coffee-script rack-test]
11
+ mime-types net-scp multi_json turbolinks formatador coffee-script rack-test] +
12
+ %w[devise]
12
13
  # How I got those:
13
14
  require 'gems'
14
15
  Gems.most_downloaded
@@ -12,7 +12,6 @@
12
12
  # Other differences from wwtd:
13
13
  # * automatically installs the bundler gem if it is missing from a ruby version.
14
14
  #
15
- require 'term/ansicolor'
16
15
  require 'yaml'
17
16
  TRAVIS_CONFIG = '.travis.yml'
18
17
 
@@ -1,5 +1,7 @@
1
1
  module DeepCover
2
2
  require 'parser'
3
+ require 'term/ansicolor'
4
+ require 'pry'
3
5
  require_relative 'deep_cover/backports'
4
6
  require_relative 'deep_cover/tools'
5
7
  require_relative_dir 'deep_cover/parser_ext'
@@ -33,7 +33,13 @@ module DeepCover
33
33
  def each_node(from = covered_code.root, &block)
34
34
  return to_enum(:each_node) unless block_given?
35
35
  children = node_children(from)
36
- yield from, children unless from.is_a?(Node::Root)
36
+ begin
37
+ yield from, children unless from.is_a?(Node::Root)
38
+ rescue ProblemWithDiagnostic
39
+ raise
40
+ rescue StandardError, SystemStackError => e
41
+ raise ProblemWithDiagnostic.new(covered_code, from.diagnostic_expression, e)
42
+ end
37
43
  children.each do |child|
38
44
  each_node(child, &block)
39
45
  end
@@ -9,7 +9,7 @@ module DeepCover
9
9
  runs = node_runs(node)
10
10
  if runs != nil
11
11
  node.proper_range.each do |pos|
12
- bc[buffer.line_for_position(pos)-1][buffer.column_for_position(pos)] = runs > 0 ? ' ' : 'x'
12
+ bc[buffer.line_for_position(pos)-buffer.first_line][buffer.column_for_position(pos)] = runs > 0 ? ' ' : 'x'
13
13
  end
14
14
  end
15
15
  end
@@ -3,7 +3,7 @@ module DeepCover
3
3
  # Returns an array of runs, one per line.
4
4
  def results
5
5
  disallow_partial = !options.fetch(:allow_partial, true)
6
- line_hits = Array.new(covered_code.nb_lines)
6
+ line_hits = Array.new(covered_code.nb_lines + covered_code.lineno - 1)
7
7
  each_node do |node, _children|
8
8
  if (runs = node_runs(node))
9
9
  node.executed_locs.each do |loc|
@@ -1,5 +1,3 @@
1
- require 'term/ansicolor'
2
-
3
1
  module DeepCover
4
2
  module CLI
5
3
  class Debugger
@@ -37,8 +37,9 @@ module DeepCover
37
37
  o.banner = "usage: deep-cover [options] [path/to/app/or/gem]"
38
38
  o.separator ''
39
39
  o.string '-o', '--output', 'output folder', default: './coverage'
40
- o.string '-c', '--command', 'command to run tests', default: 'rake'
40
+ o.string '-c', '--command', 'command to run tests', default: 'bundle exec rake'
41
41
  o.bool '--bundle', 'run bundle before the tests', default: true
42
+ o.bool '--process', 'turn off to only redo the reporting', default: true
42
43
  o.separator 'Coverage options'
43
44
  @ignore_uncovered_map = Analyser.optionally_covered.map do |option|
44
45
  default = Config::DEFAULTS[:ignore_uncovered].include?(option)
@@ -8,10 +8,10 @@ module DeepCover
8
8
  # matches regular files, .files, ..files, but not '.' or '..'
9
9
  GLOB_ALL_CONTENT = '{,.[^.],..?}*'
10
10
 
11
- def initialize(gem_path, command: 'rake', **options)
11
+ def initialize(source_path, command: 'rake', **options)
12
12
  @command = command
13
13
  @options = options
14
- @root_path = gem_path = Pathname.new(gem_path).expand_path
14
+ @root_path = @source_path = Pathname.new(source_path).expand_path
15
15
  unless @root_path.join('Gemfile').exist?
16
16
  # E.g. rails/activesupport
17
17
  @root_path = @root_path.dirname
@@ -20,40 +20,85 @@ module DeepCover
20
20
  @dest_root = Pathname('~/test_deep_cover').expand_path
21
21
  @dest_root = Pathname.new(Dir.mktmpdir("deep_cover_test")) unless @dest_root.exist?
22
22
 
23
- FileUtils.rm_rf(Dir.glob("#{@dest_root}/#{GLOB_ALL_CONTENT}"))
24
- gem_relative_path = gem_path.relative_path_from(@root_path)
23
+ gem_relative_path = @source_path.relative_path_from(@root_path)
25
24
  @main_path = @dest_root.join(gem_relative_path)
25
+ singleton_class.include self.class.const_get(Tools.camelize(style))
26
+ end
27
+
28
+ def clear
29
+ FileUtils.rm_rf(Dir.glob("#{@dest_root}/#{GLOB_ALL_CONTENT}"))
26
30
  end
27
31
 
28
32
  def copy
29
33
  return true if @copied
34
+ puts "Cloning..."
30
35
  FileUtils.cp_r(Dir.glob("#{@root_path}/#{GLOB_ALL_CONTENT}"), @dest_root)
31
36
  @copied = true
32
37
  end
33
38
 
34
39
  def patch_ruby_file(ruby_file)
35
- content = File.read(ruby_file)
40
+ content = ruby_file.read
36
41
  # Insert our code after leading comments:
37
42
  content.sub!(/^((#.*\n+)*)/, "#{$1}require 'deep_cover/auto_run';DeepCover::AutoRun.run! '#{@dest_root}';")
38
- File.write(ruby_file, content)
43
+ ruby_file.write(content)
39
44
  end
40
45
 
41
- def each_gem_path
42
- return to_enum __method__ unless block_given?
43
- if @main_path.join('lib').exist?
44
- yield @main_path
46
+ def style
47
+ if @source_path.join('config/environments/test.rb').exist?
48
+ :rails
49
+ elsif @source_path.join('lib').exist?
50
+ :single_gem
45
51
  else # Rails style
52
+ :gem_collection
53
+ end
54
+ end
55
+
56
+ # Style specific functionality
57
+ module Gem
58
+ def each_main_ruby_files(&block)
59
+ each_gem_path do |dest_path|
60
+ main = dest_path.join('lib/*.rb')
61
+ Pathname.glob(main).select(&:file?).each(&block)
62
+ end
63
+ end
64
+
65
+ def each_dir_to_cover
66
+ each_gem_path do |dest_path|
67
+ yield dest_path.join('lib')
68
+ end
69
+ end
70
+ end
71
+
72
+ module SingleGem
73
+ include Gem
74
+ def each_gem_path
75
+ yield @main_path
76
+ end
77
+ end
78
+
79
+ module GemCollection
80
+ include Gem
81
+ def each_gem_path
46
82
  Pathname.glob(@main_path.join('*/lib')).each{|p| yield p.dirname}
47
83
  end
48
84
  end
49
85
 
86
+ module Rails
87
+ def each_main_ruby_files
88
+ yield @main_path.join('config/environments/test.rb')
89
+ end
90
+
91
+ def each_dir_to_cover
92
+ yield @main_path.join('app')
93
+ yield @main_path.join('lib')
94
+ end
95
+ end
96
+
97
+ # Back to global functionality
50
98
  def patch_main_ruby_files
51
- each_gem_path do |dest_path|
52
- main = dest_path.join('lib/*.rb')
53
- Dir.glob(main).select{|p| File.file?(p) }.each do |main|
54
- puts "Patching #{main}"
55
- patch_ruby_file(main)
56
- end
99
+ each_main_ruby_files do |main|
100
+ puts "Patching #{main}"
101
+ patch_ruby_file(main)
57
102
  end
58
103
  end
59
104
 
@@ -88,11 +133,12 @@ module DeepCover
88
133
 
89
134
  def cover
90
135
  coverage = Coverage.new
91
- each_gem_path do |dest_path|
92
- FileUtils.cp_r("#{dest_path}/lib", "#{dest_path}/lib_original")
93
- Tools.dump_covered_code(File.join(dest_path, 'lib_original'),
136
+ each_dir_to_cover do |to_cover|
137
+ original = to_cover.sub_ext('_original')
138
+ FileUtils.cp_r(to_cover, original)
139
+ Tools.dump_covered_code(original,
94
140
  coverage: coverage, root_path: @dest_root.to_s,
95
- dest_path: File.join(dest_path, 'lib'))
141
+ dest_path: to_cover)
96
142
  end
97
143
  coverage.save(@dest_root.to_s)
98
144
  end
@@ -116,11 +162,14 @@ module DeepCover
116
162
  end
117
163
 
118
164
  def run
119
- copy
120
- cover
121
- patch
122
- bundle if @options.fetch(:bundle, true)
123
- process
165
+ if @options.fetch(:process, true)
166
+ clear
167
+ copy
168
+ cover
169
+ patch
170
+ bundle if @options.fetch(:bundle, true)
171
+ process
172
+ end
124
173
  report
125
174
  end
126
175
  end
@@ -3,7 +3,6 @@ module DeepCover
3
3
  silence_warnings do
4
4
  require 'parser/current'
5
5
  end
6
- require 'pry'
7
6
  require_relative 'covered_code'
8
7
  require 'securerandom'
9
8
 
@@ -133,11 +132,15 @@ module DeepCover
133
132
 
134
133
  def save_trackers(global)
135
134
  saved?
135
+ trackers = eval(global)
136
+ # Some testing involves more than one process, some of which don't run any of our covered code.
137
+ # Don't save anything if that's the case
138
+ return if trackers.nil?
136
139
  basename = TRACKER_TEMPLATE % {unique: SecureRandom.urlsafe_base64}
137
140
  dir_path.join(basename).binwrite(Marshal.dump({
138
141
  version: DeepCover::VERSION,
139
142
  global: global,
140
- trackers: eval(global),
143
+ trackers: trackers,
141
144
  }))
142
145
  end
143
146
 
@@ -6,12 +6,11 @@ module DeepCover
6
6
  @@counter = 0
7
7
  @@globals = Hash.new{|h, global| h[global] = eval("#{global} ||= {}") }
8
8
 
9
- def initialize(path: nil, source: nil, lineno: nil, tracker_global: DEFAULT_TRACKER_GLOBAL, local_var: '_temp', name: nil)
9
+ def initialize(path: nil, source: nil, lineno: 1, tracker_global: DEFAULT_TRACKER_GLOBAL, local_var: '_temp', name: nil)
10
10
  raise "Must provide either path or source" unless path || source
11
11
 
12
- @buffer = ::Parser::Source::Buffer.new(path)
12
+ @buffer = ::Parser::Source::Buffer.new(path, lineno)
13
13
  @buffer.source = source ||= File.read(path)
14
- @lineno = lineno
15
14
  @tracker_count = 0
16
15
  @tracker_global = tracker_global
17
16
  @local_var = local_var
@@ -23,6 +22,10 @@ module DeepCover
23
22
  @buffer.name || "(source: '#{@buffer.source[0..20]}...')"
24
23
  end
25
24
 
25
+ def lineno
26
+ @buffer.first_line
27
+ end
28
+
26
29
  def nb_lines
27
30
  @nb_lines ||= begin
28
31
  lines = buffer.source_lines
@@ -37,7 +40,7 @@ module DeepCover
37
40
  def execute_code(binding: DeepCover::GLOBAL_BINDING.dup)
38
41
  return if has_executed?
39
42
  global[nb] = Array.new(@tracker_count, 0)
40
- eval(@covered_source, binding, @buffer.name || '<raw_code>', @lineno || 1)
43
+ eval(@covered_source, binding, @buffer.name || '<raw_code>', lineno)
41
44
  self
42
45
  end
43
46
 
@@ -30,9 +30,38 @@ module DeepCover
30
30
 
31
31
  ### Public API
32
32
 
33
+ # Search self and descendants for a particular Class or type
34
+ def find_all(lookup)
35
+ case lookup
36
+ when ::Class
37
+ each_node.grep(lookup)
38
+ when ::Symbol
39
+ each_node.find_all{|n| n.type == lookup}
40
+ when ::String
41
+ each_node.find_all{|n| n.source == lookup}
42
+ when ::Regexp
43
+ each_node.find_all{|n| n.source =~ lookup}
44
+ else
45
+ binding.pry
46
+ raise ::TypeError, "Expected class or symbol, got #{lookup.class}: #{lookup.inspect}"
47
+ end
48
+ end
49
+
33
50
  # Shortcut to access children
34
51
  def [](v)
35
- children[v]
52
+ if v.is_a?(Integer)
53
+ children.fetch(v)
54
+ else
55
+ found = find_all(v)
56
+ case found.size
57
+ when 1
58
+ found.first
59
+ when 0
60
+ raise "No children of type #{v}"
61
+ else
62
+ raise "Ambiguous lookup #{v}, found #{found}."
63
+ end
64
+ end
36
65
  end
37
66
 
38
67
  # Shortcut to create a node from source code
@@ -106,7 +135,6 @@ module DeepCover
106
135
 
107
136
  private
108
137
  def diagnose(exception)
109
- exp = base_node.loc.expression
110
138
  msg = if self.class == Node
111
139
  "Unknown node type encountered: #{base_node.type}"
112
140
  else
@@ -116,7 +144,7 @@ module DeepCover
116
144
  'Attempting to continue, but this node will not be handled properly',
117
145
  ('Its subnodes will be ignored' if children.empty?),
118
146
  'Source:',
119
- exp && exp.source,
147
+ expression,
120
148
  "Original exception:",
121
149
  exception.inspect,
122
150
  ].join("\n")
@@ -49,6 +49,10 @@ module DeepCover
49
49
  expression.source if expression
50
50
  end
51
51
 
52
+ def diagnostic_expression
53
+ expression || parent.diagnostic_expression
54
+ end
55
+
52
56
  # Returns an array of character numbers (in the original buffer) that
53
57
  # pertain exclusively to this node (and thus not to any children).
54
58
  def proper_range
@@ -58,6 +58,11 @@ module DeepCover
58
58
  flow_entry_count
59
59
  end
60
60
  end
61
+
62
+ # Returns the counts in a hash
63
+ def counts
64
+ {flow_entry: flow_entry_count, flow_completion: flow_completion_count, execution: execution_count}
65
+ end
61
66
  end
62
67
  end
63
68
  end
@@ -37,16 +37,25 @@ module DeepCover
37
37
 
38
38
  private
39
39
 
40
- # Only need to add them to deal with ambiguous cases where a method is hidden by a local. Ex:
40
+ # In different circumstances, we need ().
41
+ # Deal with ambiguous cases where a method is hidden by a local. Ex:
41
42
  # foo 42, 'hello' #=> Works
42
43
  # foo (42), 'hello' #=> Simplification of what DeepCover would generate, still works
43
44
  # foo = 1; foo 42, 'hello' #=> works
44
45
  # foo = 1; foo (42), 'hello' #=> syntax error.
45
46
  # foo = 1; foo((42), 'hello') #=> works
47
+ # Deal with do/end block. Ex:
48
+ # x.foo 42, 43 # => ok
49
+ # x.foo (42), 43 # => ok
50
+ # x.foo ((42)), 43 # => ok
51
+ # x.foo 42, 43 do ; end # => ok
52
+ # x.foo (42), 43 do ; end # => ok
53
+ # x.foo ((42)), 43 do ; end # => parse error!
46
54
  def need_parentheses?
47
55
  true unless
48
56
  arguments.empty? || # No issue when no arguments
49
- receiver || # No ambiguity if there is a receiver
57
+ loc_hash[:selector_end] || # No issue with foo[bar]= and such
58
+ loc_hash[:operator] || # No issue with foo.bar=
50
59
  loc_hash[:begin] # Ok if has parentheses
51
60
  end
52
61
  end
@@ -0,0 +1,61 @@
1
+ module DeepCover
2
+ class ProblemWithDiagnostic < StandardError
3
+ attr_reader :covered_code, :line_range, :original_exception
4
+
5
+ def initialize(covered_code, line_range, original_exception=nil)
6
+ @covered_code = covered_code
7
+ if line_range.is_a?(Parser::Source::Range)
8
+ @line_range = line_range.line..line_range.last_line
9
+ else
10
+ @line_range = line_range
11
+ end
12
+ @original_exception = original_exception
13
+ end
14
+
15
+ def message
16
+ msg = []
17
+ msg << "You found a problem with DeepCover!"
18
+ msg << "Please open an issue at https://github.com/deep-cover/deep-cover/issues"
19
+ msg << "and include the following diagnostic information:"
20
+ extra = begin
21
+ diagnostic_information_lines.map{|line| "| #{line}"}
22
+ rescue ProblemWithDiagnostic
23
+ ["Oh no! We're in deep trouble!!!"]
24
+ rescue Exception => e
25
+ ["Oh no! Even diagnostics are failing: #{e}\n#{e.backtrace}"]
26
+ end
27
+ msg.concat(extra)
28
+ msg.join("\n")
29
+ end
30
+
31
+ def diagnostic_information_lines
32
+ lines = []
33
+ lines << "Source file: #{covered_code.path}"
34
+ lines << "Line numbers: #{line_range}"
35
+ lines << "Source lines around location:"
36
+ lines.concat source_lines.map{|line| " #{line}" }
37
+ if original_exception
38
+ lines << "Original exception:"
39
+ lines << " #{original_exception.class.name}: #{original_exception.message}"
40
+ backtrace = Tools.truncate_backtrace(original_exception)
41
+ lines.concat backtrace.map{|line| " #{line}"}
42
+ end
43
+ lines
44
+ end
45
+
46
+ def source_lines(nb_context_line: 7)
47
+ first_index = line_range.begin - nb_context_line - buffer.first_line
48
+ first_index = 0 if first_index < 0
49
+ last_index = line_range.end + nb_context_line - buffer.first_line
50
+ last_index = 0 if last_index < 0
51
+
52
+ lines = buffer.source_lines[first_index..last_index]
53
+
54
+ Tools.number_lines(lines, lineno: buffer.first_line, bad_linenos: line_range.to_a)
55
+ end
56
+
57
+ def buffer
58
+ covered_code.buffer
59
+ end
60
+ end
61
+ end
@@ -7,8 +7,10 @@ module DeepCover
7
7
  cur_lineno = lineno + i
8
8
  cur_lineno_s = cur_lineno.to_s.rjust(nb_lineno_digits)
9
9
  if bad_linenos.include?(cur_lineno)
10
+ cur_lineno_s = "*#{cur_lineno_s}" unless bad_linenos.empty?
10
11
  prefix = Term::ANSIColor.red("#{cur_lineno_s} | ")
11
12
  else
13
+ cur_lineno_s = " #{cur_lineno_s}" unless bad_linenos.empty?
12
14
  prefix = Term::ANSIColor.white("#{cur_lineno_s} | ")
13
15
  end
14
16
  "#{prefix}#{line}"
@@ -3,7 +3,7 @@ module DeepCover
3
3
  def our_coverage(source, fn, lineno, **options)
4
4
  covered_code = CoveredCode.new(source:source, path: fn, lineno: lineno)
5
5
  Tools.execute_sample(covered_code)
6
- covered_code.line_coverage(options)
6
+ covered_code.line_coverage(options)[(lineno-1)..-1]
7
7
  end
8
8
  end
9
9
  end
@@ -0,0 +1,30 @@
1
+ module DeepCover
2
+ module Tools::TruncateBacktrace
3
+ def truncate_backtrace(backtrace, extra_context: 10)
4
+ backtrace = backtrace.backtrace if backtrace.is_a?(Exception)
5
+ trace_lines = backtrace.uniq
6
+
7
+ keep_from_begin = 0
8
+ keep_from_end = backtrace.size - 1
9
+
10
+ trace_lines.each do |line|
11
+ from_begin = backtrace.index(line)
12
+ from_end = backtrace.rindex(line)
13
+ if from_begin <= backtrace.size - 1 - from_end
14
+ keep_from_begin = [keep_from_begin, from_begin].max
15
+ else
16
+ keep_from_end = [keep_from_end, from_end].min
17
+ end
18
+ end
19
+
20
+ keep_from_begin += extra_context
21
+ keep_from_end -= extra_context
22
+
23
+ return backtrace if keep_from_begin + 5 >= keep_from_end
24
+
25
+ result = backtrace[0..keep_from_begin]
26
+ result << "... #{keep_from_end - keep_from_begin - 1} levels..."
27
+ result.concat backtrace[keep_from_end..-1]
28
+ end
29
+ end
30
+ end
@@ -1,3 +1,3 @@
1
1
  module DeepCover
2
- VERSION = "0.1.13"
2
+ VERSION = "0.1.14"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deep-cover
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ version: 0.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-André Lafortune
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2017-11-05 00:00:00.000000000 Z
12
+ date: 2017-11-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parser
@@ -288,6 +288,7 @@ files:
288
288
  - lib/deep_cover/node/splat.rb
289
289
  - lib/deep_cover/node/variables.rb
290
290
  - lib/deep_cover/parser_ext/range.rb
291
+ - lib/deep_cover/problem_with_diagnostic.rb
291
292
  - lib/deep_cover/reporter.rb
292
293
  - lib/deep_cover/reporter/istanbul.rb
293
294
  - lib/deep_cover/tools.rb
@@ -304,6 +305,7 @@ files:
304
305
  - lib/deep_cover/tools/require_relative_dir.rb
305
306
  - lib/deep_cover/tools/silence_warnings.rb
306
307
  - lib/deep_cover/tools/slice.rb
308
+ - lib/deep_cover/tools/truncate_backtrace.rb
307
309
  - lib/deep_cover/version.rb
308
310
  homepage: http://github.com
309
311
  licenses:
@@ -325,7 +327,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
325
327
  version: '0'
326
328
  requirements: []
327
329
  rubyforge_project:
328
- rubygems_version: 2.6.13
330
+ rubygems_version: 2.6.14
329
331
  signing_key:
330
332
  specification_version: 4
331
333
  summary: Write a short summary, because Rubygems requires one.