norma43_parser 2.1.1 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +22 -0
- data/.github/workflows/release.yml +33 -0
- data/.rspec +1 -0
- data/CHANGELOG.md +26 -10
- data/Gemfile +2 -2
- data/Gemfile.lock +51 -51
- data/README.md +2 -0
- data/lib/norma43/models/account/spanish_iban.rb +107 -0
- data/lib/norma43/models/account.rb +63 -0
- data/lib/norma43/models/additional_currency.rb +22 -0
- data/lib/norma43/models/additional_item.rb +20 -0
- data/lib/norma43/models/document.rb +42 -0
- data/lib/norma43/models/mixins/attributes_assignment.rb +33 -0
- data/lib/norma43/models/transaction.rb +51 -0
- data/lib/norma43/models.rb +0 -78
- data/lib/norma43/version.rb +1 -1
- data/norma43_parser.gemspec +3 -6
- data/spec/example1_parse_spec.rb +1 -1
- data/spec/norma43/line_processors/account_end_spec.rb +1 -4
- data/spec/norma43/line_processors/account_start_spec.rb +3 -3
- data/spec/norma43/line_processors/additional_currency_spec.rb +3 -3
- data/spec/norma43/line_processors/{additional_items_spec.rb → additional_item_spec.rb} +3 -3
- data/spec/norma43/line_processors/document_end_spec.rb +3 -6
- data/spec/norma43/line_processors/document_start_spec.rb +3 -3
- data/spec/norma43/line_processors/transaction_spec.rb +3 -3
- data/spec/norma43/models/account/spanish_iban_spec.rb +107 -0
- data/spec/norma43/models/account_spec.rb +54 -0
- data/spec/norma43/models/document_spec.rb +35 -0
- data/spec/norma43/models/transaction_spec.rb +25 -0
- data/spec/norma43_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -0
- data/spec/support/shared_examples_for_models.rb +61 -0
- metadata +29 -37
data/lib/norma43/models.rb
CHANGED
@@ -1,86 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "virtus"
|
4
|
-
|
5
3
|
module Norma43
|
6
4
|
module Models
|
7
|
-
# forward declarations
|
8
|
-
class Account; end
|
9
|
-
class Transaction; end
|
10
|
-
class AdditionalItem; end
|
11
|
-
class AdditionalCurrency; end
|
12
5
|
DEBIT_CODE = 1
|
13
6
|
CREDIT_CODE = 2
|
14
|
-
|
15
|
-
class Document
|
16
|
-
include Virtus.model
|
17
|
-
|
18
|
-
attribute :id
|
19
|
-
attribute :created_at
|
20
|
-
attribute :delivery_number
|
21
|
-
attribute :file_type
|
22
|
-
attribute :name
|
23
|
-
attribute :number_of_lines
|
24
|
-
attribute :accounts, Array[Account]
|
25
|
-
|
26
|
-
def transaction_date
|
27
|
-
accounts.map(&:date).compact.first
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class Account
|
32
|
-
include Virtus.model
|
33
|
-
|
34
|
-
attribute :bank_code
|
35
|
-
attribute :branch_code
|
36
|
-
attribute :account_number
|
37
|
-
attribute :start_date
|
38
|
-
attribute :end_date
|
39
|
-
attribute :balance_code
|
40
|
-
attribute :balance_amount
|
41
|
-
attribute :currency_code
|
42
|
-
attribute :information_mode_code
|
43
|
-
attribute :abbreviated_name
|
44
|
-
attribute :debit_entries
|
45
|
-
attribute :debit_amount
|
46
|
-
attribute :credit_entries
|
47
|
-
attribute :credit_amount
|
48
|
-
attribute :transactions, Array[Transaction]
|
49
|
-
end
|
50
|
-
|
51
|
-
class Transaction
|
52
|
-
include Virtus.model
|
53
|
-
|
54
|
-
attribute :origin_branch_code
|
55
|
-
attribute :transaction_date
|
56
|
-
attribute :value_date
|
57
|
-
attribute :shared_item
|
58
|
-
attribute :own_item
|
59
|
-
attribute :amount_code
|
60
|
-
attribute :amount
|
61
|
-
attribute :document_number
|
62
|
-
attribute :reference_1
|
63
|
-
attribute :reference_2
|
64
|
-
attribute :additional_items, Array[AdditionalItem]
|
65
|
-
attribute :additional_currency, AdditionalCurrency
|
66
|
-
def debit?; self.amount_code == DEBIT_CODE end
|
67
|
-
end
|
68
|
-
|
69
|
-
class AdditionalItem
|
70
|
-
include Virtus.model
|
71
|
-
|
72
|
-
attribute :data_code
|
73
|
-
attribute :item_1
|
74
|
-
attribute :item_2
|
75
|
-
end
|
76
|
-
|
77
|
-
class AdditionalCurrency
|
78
|
-
include Virtus.model
|
79
|
-
|
80
|
-
attribute :data_code
|
81
|
-
attribute :currency_code
|
82
|
-
attribute :amount
|
83
|
-
attribute :free
|
84
|
-
end
|
85
7
|
end
|
86
8
|
end
|
data/lib/norma43/version.rb
CHANGED
data/norma43_parser.gemspec
CHANGED
@@ -13,17 +13,14 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "https://github.com/sequra/norma43_parser"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
|
-
spec.required_ruby_version = "
|
16
|
+
spec.required_ruby_version = ">= 3.0"
|
17
17
|
|
18
18
|
spec.files = `git ls-files -z`.split("\x0")
|
19
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
20
|
spec.require_paths = ["lib"]
|
22
21
|
|
23
|
-
spec.add_runtime_dependency "virtus", "~> 1.0"
|
24
22
|
spec.add_runtime_dependency "zeitwerk", "~> 2.0"
|
25
23
|
|
26
|
-
spec.add_development_dependency "
|
27
|
-
spec.add_development_dependency "
|
28
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
24
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.9"
|
29
26
|
end
|
data/spec/example1_parse_spec.rb
CHANGED
@@ -3,10 +3,7 @@
|
|
3
3
|
module Norma43
|
4
4
|
module LineProcessors
|
5
5
|
RSpec.describe AccountEnd do
|
6
|
-
let
|
7
|
-
double "Line", attributes: {}
|
8
|
-
end
|
9
|
-
|
6
|
+
let(:line) { instance_double(LineParsers::AccountEnd, attributes: {}) }
|
10
7
|
let(:account) { Norma43::Models::Account.new }
|
11
8
|
let(:contexts) { Norma43::Utils::Contexts.new(
|
12
9
|
[
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Norma43
|
4
4
|
module LineProcessors
|
5
|
-
RSpec.describe
|
6
|
-
let(:line) {
|
5
|
+
RSpec.describe AccountStart do
|
6
|
+
let(:line) { instance_double(LineParsers::AccountStart, attributes: {}) }
|
7
7
|
let(:document) { Norma43::Models::Document.new }
|
8
8
|
let(:contexts) { Norma43::Utils::Contexts.new }
|
9
9
|
|
@@ -20,7 +20,7 @@ module Norma43
|
|
20
20
|
end
|
21
21
|
|
22
22
|
context "when AccountStart is called" do
|
23
|
-
let(:fake_account) {
|
23
|
+
let(:fake_account) { instance_double(Norma43::Models::Account) }
|
24
24
|
before do
|
25
25
|
allow(Norma43::Models::Account).to receive(:new) { fake_account }
|
26
26
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Norma43
|
4
4
|
module LineProcessors
|
5
|
-
RSpec.describe
|
6
|
-
let(:line) {
|
5
|
+
RSpec.describe AdditionalCurrency do
|
6
|
+
let(:line) { instance_double(LineParsers::AdditionalCurrency, attributes: {}) }
|
7
7
|
let(:transaction) { Norma43::Models::Transaction.new }
|
8
8
|
let(:contexts) { Norma43::Utils::Contexts.new(
|
9
9
|
[
|
@@ -22,7 +22,7 @@ module Norma43
|
|
22
22
|
end
|
23
23
|
|
24
24
|
context "when AdditionalCurrency is called" do
|
25
|
-
let(:fake_additional_currency) {
|
25
|
+
let(:fake_additional_currency) { instance_double(Models::AdditionalCurrency) }
|
26
26
|
before do
|
27
27
|
allow(Models::AdditionalCurrency).to receive(:new) { fake_additional_currency }
|
28
28
|
end
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Norma43
|
4
4
|
module LineProcessors
|
5
|
-
RSpec.describe
|
6
|
-
let(:line) {
|
5
|
+
RSpec.describe AdditionalItem do
|
6
|
+
let(:line) { instance_double(LineParsers::AdditionalItem, attributes: {}) }
|
7
7
|
let(:transaction) { Norma43::Models::Transaction.new }
|
8
8
|
let(:contexts) { Norma43::Utils::Contexts.new(
|
9
9
|
[
|
@@ -22,7 +22,7 @@ module Norma43
|
|
22
22
|
end
|
23
23
|
|
24
24
|
context "when AdditionalItem is called" do
|
25
|
-
let(:fake_additional_item) {
|
25
|
+
let(:fake_additional_item) { instance_double(Models::AdditionalItem) }
|
26
26
|
before do
|
27
27
|
allow(Models::AdditionalItem).to receive(:new) { fake_additional_item }
|
28
28
|
end
|
@@ -2,15 +2,12 @@
|
|
2
2
|
|
3
3
|
module Norma43
|
4
4
|
module LineProcessors
|
5
|
-
RSpec.describe
|
6
|
-
|
7
|
-
end
|
8
|
-
|
9
|
-
let(:line) { double "Line", record_number: 35 }
|
5
|
+
RSpec.describe DocumentEnd do
|
6
|
+
let(:line) { instance_double(LineParsers::DocumentEnd, record_number: 35) }
|
10
7
|
|
11
8
|
it "moves to the nearest document context" do
|
12
9
|
document = Norma43::Models::Document.new
|
13
|
-
contexts = Norma43::Utils::Contexts.new [
|
10
|
+
contexts = Norma43::Utils::Contexts.new [anything, document, anything, anything]
|
14
11
|
|
15
12
|
DocumentEnd.call line, contexts
|
16
13
|
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Norma43
|
4
4
|
module LineProcessors
|
5
|
-
RSpec.describe
|
6
|
-
let
|
5
|
+
RSpec.describe DocumentStart do
|
6
|
+
let(:line) { instance_double(LineParsers::DocumentStart, attributes: {}) }
|
7
7
|
|
8
8
|
it "instantiates a new document with the line attributes" do
|
9
9
|
allow(Models::Document).to receive :new
|
@@ -14,7 +14,7 @@ module Norma43
|
|
14
14
|
end
|
15
15
|
|
16
16
|
it "sets the document as the current context" do
|
17
|
-
fake_document =
|
17
|
+
fake_document = instance_double(Models::Document)
|
18
18
|
allow(Models::Document).to receive(:new) { fake_document }
|
19
19
|
|
20
20
|
contexts = DocumentStart.call line, Norma43::Utils::Contexts.new
|
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Norma43
|
4
4
|
module LineProcessors
|
5
|
-
RSpec.describe
|
6
|
-
let(:line) {
|
5
|
+
RSpec.describe Transaction do
|
6
|
+
let(:line) { instance_double(LineParsers::Transaction, attributes: {}) }
|
7
7
|
let(:account) { Norma43::Models::Account.new }
|
8
8
|
let(:contexts) { Norma43::Utils::Contexts.new(
|
9
9
|
[
|
@@ -22,7 +22,7 @@ module Norma43
|
|
22
22
|
end
|
23
23
|
|
24
24
|
context "when Transaction is called" do
|
25
|
-
let(:fake_transaction) {
|
25
|
+
let(:fake_transaction) { instance_double(Models::Transaction) }
|
26
26
|
before do
|
27
27
|
allow(Models::Transaction).to receive(:new) { fake_transaction }
|
28
28
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Norma43
|
4
|
+
module Models
|
5
|
+
class Account
|
6
|
+
RSpec.describe SpanishIban do
|
7
|
+
def build_account(**attributes)
|
8
|
+
instance_double(Account, **attributes)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".from_account" do
|
12
|
+
subject(:iban) { described_class.from_account(account) }
|
13
|
+
|
14
|
+
context "with the example in the documentation" do
|
15
|
+
let(:account) { build_account(bank_code: 81, branch_code: 54, account_number: 1234567) }
|
16
|
+
it { is_expected.to eq("ES5400810054180001234567") }
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with the account from the example1.n43 fixture" do
|
20
|
+
let(:account) {
|
21
|
+
file.seek 2
|
22
|
+
bank_code = file.read(4).to_i
|
23
|
+
branch_code = file.read(4).to_i
|
24
|
+
account_number = file.read(10).to_i
|
25
|
+
|
26
|
+
build_account(bank_code: bank_code, branch_code: branch_code, account_number: account_number)
|
27
|
+
}
|
28
|
+
let(:file) { File.open(File.join(__dir__, "../../../fixtures/example1.n43"), encoding: "iso-8859-1") }
|
29
|
+
|
30
|
+
it { is_expected.to eq("ES1799991111710123456789") }
|
31
|
+
|
32
|
+
after { file.close }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with minimal edge-case" do
|
36
|
+
let(:account) { build_account(bank_code: 3, branch_code: 0, account_number: 0) }
|
37
|
+
it { is_expected.to eq("ES8700030000300000000000") }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with extreme edge-case" do
|
41
|
+
let(:account) { build_account(bank_code: 9000, branch_code: 9999, account_number: 9999999999) }
|
42
|
+
it { is_expected.to eq("ES3790009999309999999999") }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#to_s" do
|
47
|
+
subject { described_class.new(bank_code: 0, branch_code: 0, account_number: 0) }
|
48
|
+
|
49
|
+
it { is_expected.to(respond_to(:to_s)) }
|
50
|
+
|
51
|
+
context "with incorrect account values" do
|
52
|
+
subject { described_class.new(bank_code: bank_code, branch_code: branch_code, account_number: account_number).to_s }
|
53
|
+
|
54
|
+
let(:bank_code) { 9999 }
|
55
|
+
let(:branch_code) { 1111 }
|
56
|
+
let(:account_number) { 123456789 }
|
57
|
+
|
58
|
+
context "with missing bank code" do
|
59
|
+
let(:bank_code) { nil }
|
60
|
+
it { is_expected.to be_empty }
|
61
|
+
end
|
62
|
+
|
63
|
+
context "with missing branch code" do
|
64
|
+
let(:branch_code) { nil }
|
65
|
+
it { is_expected.to be_empty }
|
66
|
+
end
|
67
|
+
|
68
|
+
context "with missing account number" do
|
69
|
+
let(:account_number) { nil }
|
70
|
+
it { is_expected.to be_empty }
|
71
|
+
end
|
72
|
+
|
73
|
+
context "with negative bank code" do
|
74
|
+
let(:bank_code) { -3 }
|
75
|
+
it { is_expected.to be_empty }
|
76
|
+
end
|
77
|
+
|
78
|
+
context "with negative branch code" do
|
79
|
+
let(:bank_code) { -1 }
|
80
|
+
it { is_expected.to be_empty }
|
81
|
+
end
|
82
|
+
|
83
|
+
context "with negative account number" do
|
84
|
+
let(:account_number) { -123456789 }
|
85
|
+
it { is_expected.to be_empty }
|
86
|
+
end
|
87
|
+
|
88
|
+
context "with more than 4 digits in the bank code" do
|
89
|
+
let(:bank_code) { 99990 }
|
90
|
+
it { is_expected.to be_empty }
|
91
|
+
end
|
92
|
+
|
93
|
+
context "with more than 4 digits in the branch code" do
|
94
|
+
let(:bank_code) { 11110 }
|
95
|
+
it { is_expected.to be_empty }
|
96
|
+
end
|
97
|
+
|
98
|
+
context "with more than 10 digits in the account number" do
|
99
|
+
let(:account_number) { 12345678900 }
|
100
|
+
it { is_expected.to be_empty }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Norma43
|
4
|
+
module Models
|
5
|
+
RSpec.describe Account do
|
6
|
+
it_behaves_like "a model"
|
7
|
+
|
8
|
+
describe "#iban" do
|
9
|
+
it { is_expected.to respond_to(:iban) }
|
10
|
+
|
11
|
+
context "with the example in the documentation" do
|
12
|
+
it "returns the correct IBAN string" do
|
13
|
+
account = subject
|
14
|
+
account.account_number = 1234567
|
15
|
+
account.bank_code = 81
|
16
|
+
account.branch_code = 54
|
17
|
+
|
18
|
+
expect(account.iban).to eq("ES5400810054180001234567")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with missing bank data" do
|
23
|
+
subject { described_class.new.iban }
|
24
|
+
it { is_expected.to be_nil }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with missing bank code" do
|
28
|
+
subject { described_class.new(bank_code: nil, branch_code: 1234, account_number: 1234).iban }
|
29
|
+
it { is_expected.to be_nil }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with missing branch code" do
|
33
|
+
subject { described_class.new(bank_code: 1234, branch_code: nil, account_number: 1234).iban }
|
34
|
+
it { is_expected.to be_nil }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "with missing account number" do
|
38
|
+
subject { described_class.new(bank_code: 1234, branch_code: 1234, account_number: nil).iban }
|
39
|
+
it { is_expected.to be_nil }
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with negative account number" do
|
43
|
+
subject { described_class.new(bank_code: 1234, branch_code: 1234, account_number: -1234).iban }
|
44
|
+
it { is_expected.to be_nil }
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with an account number which is too large" do
|
48
|
+
subject { described_class.new(bank_code: 1234, branch_code: 1234, account_number: 1*10**10).iban }
|
49
|
+
it { is_expected.to be_nil }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Norma43
|
4
|
+
module Models
|
5
|
+
RSpec.describe Document do
|
6
|
+
it_behaves_like "a model"
|
7
|
+
|
8
|
+
describe "#transaction_date" do
|
9
|
+
it { is_expected.to respond_to(:transaction_date) }
|
10
|
+
|
11
|
+
context "when there are no accounts" do
|
12
|
+
subject(:document) { described_class.new({ accounts: [] }) }
|
13
|
+
|
14
|
+
it { expect(document.transaction_date).to be_nil }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when there are accounts" do
|
18
|
+
subject(:document) { described_class.new({ accounts: [account] }) }
|
19
|
+
|
20
|
+
let(:account) {
|
21
|
+
Account.new(transactions: [
|
22
|
+
nil,
|
23
|
+
Transaction.new(transaction_date: nil),
|
24
|
+
Transaction.new(transaction_date: Date.parse("2024-01-23")),
|
25
|
+
])
|
26
|
+
}
|
27
|
+
|
28
|
+
it "returns the date of the first account with a transaction date" do
|
29
|
+
expect(document.transaction_date).to eq(Date.parse("2024-01-23"))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Norma43
|
4
|
+
module Models
|
5
|
+
RSpec.describe Transaction do
|
6
|
+
it_behaves_like "a model"
|
7
|
+
|
8
|
+
describe "#debit?" do
|
9
|
+
it { is_expected.to respond_to(:debit?) }
|
10
|
+
|
11
|
+
context "when amount code is code for debits" do
|
12
|
+
subject(:transaction) { described_class.new(amount_code: 1) }
|
13
|
+
|
14
|
+
it { expect(transaction.debit?).to be_truthy }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when amount code is code for credits" do
|
18
|
+
subject(:transaction) { described_class.new(amount_code: 2) }
|
19
|
+
|
20
|
+
it { expect(transaction.debit?).to be_falsey }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/norma43_spec.rb
CHANGED
@@ -6,7 +6,7 @@ RSpec.describe Norma43 do
|
|
6
6
|
describe "#parse" do
|
7
7
|
it "returns the parser results" do
|
8
8
|
text = "some total-in text"
|
9
|
-
parser =
|
9
|
+
parser = instance_double(Norma43::Parser, result: "result")
|
10
10
|
expect(Norma43::Parser).to receive(:new).with(text) { parser }
|
11
11
|
|
12
12
|
expect(Norma43.parse(text)).to eq "result"
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "norma43"
|
4
|
+
|
3
5
|
RSpec.configure do |config|
|
4
6
|
config.order = :random
|
5
7
|
Kernel.srand config.seed
|
@@ -11,6 +13,7 @@ RSpec.configure do |config|
|
|
11
13
|
config.mock_with :rspec do |mocks|
|
12
14
|
mocks.syntax = :expect
|
13
15
|
mocks.verify_partial_doubles = true
|
16
|
+
mocks.verify_doubled_constant_names = true
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_examples "a model" do
|
4
|
+
it { is_expected.to respond_to(:attributes) }
|
5
|
+
it { is_expected.to respond_to(:attributes=) }
|
6
|
+
it { is_expected.to respond_to(:to_h) }
|
7
|
+
it { is_expected.to respond_to(:to_hash) }
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
subject(:model) { described_class.new(attributes) }
|
11
|
+
|
12
|
+
context "when instantiated with an empty hash" do
|
13
|
+
let(:attributes) { {} }
|
14
|
+
|
15
|
+
it "accepts it without failing" do
|
16
|
+
expect { model }.not_to raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#attributes" do
|
22
|
+
subject { described_class.new.attributes }
|
23
|
+
|
24
|
+
it { is_expected.not_to be_empty }
|
25
|
+
it { is_expected.to respond_to(:each_pair) }
|
26
|
+
it { is_expected.to respond_to(:to_h) }
|
27
|
+
it { is_expected.to respond_to(:to_hash) }
|
28
|
+
it { is_expected.to respond_to(:keys) }
|
29
|
+
|
30
|
+
describe "#attributes.keys" do
|
31
|
+
subject { super().keys }
|
32
|
+
|
33
|
+
it { is_expected.not_to be_empty }
|
34
|
+
it { is_expected.to all(be_a(Symbol)) }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#attributes=" do
|
39
|
+
subject { described_class.new.attributes=(attributes) }
|
40
|
+
|
41
|
+
context "when passed an empty hash" do
|
42
|
+
let(:attributes) { {} }
|
43
|
+
|
44
|
+
it "accepts it without failing" do
|
45
|
+
expect { subject }.not_to raise_error
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when passed a hash with unknown attribute names" do
|
50
|
+
let(:attributes) { { potato: nil } }
|
51
|
+
|
52
|
+
it "accepts it without failing" do
|
53
|
+
expect { subject }.not_to raise_error
|
54
|
+
end
|
55
|
+
|
56
|
+
it "does not set any new method" do
|
57
|
+
expect { subject.potato }.to raise_error(NoMethodError, /undefined method.+potato/i)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|