blue_button_parser 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.
data/test/helper.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+ require 'json'
13
+
14
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
+ require 'blue_button_parser'
17
+
18
+ class Test::Unit::TestCase
19
+ end
@@ -0,0 +1,257 @@
1
+ require 'helper'
2
+
3
+ class BlueButtonParserTest < Test::Unit::TestCase
4
+
5
+ def test_parse_section_breaks
6
+ str = <<-EOS
7
+ ----------------------------- SECTION 1 ----------------------------
8
+ foo
9
+ ------------------------- SECTION 2 -------------------------
10
+ Instructions: -- TAKE WITH FOOD --
11
+
12
+ ---------------------------------
13
+ EOS
14
+ bbp = BlueButtonParser.new(str)
15
+ assert_equal ["SECTION 1", "SECTION 2"], bbp.data.keys, "parser should correctly construct sections in hash output"
16
+ end
17
+
18
+ def test_parse_simple_key_value
19
+ str = <<-EOS
20
+ ------- SECTION ---------
21
+ Zip/Post Code: 00001
22
+ EOS
23
+ expected = {"SECTION" => {"Zip/Post Code" => "00001"}}
24
+ bbp = BlueButtonParser.new(str)
25
+ assert_equal(expected, bbp.data, "should handle simple case with one key-value pair")
26
+ end
27
+
28
+ def test_parse_multiple_key_values
29
+ str = <<-EOS
30
+ ------- SECTION ---------
31
+ Name: MHVTESTVETERAN, ONE Date of Birth: 01 Mar 1948
32
+ EOS
33
+ expected = {"SECTION" => {"Name" => "MHVTESTVETERAN, ONE", "Date of Birth" => "01 Mar 1948"}}
34
+ config = {"SECTION" => {:same_line_keys => ["Name", "Date of Birth"]}}
35
+ bbp = BlueButtonParser.new(str, config)
36
+ assert_equal(expected, bbp.data, "should handle two key-value pairs in single line")
37
+ end
38
+
39
+ def test_parse_two_sets_of_multiple_key_values_in_same_section
40
+ str = <<-EOS
41
+ ------- SECTION ---------
42
+ Name: MHVTESTVETERAN, ONE Date of Birth: 01 Mar 1948
43
+ Gender: Male Blood Type: AB+ Organ Donor: Yes
44
+ EOS
45
+ expected = {"SECTION" => {"Name" => "MHVTESTVETERAN, ONE", "Date of Birth" => "01 Mar 1948", "Gender" => "Male", "Blood Type" => "AB+", "Organ Donor" => "Yes"}}
46
+ config = {"SECTION" => {:same_line_keys => [["Name", "Date of Birth"], ["Gender", "Blood Type", "Organ Donor"]]}}
47
+ bbp = BlueButtonParser.new(str, config)
48
+ assert_equal(expected, bbp.data, "should handle a section having two sets of key-value pairs in single lines")
49
+ end
50
+
51
+ def test_parse_line_wrap_value_with_empty_line_delimiter
52
+ str = <<-EOS
53
+ ------ SECTION ---------
54
+ Comments: BP taken standing. BP continues at goal. Doctor says to continue BP
55
+ medications as directed
56
+
57
+ EOS
58
+ expected = {"SECTION" => {"Comments" => "BP taken standing. BP continues at goal. Doctor says to continue BP \nmedications as directed"}}
59
+ bbp = BlueButtonParser.new(str)
60
+ assert_equal(expected, bbp.data, "should handle value that wraps lines")
61
+ end
62
+
63
+ def test_parse_line_wrap_value_without_empty_line_delimiter
64
+ str = <<-EOS
65
+ ------ SECTION ---------
66
+ Results: BP taken standing. BP continues at goal. Doctor says to continue BP
67
+ medications as directed
68
+ Status: pending
69
+ EOS
70
+ expected = {"SECTION" => {"Results" => "BP taken standing. BP continues at goal. Doctor says to continue BP \nmedications as directed", "Status" => "pending"}}
71
+ bbp = BlueButtonParser.new(str)
72
+ assert_equal(expected, bbp.data, "should handle value that wraps lines but does not end with empty line")
73
+ end
74
+
75
+ def test_parse_line_wrap_value_with_dashed_line
76
+ # As seen in IMMUNIZATIONS/Reactions
77
+ str = <<-EOS
78
+ ------ SECTION ---------
79
+ Reactions:
80
+ ---------------------------------
81
+ Pain
82
+
83
+ EOS
84
+ expected = {"SECTION" => {"Reactions" => "Pain"}}
85
+ bbp = BlueButtonParser.new(str)
86
+ assert_equal(expected, bbp.data, "should handle value that wraps lines")
87
+ end
88
+
89
+ def test_parse_line_wrap_value_with_keyish_item_in_value
90
+ str = <<-EOS
91
+ ------ SECTION ---------
92
+ Note: This appointment has pre-appointment activity scheduled:
93
+ Lab: 27 Jan 2012 @ 1000
94
+
95
+ EOS
96
+ expected = {"SECTION" => {"Note" => "This appointment has pre-appointment activity scheduled: \n Lab: 27 Jan 2012 @ 1000"}}
97
+ bbp = BlueButtonParser.new(str)
98
+ assert_equal(expected, bbp.data, "should handle value that wraps lines, but has a key-like element in the wrapped text")
99
+ end
100
+
101
+ def test_parse_collections_with_empty_line_delimiter
102
+ str = <<-EOS
103
+ ------ SECTION ---------
104
+ Contact Name: Foo
105
+ Contact Email: Zip
106
+
107
+ Contact Name: Bar
108
+ Contact Email: Zap
109
+
110
+ EOS
111
+ expected = {"SECTION" => {"Contacts" => [
112
+ {"Contact Name" => "Foo", "Contact Email" => "Zip"},
113
+ {"Contact Name" => "Bar", "Contact Email" => "Zap"}] }}
114
+ config = {"SECTION" => {:collection => {"Contacts" => {:item_starts_with => "Contact Name"}}}}
115
+ bbp = BlueButtonParser.new(str, config)
116
+ assert_equal(expected, bbp.data, "should find collections")
117
+ end
118
+
119
+ def test_parse_collections_with_empty_line_not_a_delimiter
120
+ # As seen in the "MEDICATIONS AND SUPPLEMENTS" section
121
+ str = <<-EOS
122
+ ------ SECTION ---------
123
+ Contact Name: Foo
124
+ Contact Email: Zip
125
+
126
+ Contact Location: MA
127
+
128
+ Contact Name: Bar
129
+ Contact Email: Zap
130
+
131
+ Contact Location: CA
132
+
133
+ EOS
134
+ expected = {"SECTION" => {"Contacts" => [
135
+ {"Contact Name" => "Foo", "Contact Email" => "Zip", "Contact Location" => "MA"},
136
+ {"Contact Name" => "Bar", "Contact Email" => "Zap", "Contact Location" => "CA"}] }}
137
+ config = {"SECTION" => {:collection => {"Contacts" => {:item_starts_with => "Contact Name"}}}}
138
+ bbp = BlueButtonParser.new(str, config)
139
+ assert_equal(expected, bbp.data, "should find collections where you can't assume empty line is a delimiter")
140
+ end
141
+
142
+ def test_columns_widths
143
+ bbp = BlueButtonParser.new("")
144
+ line = " Foo Bar Sup"
145
+ columns = ["Foo", "Bar", "Sup"]
146
+ expected_widths = [2, 6, 10]
147
+ assert_equal expected_widths, bbp.send(:column_widths, line, columns)
148
+ end
149
+
150
+ def test_parse_table_line
151
+ bbp = BlueButtonParser.new("")
152
+ line = " a b c "
153
+ columns = ["Foo", "Bar", "Sup"]
154
+ widths = [2, 6, 10]
155
+ expected_output = {"Foo" => "a", "Bar" => "b", "Sup" => "c"}
156
+ assert_equal expected_output, bbp.send(:parse_table_line, line, columns, widths)
157
+ end
158
+
159
+ def test_parse_tables
160
+ # Note that "Type" column header does not start at same character position as the row values!
161
+ str = <<-EOS
162
+ --------------------- SECTION ---------------------
163
+
164
+ VA Treating Facility Type
165
+ ---------------------------- -----------
166
+ AUSTIN MHV OTHER
167
+ PORTLAND, OREGON VA MEDICAL CENTER VAMC
168
+
169
+ EOS
170
+ expected = {"SECTION" => {"Facilities" => [
171
+ {"VA Treating Facility" => "AUSTIN MHV", " Type" => "OTHER"},
172
+ {"VA Treating Facility" => "PORTLAND, OREGON VA MEDICAL CENTER", " Type" => "VAMC"}] }}
173
+ config = {"SECTION" => {:collection => {"Facilities" => {:table_columns => ["VA Treating Facility", " Type"]}}}}
174
+ bbp = BlueButtonParser.new(str, config)
175
+ assert_equal(expected, bbp.data, "should parse simple table")
176
+ end
177
+
178
+ def test_parse_tables_with_missing_values
179
+ str = <<-EOS
180
+ ---------------------------- SECTION -------------------------
181
+
182
+ Wellness Reminder Due Date Last Completed Location
183
+ ----------------------------------------------------------------------------
184
+ Control of Your Cholesterol DUE NOW UNKNOWN PORTLAND, OR
185
+ Pneumonia Vaccine 06 Mar 2011 PORTLAND, OR
186
+
187
+ EOS
188
+ expected = {"SECTION" => {"Reminders" => [
189
+ {"Wellness Reminder" => "Control of Your Cholesterol", "Due Date" => "DUE NOW", "Last Completed" => "UNKNOWN", "Location" => "PORTLAND, OR"},
190
+ {"Wellness Reminder" => "Pneumonia Vaccine", "Due Date" => nil, "Last Completed" => "06 Mar 2011", "Location" => "PORTLAND, OR"}
191
+ ]}}
192
+ config = {"SECTION" => {:collection => {"Reminders" => {:table_columns => ["Wellness Reminder", "Due Date", "Last Completed", "Location"]}}}}
193
+ bbp = BlueButtonParser.new(str, config)
194
+ assert_equal(expected, bbp.data, "should parse simple table with missing value")
195
+ end
196
+
197
+ def test_parse_multiple_tables_with_same_columns
198
+ str = <<-EOS
199
+ ---------------------------- SECTION -------------------------
200
+
201
+ -- Regular Active Service
202
+ Service Begin Date End Date Character of Service Rank
203
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
204
+ Army 06/11/2005 03/26/2007 Honorable COL
205
+
206
+ -- Reserve/Guard Association Periods
207
+ Service Begin Date End Date Character of Service Rank
208
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
209
+ Army Guard 01/11/1987 08/24/1993 Unknown
210
+
211
+ EOS
212
+ expected = {"SECTION" => {
213
+ "Regular Active Service"=> [{"Service" => "Army", "Begin Date" => "06/11/2005", "End Date" => "03/26/2007", "Character of Service" => "Honorable", "Rank" => "COL"}],
214
+ "Reserve/Guard Association Periods"=> [{"Service" => "Army Guard", "Begin Date" => "01/11/1987", "End Date" => "08/24/1993", "Character of Service" => "Unknown", "Rank" => nil}]
215
+ }}
216
+ config = {"SECTION" => {:collection => {
217
+ "Regular Active Service" => {:table_starts_with => "-- Regular Active Service", :table_columns => ["Service", "Begin Date", "End Date", "Character of Service", "Rank"] },
218
+ "Reserve/Guard Association Periods" => {:table_starts_with => "-- Reserve/Guard Association Periods", :table_columns => ["Service", "Begin Date", "End Date", "Character of Service", "Rank"] },
219
+ }}}
220
+ bbp = BlueButtonParser.new(str, config)
221
+ assert_equal(expected, bbp.data)
222
+ end
223
+
224
+ def test_parse_entire_sample_blue_button_document
225
+ bbp = BlueButtonParser.new(File.read(File.dirname(__FILE__) + "/data/blue_button_example_data.txt"))
226
+ parsed_data = bbp.data
227
+ expected_data = JSON.parse(File.read(File.dirname(__FILE__) + "/data/expected_json_output.js"))
228
+
229
+ sections = [
230
+ "MY HEALTHEVET PERSONAL INFORMATION REPORT",
231
+ "DOWNLOAD REQUEST SUMMARY",
232
+ "MY HEALTHEVET ACCOUNT SUMMARY",
233
+ "DEMOGRAPHICS",
234
+ "HEALTH CARE PROVIDERS",
235
+ "TREATMENT FACILITIES",
236
+ "HEALTH INSURANCE",
237
+ "VA WELLNESS REMINDERS",
238
+ "VA APPOINTMENTS",
239
+ "VA MEDICATION HISTORY",
240
+ "MEDICATIONS AND SUPPLEMENTS",
241
+ "VA ALLERGIES",
242
+ "ALLERGIES/ADVERSE REACTIONS",
243
+ "MEDICAL EVENTS",
244
+ "IMMUNIZATIONS",
245
+ "VA LABORATORY RESULTS",
246
+ "LABS AND TESTS",
247
+ "VITALS AND READINGS",
248
+ "FAMILY HEALTH HISTORY",
249
+ "MILITARY HEALTH HISTORY",
250
+ ]
251
+
252
+ sections.each do |section|
253
+ assert_equal expected_data[section], parsed_data[section], "parsed section does not match expected JSON for section '#{section}'"
254
+ end
255
+ end
256
+
257
+ end
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blue_button_parser
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - PatientsLikeMe
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-12-22 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: shoulda
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: bundler
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 23
44
+ segments:
45
+ - 1
46
+ - 0
47
+ - 0
48
+ version: 1.0.0
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: jeweler
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 7
60
+ segments:
61
+ - 1
62
+ - 6
63
+ - 4
64
+ version: 1.6.4
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: rcov
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: json
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ type: :development
94
+ version_requirements: *id005
95
+ description: Converts a BlueButton free text data file to a structured data Hash
96
+ email: open_source@patientslikeme.com
97
+ executables: []
98
+
99
+ extensions: []
100
+
101
+ extra_rdoc_files:
102
+ - LICENSE.txt
103
+ - README.rdoc
104
+ files:
105
+ - .document
106
+ - Gemfile
107
+ - Gemfile.lock
108
+ - LICENSE.txt
109
+ - README.rdoc
110
+ - Rakefile
111
+ - VERSION
112
+ - blue_button_parser.gemspec
113
+ - lib/blue_button_parser.rb
114
+ - test/data/blue_button_example_data.txt
115
+ - test/data/expected_json_output.js
116
+ - test/helper.rb
117
+ - test/test_blue_button_parser.rb
118
+ has_rdoc: true
119
+ homepage: http://github.com/patientslikeme/blue_button_parser
120
+ licenses:
121
+ - MIT
122
+ post_install_message:
123
+ rdoc_options: []
124
+
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ hash: 3
133
+ segments:
134
+ - 0
135
+ version: "0"
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ hash: 3
142
+ segments:
143
+ - 0
144
+ version: "0"
145
+ requirements: []
146
+
147
+ rubyforge_project:
148
+ rubygems_version: 1.4.1
149
+ signing_key:
150
+ specification_version: 3
151
+ summary: Converts a BlueButton free text data file to a structured data Hash
152
+ test_files: []
153
+