blue_button_parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+