percept 0.0.1 → 3.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 +5 -5
- data/.github/workflows/ruby.yml +34 -0
- data/.gitignore +3 -1
- data/.rspec +3 -0
- data/.rubocop.yml +110 -0
- data/.rubocop_todo.yml +383 -0
- data/.tool-versions +2 -0
- data/Gemfile +12 -1
- data/Gemfile.lock +138 -0
- data/Guardfile +10 -0
- data/README.md +20 -0
- data/Rakefile +18 -0
- data/bin/percept +8 -1
- data/lib/ext/rmagick_pixel.rb +19 -0
- data/lib/percept/checkbox_collection.rb +19 -0
- data/lib/percept/checkbox_detector.rb +19 -0
- data/lib/percept/checkbox_field.rb +24 -0
- data/lib/percept/color_utils.rb +17 -0
- data/lib/percept/config.rb +35 -0
- data/lib/percept/field.rb +74 -0
- data/lib/percept/field_collection.rb +29 -0
- data/lib/percept/field_detector.rb +56 -0
- data/lib/percept/image.rb +60 -0
- data/lib/percept/line.rb +116 -4
- data/lib/percept/line_collection.rb +88 -0
- data/lib/percept/line_detector.rb +102 -0
- data/lib/percept/line_filter.rb +95 -0
- data/lib/percept/pixel.rb +28 -0
- data/lib/percept/pixel_utils.rb +73 -0
- data/lib/percept/rmagick_image.rb +49 -0
- data/lib/percept/runner.rb +15 -96
- data/lib/percept/utils.rb +15 -0
- data/lib/percept/version.rb +3 -1
- data/lib/percept.rb +40 -1
- data/percept.gemspec +6 -7
- data/spec/fixtures/black_lines.png +0 -0
- data/spec/fixtures/bottom_line.png +0 -0
- data/spec/fixtures/bumpy_no_line.png +0 -0
- data/spec/fixtures/corners.png +0 -0
- data/spec/fixtures/divots.png +0 -0
- data/spec/fixtures/field_next_to_text.png +0 -0
- data/spec/fixtures/gray_cell_bottom.png +0 -0
- data/spec/fixtures/gray_image_section.png +0 -0
- data/spec/fixtures/grey_lines.png +0 -0
- data/spec/fixtures/high_line.png +0 -0
- data/spec/fixtures/large_checkbox.png +0 -0
- data/spec/fixtures/large_checkboxes.png +0 -0
- data/spec/fixtures/light_gray.png +0 -0
- data/spec/fixtures/low_line.png +0 -0
- data/spec/fixtures/low_lines.png +0 -0
- data/spec/fixtures/mid_lines.png +0 -0
- data/spec/fixtures/more_corners.png +0 -0
- data/spec/fixtures/more_text_on_line.png +0 -0
- data/spec/fixtures/nub_both_sides.png +0 -0
- data/spec/fixtures/nub_bottom_left.png +0 -0
- data/spec/fixtures/nub_top_right.png +0 -0
- data/spec/fixtures/nubs.png +0 -0
- data/spec/fixtures/slanted_left.png +0 -0
- data/spec/fixtures/slanted_right.png +0 -0
- data/spec/fixtures/small_checkbox.png +0 -0
- data/spec/fixtures/text_no_line.png +0 -0
- data/spec/fixtures/text_no_line_2.png +0 -0
- data/spec/fixtures/text_on_line.png +0 -0
- data/spec/fixtures/thick_line.png +0 -0
- data/spec/fixtures/thin_field.png +0 -0
- data/spec/percept/checkbox_field/height_spec.rb +15 -0
- data/spec/percept/checkbox_field/width_spec.rb +15 -0
- data/spec/percept/field/contains_spec.rb +50 -0
- data/spec/percept/field_detector/detect_field_spec.rb +90 -0
- data/spec/percept/field_detector/detect_fields_spec.rb +42 -0
- data/spec/percept/fields_collection/shovel_spec.rb +53 -0
- data/spec/percept/line/approxequals_spec.rb +60 -0
- data/spec/percept/line/initialize_spec.rb +29 -0
- data/spec/percept/line/length_spec.rb +22 -0
- data/spec/percept/line/merge_bang_spec.rb +58 -0
- data/spec/percept/line/pixels_spec.rb +15 -0
- data/spec/percept/line/split_spec.rb +28 -0
- data/spec/percept/line/to_s_spec.rb +13 -0
- data/spec/percept/line_collection/merge_line_spec.rb +50 -0
- data/spec/percept/line_collection/remove_unwanted_lines_bang_spec.rb +17 -0
- data/spec/percept/line_collection/split_spec.rb +20 -0
- data/spec/percept/line_collection/to_s_spec.rb +11 -0
- data/spec/percept/line_detector/detect_lines_spec.rb +93 -0
- data/spec/percept/line_detector/scaled_color_spec.rb +14 -0
- data/spec/percept/line_filter/filter_line_predicate_spec.rb +29 -0
- data/spec/percept/line_filter/left_bottom_corner_predicate_spec.rb +49 -0
- data/spec/percept/line_filter/left_top_corner_predicate_spec.rb +50 -0
- data/spec/percept/line_filter/right_bottom_corner_predicate_spec.rb +49 -0
- data/spec/percept/line_filter/right_top_corner_predicate_spec.rb +49 -0
- data/spec/percept/line_filter/table_bottom_predicate_spec.rb +48 -0
- data/spec/percept/line_filter/table_top_predicate_spec.rb +48 -0
- data/spec/percept/pixel/blackish_predicate_spec.rb +36 -0
- data/spec/percept/rmagick_image/interface_spec.rb +11 -0
- data/spec/percept/runner/color_fields_spec.rb +28 -0
- data/spec/percept/runner/color_lines_spec.rb +27 -0
- data/spec/shared_examples/image_interface_shared_examples.rb +162 -0
- data/spec/spec_helper.rb +52 -0
- data/tddium.yml +12 -0
- data/test_images/funky_image.png +0 -0
- data/test_images/interaction_test.png +0 -0
- data/test_images/jagged_lines.png +0 -0
- data/test_images/permission.png +0 -0
- data/test_images/rough.png +0 -0
- data/test_images/slanted.png +0 -0
- data/test_images/time_sheet.png +0 -0
- data/test_images/travel_reimbursement.png +0 -0
- data/test_images/warehouse_form.png +0 -0
- metadata +171 -34
- data/new_permission.png +0 -0
- data/permission.png +0 -0
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe Percept::CheckboxField, '#height' do
|
2
|
+
|
3
|
+
it 'returns the height' do
|
4
|
+
field = Percept::CheckboxField.new(
|
5
|
+
start_x: 5,
|
6
|
+
end_x: 10,
|
7
|
+
start_y: 7,
|
8
|
+
end_y: 12,
|
9
|
+
)
|
10
|
+
expect(field.height).to eq 5
|
11
|
+
field.start_y = 9
|
12
|
+
expect(field.height).to eq 3
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe Percept::CheckboxField, '#width' do
|
2
|
+
|
3
|
+
it 'returns the width' do
|
4
|
+
field = Percept::CheckboxField.new(
|
5
|
+
start_x: 5,
|
6
|
+
end_x: 10,
|
7
|
+
start_y: 7,
|
8
|
+
end_y: 12,
|
9
|
+
)
|
10
|
+
expect(field.width).to eq 5
|
11
|
+
field.start_x = 7
|
12
|
+
expect(field.width).to eq 3
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
describe Percept::Field, '#contains?' do
|
2
|
+
|
3
|
+
let(:field1) do
|
4
|
+
Percept::Field.new(
|
5
|
+
start_x: 10,
|
6
|
+
start_y: 10,
|
7
|
+
end_x: 20,
|
8
|
+
end_y: 20,
|
9
|
+
line: 'line',
|
10
|
+
image: 'image',
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:field2) do
|
15
|
+
Percept::Field.new(
|
16
|
+
start_x: 15,
|
17
|
+
start_y: 15,
|
18
|
+
end_x: 25,
|
19
|
+
end_y: 18,
|
20
|
+
line: 'line',
|
21
|
+
image: 'image',
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:field3) do
|
26
|
+
Percept::Field.new(
|
27
|
+
start_x: 100,
|
28
|
+
start_y: 100,
|
29
|
+
end_x: 200,
|
30
|
+
end_y: 200,
|
31
|
+
line: 'line',
|
32
|
+
image: 'image',
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when the fields overlap' do
|
37
|
+
it 'returns true' do
|
38
|
+
expect(field1.overlaps?(field2)).to eq true
|
39
|
+
expect(field2.overlaps?(field1)).to eq true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when the fields do not overlap' do
|
44
|
+
it 'returns false' do
|
45
|
+
expect(field1.overlaps?(field3)).to eq false
|
46
|
+
expect(field3.overlaps?(field1)).to eq false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
describe Percept::FieldDetector, '#detect_field' do
|
2
|
+
|
3
|
+
let(:min_field_height) { 5 }
|
4
|
+
let(:max_field_height) { 10 }
|
5
|
+
let(:field_detector) { Percept::FieldDetector.new }
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Percept.configure do |config|
|
9
|
+
config.min_field_height = min_field_height
|
10
|
+
config.max_field_height = max_field_height
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when top of image > max_field_height above line' do
|
15
|
+
let(:image_path) { File.join(fixture_path, 'low_line.png') }
|
16
|
+
let(:image) { image_class.new(image_path) }
|
17
|
+
|
18
|
+
it 'returns a field that has height of max_field_height' do
|
19
|
+
expect(image.lines.size).to eq 1
|
20
|
+
field = field_detector.detect_field(image.lines.first, image)
|
21
|
+
expect(field.height).to eq max_field_height
|
22
|
+
expect(field.width).to eq 32
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when top of image < max_field_height above line' do
|
27
|
+
let(:image_path) { File.join(fixture_path, 'high_line.png') }
|
28
|
+
let(:image) { image_class.new(image_path) }
|
29
|
+
|
30
|
+
it 'returns field with height of distance between line and top' do
|
31
|
+
expect(image.lines.size).to eq 1
|
32
|
+
field = field_detector.detect_field(image.lines.first, image)
|
33
|
+
expect(field.height).to eq 5
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when another line is < max_field_height above line' do
|
38
|
+
let(:image_path) { File.join(fixture_path, 'mid_lines.png') }
|
39
|
+
let(:image) { image_class.new(image_path) }
|
40
|
+
|
41
|
+
it 'returns field with height of distance between lines' do
|
42
|
+
expect(image.lines.size).to eq 2
|
43
|
+
field = field_detector.detect_field(image.lines.last, image)
|
44
|
+
expect(field.height).to eq 6
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when another line is < min_field_height above line' do
|
49
|
+
let(:image_path) { File.join(fixture_path, 'low_lines.png') }
|
50
|
+
let(:image) { image_class.new(image_path) }
|
51
|
+
|
52
|
+
it 'does not return a field' do
|
53
|
+
expect(image.lines.size).to eq 2
|
54
|
+
field = field_detector.detect_field(image.lines.last, image)
|
55
|
+
expect(field).to be_nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when there are nubs above the line' do
|
60
|
+
let(:image_path) { File.join(fixture_path, 'nubs.png') }
|
61
|
+
let(:image) { image_class.new(image_path) }
|
62
|
+
|
63
|
+
it 'returns a field that ignores the nubs' do
|
64
|
+
expect(image.lines.size).to eq 1
|
65
|
+
field = field_detector.detect_field(image.lines.last, image)
|
66
|
+
expect(field).not_to be_nil
|
67
|
+
expect(field.end_y).to eq 12
|
68
|
+
expect(field.start_y).to eq 2
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when the line is slanted to the left' do
|
73
|
+
let(:image_path) { File.join(fixture_path, 'slanted_left.png') }
|
74
|
+
let(:image) { image_class.new(image_path) }
|
75
|
+
|
76
|
+
it 'returns a field from the top of the line' do
|
77
|
+
expect(image.lines.size).to eq 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when the line is slanted to the right' do
|
82
|
+
let(:image_path) { File.join(fixture_path, 'slanted_right.png') }
|
83
|
+
let(:image) { image_class.new(image_path) }
|
84
|
+
|
85
|
+
it 'returns a field from the top of the line' do
|
86
|
+
expect(image.lines.size).to eq 1
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
describe Percept::FieldDetector, '#detect_fields' do
|
2
|
+
|
3
|
+
let(:field_detector) { Percept::FieldDetector.new }
|
4
|
+
|
5
|
+
it 'detects fields next to text' do
|
6
|
+
image = image_class.new(File.join(fixture_path, 'field_next_to_text.png'))
|
7
|
+
fields = field_detector.detect_fields(image)
|
8
|
+
expect(fields.size).to eq 1
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'detects thin fields' do
|
12
|
+
image = image_class.new(File.join(fixture_path, 'thin_field.png'))
|
13
|
+
fields = field_detector.detect_fields(image)
|
14
|
+
expect(fields.size).to eq 1
|
15
|
+
|
16
|
+
field = fields.first
|
17
|
+
expect(field.start_x).to eq 33
|
18
|
+
expect(field.end_x).to eq 115
|
19
|
+
expect(field.start_y).to eq 14
|
20
|
+
expect(field.end_y).to eq 38
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when there is only text' do
|
24
|
+
it 'does not return any fields' do
|
25
|
+
image = image_class.new(File.join(fixture_path, 'text_no_line.png'))
|
26
|
+
expect(field_detector.detect_fields(image).size).to eq 0
|
27
|
+
image = image_class.new(File.join(fixture_path, 'text_no_line_2.png'))
|
28
|
+
expect(field_detector.detect_fields(image).size).to eq 0
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'detects fields with text on them on the left side' do
|
33
|
+
image = image_class.new(File.join(fixture_path, 'text_on_line.png'))
|
34
|
+
expect(field_detector.detect_fields(image).size).to eq 1
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'detects fields with text on them on the both sides' do
|
38
|
+
image = image_class.new(File.join(fixture_path, 'more_text_on_line.png'))
|
39
|
+
expect(field_detector.detect_fields(image).size).to eq 1
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
describe Percept::FieldCollection, '#<<' do
|
2
|
+
let(:field1) do
|
3
|
+
Percept::Field.new(
|
4
|
+
start_x: 10,
|
5
|
+
start_y: 10,
|
6
|
+
end_x: 20,
|
7
|
+
end_y: 20,
|
8
|
+
line: 'line',
|
9
|
+
image: 'image',
|
10
|
+
)
|
11
|
+
end
|
12
|
+
let(:field2) do
|
13
|
+
Percept::Field.new(
|
14
|
+
start_x: 15,
|
15
|
+
start_y: 15,
|
16
|
+
end_x: 25,
|
17
|
+
end_y: 18,
|
18
|
+
line: 'line',
|
19
|
+
image: 'image',
|
20
|
+
)
|
21
|
+
end
|
22
|
+
let(:field3) do
|
23
|
+
Percept::Field.new(
|
24
|
+
start_x: 100,
|
25
|
+
start_y: 100,
|
26
|
+
end_x: 200,
|
27
|
+
end_y: 200,
|
28
|
+
line: 'line',
|
29
|
+
image: 'image',
|
30
|
+
)
|
31
|
+
end
|
32
|
+
let(:fields_collection) { Percept::FieldCollection.new }
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
fields_collection << field1
|
36
|
+
expect(fields_collection.size).to eq 1
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when the incoming field overlaps an existing one' do
|
40
|
+
it 'does not add the field to the list' do
|
41
|
+
fields_collection << field2
|
42
|
+
expect(fields_collection.size).to eq 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'when the incoming field does not overlap an existing one' do
|
47
|
+
it 'adds the field to the list' do
|
48
|
+
fields_collection << field3
|
49
|
+
expect(fields_collection.size).to eq 2
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
describe Percept::Line, '#=~' do
|
2
|
+
let(:params) { { rows: nil, image: nil } }
|
3
|
+
|
4
|
+
context 'when the lines have the same length' do
|
5
|
+
let(:params) { { start_x: 5, end_x: 10, rows: nil, image: nil } }
|
6
|
+
|
7
|
+
context 'when start_y equals the other end_y' do
|
8
|
+
it 'returns true' do
|
9
|
+
line1 = Percept::Line.new(params.merge(start_y: 8))
|
10
|
+
line2 = Percept::Line.new(params.merge(start_y: 7))
|
11
|
+
expect(line1 =~ line2).to be true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when end_y equals the other start_y' do
|
16
|
+
it 'returns true' do
|
17
|
+
line1 = Percept::Line.new(params.merge(start_y: 7))
|
18
|
+
line2 = Percept::Line.new(params.merge(start_y: 8))
|
19
|
+
expect(line1 =~ line2).to be true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when neither start_y matches the other end_y' do
|
24
|
+
it 'returns false' do
|
25
|
+
line1 = Percept::Line.new(params.merge(start_y: 6))
|
26
|
+
line2 = Percept::Line.new(params.merge(start_y: 8))
|
27
|
+
expect(line1 =~ line2).to be false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when the lines have x overlap' do
|
33
|
+
it 'returns true' do
|
34
|
+
line1 = Percept::Line.new(params.merge(start_x: 2, end_x: 7, start_y: 7))
|
35
|
+
line2 = Percept::Line.new(params.merge(start_x: 4, end_x: 9, start_y: 8))
|
36
|
+
expect(line1 =~ line2).to be true
|
37
|
+
line1 = Percept::Line.new(params.merge(start_x: 4, end_x: 9, start_y: 7))
|
38
|
+
line2 = Percept::Line.new(params.merge(start_x: 2, end_x: 7, start_y: 8))
|
39
|
+
expect(line1 =~ line2).to be true
|
40
|
+
line1 = Percept::Line.new(params.merge(start_x: 5, end_x: 9, start_y: 7))
|
41
|
+
line2 = Percept::Line.new(params.merge(start_x: 2, end_x: 5, start_y: 8))
|
42
|
+
expect(line1 =~ line2).to be true
|
43
|
+
line1 = Percept::Line.new(params.merge(start_x: 2, end_x: 5, start_y: 7))
|
44
|
+
line2 = Percept::Line.new(params.merge(start_x: 5, end_x: 9, start_y: 8))
|
45
|
+
expect(line1 =~ line2).to be true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when the lines do not have x overlap' do
|
50
|
+
it 'returns true' do
|
51
|
+
line1 = Percept::Line.new(params.merge(start_x: 2, end_x: 5, start_y: 7))
|
52
|
+
line2 = Percept::Line.new(params.merge(start_x: 6, end_x: 9, start_y: 8))
|
53
|
+
expect(line1 =~ line2).to be false
|
54
|
+
line1 = Percept::Line.new(params.merge(start_x: 6, end_x: 9, start_y: 7))
|
55
|
+
line2 = Percept::Line.new(params.merge(start_x: 2, end_x: 5, start_y: 8))
|
56
|
+
expect(line1 =~ line2).to be false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
describe Percept::Line, '#initialize' do
|
2
|
+
|
3
|
+
let(:params) do
|
4
|
+
{ start_x: 3, end_x: 10, start_y: 5, row: 'my_row', image: 'my_image' }
|
5
|
+
end
|
6
|
+
let(:line) { Percept::Line.new(params) }
|
7
|
+
|
8
|
+
it 'sets its variables' do
|
9
|
+
expect(line.start_x).to eq 3
|
10
|
+
expect(line.end_x).to eq 10
|
11
|
+
expect(line.start_y).to eq 5
|
12
|
+
expect(line.rows).to eq ['my_row']
|
13
|
+
expect(line.image).to eq 'my_image'
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when :end_y is not given' do
|
17
|
+
it 'sets :end_y to :start_y + 1' do
|
18
|
+
expect(line.end_y).to eq 6
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when :end_y is given' do
|
23
|
+
it 'uses the given value' do
|
24
|
+
params[:end_y] = 15
|
25
|
+
expect(line.end_y).to eq 15
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
describe Percept::Line, '#length' do
|
2
|
+
|
3
|
+
let(:line) do
|
4
|
+
Percept::Line.new(
|
5
|
+
start_y: 5,
|
6
|
+
end_y: 10,
|
7
|
+
start_x: 6,
|
8
|
+
end_x: 8,
|
9
|
+
row: 'no row',
|
10
|
+
image: 'no image',
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'returns end_x - start_x' do
|
15
|
+
expect(line.length).to eq 2
|
16
|
+
line.end_x = 15
|
17
|
+
expect(line.length).to eq 9
|
18
|
+
line.start_x = 5
|
19
|
+
expect(line.length).to eq 10
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
describe Percept::Line, '#merge!' do
|
2
|
+
|
3
|
+
let(:params) do
|
4
|
+
{ start_x: 3, end_x: 10, start_y: 5, row: 'my_row', image: 'my_image' }
|
5
|
+
end
|
6
|
+
|
7
|
+
let(:line) do
|
8
|
+
Percept::Line.new(params)
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'when start_y is greater than the other start_y' do
|
12
|
+
it 'sets the start_y to the other start_y' do
|
13
|
+
other_line = Percept::Line.new(params.merge(start_y: 4))
|
14
|
+
line.merge!(other_line)
|
15
|
+
expect(line.start_y).to eq 4
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when end_y is less than the other end_y' do
|
20
|
+
it 'sets the end_y to the other end_y' do
|
21
|
+
other_line = Percept::Line.new(params.merge(start_y: 6))
|
22
|
+
line.merge!(other_line)
|
23
|
+
expect(line.end_y).to eq 7
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when start_x is greater than the other start_x' do
|
28
|
+
it 'sets the start_x to the other start_x' do
|
29
|
+
other_line = Percept::Line.new(params.merge(start_x: 2))
|
30
|
+
line.merge!(other_line)
|
31
|
+
expect(line.start_x).to eq 2
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when end_x is less than the other end_x' do
|
36
|
+
it 'sets the end_x to the other end_x' do
|
37
|
+
other_line = Percept::Line.new(params.merge(end_x: 11))
|
38
|
+
line.merge!(other_line)
|
39
|
+
expect(line.end_x).to eq 11
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when start_x is greater than the other start_x' do
|
43
|
+
it 'sets the start_x to the other start_x' do
|
44
|
+
other_line = Percept::Line.new(params.merge(end_x: 11, start_x: 2))
|
45
|
+
line.merge!(other_line)
|
46
|
+
expect(line.end_x).to eq 11
|
47
|
+
expect(line.start_x).to eq 2
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'combines the rows' do
|
53
|
+
other_line = Percept::Line.new(params.merge(row: 'other_row'))
|
54
|
+
line.merge!(other_line)
|
55
|
+
expect(line.rows).to eq %w(my_row other_row)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe Percept::Line, '#pixels' do
|
2
|
+
|
3
|
+
let(:image) { image_class.new(File.join(fixture_path, 'low_line.png')) }
|
4
|
+
let(:line) { image.lines.first }
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Percept.config.line_length = 30
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'returns the associated pixels for the line' do
|
11
|
+
expect(line.pixels.size).to eq 32
|
12
|
+
expect(line.pixels.all?(&:blackish?)).to eq true
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
describe Percept::Line, '#split' do
|
2
|
+
|
3
|
+
let(:more_corners_path) { File.join(fixture_path, 'more_corners.png') }
|
4
|
+
let(:image) { image_class.new(more_corners_path) }
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Percept.config.line_length = 30
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'returns a collection of lines split by vertical dividers' do
|
11
|
+
line = image.lines[8]
|
12
|
+
Percept.config.line_length = 32
|
13
|
+
lines = line.split
|
14
|
+
expect(lines).to be_empty
|
15
|
+
Percept.config.line_length = 5
|
16
|
+
lines = line.split
|
17
|
+
expect(lines.length).to eq 2
|
18
|
+
expect(lines.first.length).to eq 30
|
19
|
+
expect(lines.last.length).to eq 6
|
20
|
+
|
21
|
+
line_2 = image.lines[9]
|
22
|
+
lines = line_2.split
|
23
|
+
expect(lines.length).to eq 2
|
24
|
+
expect(lines.last.length).to eq 30
|
25
|
+
expect(lines.first.length).to eq 6
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
describe Percept::Line, '#to_s' do
|
2
|
+
|
3
|
+
let(:attributes) { { start_x: 3, end_x: 10, start_y: 5 } }
|
4
|
+
|
5
|
+
let(:line) do
|
6
|
+
Percept::Line.new(attributes.merge(row: 'my_row', image: 'my_image'))
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'returns a string of the line attributes' do
|
10
|
+
expect(line.to_s).to eq attributes.merge(end_y: 6).to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
describe Percept::LineCollection, '#merge_line' do
|
2
|
+
|
3
|
+
let(:thick_image_path) { File.join(fixture_path, 'thick_line.png') }
|
4
|
+
let(:thick_image) { image_class.new(thick_image_path) }
|
5
|
+
let(:nub_bottom_left_path) { File.join(fixture_path, 'nub_bottom_left.png') }
|
6
|
+
let(:nub_bottom_left) { image_class.new(nub_bottom_left_path) }
|
7
|
+
let(:nub_top_right_path) { File.join(fixture_path, 'nub_top_right.png') }
|
8
|
+
let(:nub_top_right) { image_class.new(nub_bottom_left_path) }
|
9
|
+
let(:nub_both_sides_path) { File.join(fixture_path, 'nub_both_sides.png') }
|
10
|
+
let(:nub_both_sides) { image_class.new(nub_bottom_left_path) }
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
Percept.config.line_length = 30
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when there is a thick line in the image' do
|
17
|
+
it 'merges the lines together' do
|
18
|
+
lines = thick_image.lines
|
19
|
+
expect(lines.size).to eq 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when there is a nub on the bottom line to the left' do
|
24
|
+
it 'merges the two lines together' do
|
25
|
+
lines = nub_bottom_left.lines
|
26
|
+
expect(lines.size).to eq 1
|
27
|
+
line = lines.first
|
28
|
+
expect(line.end_y - line.start_y).to eq 2
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when there is a nub on the top line to the right' do
|
33
|
+
it 'merges the two lines together' do
|
34
|
+
lines = nub_top_right.lines
|
35
|
+
expect(lines.size).to eq 1
|
36
|
+
line = lines.first
|
37
|
+
expect(line.end_y - line.start_y).to eq 2
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when there is a nub on both sides of a line' do
|
42
|
+
it 'merges the two lines together' do
|
43
|
+
lines = nub_both_sides.lines
|
44
|
+
expect(lines.size).to eq 1
|
45
|
+
line = lines.first
|
46
|
+
expect(line.end_y - line.start_y).to eq 2
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe Percept::LineCollection, '#remove_unwanted_lines!' do
|
2
|
+
|
3
|
+
let(:image_path) { File.join(fixture_path, 'corners.png') }
|
4
|
+
let(:image) { image_class.new(image_path) }
|
5
|
+
let(:collection) { image.lines }
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Percept.config.line_length = 30
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'removes lines that are table borders' do
|
12
|
+
expect(collection.size).to eq 10
|
13
|
+
collection.remove_unwanted_lines!
|
14
|
+
expect(collection.size).to eq 9
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
describe Percept::LineCollection, '#split' do
|
2
|
+
|
3
|
+
let(:image_path) { File.join(fixture_path, 'more_corners.png') }
|
4
|
+
let(:image) { image_class.new(image_path) }
|
5
|
+
let(:collection) { image.lines }
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
Percept.config.line_length = 30
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns a new collection with associated lines split' do
|
12
|
+
expect(collection.length).to eq 10
|
13
|
+
new_collection = collection.split
|
14
|
+
expect(new_collection.length).to eq 10
|
15
|
+
Percept.config.line_length = 5
|
16
|
+
new_collection = collection.split
|
17
|
+
expect(new_collection.length).to eq 12
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
describe Percept::LineCollection, '#to_s' do
|
2
|
+
|
3
|
+
let(:collection) { Percept::LineCollection.new }
|
4
|
+
|
5
|
+
it 'returns a stringified version of its associated lines' do
|
6
|
+
lines = %w(line_1 line_2)
|
7
|
+
collection.lines = lines
|
8
|
+
expect(collection.to_s).to eq lines.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|