rodiff 1.1.1 → 1.2.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/README.md +58 -2
- data/lib/rodiff/configuration.rb +81 -0
- data/lib/rodiff/helpers/file_finder.rb +39 -0
- data/lib/rodiff/version.rb +1 -1
- metadata +12 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 864417eae37667c26264ea7de3365d12511c4069d89e83c859641de7c00c22cc
|
|
4
|
+
data.tar.gz: 5cc69618a1b4893e10d428a387e85f813b26278496f2601abc5315113726e3a3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f77b00f02f5f934de75c153c82c8000641a8e1f6e8edebab6f56c0f42af3a34179ca3796a49f82506747934d6f1cc1d34fed2e027290febad530ca92e5630321
|
|
7
|
+
data.tar.gz: 3551ea66e08e3c8f65bd7ed32fc47f5a3b0681ebd08646edc313284dc9260e04c855a7a9c2cb7d3c7fc1e878f56d40c8fe1b95c06a51a9076a52296bec778357
|
data/README.md
CHANGED
|
@@ -9,10 +9,9 @@ A ruby image comparison tool powered by [Odiff](https://github.com/dmtrKovalenko
|
|
|
9
9
|
|
|
10
10
|
## Motivation
|
|
11
11
|
|
|
12
|
-
A strong candidate against the veteran players on the internet like [pixelmatch](https://github.com/mapbox/pixelmatch) and [ImageMagick](https://github.com/ImageMagick/ImageMagick)
|
|
13
|
-
|
|
14
12
|
Impressive [benchmarks](https://github.com/dmtrKovalenko/odiff#benchmarks) from `Odiff`.
|
|
15
13
|
|
|
14
|
+
A strong candidate against the veteran players like [pixelmatch](https://github.com/mapbox/pixelmatch) and [ImageMagick](https://github.com/ImageMagick/ImageMagick)
|
|
16
15
|
|
|
17
16
|
## Getting Started
|
|
18
17
|
|
|
@@ -51,6 +50,63 @@ or, for relative paths like `./node_modules/.bin/odiff`:
|
|
|
51
50
|
ODIFF_INSTALL_DIR=node_modules/.bin
|
|
52
51
|
```
|
|
53
52
|
|
|
53
|
+
## Configuration
|
|
54
|
+
|
|
55
|
+
Rodiff automatically discovers and loads configuration from `.rodiff.yml` files in your project.
|
|
56
|
+
|
|
57
|
+
### Configuration File Discovery
|
|
58
|
+
|
|
59
|
+
Rodiff searches for `.rodiff.yml` starting from the current directory and traversing upward to your home directory:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
/home/username/projects/myapp/src/tests/.rodiff.yml ← checks here first
|
|
63
|
+
/home/username/projects/myapp/src/.rodiff.yml
|
|
64
|
+
/home/username/projects/myapp/.rodiff.yml ← typically found here
|
|
65
|
+
/home/username/projects/.rodiff.yml
|
|
66
|
+
/home/username/.rodiff.yml ← stops here (home directory)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Configuration Options
|
|
70
|
+
|
|
71
|
+
Create a `.rodiff.yml` file in your project root:
|
|
72
|
+
|
|
73
|
+
```yaml
|
|
74
|
+
# File patterns for image comparison (supports glob patterns)
|
|
75
|
+
include_pattern: "screenshots/**/*.png"
|
|
76
|
+
exclude_pattern: "screenshots/archived/**"
|
|
77
|
+
|
|
78
|
+
# Comparison settings
|
|
79
|
+
color_threshold: 0.1 # 0.0 - 1.0 (lower = stricter)
|
|
80
|
+
ignore_antialiasing: false # Ignore antialiasing differences
|
|
81
|
+
output_diff_mask: false # Output black/white mask instead of diff image
|
|
82
|
+
|
|
83
|
+
# Error handling
|
|
84
|
+
fail_if_no_comparison: false # Exit with error if no images found
|
|
85
|
+
exit_code_error: 1 # Exit code for errors (not image differences)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Programmatic Configuration
|
|
89
|
+
|
|
90
|
+
You can also configure Rodiff programmatically:
|
|
91
|
+
|
|
92
|
+
```ruby
|
|
93
|
+
Rodiff.configure do |config|
|
|
94
|
+
config.include_pattern = "**/*.png"
|
|
95
|
+
config.color_threshold = 0.15
|
|
96
|
+
config.ignore_antialiasing = true
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Or override specific values:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
config = Rodiff::Configuration.new
|
|
104
|
+
config.overrides(
|
|
105
|
+
color_threshold: 0.2,
|
|
106
|
+
output_diff_mask: true
|
|
107
|
+
)
|
|
108
|
+
```
|
|
109
|
+
|
|
54
110
|
## Development
|
|
55
111
|
|
|
56
112
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/rodiff/configuration.rb
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "yaml"
|
|
3
4
|
require "rodiff/error"
|
|
4
5
|
require "rodiff/executable"
|
|
6
|
+
require "rodiff/helpers/file_finder"
|
|
5
7
|
|
|
6
8
|
module Rodiff
|
|
7
9
|
def self.configuration
|
|
@@ -15,6 +17,15 @@ module Rodiff
|
|
|
15
17
|
class Configuration
|
|
16
18
|
class UnknownConfiguration < Rodiff::Error; end
|
|
17
19
|
|
|
20
|
+
DOTFILE = ".rodiff.yml"
|
|
21
|
+
GEM_ROOT = if RUBY_VERSION >= "3.1"
|
|
22
|
+
File.dirname(__FILE__, 3).freeze
|
|
23
|
+
else
|
|
24
|
+
File.expand_path(File.join(File.dirname(__FILE__), "..", "..")).freeze
|
|
25
|
+
end
|
|
26
|
+
DEFAULT_CONFIG = File.join(GEM_ROOT, "config", "default.yml").freeze
|
|
27
|
+
SEARCH_ROOT = Dir.home.freeze
|
|
28
|
+
|
|
18
29
|
ATTRS = Module.new.tap { |mod| include mod }
|
|
19
30
|
READER_ATTRS = {
|
|
20
31
|
default_dir: "/"
|
|
@@ -67,6 +78,9 @@ module Rodiff
|
|
|
67
78
|
|
|
68
79
|
READER_ATTRS.each { |key, value| instance_variable_set("@#{key}", value) }
|
|
69
80
|
ACCESSOR_ATTRS.each { |key, value| instance_variable_set("@#{key}", value) }
|
|
81
|
+
|
|
82
|
+
load_from_file(DEFAULT_CONFIG)
|
|
83
|
+
load_from_file(config_file_override) if config_file_override
|
|
70
84
|
end
|
|
71
85
|
|
|
72
86
|
def odiff_exe_path
|
|
@@ -84,6 +98,38 @@ module Rodiff
|
|
|
84
98
|
|
|
85
99
|
private
|
|
86
100
|
|
|
101
|
+
def config_file_override(start_dir: Dir.pwd)
|
|
102
|
+
@config_file_override ||= begin
|
|
103
|
+
finder = Helpers::FileFinder.new("/")
|
|
104
|
+
finder.find_upwards(DOTFILE, start_dir, SEARCH_ROOT)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def load_from_file(path)
|
|
109
|
+
yml_config = YAML.load_file(path) if File.exist?(path)
|
|
110
|
+
|
|
111
|
+
if yml_config.is_a?(Hash)
|
|
112
|
+
yml_config.each do |key, value|
|
|
113
|
+
validate_config_key!(key.to_sym)
|
|
114
|
+
public_send("#{key}=", value) if respond_to?("#{key}=")
|
|
115
|
+
end
|
|
116
|
+
elsif empty_yml?(yml_config)
|
|
117
|
+
warn "Configuration file #{path} is empty"
|
|
118
|
+
else
|
|
119
|
+
warn "Configuration file #{path} must contain a Hash, got #{yml_config.class}"
|
|
120
|
+
end
|
|
121
|
+
rescue Psych::SyntaxError => e
|
|
122
|
+
raise Rodiff::Error, "Invalid YAML in #{path}: #{e.message}"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def empty_yml?(data)
|
|
126
|
+
# Ruby 2.7-3.0 with Psych 3.x
|
|
127
|
+
return data == false if RUBY_VERSION < "3.1"
|
|
128
|
+
|
|
129
|
+
# Ruby 3.1+ with Psych 4.x
|
|
130
|
+
data.nil?
|
|
131
|
+
end
|
|
132
|
+
|
|
87
133
|
def validate_config_key!(key)
|
|
88
134
|
return if READER_ATTRS.key?(key) || ACCESSOR_ATTRS.key?(key)
|
|
89
135
|
|
|
@@ -94,5 +140,40 @@ module Rodiff
|
|
|
94
140
|
validate_config_key!(key)
|
|
95
141
|
@config_overrides.fetch(key, &block)
|
|
96
142
|
end
|
|
143
|
+
|
|
144
|
+
def files_from_dir(dir)
|
|
145
|
+
included_files = files_from_glob(file_glob_pattern(dir, include_pattern))
|
|
146
|
+
excluded_files = files_from_glob(file_glob_pattern(dir, exclude_pattern))
|
|
147
|
+
(included_files - excluded_files).uniq
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def files_from_glob(file_glob)
|
|
151
|
+
files = Dir.glob(file_glob)
|
|
152
|
+
files.map { |file| File.expand_path(file) }.sort
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def file_glob_pattern(path, pattern)
|
|
156
|
+
trimmed = "{#{pattern.gsub(%r{\s*,\s*}, ",")}}"
|
|
157
|
+
return trimmed if pattern =~ %r{^(\./)?#{Regexp.escape(path)}} || absolute_pattern?(pattern)
|
|
158
|
+
|
|
159
|
+
File.join(path, trimmed)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def absolute_pattern?(pattern)
|
|
163
|
+
return pattern.start_with?(File::Separator) unless windows?
|
|
164
|
+
return false unless File::ALT_SEPARATOR
|
|
165
|
+
|
|
166
|
+
win_absolute_pattern = %r{\A\w+:#{Regexp.escape(File::ALT_SEPARATOR)}}.match?(pattern)
|
|
167
|
+
win_network_pattern = pattern.start_with?(File::ALT_SEPARATOR * 2)
|
|
168
|
+
win_absolute_pattern || win_network_pattern
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def windows?
|
|
172
|
+
@windows ||= begin
|
|
173
|
+
require "rbconfig"
|
|
174
|
+
os = RbConfig::CONFIG["host_os"]
|
|
175
|
+
os.match?(%r{mingw})
|
|
176
|
+
end
|
|
177
|
+
end
|
|
97
178
|
end
|
|
98
179
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rodiff
|
|
4
|
+
module Helpers
|
|
5
|
+
class FileFinder
|
|
6
|
+
attr_reader :root_dir
|
|
7
|
+
|
|
8
|
+
def initialize(root)
|
|
9
|
+
@root_dir = root
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def find_upwards(filename, start_dir, stop_dir = nil)
|
|
13
|
+
traverse_upwards(filename, start_dir, stop_dir) { |file| return file if file } # return first result
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def find_top_most(filename, start_dir, stop_dir = nil)
|
|
17
|
+
top_most_file = nil
|
|
18
|
+
traverse_upwards(filename, start_dir, stop_dir) { |file| top_most_file = file }
|
|
19
|
+
top_most_file
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def traverse_upwards(filename, start_dir, stop_dir)
|
|
25
|
+
start = Pathname.new(start_dir).expand_path
|
|
26
|
+
root = Pathname.new(root_dir).expand_path
|
|
27
|
+
return unless start.to_s.start_with?(root.to_s)
|
|
28
|
+
|
|
29
|
+
stop = Pathname.new(stop_dir).expand_path if stop_dir
|
|
30
|
+
start.ascend do |dir|
|
|
31
|
+
file = File.join(dir, filename)
|
|
32
|
+
yield(file) if File.exist?(file)
|
|
33
|
+
|
|
34
|
+
break if dir == stop || dir == root
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/rodiff/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rodiff
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ryan Chang
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: thor
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
18
|
version: 1.3.2
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 1.5.0
|
|
20
22
|
type: :runtime
|
|
21
23
|
prerelease: false
|
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
25
|
requirements:
|
|
24
|
-
- - "
|
|
26
|
+
- - ">="
|
|
25
27
|
- !ruby/object:Gem::Version
|
|
26
28
|
version: 1.3.2
|
|
27
|
-
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: 1.5.0
|
|
28
32
|
email:
|
|
29
33
|
- ryancyq@gmail.com
|
|
30
34
|
executables:
|
|
@@ -41,6 +45,7 @@ files:
|
|
|
41
45
|
- lib/rodiff/configuration.rb
|
|
42
46
|
- lib/rodiff/error.rb
|
|
43
47
|
- lib/rodiff/executable.rb
|
|
48
|
+
- lib/rodiff/helpers/file_finder.rb
|
|
44
49
|
- lib/rodiff/odiff.rb
|
|
45
50
|
- lib/rodiff/version.rb
|
|
46
51
|
homepage: https://github.com/ryancyq/rodiff
|
|
@@ -51,7 +56,6 @@ metadata:
|
|
|
51
56
|
allowed_push_host: https://rubygems.org
|
|
52
57
|
changelog_uri: https://github.com/ryancyq/rodiff/blob/main/CHANGELOG.md
|
|
53
58
|
homepage_uri: https://github.com/ryancyq/rodiff
|
|
54
|
-
post_install_message:
|
|
55
59
|
rdoc_options: []
|
|
56
60
|
require_paths:
|
|
57
61
|
- lib
|
|
@@ -67,8 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
67
71
|
version: 3.2.0
|
|
68
72
|
requirements:
|
|
69
73
|
- odiff, >= 3.0
|
|
70
|
-
rubygems_version:
|
|
71
|
-
signing_key:
|
|
74
|
+
rubygems_version: 4.0.3
|
|
72
75
|
specification_version: 4
|
|
73
76
|
summary: A ruby image comparison tool powered by ODiff in OCamel
|
|
74
77
|
test_files: []
|