bollettino 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +103 -0
- data/.travis.yml +3 -3
- data/CHANGELOG.md +31 -3
- data/README.md +8 -8
- data/bollettino.gemspec +10 -7
- data/lib/bollettino.rb +15 -12
- data/lib/bollettino/generator.rb +24 -20
- data/lib/bollettino/model/address.rb +22 -0
- data/lib/bollettino/model/base.rb +9 -0
- data/lib/bollettino/model/payee.rb +21 -0
- data/lib/bollettino/model/payer.rb +20 -0
- data/lib/bollettino/model/payment_order.rb +24 -0
- data/lib/bollettino/model/slip.rb +25 -0
- data/lib/bollettino/renderer/address.rb +32 -0
- data/lib/bollettino/renderer/base.rb +46 -0
- data/lib/bollettino/renderer/errors.rb +14 -0
- data/lib/bollettino/renderer/payee.rb +34 -0
- data/lib/bollettino/renderer/payer.rb +28 -0
- data/lib/bollettino/renderer/payment_order.rb +45 -0
- data/lib/bollettino/renderer/slip.rb +29 -0
- data/lib/bollettino/version.rb +3 -1
- data/spec/integration/generation_spec.rb +8 -9
- data/spec/spec_helper.rb +9 -1
- data/spec/unit/bollettino/generator_spec.rb +8 -35
- data/spec/unit/bollettino/model/address_spec.rb +20 -0
- data/spec/unit/bollettino/model/payee_spec.rb +18 -0
- data/spec/unit/bollettino/model/payer_spec.rb +24 -0
- data/spec/unit/bollettino/model/payment_order_spec.rb +19 -0
- data/spec/unit/bollettino/model/slip_spec.rb +29 -0
- data/spec/unit/bollettino/renderer/address_spec.rb +28 -0
- data/spec/unit/bollettino/renderer/payee_spec.rb +39 -0
- data/spec/unit/bollettino/renderer/payer_spec.rb +41 -0
- data/spec/unit/bollettino/renderer/payment_order_spec.rb +40 -0
- data/spec/unit/bollettino/renderer/slip_spec.rb +54 -0
- metadata +81 -51
- data/lib/bollettino/models/address.rb +0 -18
- data/lib/bollettino/models/payee.rb +0 -17
- data/lib/bollettino/models/payer.rb +0 -16
- data/lib/bollettino/models/payment_order.rb +0 -20
- data/lib/bollettino/models/slip.rb +0 -21
- data/lib/bollettino/renderer.rb +0 -47
- data/lib/bollettino/renderers/address_renderer.rb +0 -24
- data/lib/bollettino/renderers/payee_renderer.rb +0 -26
- data/lib/bollettino/renderers/payer_renderer.rb +0 -20
- data/lib/bollettino/renderers/payment_order_renderer.rb +0 -37
- data/lib/bollettino/renderers/slip_renderer.rb +0 -21
- data/spec/unit/bollettino/models/address_spec.rb +0 -12
- data/spec/unit/bollettino/models/payee_spec.rb +0 -10
- data/spec/unit/bollettino/models/payer_spec.rb +0 -12
- data/spec/unit/bollettino/models/payment_order_spec.rb +0 -11
- data/spec/unit/bollettino/models/slip_spec.rb +0 -15
- data/spec/unit/bollettino/renderers/address_renderer_spec.rb +0 -23
- data/spec/unit/bollettino/renderers/payee_renderer_spec.rb +0 -37
- data/spec/unit/bollettino/renderers/payer_renderer_spec.rb +0 -27
- data/spec/unit/bollettino/renderers/payment_order_renderer_spec.rb +0 -39
- data/spec/unit/bollettino/renderers/slip_renderer_spec.rb +0 -34
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Renderer
|
5
|
+
class Address < Base
|
6
|
+
class << self
|
7
|
+
def render(image, address)
|
8
|
+
render_street(image, address)
|
9
|
+
render_zip(image, address)
|
10
|
+
render_location(image, address)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def render_street(image, address)
|
16
|
+
write_text(image, [85, 267], address.street[0..29], KERNING_NORMAL, FONT_SIZE_SMALL)
|
17
|
+
write_text(image, [1508, 267], address.street[0..22], KERNING_BOX_SMALLEST)
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_zip(image, address)
|
21
|
+
write_text(image, [85, 223], address.zip[0..29], KERNING_NORMAL, FONT_SIZE_SMALL)
|
22
|
+
write_text(image, [1508, 200], address.zip[0..4], KERNING_BOX_SMALLEST)
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_location(image, address)
|
26
|
+
write_text(image, [85, 180], address.location[0..29], KERNING_NORMAL, FONT_SIZE_SMALL)
|
27
|
+
write_text(image, [1713, 200], address.location[0..16], KERNING_BOX_SMALLEST)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Renderer
|
5
|
+
# Base renderer
|
6
|
+
#
|
7
|
+
# @abstract Subclass and override {.render} to create a renderer
|
8
|
+
#
|
9
|
+
# @author Alessandro Desantis <desa.alessandro@gmail.com>
|
10
|
+
class Base
|
11
|
+
class << self
|
12
|
+
KERNING_NORMAL = 1
|
13
|
+
|
14
|
+
KERNING_BOX = 17.5
|
15
|
+
KERNING_BOX_SMALLER = 17
|
16
|
+
KERNING_BOX_SMALLEST = 16
|
17
|
+
|
18
|
+
FONT_SIZE_NORMAL = 30
|
19
|
+
FONT_SIZE_SMALL = 25
|
20
|
+
|
21
|
+
# Renders the given model on the image.
|
22
|
+
#
|
23
|
+
# @param image [MiniMagick::Image]
|
24
|
+
# @param model
|
25
|
+
#
|
26
|
+
# @abstract This method must be overridden by the renderers
|
27
|
+
def render(_image, _model)
|
28
|
+
fail NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def write_text(image, coords, text, kerning = KERNING_NORMAL, font_size = FONT_SIZE_NORMAL)
|
34
|
+
image.combine_options do |c|
|
35
|
+
c.font 'courier'
|
36
|
+
c.fill 'black'
|
37
|
+
c.pointsize font_size
|
38
|
+
c.gravity 'southwest'
|
39
|
+
c.kerning kerning
|
40
|
+
c.draw %(text #{coords.join(',')} "#{text.to_s.upcase.gsub('"', '\"')}")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Renderer
|
5
|
+
# Rendering error
|
6
|
+
#
|
7
|
+
# This error is usually raised when some data can't be renderered because
|
8
|
+
# it's malformed.
|
9
|
+
#
|
10
|
+
# @author Alessandro Desantis <desa.alessandro@gmail.com>
|
11
|
+
class RenderingError < StandardError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Renderer
|
5
|
+
class Payee < Base
|
6
|
+
class << self
|
7
|
+
def render(image, payee)
|
8
|
+
render_account_number(image, payee)
|
9
|
+
render_name(image, payee)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def render_account_number(image, payee)
|
15
|
+
if payee.account_number.length > 10
|
16
|
+
fail RenderingError, "Account number can't be longer than 10 characters"
|
17
|
+
end
|
18
|
+
|
19
|
+
[[265, 695], [1310, 695]].each do |coords|
|
20
|
+
write_text(image, coords, payee.account_number, KERNING_BOX)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def render_name(image, payee)
|
25
|
+
write_text(image, [90, 585], payee.name[0..46])
|
26
|
+
write_text(image, [90, 545], payee.name[47..93])
|
27
|
+
|
28
|
+
write_text(image, [1105, 590], payee.name[0..33], KERNING_BOX_SMALLER)
|
29
|
+
write_text(image, [1105, 545], payee.name[34..67], KERNING_BOX_SMALLER)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Renderer
|
5
|
+
class Payer < Base
|
6
|
+
class << self
|
7
|
+
def render(image, payer)
|
8
|
+
render_name(image, payer)
|
9
|
+
render_address(image, payer)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def render_name(image, payer)
|
15
|
+
write_text(image, [85, 360], payer.name[0..24])
|
16
|
+
write_text(image, [85, 315], payer.name[25..49])
|
17
|
+
|
18
|
+
write_text(image, [1508, 375], payer.name[0..22], KERNING_BOX_SMALLEST)
|
19
|
+
write_text(image, [1508, 330], payer.name[23..45], KERNING_BOX_SMALLEST)
|
20
|
+
end
|
21
|
+
|
22
|
+
def render_address(image, payer)
|
23
|
+
Address.render(image, payer.address)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Renderer
|
5
|
+
class PaymentOrder < Base
|
6
|
+
class << self
|
7
|
+
def render(image, payment_order)
|
8
|
+
render_numeric_amount(image, payment_order)
|
9
|
+
render_text_amount(image, payment_order)
|
10
|
+
render_reason(image, payment_order)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def render_numeric_amount(image, payment_order)
|
16
|
+
numeric_amount = payment_order.numeric_amount
|
17
|
+
numeric_amount = format('%.2f', numeric_amount).delete('.')
|
18
|
+
|
19
|
+
if numeric_amount.length > 7
|
20
|
+
fail RenderingError, "Numeric amount can't be longer than 7 total digits"
|
21
|
+
end
|
22
|
+
|
23
|
+
numeric_amount_x = 1000 - 35 * numeric_amount.length.to_i
|
24
|
+
|
25
|
+
[[numeric_amount_x, 690], [numeric_amount_x + 1315, 690]].each do |coords|
|
26
|
+
write_text(image, coords, numeric_amount, KERNING_BOX)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def render_reason(image, payment_order)
|
31
|
+
write_text(image, [90, 475], payment_order.reason[0..46])
|
32
|
+
write_text(image, [90, 435], payment_order.reason[47..93])
|
33
|
+
|
34
|
+
write_text(image, [1110, 475], payment_order.reason[0..60])
|
35
|
+
write_text(image, [1110, 435], payment_order.reason[61..121])
|
36
|
+
end
|
37
|
+
|
38
|
+
def render_text_amount(image, payment_order)
|
39
|
+
write_text(image, [245, 650], payment_order.text_amount[0..38])
|
40
|
+
write_text(image, [1435, 650], payment_order.text_amount[0..44])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Renderer
|
5
|
+
class Slip < Base
|
6
|
+
class << self
|
7
|
+
def render(image, slip)
|
8
|
+
render_payment_order(image, slip)
|
9
|
+
render_payee(image, slip)
|
10
|
+
render_payer(image, slip)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def render_payment_order(image, slip)
|
16
|
+
PaymentOrder.render(image, slip.payment_order)
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_payee(image, slip)
|
20
|
+
Payee.render(image, slip.payee)
|
21
|
+
end
|
22
|
+
|
23
|
+
def render_payer(image, slip)
|
24
|
+
Payer.render(image, slip.payer)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/bollettino/version.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe 'The generation' do
|
4
4
|
let(:payee) do
|
5
|
-
Bollettino::Payee.new(
|
5
|
+
Bollettino::Model::Payee.new(
|
6
6
|
account_number: '0123456789',
|
7
7
|
name: 'Acme Inc.'
|
8
8
|
)
|
9
9
|
end
|
10
10
|
|
11
11
|
let(:payer) do
|
12
|
-
Bollettino::Payer.new(
|
12
|
+
Bollettino::Model::Payer.new(
|
13
13
|
name: 'John Doe',
|
14
|
-
address: Bollettino::Address.new(
|
14
|
+
address: Bollettino::Model::Address.new(
|
15
15
|
street: '3681 Foggy Moor',
|
16
16
|
zip: '19147-0834',
|
17
17
|
location: 'Grayson'
|
@@ -20,16 +20,15 @@ RSpec.describe 'The generation' do
|
|
20
20
|
end
|
21
21
|
|
22
22
|
let(:payment_order) do
|
23
|
-
Bollettino::PaymentOrder.new(
|
23
|
+
Bollettino::Model::PaymentOrder.new(
|
24
24
|
numeric_amount: 54.31,
|
25
25
|
text_amount: 'Cinquantaquattro/31',
|
26
26
|
reason: 'Invoice INV-1391'
|
27
27
|
)
|
28
|
-
|
29
28
|
end
|
30
29
|
|
31
30
|
let(:slip) do
|
32
|
-
Bollettino::Slip.new(
|
31
|
+
Bollettino::Model::Slip.new(
|
33
32
|
payee: payee,
|
34
33
|
payer: payer,
|
35
34
|
payment_order: payment_order
|
@@ -38,13 +37,13 @@ RSpec.describe 'The generation' do
|
|
38
37
|
|
39
38
|
let(:slip_path) { File.expand_path('../../../tmp/slip.png', __FILE__) }
|
40
39
|
|
41
|
-
before
|
40
|
+
before do
|
42
41
|
FileUtils.rm(slip_path) if File.exist?(slip_path)
|
43
42
|
end
|
44
43
|
|
45
44
|
it 'creates the slip' do
|
46
45
|
expect {
|
47
46
|
Bollettino::Generator.new.generate!(slip, slip_path)
|
48
|
-
}.to change{File.exist?(slip_path)}.from(false).to(true)
|
47
|
+
}.to change { File.exist?(slip_path) }.from(false).to(true)
|
49
48
|
end
|
50
49
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'coveralls'
|
2
|
+
Coveralls.wear!
|
3
|
+
|
1
4
|
require 'bollettino'
|
2
5
|
|
3
6
|
# This file was generated by the `rspec --init` command. Conventionally, all
|
@@ -33,7 +36,12 @@ RSpec.configure do |config|
|
|
33
36
|
|
34
37
|
# rspec-mocks config goes here. You can use an alternate test double
|
35
38
|
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
36
|
-
config.mock_with :
|
39
|
+
config.mock_with :rspec do |mocks|
|
40
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
41
|
+
# a real object. This is generally recommended, and will default to
|
42
|
+
# `true` in RSpec 4.
|
43
|
+
mocks.verify_partial_doubles = true
|
44
|
+
end
|
37
45
|
|
38
46
|
# These two settings work together to allow you to limit a spec run
|
39
47
|
# to individual examples or groups you care about by tagging them with
|
@@ -1,49 +1,22 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Bollettino::Generator do
|
4
4
|
subject { described_class.new }
|
5
5
|
|
6
6
|
describe '#generate!' do
|
7
|
-
let(:slip)
|
8
|
-
|
7
|
+
let(:slip) { instance_double('Bollettino::Model::Slip') }
|
8
|
+
let(:image) { instance_double('MiniMagick::Image') }
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
name: rs
|
14
|
-
),
|
15
|
-
payment_order: stub(
|
16
|
-
numeric_amount: 1,
|
17
|
-
text_amount: rs,
|
18
|
-
reason: rs
|
19
|
-
),
|
20
|
-
payer: stub(
|
21
|
-
name: rs,
|
22
|
-
address: stub(
|
23
|
-
street: rs,
|
24
|
-
location: rs,
|
25
|
-
zip: rs
|
26
|
-
)
|
27
|
-
)
|
28
|
-
)
|
10
|
+
before do
|
11
|
+
allow(MiniMagick::Image).to receive(:open).and_return(image)
|
12
|
+
allow(Bollettino::Renderer::Slip).to receive(:render)
|
29
13
|
end
|
30
14
|
|
31
|
-
it '
|
32
|
-
image
|
33
|
-
image
|
34
|
-
.expects(:write)
|
15
|
+
it 'creates the image' do
|
16
|
+
expect(image).to receive(:write)
|
35
17
|
.with('slip.png')
|
36
18
|
.once
|
37
19
|
|
38
|
-
MiniMagick::Image
|
39
|
-
.expects(:open)
|
40
|
-
.once
|
41
|
-
.returns(image)
|
42
|
-
|
43
|
-
Bollettino::Renderer::SlipRenderer
|
44
|
-
.expects(:render)
|
45
|
-
.once
|
46
|
-
|
47
20
|
subject.generate!(slip, 'slip.png')
|
48
21
|
end
|
49
22
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Model
|
5
|
+
RSpec.describe Address do
|
6
|
+
subject do
|
7
|
+
described_class.new(
|
8
|
+
street: '3681 Foggy Moor',
|
9
|
+
zip: '19147-0834',
|
10
|
+
city: 'Grayson',
|
11
|
+
state: 'Pennsylvania'
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'is instantiated correctly' do
|
16
|
+
expect { subject }.not_to raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Model
|
5
|
+
RSpec.describe Payee do
|
6
|
+
subject do
|
7
|
+
described_class.new(
|
8
|
+
account_number: '0123456789',
|
9
|
+
name: 'Acme Inc.'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'is instantiated correctly' do
|
14
|
+
expect { subject }.not_to raise_error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bollettino
|
4
|
+
module Model
|
5
|
+
RSpec.describe Payer do
|
6
|
+
subject do
|
7
|
+
described_class.new(
|
8
|
+
name: 'John Doe',
|
9
|
+
address: address
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:address) { instance_double('Bollettino::Model::Address') }
|
14
|
+
|
15
|
+
before do
|
16
|
+
allow(address).to receive(:to_hash).and_return({})
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'is instantiated correctly' do
|
20
|
+
expect { subject }.not_to raise_error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|