ojo 0.0.2 → 1.0.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
  SHA1:
3
- metadata.gz: 1507dfd7d37a94f8869aedfad8a794085050ded5
4
- data.tar.gz: d76df5592c3427e336c82ac0aa7bd78640bc2a14
3
+ metadata.gz: 9fb122efa0d57d0f24c768e2ddd60877062746bf
4
+ data.tar.gz: 372a6fdbe461d6aa7b519bf4bbd4182a2df03e4f
5
5
  SHA512:
6
- metadata.gz: 64b39c3507560aebbb5af6da31ae2c59e7f912b531ce55bb47c740ba0bacc833583aaeb481ff4532f03ab5ad3e994a66dbb084e495abb631e3c410a18bdfa767
7
- data.tar.gz: acdf69ac9f811cfa2ab18ed741c2d967d14162776797f02b55e8dd786b9fc6584d83975e07b0fa6b1d03ad66ce3c665a2e8ce5f8190e6b5125f070f47832dba8
6
+ metadata.gz: 336ea819a2118e57a750a404a8ed0256aaa8c5c1c3970d7c958be4d3cc065e1e42c3518294472fe92686aaf68046949d277215d8cc772b81393a58fabd337ca0
7
+ data.tar.gz: b63f2c1b6cbcb0ead4b42404f1411839963d88ab5be0e4cf18d161c02b8a2814813a4e7050782091903010f38c8a8068a134fb5257d07cf2a44986585b5c669c
data/.gitignore CHANGED
@@ -14,3 +14,4 @@
14
14
  mkmf.log
15
15
 
16
16
  /test/test_app/tmp
17
+ /test/test_app/log
@@ -1 +1 @@
1
- ruby-2.1.2
1
+ ruby-2.1.5
@@ -1,3 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "2.1.2"
3
+ - "2.1.5"
4
+ addons:
5
+ code_climate:
6
+ repo_token: f0b4c444b697cf8dd7fb56fe8f02fda41af6699511ca954e4c51a9ba33163abb
data/Gemfile CHANGED
@@ -12,3 +12,7 @@ gem 'poltergeist'
12
12
  gem 'capybara'
13
13
  gem 'ae_page_objects', '1.3.0'
14
14
  gem 'sqlite3'
15
+
16
+ group :test do
17
+ gem 'codeclimate-test-reporter', require: nil
18
+ end
data/README.md CHANGED
@@ -4,6 +4,7 @@ Ojo is not fancy. it just does a simple comparison of two sets of screenshots. t
4
4
 
5
5
  [![Build Status](https://travis-ci.org/QuantumGeordie/ojo.svg)](https://travis-ci.org/QuantumGeordie/ojo)
6
6
  [![Code Climate](https://codeclimate.com/github/QuantumGeordie/ojo/badges/gpa.svg)](https://codeclimate.com/github/QuantumGeordie/ojo)
7
+ [![Test Coverage](https://codeclimate.com/github/QuantumGeordie/ojo/badges/coverage.svg)](https://codeclimate.com/github/QuantumGeordie/ojo)
7
8
 
8
9
  ## Installation
9
10
 
@@ -25,7 +26,9 @@ Or install it yourself as:
25
26
 
26
27
  in a rails initializer do something like this to tell `Ojo` where the files to compare are.
27
28
 
28
- `Ojo.location = '/path/to/screenshots'`
29
+ Ojo.configure do |config|
30
+ config.location = '/path/to/screenshots'
31
+ end
29
32
 
30
33
  ### Screenshotter
31
34
 
data/lib/ojo.rb CHANGED
@@ -1,13 +1,17 @@
1
+ require 'collimator'
2
+
1
3
  require 'ojo/rails/engine' if defined?(Rails)
2
4
  require 'ojo/version'
3
5
  require 'ojo/comparison'
4
6
  require 'ojo/locations'
5
7
  require 'ojo/output'
6
8
  require 'ojo/screenshot'
7
-
8
- require 'collimator'
9
+ require 'ojo/configuration'
10
+ require 'ojo/file_sizer'
11
+ require 'ojo/image_magician'
12
+ require 'ojo/data_sets'
13
+ require 'ojo/manager'
9
14
 
10
15
  module Ojo
11
16
  include Collimator
12
-
13
17
  end
@@ -1,88 +1,66 @@
1
1
  module Ojo
2
- require 'open4'
3
- require 'fileutils'
2
+ class Ojo
3
+ def compare(branch_1, branch_2)
4
+ all_files = compile_file_lists(get_branch_files(branch_1), get_branch_files(branch_2))
4
5
 
5
- def self.compare(branch_1, branch_2)
6
- all_files = compile_file_lists(get_branch_files(branch_1), get_branch_files(branch_2))
6
+ FileUtils.mkdir_p(File.join(::Ojo.configuration.location, 'diff'))
7
7
 
8
- FileUtils.mkdir_p(File.join(self.location, 'diff'))
8
+ all_same = true
9
+ results = { :location => ::Ojo.configuration.location, :branch_1 => branch_1, :branch_2 => branch_2, :results => {} }
9
10
 
10
- all_same = true
11
- results = { :location => self.location, :branch_1 => branch_1, :branch_2 => branch_2, :results => {} }
11
+ ::Ojo::ProgressBar.start({:min => 0, :max => all_files.count, :method => :percent, :step_size => 1})
12
12
 
13
- ProgressBar.start({:min => 0, :max => all_files.count, :method => :percent, :step_size => 1})
13
+ all_files.each do |file|
14
+ diff_file = File.join(::Ojo.configuration.location, 'diff', File.basename(file))
14
15
 
15
- all_files.each do |file|
16
- diff_file = File.join(self.location, 'diff', File.basename(file))
16
+ file_1 = make_comparable_filename(branch_1, file)
17
+ file_2 = make_comparable_filename(branch_2, file)
17
18
 
18
- file_1 = File.join(location, branch_1, file)
19
- file_2 = File.join(location, branch_2, file)
19
+ this_same = compare_one_set(file_1, file_2, diff_file)
20
+ results[:results][file] = { :same => this_same, :file_1 => file_1, :file_2 => file_2 }
21
+ all_same = all_same && (this_same != false)
20
22
 
21
- file_1 = nil unless File.exist?(file_1)
22
- file_2 = nil unless File.exist?(file_2)
23
+ File.delete(diff_file) if this_same
23
24
 
24
- this_same = compare_one_set(file_1, file_2, diff_file)
25
- results[:results][file] = { :same => this_same, :file_1 => file_1, :file_2 => file_2 }
26
- all_same = all_same && (this_same != false)
25
+ ::Ojo::ProgressBar.increment
26
+ end
27
27
 
28
- File.delete(diff_file) if this_same
29
-
30
- ProgressBar.increment
28
+ ::Ojo::ProgressBar.complete
29
+ [all_same, results]
31
30
  end
32
31
 
33
- ProgressBar.complete
34
- [all_same, results]
35
- end
36
-
37
- private
32
+ private
38
33
 
39
- def self.compare_one_set(file_1, file_2, diff_file)
40
- same = nil
41
- if file_1 && file_2
42
- comparison_results = run_comparison(file_1, file_2, 'ae', '2%', diff_file)
43
- same = unpack_comparison_results(comparison_results)
34
+ def make_comparable_filename(branch, file_base)
35
+ name = File.join(::Ojo.configuration.location, branch, file_base)
36
+ name = nil unless File.exist?(name)
37
+ name
44
38
  end
45
- same
46
- end
47
-
48
- def self.get_branch_files(branch_name)
49
- Dir[File.join(self.location, branch_name, '*.png')].map{ |f| File.basename(f) }
50
- end
51
-
52
- def self.compile_file_lists(files_1, files_2)
53
- all_files = files_1.dup
54
- all_files + files_2.select{ |f2| !files_1.include?(f2) }
55
- end
56
-
57
- def self.unpack_comparison_results(packed)
58
- return false if packed.include?('image widths or heights differ')
59
39
 
60
- outputs = packed.split(/\n/)
40
+ def compare_one_set(file_1, file_2, diff_file)
41
+ same = nil
42
+ if file_1 && file_2
43
+ ::Ojo::FileSizer.new.make_files_same_size(file_1, file_2)
61
44
 
62
- outputs.map! do |o|
63
- o.strip if o.strip.start_with?('red', 'green', 'blue', 'alpha', 'all')
45
+ same = compare_files(file_1, file_2, ::Ojo.configuration.metric, ::Ojo.configuration.fuzz, diff_file)
46
+ end
47
+ same
64
48
  end
65
- outputs.compact!
66
49
 
67
- same = true
68
-
69
- outputs.each do |o|
70
- parts = o.split(' ')
71
- same = same && parts[1].to_f == 0
50
+ def get_branch_files(branch_name)
51
+ Dir[File.join(::Ojo.configuration.location, branch_name, '*.png')].map{ |f| File.basename(f) }
72
52
  end
73
53
 
74
- return same
75
- end
54
+ def compile_file_lists(files_1, files_2)
55
+ all_files = files_1.dup
56
+ all_files + files_2.select{ |f2| !files_1.include?(f2) }
57
+ end
76
58
 
77
- def self.run_comparison(file_1, file_2, metric, fuzz_factor, resulting_file)
78
- imagemagick_command = "compare -verbose -metric #{metric} -fuzz #{fuzz_factor} #{file_1} #{file_2} #{resulting_file}"
59
+ def compare_files(file_1, file_2, metric, fuzz_factor, resulting_file)
60
+ im = "compare -verbose -metric #{metric} -fuzz #{fuzz_factor} #{file_1} #{file_2} #{resulting_file}"
61
+ raw_result = ::Ojo::ImageMagician.new.make_magic(im)
79
62
 
80
- output = nil
81
- status = Open4::popen4(imagemagick_command) do |pid, stdin, stdout, stderr|
82
- output = stderr.read
63
+ ::Ojo::ImageMagician.new.unpack_comparison_result raw_result
83
64
  end
84
-
85
- output
86
65
  end
87
-
88
66
  end
@@ -0,0 +1,22 @@
1
+ module Ojo
2
+ class << self
3
+ attr_accessor :configuration
4
+ end
5
+
6
+ def self.configure
7
+ self.configuration ||= Configuration.new
8
+ yield(configuration) if block_given?
9
+ end
10
+
11
+ class Configuration
12
+ attr_accessor :fuzz
13
+ attr_accessor :location
14
+ attr_accessor :metric
15
+
16
+ def initialize
17
+ @location = nil
18
+ @fuzz = '2%'
19
+ @metric = 'ae'
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ module Ojo
2
+ class DataSets
3
+ def sets_available
4
+ data_sets = []
5
+ if ::Ojo.configuration.location
6
+ data_sets = Dir[File.join(::Ojo.configuration.location, '*')].select{ |d| File.directory?(d) && File.basename(d) != 'diff' }.map{ |d| File.basename(d) }.sort
7
+ end
8
+ data_sets
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+ module Ojo
2
+ class FileSizer
3
+ def make_files_same_size(file_1, file_2)
4
+ dim_1 = get_file_dimensions(file_1)
5
+ dim_2 = get_file_dimensions(file_2)
6
+
7
+ unless dim_1 == dim_2
8
+ x, y = max_dimensions(dim_1, dim_2)
9
+ add_extra_to_file x, y, file_1
10
+ add_extra_to_file x, y, file_2
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def get_file_dimensions(file)
17
+ im = "identify -format '%[fx:w]x%[fx:h]' #{file}"
18
+
19
+ output = nil
20
+ status = Open4::popen4(im) do |pid, stdin, stdout, stderr|
21
+ output = stdout.read
22
+ end
23
+ raise "problem getting dimensions of #{file}" unless status.success?
24
+ output.chomp
25
+ end
26
+
27
+ def add_extra_to_file(x, y, filename)
28
+ basename = File.basename(filename, '.*')
29
+ temp_filename = File.join(File.dirname(filename), "#{basename}_tmp.png")
30
+ make_canvas x, y, temp_filename
31
+
32
+ im = "convert #{temp_filename} #{filename} -composite #{temp_filename}"
33
+ ::Ojo::ImageMagician.new.make_magic(im)
34
+
35
+ FileUtils.mv(temp_filename, filename)
36
+ end
37
+
38
+ def max_dimensions(dim_1, dim_2)
39
+ x1, y1 = dim_1.split('x')
40
+ x2, y2 = dim_2.split('x')
41
+
42
+ x = [x1, x2].max
43
+ y = [y1, y2].max
44
+ [x, y]
45
+ end
46
+
47
+ def make_canvas(x, y, filename)
48
+ im = "convert -size #{x}x#{y} canvas:yellow #{filename}"
49
+ ::Ojo::ImageMagician.new.make_magic(im)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,40 @@
1
+ module Ojo
2
+ class ImageMagician
3
+ def make_magic(command_string)
4
+ output = nil
5
+ status = Open4::popen4(command_string) do |pid, stdin, stdout, stderr|
6
+ output = stderr.read
7
+ end
8
+ output
9
+ end
10
+
11
+ def unpack_comparison_result(packed)
12
+ return false if packed.include?('image widths or heights differ')
13
+
14
+ color_values = get_color_values(packed)
15
+
16
+ same = true
17
+ color_values.each_pair do |color, value|
18
+ same = same && value.to_f == 0
19
+ end
20
+
21
+ return same
22
+ end
23
+
24
+ private
25
+
26
+ def get_color_values(raw)
27
+ # raw looks like
28
+ # "/Users/geordie/src/gems/ojo/tmp/branch_1/test_one.png PNG 200x200 200x200+0+0 16-bit sRGB 1.04KB 0.000u 0:00.000\n/Users/geordie/src/gems/ojo/tmp/branch_2/test_one.png PNG 200x200 200x200+0+0 16-bit sRGB 1.05KB 0.000u 0:00.000\nImage: /Users/geordie/src/gems/ojo/tmp/branch_1/test_one.png\n Channel distortion: AE\n red: 944\n green: 944\n blue: 944\n all: 944\n/Users/geordie/src/gems/ojo/tmp/branch_1/test_one.png=>/Users/geordie/src/gems/ojo/tmp/diff/test_one.png PNG 200x200 200x200+0+0 16-bit sRGB 6c 1.18KB 0.010u 0:00.000\n"
29
+ outputs = raw.split(/\n/).select { |o| o.strip.start_with?('red', 'green', 'blue', 'alpha', 'all') }
30
+
31
+ out_hash = {}
32
+ outputs.each do |line|
33
+ k, v = line.strip.split(':')
34
+ out_hash[k.to_sym] = v.strip
35
+ end
36
+
37
+ out_hash
38
+ end
39
+ end
40
+ end
@@ -1,20 +1,11 @@
1
1
  module Ojo
2
- @location = nil
3
-
4
2
  def self.location=(location)
5
- @location = location
3
+ ::Ojo.configure unless ::Ojo.configuration
4
+ ::Ojo.configuration.location = location
6
5
  end
7
6
 
8
7
  def self.location
9
- @location
10
- end
11
-
12
- def self.get_data_sets_available
13
- data_sets = []
14
- if @location
15
- data_sets = Dir[File.join(location, '*')].select{ |d| File.directory?(d) && File.basename(d) != 'diff' }.map{ |d| File.basename(d) }
16
- end
17
- data_sets
8
+ ::Ojo.configuration.location
18
9
  end
19
10
 
20
11
  def self.display_data_sets(data_sets)
@@ -0,0 +1,49 @@
1
+ module Ojo
2
+ class Manager
3
+ def location
4
+ puts "Ojo file location: #{::Ojo.configuration.location}"
5
+ end
6
+
7
+ def data_sets
8
+ data_sets = ::Ojo::DataSets.new.sets_available
9
+ ::Ojo.display_data_sets(data_sets)
10
+ end
11
+
12
+ def clear_diff
13
+ FileUtils.rm_rf File.join(::Ojo.configuration.location, 'diff')
14
+ end
15
+
16
+ def clear_all
17
+ data_sets = ::Ojo::DataSets.new.sets_available
18
+ FileUtils.rm_rf File.join(::Ojo.configuration.location, 'diff')
19
+ data_sets.each { |d| FileUtils.rm_rf(File.join(::Ojo.configuration.location, d)) }
20
+ end
21
+
22
+ def compare(branch_1, branch_2)
23
+ unless branch_1 && branch_2
24
+ branches = ::Ojo::DataSets.new.sets_available
25
+ unless branch_1
26
+ branches.each do |branch|
27
+ if branch != branch_2
28
+ branch_1 = branch
29
+ break
30
+ end
31
+ end
32
+ end
33
+
34
+ unless branch_2
35
+ branches.each do |branch|
36
+ if branch != branch_1
37
+ branch_2 = branch
38
+ break
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ results = ::Ojo::Ojo.new.compare(branch_1, branch_2)
45
+ ::Ojo::Output.new.display_to_console results[1]
46
+ end
47
+
48
+ end
49
+ end
@@ -1,90 +1,94 @@
1
1
  module Ojo
2
- def self.display_to_console(data)
3
- format_table data
2
+ class Output
3
+ include Collimator::Table
4
4
 
5
- failure_count = 0
5
+ def display_to_console(data)
6
+ format_table data
6
7
 
7
- data[:results].each_key do |basename|
8
- file_1 = file_basename(data[:results][basename][:file_1])
9
- file_2 = file_basename(data[:results][basename][:file_2])
8
+ failure_count = 0
10
9
 
11
- color = :blue
12
- result_text = '--'
10
+ data[:results].each_key do |basename|
11
+ file_1 = file_basename(data[:results][basename][:file_1])
12
+ file_2 = file_basename(data[:results][basename][:file_2])
13
13
 
14
- if test_performed?(data[:results][basename])
15
- same = data[:results][basename][:same]
16
- color = same ? :green : :red
17
- result_text = same ? 'PASS' : 'FAIL'
18
- failure_count += 1 unless same
19
- end
20
-
21
- one_row file_1, file_2, result_text, color
22
- end
23
- format_table_footer failure_count, data
24
- end
25
-
26
- private
14
+ color = :blue
15
+ result_text = '--'
27
16
 
28
- def self.format_table_footer(failure_count, data)
29
- Table.footer(results_message(failure_count == 0, failure_count), :justification => :center)
30
- Table.footer("Difference Files at #{File.join(data[:location], 'diff')}", :justification => :center)
17
+ if test_performed?(data[:results][basename])
18
+ same = data[:results][basename][:same]
19
+ color = same ? :green : :red
20
+ result_text = same ? 'PASS' : 'FAIL'
21
+ failure_count += 1 unless same
22
+ end
31
23
 
32
- Table.tabulate
33
- end
24
+ one_row file_1, file_2, result_text, color
25
+ end
26
+ format_table_footer failure_count, data
27
+ end
34
28
 
35
- def self.file_basename(filename)
36
- out = filename
37
- out = File.basename(filename) unless out.nil?
38
- out
39
- end
29
+ private
40
30
 
41
- def self.test_performed?(data)
42
- !data[:same].nil?
43
- end
31
+ def format_table_footer(failure_count, data)
32
+ Collimator::Table.footer(results_message(failure_count == 0, failure_count), :justification => :center)
33
+ Collimator::Table.footer("Difference Files at #{File.join(data[:location], 'diff')}", :justification => :center)
44
34
 
45
- def self.format_table_header(data)
46
- Table.header("Ojo v.#{VERSION}")
47
- Table.header("file location: #{data[:location]}")
48
- Table.header(Date.today.strftime('%m/%d/%Y'))
49
- end
35
+ Collimator::Table.tabulate
36
+ end
50
37
 
51
- def self.format_table(data)
52
- format_table_header data
38
+ def file_basename(filename)
39
+ out = filename
40
+ out = File.basename(filename) unless out.nil?
41
+ out
42
+ end
53
43
 
54
- Table.column(data[:branch_1], :width => 60, :padding => 2, :justification => :left)
55
- Table.column(data[:branch_2], :width => 60, :padding => 2, :justification => :left)
56
- Table.column('Results', :width => 11, :justification => :center)
57
- end
44
+ def test_performed?(data)
45
+ !data[:same].nil?
46
+ end
58
47
 
59
- def self.one_row(file_1, file_2, result_text, color)
60
- max_printable_length = 50
48
+ def format_table_header(data)
49
+ Collimator::Table.header("Ojo v.#{VERSION}")
50
+ Collimator::Table.header("file location: #{data[:location]}")
51
+ Collimator::Table.header(Date.today.strftime('%m/%d/%Y'))
52
+ end
61
53
 
62
- formatted_file_1 = make_printable_name(file_1, max_printable_length)
63
- formatted_file_2 = make_printable_name(file_2, max_printable_length)
54
+ def format_table(data)
55
+ format_table_header data
64
56
 
65
- row_data = [formatted_file_1, formatted_file_2, result_text]
66
- Table.row(:data => row_data, :color => color)
67
- end
57
+ Collimator::Table.column(data[:branch_1], :width => 60, :padding => 2, :justification => :left)
58
+ Collimator::Table.column(data[:branch_2], :width => 60, :padding => 2, :justification => :left)
59
+ Collimator::Table.column('Results', :width => 11, :justification => :center)
60
+ end
68
61
 
69
- def self.results_message(same, failure_count)
70
- results_message = ['Results: ']
71
- results_message << 'All Same' if same
72
- results_message << "#{failure_count} file#{failure_count > 1 ? 's were' : ' was'} found to be different" unless same
73
- results_message.join('')
74
- end
62
+ def one_row(file_1, file_2, result_text, color)
63
+ max_printable_length = 50
75
64
 
76
- def self.make_printable_name(input, max_length)
77
- output = input || ''
65
+ formatted_file_1 = make_printable_name(file_1, max_printable_length)
66
+ formatted_file_2 = make_printable_name(file_2, max_printable_length)
78
67
 
79
- if output.length > max_length
80
- how_much_too_long = output.length - max_length
81
- center_of_string = output.length / 2
82
- front_of_new_string = output[0..(center_of_string - how_much_too_long/2 - 3)]
83
- back_of_new_string = output[(center_of_string + how_much_too_long/2 + 3)..output.length]
68
+ row_data = [formatted_file_1, formatted_file_2, result_text]
69
+ Collimator::Table.row(:data => row_data, :color => color)
70
+ end
84
71
 
85
- output = "#{front_of_new_string}....#{back_of_new_string}"
72
+ def results_message(same, failure_count)
73
+ results_message = ['Results: ']
74
+ results_message << 'All Same' if same
75
+ results_message << "#{failure_count} file#{failure_count > 1 ? 's were' : ' was'} found to be different" unless same
76
+ results_message.join('')
86
77
  end
87
78
 
88
- output
79
+ def make_printable_name(input, max_length)
80
+ output = input || ''
81
+
82
+ if output.length > max_length
83
+ how_much_too_long = output.length - max_length
84
+ center_of_string = output.length / 2
85
+ front_of_new_string = output[0..(center_of_string - how_much_too_long/2 - 3)]
86
+ back_of_new_string = output[(center_of_string + how_much_too_long/2 + 3)..output.length]
87
+
88
+ output = "#{front_of_new_string}....#{back_of_new_string}"
89
+ end
90
+
91
+ output
92
+ end
89
93
  end
90
94
  end