spec_views 3.2.1 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54310e0011e60f8a5484b9a8450101e0ae7ba804ccc2194f719cbf974b9eb500
4
- data.tar.gz: 6451285b6a799ce30614e9c36d16e3bc633a8bdebdb5938a94549dad906378ea
3
+ metadata.gz: ffc864c05ff98f751abe8d28920fb4dcddcf8da527299327a42f1565bc545718
4
+ data.tar.gz: dbb69ec88cdbaa8157875ff907f1d1b0a31475029454e5d0d23993b6c5a5e9d2
5
5
  SHA512:
6
- metadata.gz: 98f12c25bc8cde3f8f6a9aa21a3712b764dc55531299e4e7b883cb71593a19457922f8d84b30852a097bf22687fd1da1aaf9da0dcf1bf0b86b8073fa72e94350
7
- data.tar.gz: e513e67cbed82c90b6acfab920ef547b17a7f7da92409f801f5658d2b0dd283fc66c5e3d708f32a7f783c77f9909b1027e7afcb0cee8cce274b4ad07dafcd066
6
+ metadata.gz: cf0d8f5c736f7736eede534183b70d52ff1782545d2086542126dfaba9c66af03bbd46e70a073bdd4b7adcb8b4012d9e2016c789c99739308a57f53872ab1ca9
7
+ data.tar.gz: '0387e85f37e57af40325a7282dff27ac5687e13d2e7f156894dc77c8abc27fc91b2003e0aa21fadd6b51cbc9dc6c0e943ebae9bd127070a84bea03c54b723da1'
@@ -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'
@@ -84,6 +101,7 @@ module SpecViews
84
101
  def directories
85
102
  @directories ||= Pathname.new(directory_path).children.select(&:directory?).map do |path|
86
103
  next unless File.file?("#{path}/meta.txt")
104
+
87
105
  SpecViews::Directory.new(path)
88
106
  end.compact
89
107
  latest_run = @directories.map(&:last_run).max
@@ -114,7 +132,7 @@ module SpecViews
114
132
 
115
133
  def accept_directory(dir)
116
134
  FileUtils.copy_file(dir.challenger_path, dir.champion_path)
117
- FileUtils.remove_file(dir.challenger_path)
135
+ dir.remove_challenger
118
136
  end
119
137
  end
120
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.\-]/, '_').gsub('__', '_')
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
@@ -23,9 +23,8 @@ module SpecViews
23
23
  private
24
24
 
25
25
  def response_status_match?(response, expected_status)
26
- # Use "#{response.message}" to ensure local encoding
27
26
  response.status == expected_status ||
28
- "#{response.message}".parameterize.underscore == expected_status.to_s
27
+ response.message.to_s.dup.force_encoding('UTF-8').parameterize.underscore == expected_status.to_s
29
28
  end
30
29
  end
31
30
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SpecViews
2
4
  class ViewSanitizer
3
5
  delegate :each, to: :@sanitizers
@@ -17,4 +19,4 @@ module SpecViews
17
19
  string
18
20
  end
19
21
  end
20
- end
22
+ 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
@@ -6,8 +6,10 @@ Rails.application.routes.draw do
6
6
 
7
7
  resources :views, only: %i[index show] do
8
8
  collection do
9
+ get :batch
9
10
  delete :destroy_outdated
10
11
  post :accept_all
12
+ post :batch_accept
11
13
  end
12
14
  member do
13
15
  get :compare
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SpecViews
4
- VERSION = '3.2.1'
4
+ VERSION = '3.3.1'
5
5
  end
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.2.1
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Gaul
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-20 00:00:00.000000000 Z
11
+ date: 2023-11-09 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.1.6
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