rodiff 1.0.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28e710101370bfd2b8a7efd8047d9c0d40b4f68784863673cf897ed9494deaee
4
- data.tar.gz: ddf19f3a1f7f93f46fa9050431815e480dac9708a6e3337fbca9ac58ceb51fb9
3
+ metadata.gz: 864417eae37667c26264ea7de3365d12511c4069d89e83c859641de7c00c22cc
4
+ data.tar.gz: 5cc69618a1b4893e10d428a387e85f813b26278496f2601abc5315113726e3a3
5
5
  SHA512:
6
- metadata.gz: 0073e776a4217abf7467ea32211340f1d0f0a6f01b40b3585d32efb77a55536d6826df8ff29de85876a853863ccd505b498fa999b2cdeb378b614a65f8e6a05f
7
- data.tar.gz: b45fc039a867b9948cd8735deb59505177fd373bb280c273bd4b76107da1aef7d61f22e42bad30674c55165a17e7ba00f5ecab5a6853b23796d9774cc6cc703f
6
+ metadata.gz: f77b00f02f5f934de75c153c82c8000641a8e1f6e8edebab6f56c0f42af3a34179ca3796a49f82506747934d6f1cc1d34fed2e027290febad530ca92e5630321
7
+ data.tar.gz: 3551ea66e08e3c8f65bd7ed32fc47f5a3b0681ebd08646edc313284dc9260e04c855a7a9c2cb7d3c7fc1e878f56d40c8fe1b95c06a51a9076a52296bec778357
data/README.md CHANGED
@@ -1,14 +1,17 @@
1
1
  # rodiff
2
2
 
3
- A ruby wrapper for [Odiff](https://github.com/dmtrKovalenko/odiff), an image comparison tool written in OCamel.
3
+ [![Version][rubygems_badge]][rubygems]
4
+ [![CI][ci_badge]][ci_workflows]
5
+ [![Coverage][coverage_badge]][coverage]
6
+ [![Maintainability][maintainability_badge]][maintainability]
4
7
 
8
+ A ruby image comparison tool powered by [Odiff](https://github.com/dmtrKovalenko/odiff) in OCamel.
5
9
 
6
10
  ## Motivation
7
11
 
8
- A strong candidate against the veteran players on the internet like [pixelmatch](https://github.com/mapbox/pixelmatch) and [ImageMagick](https://github.com/ImageMagick/ImageMagick)
9
-
10
12
  Impressive [benchmarks](https://github.com/dmtrKovalenko/odiff#benchmarks) from `Odiff`.
11
13
 
14
+ A strong candidate against the veteran players like [pixelmatch](https://github.com/mapbox/pixelmatch) and [ImageMagick](https://github.com/ImageMagick/ImageMagick)
12
15
 
13
16
  ## Getting Started
14
17
 
@@ -27,7 +30,7 @@ This gem wraps the [standalone executable](https://github.com/dmtrKovalenko/odif
27
30
  Supported platforms are:
28
31
  - arm64-darwin (macos-arm64)
29
32
  - x64-mingw32 (windows-x64)
30
- - x64-mingw-ucr (windows-x64)
33
+ - x64-mingw-ucrt (windows-x64)
31
34
  - x86_64-darwin (macos-x64)
32
35
  - x86_64-linux (linux-x64)
33
36
 
@@ -35,7 +38,7 @@ Supported platforms are:
35
38
 
36
39
  If you are not able to use the vendored standalone executables, a local installation of the `Odiff` executable can be configured by setting an environment variable named `ODIFF_INSTALL_DIR` to the directory path containing the executable.
37
40
 
38
- For example, if you've installed `odiff` via npm which could be something like `/path/to/node_modules/bin/odiff`, then you should set your environment variable like so:
41
+ For example, if you've installed the [`odiff-bin`](https://github.com/dmtrKovalenko/odiff#cross-platform) npm package and had the binaries downloaded at `/path/to/node_modules/bin/odiff`, then you should set your environment variable like so:
39
42
 
40
43
  ``` sh
41
44
  ODIFF_INSTALL_DIR=/path/to/node_modules/bin
@@ -47,6 +50,63 @@ or, for relative paths like `./node_modules/.bin/odiff`:
47
50
  ODIFF_INSTALL_DIR=node_modules/.bin
48
51
  ```
49
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
+
50
110
  ## Development
51
111
 
52
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.
@@ -93,4 +153,17 @@ See https://bundler.io/man/bundle-config.1.html for more information.
93
153
  ## License
94
154
 
95
155
  Rodiff is released under the [MIT License](https://opensource.org/licenses/MIT).
96
- Odiff is released under the [MIT License](https://opensource.org/licenses/MIT).
156
+ Odiff is released under the [MIT License](https://opensource.org/licenses/MIT).
157
+
158
+ ## Contributing
159
+
160
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/ryancyq/rodiff](https://github.com/ryancyq/rodiff).
161
+
162
+ [rubygems_badge]: https://img.shields.io/gem/v/rodiff.svg
163
+ [rubygems]: https://rubygems.org/gems/rodiff
164
+ [ci_badge]: https://github.com/ryancyq/rodiff/actions/workflows/ci.yml/badge.svg
165
+ [ci_workflows]: https://github.com/ryancyq/rodiff/actions/workflows/ci.yml
166
+ [coverage_badge]: https://codecov.io/gh/ryancyq/rodiff/graph/badge.svg?token=SYR7FSDWT5
167
+ [coverage]: https://codecov.io/gh/ryancyq/rodiff
168
+ [maintainability_badge]: https://api.codeclimate.com/v1/badges/d5b1002a1a7162f86a7a/maintainability
169
+ [maintainability]: https://codeclimate.com/github/ryancyq/rodiff/maintainability
data/exe/rodiff CHANGED
@@ -1,23 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
2
 
4
3
  $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
5
4
 
6
5
  require "rodiff/cli"
7
6
 
8
- begin
9
- verbose = ARGV.delete "--verbose"
10
- command = [Rodiff::CLI.executable, *ARGV]
11
- puts "rodiff: #{command.inspect}" if verbose
12
-
13
- if Gem.win_platform?
14
- # use system rather than exec as exec inexplicably fails to find the executable on Windows
15
- # see related https://github.com/rubys/sprockets-esbuild/pull/4
16
- system(*command, exception: true)
17
- else
18
- exec(*command)
19
- end
20
- rescue Rodiff::CLI::CommandError => e
21
- warn("ERROR: #{e.message}")
22
- exit 1
23
- end
7
+ # set invoked_via_subcommand to ensure default command is used
8
+ Rodiff::CLI.start(ARGV, invoked_via_subcommand: true)
data/lib/rodiff/cli.rb CHANGED
@@ -1,87 +1,69 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rodiff/odiff"
3
+ require "thor"
4
+ require "open3"
5
+ require "shellwords"
4
6
 
5
- module Rodiff
6
- class CLI
7
- DEFAULT_DIR = File.expand_path(File.join(__dir__, "..", "..", "exe"))
8
-
9
- class CommandError < StandardError; end
7
+ require "rodiff/configuration"
8
+ require "rodiff/error"
9
+ require "rodiff/version"
10
10
 
11
- class UnsupportedPlatform < CommandError
12
- def initialize(platform)
13
- super(
14
- <<~MSG
15
- odiff does not support the #{platform} platform
16
- Please install odiff following instructions at https://github.com/dmtrKovalenko/odiff#installation
17
- MSG
18
- )
11
+ module Rodiff
12
+ class CLI < Thor
13
+ package_name "rodiff"
14
+
15
+ default_command :compare
16
+
17
+ desc "version", "Print version"
18
+ map ["-v", "--version"] => :version
19
+ method_option :odiff, type: :boolean, required: false
20
+ def version
21
+ if options.odiff?
22
+ odiff_exec("--version")
23
+ else
24
+ say Rodiff::VERSION
19
25
  end
20
26
  end
21
27
 
22
- class ExecutableNotFound < CommandError
23
- def initialize(platform, exe_path)
24
- super(
25
- <<~MSG
26
- Cannot find the odiff executable for #{platform} in #{exe_path}
27
-
28
- If you're using bundler, please make sure you're on the latest bundler version:
29
-
30
- gem install bundler
31
- bundle update --bundler
28
+ desc "compare [BASELINE] [VARIANT] [DIFF]", "Compare VARIANT against BASELINE, output to DIFF"
29
+ method_option :verbose, type: :boolean, default: false
30
+ def compare(baseline = nil, variant = nil, diff = nil)
31
+ all_present, all_absent = args_presence(baseline, variant, diff)
32
+ raise ArgumentError, "BASELINE, VARIANT, DIFF must be provided" unless all_present ^ all_absent
32
33
 
33
- Then make sure your lock file includes this platform by running:
34
-
35
- bundle lock --add-platform #{platform}
36
- bundle install
37
-
38
- See `bundle lock --help` output for details.
39
-
40
- If you're still seeing this message after taking those steps, try running
41
- `bundle config` and ensure `force_ruby_platform` isn't set to `true`. See
42
- https://github.com/ryancyq/rodiff#check-bundle_force_ruby_platform
43
- for more details.
44
- MSG
45
- )
46
- end
34
+ odiff_exec(baseline, variant, diff)
35
+ rescue Rodiff::Error => e
36
+ raise Thor::Error, "ERROR: #{e.message}"
47
37
  end
48
38
 
49
- class InstallDirectoryNotFound < CommandError
50
- def initialize(install_dir)
51
- super("ODIFF_INSTALL_DIR is set to #{install_dir}, but that directory does not exist.")
52
- end
39
+ def self.exit_on_failure?
40
+ true
53
41
  end
54
42
 
55
- class << self
56
- def platform
57
- %i[cpu os].map { |m| Gem::Platform.local.public_send(m) }.join("-")
58
- end
43
+ private
59
44
 
60
- def supported_platform?(platform = nil)
61
- return Gem::Platform.match_gem?(Gem::Platform.new(platform), "rodiff") unless platform.nil?
45
+ def config
46
+ Rodiff.configuration
47
+ end
62
48
 
63
- Rodiff::Odiff::PLATFORMS.keys.any? { |p| Gem::Platform.match_gem?(Gem::Platform.new(p), "rodiff") }
49
+ def args_presence(*args)
50
+ args.each_with_object([true, true]) do |e, acc|
51
+ acc[0] = false if e.nil? || e == ""
52
+ acc[1] = false unless e.nil? || e == ""
64
53
  end
54
+ end
65
55
 
66
- def executable(exe_path: DEFAULT_DIR)
67
- if (odiff_install_dir = ENV.fetch("ODIFF_INSTALL_DIR", nil))
68
- raise InstallDirectoryNotFound, odiff_install_dir unless File.directory?(odiff_install_dir)
69
-
70
- warn "NOTE: using ODIFF_INSTALL_DIR to find odiff executable: #{odiff_install_dir}"
71
- exe_path = odiff_install_dir
72
- exe_file = File.expand_path(File.join(odiff_install_dir, "odiff"))
73
- else
74
- raise UnsupportedPlatform, platform unless supported_platform?
75
-
76
- exe_files_of_platforms = File.expand_path(File.join(exe_path, "*", "odiff"))
77
- exe_file = Dir.glob(exe_files_of_platforms).find do |f|
78
- supported_platform?(File.basename(File.dirname(f)))
79
- end
80
- end
81
-
82
- raise ExecutableNotFound.new(platform, exe_path) if exe_file.nil? || !File.exist?(exe_file)
83
-
84
- exe_file
56
+ def odiff_exec(*cmd)
57
+ cmd_parts = []
58
+ cmd_parts << config.odiff_exe_path
59
+ cmd_parts.push(*cmd)
60
+
61
+ stdout, stderr, status = Open3.capture3(*cmd_parts)
62
+ if block_given?
63
+ yield stdout, stderr, status
64
+ else
65
+ say_error stderr unless stderr.nil? || stderr == ""
66
+ say stdout unless stdout.nil? || stdout == ""
85
67
  end
86
68
  end
87
69
  end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "rodiff/error"
5
+ require "rodiff/executable"
6
+ require "rodiff/helpers/file_finder"
7
+
8
+ module Rodiff
9
+ def self.configuration
10
+ @configuration ||= Rodiff::Configuration.new
11
+ end
12
+
13
+ def self.configure
14
+ yield configuration
15
+ end
16
+
17
+ class Configuration
18
+ class UnknownConfiguration < Rodiff::Error; end
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
+
29
+ ATTRS = Module.new.tap { |mod| include mod }
30
+ READER_ATTRS = {
31
+ default_dir: "/"
32
+ }.freeze
33
+
34
+ ACCESSOR_ATTRS = {
35
+ include_pattern: "{*,**/*}.jpg",
36
+ exclude_pattern: "",
37
+ compare_pattern: "",
38
+
39
+ ignore_antialiasing: false,
40
+ color_threshold: 0.1,
41
+ output_diff_mask: false,
42
+
43
+ exit_code_odiff: ->(code) { code },
44
+ exit_code_error: 1,
45
+ fail_if_no_comparison: false
46
+ }.freeze
47
+
48
+ def self.generate_config(mod, path, line, attrs)
49
+ mod.module_eval(Array(attrs).join(";").to_s, path, line)
50
+ end
51
+
52
+ def self.config_attribute(name, type:)
53
+ case type
54
+ when :reader, :writer, :accessor then "attr_#{type} :#{name}"
55
+ when :proxy
56
+ <<-RUBY
57
+ def #{name}
58
+ value_for(:#{name}) { super() }
59
+ end
60
+ RUBY
61
+ else
62
+ raise ArgumentError, "unsupported type #{type.inspect}"
63
+ end
64
+ end
65
+
66
+ generate_config ATTRS, __FILE__, __LINE__, [
67
+ *READER_ATTRS.keys.map { |key| config_attribute(key, type: :reader) },
68
+ *ACCESSOR_ATTRS.keys.map { |key| config_attribute(key, type: :accessor) }
69
+ ]
70
+
71
+ generate_config self, __FILE__, __LINE__, [
72
+ *READER_ATTRS.keys.map { |key| config_attribute(key, type: :proxy) },
73
+ *ACCESSOR_ATTRS.keys.map { |key| config_attribute(key, type: :proxy) }
74
+ ]
75
+
76
+ def initialize
77
+ @config_overrides = {}
78
+
79
+ READER_ATTRS.each { |key, value| instance_variable_set("@#{key}", value) }
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
84
+ end
85
+
86
+ def odiff_exe_path
87
+ @odiff_exe_path ||= Rodiff::Executable.resolve
88
+ end
89
+
90
+ def odiff_exe_path=(path)
91
+ @odiff_exe_path = Rodiff::Executable.resolve(exe_path: path)
92
+ end
93
+
94
+ def overrides(opts = {})
95
+ opts.each_key { |key| validate_config_key!(key) }
96
+ @config_overrides.merge!(opts.transform_keys(&:to_sym))
97
+ end
98
+
99
+ private
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
+
133
+ def validate_config_key!(key)
134
+ return if READER_ATTRS.key?(key) || ACCESSOR_ATTRS.key?(key)
135
+
136
+ raise UnknownConfiguration, "unknown config #{key.inspect}"
137
+ end
138
+
139
+ def value_for(key, &block)
140
+ validate_config_key!(key)
141
+ @config_overrides.fetch(key, &block)
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
178
+ end
179
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rodiff
4
+ class Error < StandardError; end
5
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rodiff/odiff"
4
+ require "rodiff/error"
5
+
6
+ module Rodiff
7
+ class Executable
8
+ DEFAULT_DIR = File.expand_path(File.join(__dir__, "..", "..", "exe"))
9
+ LOCAL_INSTALL_DIR_ENV = "ODIFF_INSTALL_DIR"
10
+
11
+ class UnsupportedPlatform < Rodiff::Error
12
+ def initialize(platform)
13
+ super(
14
+ <<~MSG
15
+ odiff does not support the #{platform} platform
16
+ Please install odiff following instructions at https://github.com/dmtrKovalenko/odiff#installation
17
+ MSG
18
+ )
19
+ end
20
+ end
21
+
22
+ class ExecutableNotFound < Rodiff::Error
23
+ def initialize(platform, exe_path)
24
+ super(
25
+ <<~MSG
26
+ Cannot find the odiff executable for #{platform} in #{exe_path}
27
+
28
+ If you're using bundler, please make sure you're on the latest bundler version:
29
+
30
+ gem install bundler
31
+ bundle update --bundler
32
+
33
+ Then make sure your lock file includes this platform by running:
34
+
35
+ bundle lock --add-platform #{platform}
36
+ bundle install
37
+
38
+ See `bundle lock --help` output for details.
39
+
40
+ If you're still seeing this message after taking those steps, try running
41
+ `bundle config` and ensure `force_ruby_platform` isn't set to `true`. See
42
+ https://github.com/ryancyq/rodiff#check-bundle_force_ruby_platform
43
+ for more details.
44
+ MSG
45
+ )
46
+ end
47
+ end
48
+
49
+ class InstallDirectoryNotFound < Rodiff::Error
50
+ def initialize(install_dir)
51
+ super("#{LOCAL_INSTALL_DIR_ENV} is set to #{install_dir}, but that directory does not exist.")
52
+ end
53
+ end
54
+
55
+ class << self
56
+ def platform
57
+ %i[cpu os].map { |m| Gem::Platform.local.public_send(m) }.join("-")
58
+ end
59
+
60
+ def supported_platform?(platform = nil)
61
+ return Gem::Platform.match_gem?(Gem::Platform.new(platform), "rodiff") unless platform.nil?
62
+
63
+ Rodiff::Odiff::PLATFORMS.keys.any? { |p| Gem::Platform.match_gem?(Gem::Platform.new(p), "rodiff") }
64
+ end
65
+
66
+ def resolve(exe_path: DEFAULT_DIR)
67
+ if (odiff_install_dir = ENV.fetch(LOCAL_INSTALL_DIR_ENV, nil))
68
+ exe_path = odiff_install_dir
69
+ exe_file = expand_local_install_dir(odiff_install_dir)
70
+ elsif supported_platform?
71
+ exe_file = expand_bundled_dir(exe_path)
72
+ else
73
+ raise UnsupportedPlatform, platform
74
+ end
75
+
76
+ raise ExecutableNotFound.new(platform, exe_path) if exe_file.nil? || !File.exist?(exe_file)
77
+
78
+ exe_file
79
+ end
80
+
81
+ private
82
+
83
+ def expand_local_install_dir(local_install_dir)
84
+ raise InstallDirectoryNotFound, local_install_dir unless File.directory?(local_install_dir)
85
+
86
+ warn "NOTE: using #{LOCAL_INSTALL_DIR_ENV} to find odiff executable: #{local_install_dir}"
87
+ exe_files = File.expand_path(File.join(local_install_dir, "odiff{,.exe}"))
88
+ Dir.glob(exe_files).first
89
+ end
90
+
91
+ def expand_bundled_dir(bundled_dir)
92
+ exe_files_of_platforms = File.expand_path(File.join(bundled_dir, "*", "odiff"))
93
+ Dir.glob(exe_files_of_platforms).find do |f|
94
+ supported_platform?(File.basename(File.dirname(f)))
95
+ end
96
+ end
97
+ end
98
+ end
99
+ 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/odiff.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Rodiff
4
4
  module Odiff
5
- VERSION = "v3.1.1"
5
+ VERSION = "3.1.1"
6
6
 
7
7
  # rubygems platform name => upstream release filename
8
8
  PLATFORMS = {
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rodiff
4
- VERSION = "1.0.0"
4
+ VERSION = "1.2.0"
5
5
  end
data/lib/rodiff.rb CHANGED
@@ -3,6 +3,6 @@
3
3
  module Rodiff
4
4
  end
5
5
 
6
- require_relative "rodiff/version"
7
- require_relative "rodiff/odiff"
8
- require_relative "rodiff/cli"
6
+ require "rodiff/error"
7
+ require "rodiff/configuration"
8
+ require "rodiff/executable"
metadata CHANGED
@@ -1,16 +1,34 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rodiff
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
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: 2024-09-08 00:00:00.000000000 Z
12
- dependencies: []
13
- description:
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: thor
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 1.3.2
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: 1.5.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: 1.3.2
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: 1.5.0
14
32
  email:
15
33
  - ryancyq@gmail.com
16
34
  executables:
@@ -24,6 +42,10 @@ files:
24
42
  - exe/rodiff
25
43
  - lib/rodiff.rb
26
44
  - lib/rodiff/cli.rb
45
+ - lib/rodiff/configuration.rb
46
+ - lib/rodiff/error.rb
47
+ - lib/rodiff/executable.rb
48
+ - lib/rodiff/helpers/file_finder.rb
27
49
  - lib/rodiff/odiff.rb
28
50
  - lib/rodiff/version.rb
29
51
  homepage: https://github.com/ryancyq/rodiff
@@ -34,7 +56,6 @@ metadata:
34
56
  allowed_push_host: https://rubygems.org
35
57
  changelog_uri: https://github.com/ryancyq/rodiff/blob/main/CHANGELOG.md
36
58
  homepage_uri: https://github.com/ryancyq/rodiff
37
- post_install_message:
38
59
  rdoc_options: []
39
60
  require_paths:
40
61
  - lib
@@ -49,9 +70,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
49
70
  - !ruby/object:Gem::Version
50
71
  version: 3.2.0
51
72
  requirements:
52
- - odiff, v3.1.1
53
- rubygems_version: 3.5.16
54
- signing_key:
73
+ - odiff, >= 3.0
74
+ rubygems_version: 4.0.3
55
75
  specification_version: 4
56
- summary: A ruby wrapper for odiff
76
+ summary: A ruby image comparison tool powered by ODiff in OCamel
57
77
  test_files: []