bollettino 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +103 -0
  3. data/.travis.yml +3 -3
  4. data/CHANGELOG.md +31 -3
  5. data/README.md +8 -8
  6. data/bollettino.gemspec +10 -7
  7. data/lib/bollettino.rb +15 -12
  8. data/lib/bollettino/generator.rb +24 -20
  9. data/lib/bollettino/model/address.rb +22 -0
  10. data/lib/bollettino/model/base.rb +9 -0
  11. data/lib/bollettino/model/payee.rb +21 -0
  12. data/lib/bollettino/model/payer.rb +20 -0
  13. data/lib/bollettino/model/payment_order.rb +24 -0
  14. data/lib/bollettino/model/slip.rb +25 -0
  15. data/lib/bollettino/renderer/address.rb +32 -0
  16. data/lib/bollettino/renderer/base.rb +46 -0
  17. data/lib/bollettino/renderer/errors.rb +14 -0
  18. data/lib/bollettino/renderer/payee.rb +34 -0
  19. data/lib/bollettino/renderer/payer.rb +28 -0
  20. data/lib/bollettino/renderer/payment_order.rb +45 -0
  21. data/lib/bollettino/renderer/slip.rb +29 -0
  22. data/lib/bollettino/version.rb +3 -1
  23. data/spec/integration/generation_spec.rb +8 -9
  24. data/spec/spec_helper.rb +9 -1
  25. data/spec/unit/bollettino/generator_spec.rb +8 -35
  26. data/spec/unit/bollettino/model/address_spec.rb +20 -0
  27. data/spec/unit/bollettino/model/payee_spec.rb +18 -0
  28. data/spec/unit/bollettino/model/payer_spec.rb +24 -0
  29. data/spec/unit/bollettino/model/payment_order_spec.rb +19 -0
  30. data/spec/unit/bollettino/model/slip_spec.rb +29 -0
  31. data/spec/unit/bollettino/renderer/address_spec.rb +28 -0
  32. data/spec/unit/bollettino/renderer/payee_spec.rb +39 -0
  33. data/spec/unit/bollettino/renderer/payer_spec.rb +41 -0
  34. data/spec/unit/bollettino/renderer/payment_order_spec.rb +40 -0
  35. data/spec/unit/bollettino/renderer/slip_spec.rb +54 -0
  36. metadata +81 -51
  37. data/lib/bollettino/models/address.rb +0 -18
  38. data/lib/bollettino/models/payee.rb +0 -17
  39. data/lib/bollettino/models/payer.rb +0 -16
  40. data/lib/bollettino/models/payment_order.rb +0 -20
  41. data/lib/bollettino/models/slip.rb +0 -21
  42. data/lib/bollettino/renderer.rb +0 -47
  43. data/lib/bollettino/renderers/address_renderer.rb +0 -24
  44. data/lib/bollettino/renderers/payee_renderer.rb +0 -26
  45. data/lib/bollettino/renderers/payer_renderer.rb +0 -20
  46. data/lib/bollettino/renderers/payment_order_renderer.rb +0 -37
  47. data/lib/bollettino/renderers/slip_renderer.rb +0 -21
  48. data/spec/unit/bollettino/models/address_spec.rb +0 -12
  49. data/spec/unit/bollettino/models/payee_spec.rb +0 -10
  50. data/spec/unit/bollettino/models/payer_spec.rb +0 -12
  51. data/spec/unit/bollettino/models/payment_order_spec.rb +0 -11
  52. data/spec/unit/bollettino/models/slip_spec.rb +0 -15
  53. data/spec/unit/bollettino/renderers/address_renderer_spec.rb +0 -23
  54. data/spec/unit/bollettino/renderers/payee_renderer_spec.rb +0 -37
  55. data/spec/unit/bollettino/renderers/payer_renderer_spec.rb +0 -27
  56. data/spec/unit/bollettino/renderers/payment_order_renderer_spec.rb +0 -39
  57. 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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Bollettino
2
- VERSION = '1.0.0'
4
+ VERSION = '1.0.1'
3
5
  end
@@ -1,17 +1,17 @@
1
- require 'spec_helper'
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(:each) do
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 :mocha
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
- require 'spec_helper'
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) do
8
- rs = (('A'..'Z').to_a * 10).join('')
7
+ let(:slip) { instance_double('Bollettino::Model::Slip') }
8
+ let(:image) { instance_double('MiniMagick::Image') }
9
9
 
10
- stub(
11
- payee: stub(
12
- account_number: '0123456789',
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 'writes the image' do
32
- image = mock()
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