spec_views 3.2.0 → 3.3.0
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 +4 -4
- data/app/controllers/spec_views/views_controller.rb +21 -2
- data/app/models/spec_views/batch_diff.rb +82 -0
- data/app/models/spec_views/directory.rb +20 -1
- data/app/models/spec_views/http_response_extractor.rb +1 -1
- data/app/models/spec_views/view_sanitizer.rb +3 -1
- data/app/views/layouts/spec_views.html.erb +35 -0
- data/app/views/spec_views/views/batch.html.erb +27 -0
- data/app/views/spec_views/views/index.html.erb +3 -0
- data/config/routes.rb +2 -0
- data/lib/spec_views/version.rb +1 -1
- metadata +19 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eae6dff5e22673bd670708e1ff9c1855dcde1b7a669ed512edc83df789385e09
|
4
|
+
data.tar.gz: a96b241b47200e29e362388dede1e402325ae220bdc903a975614dd72c1fdf15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e8990413a8eed49d4a16bf39165c8910c426e6b08bbf864c015ba4d2fc4652a0ed648bf3e1a51f1c9cfaa53e2f75ca49e6be355c49480840efc2b5baff2b77c
|
7
|
+
data.tar.gz: ad2c9c6e96a4ce3170157ecd631b4825c25773fd5140b7cc5e2b6608c59e923d358bb6211732545c6a54813ab24a49d13d0e81813d088d0158f108794b256b02
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'diff/lcs'
|
4
|
+
|
3
5
|
module SpecViews
|
4
6
|
class ViewsController < ApplicationController
|
5
7
|
skip_authorization_check if respond_to?(:skip_authorization_check)
|
@@ -18,6 +20,21 @@ module SpecViews
|
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
23
|
+
def batch
|
24
|
+
@change = BatchDiff.new(directories).biggest_change
|
25
|
+
redirect_to(url_for(action: :index), notice: 'No identical changes found') unless @change
|
26
|
+
end
|
27
|
+
|
28
|
+
def batch_accept
|
29
|
+
batch_diff = BatchDiff.new(directories)
|
30
|
+
batch_diff.accept_by_hash!(params[:hash])
|
31
|
+
if batch_diff.changes.size > 1
|
32
|
+
redirect_to(action: :batch)
|
33
|
+
else
|
34
|
+
redirect_to(action: :index)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
21
38
|
def show
|
22
39
|
path = directory.champion_path
|
23
40
|
path = directory.challenger_path if params[:view] == 'challenger'
|
@@ -83,8 +100,10 @@ module SpecViews
|
|
83
100
|
|
84
101
|
def directories
|
85
102
|
@directories ||= Pathname.new(directory_path).children.select(&:directory?).map do |path|
|
103
|
+
next unless File.file?("#{path}/meta.txt")
|
104
|
+
|
86
105
|
SpecViews::Directory.new(path)
|
87
|
-
end
|
106
|
+
end.compact
|
88
107
|
latest_run = @directories.map(&:last_run).max
|
89
108
|
|
90
109
|
@directories.sort_by! do |dir|
|
@@ -113,7 +132,7 @@ module SpecViews
|
|
113
132
|
|
114
133
|
def accept_directory(dir)
|
115
134
|
FileUtils.copy_file(dir.challenger_path, dir.champion_path)
|
116
|
-
|
135
|
+
dir.remove_challenger
|
117
136
|
end
|
118
137
|
end
|
119
138
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SpecViews
|
4
|
+
class BatchDiff
|
5
|
+
attr_reader :directories
|
6
|
+
|
7
|
+
Change = Struct.new(:hash, :count) do
|
8
|
+
def patched_champion
|
9
|
+
Diff::LCS.patch!(champion, diff)
|
10
|
+
end
|
11
|
+
|
12
|
+
def champion
|
13
|
+
directory.champion_html
|
14
|
+
end
|
15
|
+
|
16
|
+
def add(directory, diff)
|
17
|
+
@pairs ||= []
|
18
|
+
@pairs.push([directory, diff])
|
19
|
+
self.count += 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def directory
|
23
|
+
@pairs&.first&.first
|
24
|
+
end
|
25
|
+
|
26
|
+
def diff
|
27
|
+
@pairs&.first&.second
|
28
|
+
end
|
29
|
+
|
30
|
+
def accept!
|
31
|
+
@pairs.each do |directory, diff|
|
32
|
+
patched_champion = Diff::LCS.patch!(directory.champion_html, diff)
|
33
|
+
directory.write_champion(patched_champion)
|
34
|
+
directory.remove_challenger if patched_champion == directory.challenger_html
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(directories)
|
40
|
+
@directories = directories.select(&:challenger?).select(&:champion?).reject(&:binary?)
|
41
|
+
end
|
42
|
+
|
43
|
+
def changes
|
44
|
+
@changes ||= begin
|
45
|
+
map = {}
|
46
|
+
@directories.each do |directory|
|
47
|
+
diffs = Diff::LCS.diff(directory.champion_html, directory.challenger_html)
|
48
|
+
diffs.each do |diff|
|
49
|
+
raw_diff = diff.map do |change|
|
50
|
+
element = change.element
|
51
|
+
element = '\r' if element == "\r"
|
52
|
+
element = '\n' if element == "\n"
|
53
|
+
[change.action, element]
|
54
|
+
end
|
55
|
+
diff_hash = raw_diff.map(&:join).join
|
56
|
+
map[diff_hash] ||= Change.new(diff_hash, 0)
|
57
|
+
map[diff_hash].add(directory, diff)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
map.values.filter { |change| change.count > 1 }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def biggest_change
|
65
|
+
changes.max_by(&:count)
|
66
|
+
end
|
67
|
+
|
68
|
+
def accept_by_hash!(hash)
|
69
|
+
changes.select { |change| change.hash == hash }.map(&:accept!)
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def get_view(path, html_safe: true)
|
75
|
+
content = File.read(path)
|
76
|
+
content = content.html_safe if html_safe
|
77
|
+
content
|
78
|
+
rescue Errno::ENOENT
|
79
|
+
''
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -5,7 +5,7 @@ module SpecViews
|
|
5
5
|
attr_reader :path
|
6
6
|
|
7
7
|
def self.for_description(description, content_type: :html)
|
8
|
-
dir_name = description.strip.gsub(/[^0-9A-Za-z
|
8
|
+
dir_name = description.strip.gsub(/[^0-9A-Za-z.-]/, '_').gsub('__', '_')
|
9
9
|
new(Rails.root.join(Rails.configuration.spec_views.directory, dir_name), content_type)
|
10
10
|
end
|
11
11
|
|
@@ -46,12 +46,21 @@ module SpecViews
|
|
46
46
|
path.join("view.#{file_extension}")
|
47
47
|
end
|
48
48
|
|
49
|
+
def champion?
|
50
|
+
File.file?(champion_path)
|
51
|
+
end
|
52
|
+
|
49
53
|
def champion_html
|
50
54
|
File.read(champion_path)
|
51
55
|
rescue Errno::ENOENT
|
52
56
|
nil
|
53
57
|
end
|
54
58
|
|
59
|
+
def write_champion(content)
|
60
|
+
FileUtils.mkdir_p(path)
|
61
|
+
File.open(champion_path, binary? ? 'wb' : 'w') { |f| f.write(content) }
|
62
|
+
end
|
63
|
+
|
55
64
|
def challenger_path
|
56
65
|
path.join("challenger.#{file_extension}")
|
57
66
|
end
|
@@ -60,11 +69,21 @@ module SpecViews
|
|
60
69
|
File.file?(challenger_path)
|
61
70
|
end
|
62
71
|
|
72
|
+
def challenger_html
|
73
|
+
File.read(challenger_path)
|
74
|
+
rescue Errno::ENOENT
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
63
78
|
def write_challenger(content)
|
64
79
|
FileUtils.mkdir_p(path)
|
65
80
|
File.open(challenger_path, binary? ? 'wb' : 'w') { |f| f.write(content) }
|
66
81
|
end
|
67
82
|
|
83
|
+
def remove_challenger
|
84
|
+
FileUtils.remove_file(challenger_path)
|
85
|
+
end
|
86
|
+
|
68
87
|
def meta_path
|
69
88
|
path.join('meta.txt')
|
70
89
|
end
|
@@ -25,7 +25,7 @@ module SpecViews
|
|
25
25
|
def response_status_match?(response, expected_status)
|
26
26
|
# Use "#{response.message}" to ensure local encoding
|
27
27
|
response.status == expected_status ||
|
28
|
-
|
28
|
+
response.message.to_s.parameterize.underscore == expected_status.to_s
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -39,6 +39,38 @@
|
|
39
39
|
padding: 0;
|
40
40
|
}
|
41
41
|
|
42
|
+
.flash {
|
43
|
+
position: absolute;
|
44
|
+
z-index: 10;
|
45
|
+
top: 1.5rem;
|
46
|
+
left: 0;
|
47
|
+
right: 0;
|
48
|
+
display: flex;
|
49
|
+
justify-content: center;
|
50
|
+
font-size: 0.9rem;
|
51
|
+
pointer-events: none;
|
52
|
+
animation: fade-out 1s 1;
|
53
|
+
animation-fill-mode: forwards;
|
54
|
+
animation-delay: 5s;
|
55
|
+
}
|
56
|
+
.flash > div {
|
57
|
+
padding: 0.5rem 1rem;
|
58
|
+
background-color: var(--dark-bg-lighter);
|
59
|
+
box-shadow: 0px 1px 4px rgba(0, 0, 0, 0.65);
|
60
|
+
border: 0px solid transparent;
|
61
|
+
border-width: 0 6px;
|
62
|
+
border-color: var(--challenger);
|
63
|
+
pointer-events: all;
|
64
|
+
transition: opacity 0.25s ease-in-out;
|
65
|
+
}
|
66
|
+
.flash > div:hover {
|
67
|
+
opacity: 0;
|
68
|
+
}
|
69
|
+
@keyframes fade-out {
|
70
|
+
from { opacity :1; }
|
71
|
+
to { opacity :0; }
|
72
|
+
}
|
73
|
+
|
42
74
|
.iframes {
|
43
75
|
position: relative;
|
44
76
|
z-index: 5;
|
@@ -256,6 +288,9 @@
|
|
256
288
|
</style>
|
257
289
|
</head>
|
258
290
|
<body>
|
291
|
+
<% flash.each do |type, msg| %>
|
292
|
+
<div class="flash flash-<%= type %>"><div onclick="console.log(this.parent)"><%= msg %></div></div>
|
293
|
+
<% end %>
|
259
294
|
<%= yield %>
|
260
295
|
</body>
|
261
296
|
</html>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<div class="iframes">
|
2
|
+
<div class="w-100">
|
3
|
+
<div id="diff-settings">
|
4
|
+
<span>Batch Diff</span>
|
5
|
+
<label><input type="radio" name="diff_type" value="diffChars" checked> Characters</label>
|
6
|
+
<label><input type="radio" name="diff_type" value="diffWords"> Words</label>
|
7
|
+
<label><input type="radio" name="diff_type" value="diffLines"> Lines</label>
|
8
|
+
</div>
|
9
|
+
<div id="diff-champion"><%= @change.champion %></div>
|
10
|
+
<div id="diff-challenger"><%= @change.patched_champion %></div>
|
11
|
+
<pre id="diff-result"></pre>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
<div class="footer">
|
15
|
+
<div class="info">
|
16
|
+
<div>
|
17
|
+
<%= @change.count %> Views with this Changes
|
18
|
+
</div>
|
19
|
+
</div>
|
20
|
+
<div class="actions">
|
21
|
+
<%= link_to 'Index', url_for(action: :index), class: 'index btn' %>
|
22
|
+
<%= button_to "Accept Change for #{@change.count} Views", url_for(action: :batch_accept), { class: 'accept', params: { hash: @change.hash } } %>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
|
27
|
+
<%= javascript_include_tag 'spec_views/diff' %>
|
@@ -38,6 +38,9 @@
|
|
38
38
|
<div class="footer">
|
39
39
|
<div class="info"></div>
|
40
40
|
<div class="actions">
|
41
|
+
<% if @directories.any?(&:challenger?) %>
|
42
|
+
<%= link_to 'Batch Diff', url_for(action: :batch), class: 'diff btn' %>
|
43
|
+
<% end %>
|
41
44
|
<% if @directories.any?{ |dir| dir.last_run < @latest_run } %>
|
42
45
|
<%= button_to 'Remove Outdated', url_for(action: :destroy_outdated), method: :delete, class: 'reject' %>
|
43
46
|
<% end %>
|
data/config/routes.rb
CHANGED
data/lib/spec_views/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spec_views
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Gaul
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: diff-lcs
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rails
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,6 +107,7 @@ files:
|
|
93
107
|
- app/assets/javascripts/spec_views/jsdiff.js
|
94
108
|
- app/controllers/spec_views/views_controller.rb
|
95
109
|
- app/models/spec_views/base_matcher.rb
|
110
|
+
- app/models/spec_views/batch_diff.rb
|
96
111
|
- app/models/spec_views/capybara_session_extractor.rb
|
97
112
|
- app/models/spec_views/directory.rb
|
98
113
|
- app/models/spec_views/html_matcher.rb
|
@@ -103,6 +118,7 @@ files:
|
|
103
118
|
- app/views/layouts/spec_views.html.erb
|
104
119
|
- app/views/spec_views/views/_actions.html.erb
|
105
120
|
- app/views/spec_views/views/_directory_footer.html.erb
|
121
|
+
- app/views/spec_views/views/batch.html.erb
|
106
122
|
- app/views/spec_views/views/compare.html.erb
|
107
123
|
- app/views/spec_views/views/diff.html.erb
|
108
124
|
- app/views/spec_views/views/index.html.erb
|
@@ -133,7 +149,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
149
|
- !ruby/object:Gem::Version
|
134
150
|
version: '0'
|
135
151
|
requirements: []
|
136
|
-
rubygems_version: 3.
|
152
|
+
rubygems_version: 3.3.26
|
137
153
|
signing_key:
|
138
154
|
specification_version: 4
|
139
155
|
summary: Render views from controller specs for comparision
|