cbhpm_table 0.0.8 → 0.1.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 +4 -4
- data/.gitignore +2 -0
- data/AGENTS.md +52 -0
- data/CHANGELOG.md +46 -0
- data/README.md +13 -0
- data/cbhpm_table.gemspec +3 -3
- data/lib/cbhpm_table/version.rb +1 -1
- data/lib/cbhpm_table.rb +95 -12
- data/spec/cbhpm_table_spec.rb +141 -0
- metadata +10 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bd670a3a5f433458080a284fb65a7f5eb0db8c49ac6027218ff1bbc72646a013
|
|
4
|
+
data.tar.gz: db1a0d5849fc57531760f884881faebb3bf07f787538398a3208493bd35bf98f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 431d90858a5f234904291f69302be5e3a0ca5b858a6771e7690acbde5d141cea61d9008b19592d6c476fabdc8b2ef6008ffa1227ba48ab55e9ddb71ccc94c153
|
|
7
|
+
data.tar.gz: d7c6135732956573603735ef6869f2911da5e7ad69c1839450e945ca1982e0d7f8366498fe0e5a7b12708e3fd7f74846625797349a4630e8598ba181d1c46cd7
|
data/.gitignore
CHANGED
data/AGENTS.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to AI coding agents (Claude Code, Codex, etc.) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
`cbhpm_table` is a small Ruby gem that wraps the CBHPM (Classificação Brasileira Hierarquizada de Procedimentos Médicos) Excel spreadsheets published by the Associação Médica Brasileira, exposing their rows as Hashes. It depends on `roo-xls` (which brings `roo`) to read `.xls` and `.xlsx` files.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bundle install # install dependencies
|
|
13
|
+
bundle exec rake # run the full spec suite (default task, documentation format)
|
|
14
|
+
bundle exec rspec # run specs directly (this is what CI runs)
|
|
15
|
+
bundle exec rspec spec/cbhpm_table_spec.rb:42 # run a single example by line number
|
|
16
|
+
bundle exec rubocop # lint (.rubocop.yml disables StringLiterals and AsciiComments)
|
|
17
|
+
bundle exec rake build # build the gem into pkg/ (bundler gem tasks)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`spec_helper` (auto-required via `.rspec`) starts SimpleCov, which writes to `coverage/`.
|
|
21
|
+
|
|
22
|
+
## Architecture
|
|
23
|
+
|
|
24
|
+
All logic lives in a single class, `CBHPMTable`, in `lib/cbhpm_table.rb`.
|
|
25
|
+
|
|
26
|
+
- **Edition detection is by exact file basename.** `VERSION_FOR_FILE` maps the spreadsheet's basename (e.g. `"CBHPM 2012.xlsx"`, plus the mojibake names of the old 3a/4a/5a editions) to an edition hash. A file whose name isn't in that map has no edition metadata, and the constructor raises unless an explicit `headers_hash` is passed as the second argument to `CBHPMTable.new`.
|
|
27
|
+
- **Each edition hash** (`CBHPM3a`, `CBHPM2012`, … also registered in `VERSIONS`) holds `file_basename`, `edition_name`, `start_date`/`end_date` (strings in `dd/mm/yyyy` format), and `header_format`: a map from column index to output key (`code`, `name`, `cir_size`, `uco`, `aux_qty`, `an_size`). Column layouts differ between editions: the pre-2012 `.xls` files start at column 0, the 2012+ `.xlsx`/`.xlsm` files start at column 4. From 2022 on, column 12 ("Novo Porte Anest") also maps to `an_size`.
|
|
28
|
+
- **Reader selection** goes by file extension through `ROO_CLASS_FOR_EXTENSION` (`.xls` → `Roo::Excel`, `.xlsx`/`.xlsm` → `Roo::Excelx`). The extension match is case-sensitive.
|
|
29
|
+
- **Row access:** `headers` applies `header_format` to the raw first row. `row(i)` also normalizes the values (see below). `each_row` skips the first (header) row; with no block it returns an Enumerator. `rows` is `each_row.to_a`.
|
|
30
|
+
- **Normalization (all editions).** The spreadsheets mix types in the same column, so `import_row` normalizes every value:
|
|
31
|
+
- `nil` and blank strings become `nil`. Zero stays `0`, because porte 0 is valid.
|
|
32
|
+
- `code` becomes a String. Punctuation is stripped when 8 digits remain (`"4.02.01.02-3"` and `"3110428-2"`).
|
|
33
|
+
- `name` has its whitespace squeezed and stripped.
|
|
34
|
+
- `cir_size` is upcased (the 2020+ spreadsheets have a `9c` for code 31303366).
|
|
35
|
+
- `uco` becomes a Float, also when it comes as a String with a decimal comma (`"0,750"`).
|
|
36
|
+
- `aux_qty`/`an_size` become Integers (`"5"` → `5`).
|
|
37
|
+
- Values that can't be parsed are kept as stripped Strings, never silently corrected.
|
|
38
|
+
- **Columns mapped to the same key.** In `import_row` the rightmost non-blank value wins. From 2022 on, this makes a valid "Novo Porte Anest" override the old "Porte Anestés.", so the application only ever sees `an_size`. In `headers`, the first column's label is kept.
|
|
39
|
+
- **Discarded rows.** `each_row` keeps rows in a Hash keyed by `code`. Rows without code are dropped, and a duplicated code overwrites the earlier row while keeping its position. The gem imports; it doesn't report spreadsheet errors.
|
|
40
|
+
- **Original spreadsheets.** Keep them locally in `planilhas/` (git-ignored). The integration specs use them when present and are skipped otherwise.
|
|
41
|
+
|
|
42
|
+
### Adding a new CBHPM edition
|
|
43
|
+
|
|
44
|
+
Past additions (see the 2016/2018/2020/2022 commits) follow this pattern:
|
|
45
|
+
1. Add a `CBHPMxxxx = VERSIONS[:cbhpmxxxx] = { ... }` constant.
|
|
46
|
+
2. Add its basename to `VERSION_FOR_FILE`.
|
|
47
|
+
3. The newest edition currently has `end_date: ""` (open-ended), so set a real `end_date` on it when a newer edition supersedes it.
|
|
48
|
+
4. Bump `CBHPMTable::VERSION` in `lib/cbhpm_table/version.rb` in a separate commit.
|
|
49
|
+
|
|
50
|
+
## Tests
|
|
51
|
+
|
|
52
|
+
The specs use a trimmed fixture, `spec/cbhpm/cbhpm_cut_for_testing.xlsx`, which `VERSION_FOR_FILE` maps to the 2012 edition. The real CBHPM spreadsheets are not in the repo. Specs for the 2022/2026 spreadsheets run only when they are in `planilhas/`.
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 - 2026-10-04
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Support to CBHPM 2022 (`CBHPM_2022_atualizado.xlsm`) and CBHPM 2026 (`CBHPM_2026.xlsm`).
|
|
7
|
+
- Reading of `.xlsm` files.
|
|
8
|
+
- From 2022 on, the "Novo Porte Anest" column overrides `an_size` when present. Zero is a valid porte.
|
|
9
|
+
- AGENTS.md with guidance for AI coding agents.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Row values are normalized for every edition. This changes the returned types:
|
|
13
|
+
- `code` is a String. Punctuation is stripped when 8 digits remain (`"3110428-2"` → `"31104282"`).
|
|
14
|
+
- `name` has its whitespace squeezed.
|
|
15
|
+
- `cir_size` is upcased (`"9c"` in the 2020+ spreadsheets → `"9C"`).
|
|
16
|
+
- `uco` is a Float, also when the spreadsheet has a decimal comma (`"0,750"`).
|
|
17
|
+
- `aux_qty` and `an_size` are Integers.
|
|
18
|
+
- Blank cells are `nil`.
|
|
19
|
+
- Rows without code and rows with duplicated codes are discarded. The last row read for a code wins.
|
|
20
|
+
- CBHPM 2020 now ends on 31/12/2021.
|
|
21
|
+
- Requires Ruby >= 4.0.0. The development dependency on Bundler is no longer pinned to 1.x.
|
|
22
|
+
|
|
23
|
+
## 0.0.8 - 2022-06-06
|
|
24
|
+
- Support to CBHPM 2016, 2018 and 2020.
|
|
25
|
+
- Fix the file basename of CBHPM 2014.
|
|
26
|
+
|
|
27
|
+
## 0.0.7 - 2018-03-05
|
|
28
|
+
- Support to CBHPM 2014.
|
|
29
|
+
|
|
30
|
+
## 0.0.6 - 2016-04-18
|
|
31
|
+
- Support to the 3rd and 4th CBHPM editions.
|
|
32
|
+
|
|
33
|
+
## 0.0.5 - 2015-06-24
|
|
34
|
+
- Require Ruby >= 1.9.3.
|
|
35
|
+
|
|
36
|
+
## 0.0.4 - 2015-06-24
|
|
37
|
+
- Remove the header indication from rows.
|
|
38
|
+
|
|
39
|
+
## 0.0.3 - 2014-10-29
|
|
40
|
+
- Add `#version_format`, `#start_date` and `#end_date`.
|
|
41
|
+
|
|
42
|
+
## 0.0.2 - 2014-10-28
|
|
43
|
+
- Add `#edition_name`.
|
|
44
|
+
|
|
45
|
+
## 0.0.1 - 2014-10-28
|
|
46
|
+
- Initial release.
|
data/README.md
CHANGED
|
@@ -45,6 +45,19 @@ cbhpm_table.each_row do |row|
|
|
|
45
45
|
end
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
Supported editions: 3a, 4a, 5a, 2010, 2012, 2014, 2016, 2018, 2020, 2022 and 2026
|
|
49
|
+
(`.xls`, `.xlsx` and `.xlsm`). The edition is detected by the file basename.
|
|
50
|
+
|
|
51
|
+
Row values are normalized for every edition:
|
|
52
|
+
* `code` and `name` come as Strings.
|
|
53
|
+
* `cir_size` comes upcased (the 2020+ spreadsheets have a `9c`).
|
|
54
|
+
* `uco` comes as a Float.
|
|
55
|
+
* `aux_qty` and `an_size` come as Integers.
|
|
56
|
+
* Blank cells come as `nil`.
|
|
57
|
+
|
|
58
|
+
From the 2022 edition on, `an_size` already takes the "Novo Porte Anest" column
|
|
59
|
+
into account. Rows without code and rows with duplicated codes are discarded.
|
|
60
|
+
|
|
48
61
|
## Contributing
|
|
49
62
|
|
|
50
63
|
1. Fork it ( https://github.com/[my-github-username]/cbhpm_table/fork )
|
data/cbhpm_table.gemspec
CHANGED
|
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
|
|
|
20
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
21
21
|
spec.require_paths = ["lib"]
|
|
22
22
|
|
|
23
|
-
# This gem
|
|
24
|
-
spec.required_ruby_version = '>=
|
|
23
|
+
# This gem requires Ruby 4.0.0 or greater.
|
|
24
|
+
spec.required_ruby_version = '>= 4.0.0'
|
|
25
25
|
|
|
26
|
-
spec.add_development_dependency "bundler"
|
|
26
|
+
spec.add_development_dependency "bundler"
|
|
27
27
|
spec.add_development_dependency "rake"
|
|
28
28
|
spec.add_development_dependency "rspec"
|
|
29
29
|
spec.add_development_dependency "simplecov"
|
data/lib/cbhpm_table/version.rb
CHANGED
data/lib/cbhpm_table.rb
CHANGED
|
@@ -36,8 +36,12 @@ class CBHPMTable
|
|
|
36
36
|
fail "Can't find predefined headers for #{cbhpm_path}" unless @headers_hash
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
# When several columns map to the same key, the first column names it.
|
|
39
40
|
def headers
|
|
40
|
-
row(first_row_index)
|
|
41
|
+
header_row = roo.row(first_row_index)
|
|
42
|
+
headers_hash.each_with_object({}) do |(col, name), mapped_row|
|
|
43
|
+
mapped_row[name] ||= header_row[col]
|
|
44
|
+
end
|
|
41
45
|
end
|
|
42
46
|
|
|
43
47
|
def first_row_index
|
|
@@ -48,14 +52,52 @@ class CBHPMTable
|
|
|
48
52
|
import_row(roo.row(row_index))
|
|
49
53
|
end
|
|
50
54
|
|
|
55
|
+
# When several columns map to the same key, the rightmost non-blank value
|
|
56
|
+
# wins. From CBHPM 2022 on, this makes a valid "Novo Porte Anest" override
|
|
57
|
+
# the old "Porte Anestés." in an_size. Zero is a valid porte.
|
|
51
58
|
def import_row(row_array)
|
|
52
|
-
|
|
59
|
+
headers_hash.each_with_object({}) do |(col, name), imported_row|
|
|
60
|
+
value = normalize(name, row_array[col])
|
|
61
|
+
imported_row[name] = value unless value.nil? && imported_row.key?(name)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def normalize(name, value)
|
|
66
|
+
return nil if value.nil? || (value.is_a?(String) && value.strip.empty?)
|
|
53
67
|
|
|
54
|
-
|
|
55
|
-
|
|
68
|
+
case name
|
|
69
|
+
when "code" then normalize_code(value)
|
|
70
|
+
when "name" then value.to_s.gsub(/\s+/, " ").strip
|
|
71
|
+
when "cir_size" then value.is_a?(String) ? value.strip.upcase : value
|
|
72
|
+
when "uco" then normalize_decimal(value)
|
|
73
|
+
when "aux_qty", "an_size" then normalize_integer(value)
|
|
74
|
+
else value.is_a?(String) ? value.strip : value
|
|
56
75
|
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def normalize_code(value)
|
|
79
|
+
return integer_value(value).to_s if value.is_a?(Numeric)
|
|
80
|
+
code = value.strip
|
|
81
|
+
digits = code.delete(".-")
|
|
82
|
+
digits.match?(/\A\d{8}\z/) ? digits : code
|
|
83
|
+
end
|
|
57
84
|
|
|
58
|
-
|
|
85
|
+
def normalize_decimal(value)
|
|
86
|
+
return value.to_f if value.is_a?(Numeric)
|
|
87
|
+
decimal = value.strip
|
|
88
|
+
decimal.match?(/\A\d+([.,]\d+)?\z/) ? decimal.tr(",", ".").to_f : decimal
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def normalize_integer(value)
|
|
92
|
+
integer_value(value) || (value.is_a?(String) ? value.strip : value)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def integer_value(value)
|
|
96
|
+
case value
|
|
97
|
+
when Integer then value
|
|
98
|
+
when Float then value.to_i if value == value.to_i
|
|
99
|
+
when String then value.strip.to_i if value.strip.match?(/\A\d+\z/)
|
|
100
|
+
end
|
|
59
101
|
end
|
|
60
102
|
|
|
61
103
|
def rows
|
|
@@ -76,12 +118,18 @@ class CBHPMTable
|
|
|
76
118
|
|
|
77
119
|
attr_reader :cbhpm_path
|
|
78
120
|
|
|
79
|
-
|
|
121
|
+
# Rows without code are silently discarded. So are duplicated codes: the
|
|
122
|
+
# last row read for a code overwrites the previous ones, keeping the
|
|
123
|
+
# position of the first.
|
|
124
|
+
def each_row(&block)
|
|
80
125
|
return to_enum(:each_row) unless block_given?
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
126
|
+
unique_rows.each_value(&block)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def unique_rows
|
|
130
|
+
@unique_rows ||= roo.to_enum(:each).drop(1).each_with_object({}) do |row_array, rows|
|
|
131
|
+
imported_row = import_row(row_array)
|
|
132
|
+
rows[imported_row["code"]] = imported_row unless imported_row["code"].nil?
|
|
85
133
|
end
|
|
86
134
|
end
|
|
87
135
|
|
|
@@ -102,7 +150,9 @@ class CBHPMTable
|
|
|
102
150
|
end
|
|
103
151
|
|
|
104
152
|
private :first_row_index, :import_row, :fetch_version_format
|
|
105
|
-
private :fetch_headers_hash
|
|
153
|
+
private :fetch_headers_hash, :normalize
|
|
154
|
+
private :normalize_code, :normalize_decimal, :normalize_integer
|
|
155
|
+
private :integer_value, :unique_rows
|
|
106
156
|
|
|
107
157
|
VERSIONS = {}
|
|
108
158
|
|
|
@@ -223,6 +273,36 @@ class CBHPMTable
|
|
|
223
273
|
11 => "an_size"
|
|
224
274
|
},
|
|
225
275
|
start_date: "01/01/2020",
|
|
276
|
+
end_date: "31/12/2021" }
|
|
277
|
+
|
|
278
|
+
CBHPM2022 = VERSIONS[:cbhpm2022] =
|
|
279
|
+
{ file_basename: "CBHPM_2022_atualizado.xlsm",
|
|
280
|
+
edition_name: "2022",
|
|
281
|
+
header_format: {
|
|
282
|
+
4 => "code",
|
|
283
|
+
5 => "name",
|
|
284
|
+
8 => "cir_size",
|
|
285
|
+
9 => "uco",
|
|
286
|
+
10 => "aux_qty",
|
|
287
|
+
11 => "an_size",
|
|
288
|
+
12 => "an_size"
|
|
289
|
+
},
|
|
290
|
+
start_date: "01/01/2022",
|
|
291
|
+
end_date: "31/12/2025" }
|
|
292
|
+
|
|
293
|
+
CBHPM2026 = VERSIONS[:cbhpm2026] =
|
|
294
|
+
{ file_basename: "CBHPM_2026.xlsm",
|
|
295
|
+
edition_name: "2026",
|
|
296
|
+
header_format: {
|
|
297
|
+
4 => "code",
|
|
298
|
+
5 => "name",
|
|
299
|
+
8 => "cir_size",
|
|
300
|
+
9 => "uco",
|
|
301
|
+
10 => "aux_qty",
|
|
302
|
+
11 => "an_size",
|
|
303
|
+
12 => "an_size"
|
|
304
|
+
},
|
|
305
|
+
start_date: "01/01/2026",
|
|
226
306
|
end_date: "" }
|
|
227
307
|
|
|
228
308
|
VERSION_FOR_FILE = {
|
|
@@ -235,7 +315,10 @@ class CBHPMTable
|
|
|
235
315
|
"CBHPM 2016.xlsx" => CBHPM2016,
|
|
236
316
|
"CBHPM 2018.xlsx" => CBHPM2018,
|
|
237
317
|
"CBHPM 2020.xlsx" => CBHPM2020,
|
|
318
|
+
"CBHPM_2022_atualizado.xlsm" => CBHPM2022,
|
|
319
|
+
"CBHPM_2026.xlsm" => CBHPM2026,
|
|
238
320
|
"cbhpm_cut_for_testing.xlsx" => CBHPM2012 }
|
|
239
321
|
|
|
240
|
-
ROO_CLASS_FOR_EXTENSION = { ".xls" => Roo::Excel, ".xlsx" => Roo::Excelx
|
|
322
|
+
ROO_CLASS_FOR_EXTENSION = { ".xls" => Roo::Excel, ".xlsx" => Roo::Excelx,
|
|
323
|
+
".xlsm" => Roo::Excelx }
|
|
241
324
|
end
|
data/spec/cbhpm_table_spec.rb
CHANGED
|
@@ -96,4 +96,145 @@ describe CBHPMTable do
|
|
|
96
96
|
expect(cbhpm_table.end_date).to eq "31/12/2013"
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
|
+
|
|
100
|
+
describe "normalization of mixed cell types" do
|
|
101
|
+
let(:header_format) do
|
|
102
|
+
CBHPMTable::CBHPM2026[:header_format]
|
|
103
|
+
end
|
|
104
|
+
let(:table) do
|
|
105
|
+
CBHPMTable.new("spec/cbhpm/cbhpm_cut_for_testing.xlsx", header_format)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def raw_row(values)
|
|
109
|
+
Array.new(13).tap do |row|
|
|
110
|
+
{ "code" => 4, "name" => 5, "cir_size" => 8, "uco" => 9,
|
|
111
|
+
"aux_qty" => 10, "an_size" => 11, "novo_porte_anest" => 12 }
|
|
112
|
+
.each { |name, col| row[col] = values[name] }
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def import(values)
|
|
117
|
+
table.send(:import_row, raw_row(values))
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "converts numeric codes to String" do
|
|
121
|
+
expect(import("code" => 40901688)["code"]).to eq "40901688"
|
|
122
|
+
expect(import("code" => 40901688.0)["code"]).to eq "40901688"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "removes the punctuation of 8 digit codes" do
|
|
126
|
+
expect(import("code" => "4.02.01.02-3")["code"]).to eq "40201023"
|
|
127
|
+
expect(import("code" => "3110428-2")["code"]).to eq "31104282"
|
|
128
|
+
expect(import("code" => "330735114")["code"]).to eq "330735114"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "squeezes whitespace in names" do
|
|
132
|
+
name = " Ablação de alvos\nintracerebrais "
|
|
133
|
+
expect(import("name" => name)["name"]).to eq "Ablação de alvos intracerebrais"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "upcases cir_size" do
|
|
137
|
+
expect(import("cir_size" => " 9c ")["cir_size"]).to eq "9C"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "converts uco to Float, accepting decimal comma" do
|
|
141
|
+
expect(import("uco" => "0,750")["uco"]).to eq 0.75
|
|
142
|
+
expect(import("uco" => 7.39)["uco"]).to eq 7.39
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "converts portes and aux_qty to Integer, keeping zero" do
|
|
146
|
+
expect(import("an_size" => "5")["an_size"]).to eq 5
|
|
147
|
+
expect(import("an_size" => 5)["an_size"]).to eq 5
|
|
148
|
+
expect(import("an_size" => "0")["an_size"]).to eq 0
|
|
149
|
+
expect(import("aux_qty" => 2.0)["aux_qty"]).to eq 2
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "turns blank strings into nil" do
|
|
153
|
+
row = import("cir_size" => "", "uco" => " ", "an_size" => " ")
|
|
154
|
+
expect(row.values_at("cir_size", "uco", "an_size")).to eq [nil, nil, nil]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "keeps unparseable values as String" do
|
|
158
|
+
expect(import("aux_qty" => "2A")["aux_qty"]).to eq "2A"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
describe "anesthetic size resolution" do
|
|
162
|
+
it "prefers the new an_size" do
|
|
163
|
+
expect(import("an_size" => 3, "novo_porte_anest" => 5)["an_size"]).to eq 5
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "accepts zero as a valid new an_size" do
|
|
167
|
+
expect(import("an_size" => 2, "novo_porte_anest" => 0)["an_size"]).to eq 0
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it "falls back to the old an_size when the new one is blank" do
|
|
171
|
+
expect(import("an_size" => "3", "novo_porte_anest" => nil)["an_size"]).to eq 3
|
|
172
|
+
expect(import("an_size" => "3", "novo_porte_anest" => "")["an_size"]).to eq 3
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "maps both columns to an_size" do
|
|
176
|
+
expect(import("an_size" => 3, "novo_porte_anest" => 4).keys).to eq(
|
|
177
|
+
%w[code name cir_size uco aux_qty an_size])
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
describe "duplicated codes and rows without code" do
|
|
183
|
+
let(:roo) { instance_double(Roo::Excelx) }
|
|
184
|
+
|
|
185
|
+
before do
|
|
186
|
+
allow(Roo::Excelx).to receive(:new).and_return(roo)
|
|
187
|
+
allow(roo).to receive(:each).and_yield([])
|
|
188
|
+
.and_yield(row_array(10101012, "Primeira "))
|
|
189
|
+
.and_yield(row_array("10101020", "Outra"))
|
|
190
|
+
.and_yield(row_array(nil, ""))
|
|
191
|
+
.and_yield(row_array(" ", nil))
|
|
192
|
+
.and_yield(row_array("10101012", "Primeira"))
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def row_array(code, name)
|
|
196
|
+
Array.new(12).tap { |row| row[4] = code; row[5] = name }
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "keeps only the last row read for each code, discarding rows without code" do
|
|
200
|
+
expect(cbhpm_table.rows.map { |r| r.values_at("code", "name") }).to eq(
|
|
201
|
+
[%w[10101012 Primeira], %w[10101020 Outra]])
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
%w[CBHPM_2022_atualizado.xlsm CBHPM_2026.xlsm].each do |basename|
|
|
206
|
+
describe "original spreadsheet #{basename}" do
|
|
207
|
+
path = File.join("planilhas", basename)
|
|
208
|
+
before { skip "#{path} not available" unless File.exist?(path) }
|
|
209
|
+
|
|
210
|
+
let(:table) { CBHPMTable.new(path) }
|
|
211
|
+
let(:rows_by_code) { table.rows.to_h { |row| [row["code"], row] } }
|
|
212
|
+
|
|
213
|
+
it "is detected by its basename" do
|
|
214
|
+
expect(table.edition_name).to eq basename[/\d{4}/]
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it "returns every code as an 8 digit String" do
|
|
218
|
+
expect(rows_by_code.keys).to all(match(/\A\d{8}\z/))
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it "returns no duplicated codes" do
|
|
222
|
+
expect(table.rows.size).to eq rows_by_code.size
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
it "exposes the same keys as the previous editions" do
|
|
226
|
+
expect(table.headers.keys).to eq %w[code name cir_size uco aux_qty an_size]
|
|
227
|
+
expect(table.headers["an_size"]).to eq "Porte Anestés."
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it "upcases the lowercase cir_size of the spreadsheet" do
|
|
231
|
+
expect(rows_by_code["31303366"]["cir_size"]).to eq "9C"
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "applies the new anesthetic size" do
|
|
235
|
+
expect(rows_by_code["40202798"]["an_size"]).to eq 5
|
|
236
|
+
expect(rows_by_code["40201015"]["an_size"]).to eq 0
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
end
|
|
99
240
|
end
|
metadata
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cbhpm_table
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abinoam Praxedes Marques Jr.
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: bundler
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '0'
|
|
20
19
|
type: :development
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
|
-
- - "
|
|
23
|
+
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '0'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: rake
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -92,6 +91,8 @@ files:
|
|
|
92
91
|
- ".rspec"
|
|
93
92
|
- ".rubocop.yml"
|
|
94
93
|
- ".travis.yml"
|
|
94
|
+
- AGENTS.md
|
|
95
|
+
- CHANGELOG.md
|
|
95
96
|
- Gemfile
|
|
96
97
|
- LICENSE.txt
|
|
97
98
|
- README.md
|
|
@@ -106,7 +107,6 @@ homepage: https://github.com/abinoam/cbhpm_table
|
|
|
106
107
|
licenses:
|
|
107
108
|
- MIT
|
|
108
109
|
metadata: {}
|
|
109
|
-
post_install_message:
|
|
110
110
|
rdoc_options: []
|
|
111
111
|
require_paths:
|
|
112
112
|
- lib
|
|
@@ -114,15 +114,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
114
114
|
requirements:
|
|
115
115
|
- - ">="
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version:
|
|
117
|
+
version: 4.0.0
|
|
118
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
119
|
requirements:
|
|
120
120
|
- - ">="
|
|
121
121
|
- !ruby/object:Gem::Version
|
|
122
122
|
version: '0'
|
|
123
123
|
requirements: []
|
|
124
|
-
rubygems_version:
|
|
125
|
-
signing_key:
|
|
124
|
+
rubygems_version: 4.0.20
|
|
126
125
|
specification_version: 4
|
|
127
126
|
summary: CBHPM Table. A simple wrapper around the CBHPM excel files.
|
|
128
127
|
test_files:
|