summaryrefslogtreecommitdiff
path: root/spec/mspec/tool/remove_old_guards.rb
blob: 75c48e058433e7e5aff450bb57056659454ecf5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env ruby

# Removes old version guards in ruby/spec.
# Run it from the ruby/spec repository root.
# The argument is the new minimum supported version.
#
#   cd spec
#   ../mspec/tool/remove_old_guards.rb <ruby-version>
#
# where <ruby-version> is a version guard with which should be removed
#
# Example:
#   tool/remove_old_guards.rb 3.1
#
# As a result guards like
#   ruby_version_is "3.1" do
#     # ...
#   end
#
# will be removed.

def dedent(line)
  if line.start_with?("  ")
    line[2..-1]
  else
    line
  end
end

def each_spec_file(&block)
  Dir["*/**/*.rb"].each(&block)
end

def remove_guards(guard, keep)
  each_spec_file do |file|
    contents = File.binread(file)
    if contents =~ guard
      puts file
      lines = contents.lines.to_a
      while first = lines.find_index { |line| line =~ guard }
        comment = first
        while comment > 0 and lines[comment-1] =~ /^(\s*)#/
          comment -= 1
        end
        indent = lines[first][/^(\s*)/, 1].length
        last = (first+1...lines.size).find { |i|
          space = lines[i][/^(\s*)end$/, 1] and space.length == indent
        }
        raise file unless last
        if keep
          lines[comment..last] = lines[first+1..last-1].map { |l| dedent(l) }
        else
          if comment > 0 and lines[comment-1] == "\n"
            comment -= 1
          elsif lines[last+1] == "\n"
            last += 1
          end
          lines[comment..last] = []
        end
      end
      File.binwrite file, lines.join
    end
  end
end

def remove_empty_files
  each_spec_file do |file|
    unless file.include?("fixtures/")
      lines = File.readlines(file)
      if lines.all? { |line| line.chomp.empty? or line.start_with?('require', '#') }
        puts "Removing empty file #{file}"
        File.delete(file)
      end
    end
  end
end

def remove_unused_shared_specs
  shared_groups = {}
  # Dir["**/shared/**/*.rb"].each do |shared|
  each_spec_file do |shared|
    next if File.basename(shared) == 'constants.rb'
    contents = File.binread(shared)
    found = false
    contents.scan(/^\s*describe (:[\w_?]+), shared: true do$/) {
      shared_groups[$1] = 0
      found = true
    }
    if !found and shared.include?('shared/') and !shared.include?('fixtures/') and !shared.end_with?('/constants.rb')
      puts "no shared describe in #{shared} ?"
    end
  end

  each_spec_file do |file|
    contents = File.binread(file)
    contents.scan(/(?:it_behaves_like|it_should_behave_like) (:[\w_?]+)[,\s]/) do
      puts $1 unless shared_groups.key?($1)
      shared_groups[$1] += 1
    end
  end

  shared_groups.each_pair do |group, value|
    if value == 0
      puts "Shared describe #{group} seems unused"
    elsif value == 1
      puts "Shared describe #{group} seems used only once" if $VERBOSE
    end
  end
end

def search(regexp)
  each_spec_file do |file|
    contents = File.binread(file)
    if contents =~ regexp
      puts file
      contents.each_line do |line|
        if line =~ regexp
          puts line
        end
      end
    end
  end
end

abort "usage: #{$0} <ruby-version>" if ARGV.empty?

version = Regexp.escape(ARGV.fetch(0))
version += "(?:\\.0)?" if version.count(".") < 2
remove_guards(/ruby_version_is (["'])#{version}\1 do/, true)
remove_guards(/ruby_version_is (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, false)
remove_guards(/ruby_bug ["']#\d+["'], (["'])[0-9.]*\1 *... *(["'])#{version}\2 do/, true)

remove_empty_files
remove_unused_shared_specs

puts "Search:"
search(/(["'])#{version}\1/)
search(/^\s*#.+#{version}/)