fbo 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile.lock +2 -2
  4. data/README.md +23 -0
  5. data/lib/fbo.rb +17 -0
  6. data/lib/fbo/notices/archive.rb +8 -0
  7. data/lib/fbo/notices/fair_opportunity.rb +15 -0
  8. data/lib/fbo/notices/foreign_standard.rb +13 -0
  9. data/lib/fbo/notices/intent_to_bundle.rb +13 -0
  10. data/lib/fbo/notices/justification_approval.rb +18 -0
  11. data/lib/fbo/notices/sale_of_surplus.rb +13 -0
  12. data/lib/fbo/notices/special_notice.rb +13 -0
  13. data/lib/fbo/notices/unarchive.rb +9 -0
  14. data/lib/fbo/parser.rb +2 -15
  15. data/lib/fbo/parser/archive_handler.rb +41 -0
  16. data/lib/fbo/parser/fair_opportunity_handler.rb +61 -0
  17. data/lib/fbo/parser/foreign_standard_handler.rb +57 -0
  18. data/lib/fbo/parser/handler_selector.rb +37 -0
  19. data/lib/fbo/parser/intent_to_bundle_handler.rb +56 -0
  20. data/lib/fbo/parser/justification_approval_handler.rb +60 -0
  21. data/lib/fbo/parser/parser_helper.rb +40 -0
  22. data/lib/fbo/parser/sale_of_surplus_handler.rb +57 -0
  23. data/lib/fbo/parser/special_notice_handler.rb +57 -0
  24. data/lib/fbo/parser/unarchive_handler.rb +42 -0
  25. data/lib/fbo/version.rb +1 -1
  26. data/spec/fbo/parser/amendment_handler_spec.rb +28 -23
  27. data/spec/fbo/parser/archive_handler_spec.rb +36 -0
  28. data/spec/fbo/parser/award_handler_spec.rb +5 -0
  29. data/spec/fbo/parser/combined_solicitation_handler_spec.rb +4 -0
  30. data/spec/fbo/parser/fair_opportunity_handler_spec.rb +56 -0
  31. data/spec/fbo/parser/foreign_standard_handler_spec.rb +51 -0
  32. data/spec/fbo/parser/handler_selector_spec.rb +40 -0
  33. data/spec/fbo/parser/intent_to_bundle_handler_spec.rb +52 -0
  34. data/spec/fbo/parser/justification_approval_handler_spec.rb +53 -0
  35. data/spec/fbo/parser/modification_handler_spec.rb +5 -0
  36. data/spec/fbo/parser/presolicitation_handler_spec.rb +5 -0
  37. data/spec/fbo/parser/sale_of_surplus_handler_spec.rb +53 -0
  38. data/spec/fbo/parser/sources_sought_handler_spec.rb +27 -22
  39. data/spec/fbo/parser/special_notice_handler_spec.rb +53 -0
  40. data/spec/fbo/parser/unarchive_handler_spec.rb +37 -0
  41. data/spec/fbo/parser/unknown_handler_spec.rb +5 -0
  42. data/spec/fbo/parser_spec.rb +18 -49
  43. data/spec/fixtures/notices/archive +10 -0
  44. data/spec/fixtures/notices/fairopp +29 -0
  45. data/spec/fixtures/notices/fstd +24 -0
  46. data/spec/fixtures/notices/itb +19 -0
  47. data/spec/fixtures/notices/ja +30 -0
  48. data/spec/fixtures/notices/notanotice +7 -0
  49. data/spec/fixtures/notices/ssale +24 -0
  50. data/spec/fixtures/notices/unarchive +10 -0
  51. metadata +53 -2
@@ -0,0 +1,56 @@
1
+ module FBO::Parser::IntentToBundleHandler
2
+ TAGS = %w( ITB DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD AGENCY ) +
3
+ %w( OFFICE LOCATION SUBJECT SOLNBR NTYPE ARCHDATE CONTACT DESC AWDNBR ) +
4
+ %w( DONBR LINK URL EMAIL ADDRESS \/ITB )
5
+
6
+ ANY_ITB_TAG = TAGS.join("|")
7
+ INTENT_TO_BUNDLE_PATTERN = /^<ITB>/
8
+
9
+
10
+ def is_intent_to_bundle?(text)
11
+ text =~ INTENT_TO_BUNDLE_PATTERN
12
+ end
13
+
14
+ def parse(text)
15
+ params = {
16
+ date: date(text),
17
+ year: year(text),
18
+ zip: zip(text),
19
+ class_code: classification_code(text),
20
+ naics_code: naics_code(text),
21
+ agency: agency(text),
22
+ office: office(text),
23
+ location: location(text),
24
+ office_address: office_address(text),
25
+ subject: subject(text),
26
+ solicitation_number: solicitation_number(text),
27
+ archive_date: archive_date(text),
28
+ contact_info: contact(text),
29
+ description: description(text),
30
+ notice_type: notice_type(text),
31
+ award_number: award_number(text),
32
+ delivery_order_number: delivery_order_number(text),
33
+ link_url: link_url(text),
34
+ link_description: link_description(text),
35
+ email_address: email_address(text),
36
+ email_description: email_description(text),
37
+ correction: correction?(text)
38
+ }
39
+ FBO::Notices::IntentToBundle.new(params)
40
+ end
41
+
42
+
43
+ protected
44
+
45
+ # Returns a concatenated list of all tags for the notice
46
+ #
47
+ # @return [String]
48
+ def any_notice_tag
49
+ ANY_ITB_TAG
50
+ end
51
+
52
+
53
+ extend FBO::Parser::NoticeHandler
54
+ extend FBO::Parser::ParserHelper
55
+ extend self
56
+ end
@@ -0,0 +1,60 @@
1
+ module FBO::Parser::JustificationApprovalHandler
2
+ TAGS = %w( JA DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD ) +
3
+ %w( AGENCY OFFICE LOCATION SUBJECT SOLNBR NTYPE DESC CONTACT AWDNBR ) +
4
+ %w( AWDDATE ARCHDATE LINK URL EMAIL ADDRESS STAUTH MODNBR ) +
5
+ %w( FILELIST FILE MIMETYPE /FILE /FILELIST CORRECTION /JA )
6
+
7
+ ANY_JUSTIFICATION_APPROVAL_TAG = TAGS.join("|")
8
+ JA_PATTERN = /^<JA>/
9
+
10
+
11
+ def is_justification_approval?(text)
12
+ text =~ JA_PATTERN
13
+ end
14
+
15
+ def parse(text)
16
+ params = {
17
+ date: date(text),
18
+ year: year(text),
19
+ zip: zip(text),
20
+ class_code: classification_code(text),
21
+ naics_code: naics_code(text),
22
+ agency: agency(text),
23
+ office: office(text),
24
+ location: location(text),
25
+ office_address: office_address(text),
26
+ subject: subject(text),
27
+ solicitation_number: solicitation_number(text),
28
+ notice_type: notice_type(text),
29
+ description: description(text),
30
+ contact_info: contact(text),
31
+ statutory_authority: statutory_authority(text),
32
+ award_number: award_number(text),
33
+ modification_number: modification_number(text),
34
+ award_date: award_date(text),
35
+ archive_date: archive_date(text),
36
+ link_url: link_url(text),
37
+ link_description: link_description(text),
38
+ email_address: email_address(text),
39
+ email_description: email_description(text),
40
+ file_list: file_list(text),
41
+ correction: correction?(text)
42
+ }
43
+ FBO::Notices::JustificationApproval.new(params)
44
+ end
45
+
46
+
47
+ protected
48
+
49
+ # Returns a concatenated list of all tags for the notice
50
+ #
51
+ # @return [String]
52
+ def any_notice_tag
53
+ ANY_JUSTIFICATION_APPROVAL_TAG
54
+ end
55
+
56
+
57
+ extend FBO::Parser::NoticeHandler
58
+ extend FBO::Parser::ParserHelper
59
+ extend self
60
+ end
@@ -272,4 +272,44 @@ module FBO::Parser::ParserHelper
272
272
  false
273
273
  end
274
274
 
275
+ # Get the file list associated with the notice.
276
+ #
277
+ # @param text [String] the full text of the notice
278
+ # @return [Array] the file list
279
+ def file_list(text)
280
+ []
281
+ end
282
+
283
+ # Get the statutory authority.
284
+ #
285
+ # @param text [String] the full text of the notice
286
+ # @return [String] the name of the statutory authority
287
+ def statutory_authority(text)
288
+ simple_tag_contents(text, "STAUTH")
289
+ end
290
+
291
+ # Get the modification number.
292
+ #
293
+ # @param text [String] the full text of the notice
294
+ # @return [String] the modification number
295
+ def modification_number(text)
296
+ simple_tag_contents(text, "MODNBR")
297
+ end
298
+
299
+ # Get the delivery order number.
300
+ #
301
+ # @param text [String] the full text of the notice
302
+ # @return [String] the delivery order number
303
+ def delivery_order_number(text)
304
+ simple_tag_contents(text, "DONBR")
305
+ end
306
+
307
+ # Get the justification authority (reason).
308
+ #
309
+ # @param text [String] the full text of the notice
310
+ # @return [String] the judstification authority
311
+ def justification_authority(text)
312
+ simple_tag_contents(text, "FOJA")
313
+ end
314
+
275
315
  end
@@ -0,0 +1,57 @@
1
+ module FBO::Parser::SaleOfSurplusHandler
2
+ TAGS = %w( SSALE DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD AGENCY ) +
3
+ %w( OFFICE LOCATION SUBJECT SOLNBR RESPDATE ARCHDATE CONTACT DESC LINK ) +
4
+ %w( URL EMAIL ADDRESS SETASIDE POPADDRESS POPZIP POPCOUNTRY \/SSALE )
5
+
6
+ ANY_SSALE_TAG = TAGS.join("|")
7
+ SALE_OF_SURPLUS_PATTERN = /^<SSALE>/
8
+
9
+
10
+ def is_sale_of_surplus?(text)
11
+ text =~ SALE_OF_SURPLUS_PATTERN
12
+ end
13
+
14
+ def parse(text)
15
+ params = {
16
+ date: date(text),
17
+ year: year(text),
18
+ zip: zip(text),
19
+ class_code: classification_code(text),
20
+ naics_code: naics_code(text),
21
+ agency: agency(text),
22
+ office: office(text),
23
+ location: location(text),
24
+ office_address: office_address(text),
25
+ subject: subject(text),
26
+ solicitation_number: solicitation_number(text),
27
+ response_date: response_date(text),
28
+ archive_date: archive_date(text),
29
+ contact_info: contact(text),
30
+ description: description(text),
31
+ link_url: link_url(text),
32
+ link_description: link_description(text),
33
+ email_address: email_address(text),
34
+ email_description: email_description(text),
35
+ setaside: set_aside(text),
36
+ pop_address: pop_address(text),
37
+ pop_zip: pop_zip_code(text),
38
+ pop_country: pop_country(text)
39
+ }
40
+ FBO::Notices::SaleOfSurplus.new(params)
41
+ end
42
+
43
+
44
+ protected
45
+
46
+ # Returns a concatenated list of all tags for the notice
47
+ #
48
+ # @return [String]
49
+ def any_notice_tag
50
+ ANY_SSALE_TAG
51
+ end
52
+
53
+
54
+ extend FBO::Parser::NoticeHandler
55
+ extend FBO::Parser::ParserHelper
56
+ extend self
57
+ end
@@ -0,0 +1,57 @@
1
+ module FBO::Parser::SpecialNoticeHandler
2
+ TAGS = %w( SNOTE DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD AGENCY ) +
3
+ %w( OFFICE LOCATION SUBJECT SOLNBR RESPDATE ARCHDATE CONTACT DESC LINK ) +
4
+ %w( URL EMAIL ADDRESS SETASIDE POPADDRESS POPZIP POPCOUNTRY \/SNOTE )
5
+
6
+ ANY_SNOTE_TAG = TAGS.join("|")
7
+ SPECIAL_NOTICE_PATTERN = /^<SNOTE>/
8
+
9
+
10
+ def is_special_notice?(text)
11
+ text =~ SPECIAL_NOTICE_PATTERN
12
+ end
13
+
14
+ def parse(text)
15
+ params = {
16
+ date: date(text),
17
+ year: year(text),
18
+ zip: zip(text),
19
+ class_code: classification_code(text),
20
+ naics_code: naics_code(text),
21
+ agency: agency(text),
22
+ office: office(text),
23
+ location: location(text),
24
+ office_address: office_address(text),
25
+ subject: subject(text),
26
+ solicitation_number: solicitation_number(text),
27
+ response_date: response_date(text),
28
+ archive_date: archive_date(text),
29
+ contact_info: contact(text),
30
+ description: description(text),
31
+ link_url: link_url(text),
32
+ link_description: link_description(text),
33
+ email_address: email_address(text),
34
+ email_description: email_description(text),
35
+ setaside: set_aside(text),
36
+ pop_address: pop_address(text),
37
+ pop_zip: pop_zip_code(text),
38
+ pop_country: pop_country(text)
39
+ }
40
+ FBO::Notices::SpecialNotice.new(params)
41
+ end
42
+
43
+
44
+ protected
45
+
46
+ # Returns a concatenated list of all tags for the notice
47
+ #
48
+ # @return [String]
49
+ def any_notice_tag
50
+ ANY_SNOTE_TAG
51
+ end
52
+
53
+
54
+ extend FBO::Parser::NoticeHandler
55
+ extend FBO::Parser::ParserHelper
56
+ extend self
57
+ end
@@ -0,0 +1,42 @@
1
+ module FBO::Parser::UnarchiveHandler
2
+ TAGS = %w( UNARCHIVE DATE YEAR CBAC PASSWORD AGENCY OFFICE LOCATION NTYPE ) +
3
+ %w( SOLNBR ARCHDATE AWDNBR \/UNARCHIVE )
4
+
5
+ ANY_UNARCHIVE_TAG = TAGS.join("|")
6
+ UNARCHIVE_PATTERN = /^<UNARCHIVE>/
7
+
8
+
9
+ def is_unarchive?(text)
10
+ text =~ UNARCHIVE_PATTERN
11
+ end
12
+
13
+ def parse(text)
14
+ params = {
15
+ date: date(text),
16
+ year: year(text),
17
+ agency: agency(text),
18
+ office: office(text),
19
+ location: location(text),
20
+ solicitation_number: solicitation_number(text),
21
+ notice_type: notice_type(text),
22
+ archive_date: archive_date(text),
23
+ award_number: award_number(text)
24
+ }
25
+ FBO::Notices::Unarchive.new(params)
26
+ end
27
+
28
+
29
+ protected
30
+
31
+ # Returns a concatenated list of all tags for the notice
32
+ #
33
+ # @return [String]
34
+ def any_notice_tag
35
+ ANY_UNARCHIVE_TAG
36
+ end
37
+
38
+
39
+ extend FBO::Parser::NoticeHandler
40
+ extend FBO::Parser::ParserHelper
41
+ extend self
42
+ end
data/lib/fbo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module FBO
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -12,31 +12,36 @@ describe FBO::Parser::AmendmentHandler do
12
12
  end
13
13
 
14
14
  it "should parse all fields correctly" do
15
- combine = subject.parse(contents)
16
- combine.date.strftime("%Y-%m-%d").should eq Date.parse("2013-03-26").strftime("%Y-%m-%d")
17
- combine.year.should eq 2013
18
- combine.agency.should eq "Department of the Air Force"
19
- combine.office.should eq "Air Force Materiel Command"
20
- combine.location.should eq "Tinker AFB - OC-ALC/PKO"
21
- combine.zip.should eq "73145-9106"
22
- combine.class_code.should eq "R"
23
- combine.naics_code.should eq "541611"
24
- combine.office_address.should eq "7858 5th Street Ste 1 Tinker AFB OK 73145-9106"
25
- combine.subject.should eq "ISO 9001:2008 AS9100/9110 Registration/Surveillance/Reassessment Audit"
26
- combine.solicitation_number.should eq "FA8101-13-Q-0014"
27
- combine.response_date.strftime("%Y-%m-%d").should eq "2013-03-27"
28
- combine.archive_date.strftime("%Y-%m-%d").should eq "2013-04-26"
29
- combine.contact_info.should eq "Matthew Kinney, Contract Specialist, Phone 4057393745, Email matthew.kinney@tinker.af.mil - Kimberly L DeLong, Contracting Officer, Phone (405) 739-3514, Fax (405) 739-7957, Email kimberly.delong2@tinker.af.mil"
30
- combine.description.should eq "<p>***All quotes need to be based&nbsp;off of&nbsp;the scope and&nbsp;figures in the&nbsp;PWS and&nbsp;not OASIS<br />***IAW PWS para 1.1(e) the audit will be scheduled in May&nbsp;and must&nbsp;be&nbsp;completed in one week<br />***Organizations&nbsp;OIN 6115237940</p>"
31
- combine.link_url.should eq "https://www.fbo.gov/spg/USAF/AFMC/OCALCBC/FA8101-13-Q-0014/listing.html"
32
- combine.link_description.should eq "Link To Document"
33
- combine.setaside.should eq "Total Small Business"
34
- combine.pop_country.should eq "US"
35
- combine.pop_zip.should eq "73145"
36
- combine.pop_address.should eq "Tinker AFB\nTinker AFB, OK"
15
+ amendment = subject.parse(contents)
16
+ amendment.date.strftime("%Y-%m-%d").should eq Date.parse("2013-03-26").strftime("%Y-%m-%d")
17
+ amendment.year.should eq 2013
18
+ amendment.agency.should eq "Department of the Air Force"
19
+ amendment.office.should eq "Air Force Materiel Command"
20
+ amendment.location.should eq "Tinker AFB - OC-ALC/PKO"
21
+ amendment.zip.should eq "73145-9106"
22
+ amendment.class_code.should eq "R"
23
+ amendment.naics_code.should eq "541611"
24
+ amendment.office_address.should eq "7858 5th Street Ste 1 Tinker AFB OK 73145-9106"
25
+ amendment.subject.should eq "ISO 9001:2008 AS9100/9110 Registration/Surveillance/Reassessment Audit"
26
+ amendment.solicitation_number.should eq "FA8101-13-Q-0014"
27
+ amendment.response_date.strftime("%Y-%m-%d").should eq "2013-03-27"
28
+ amendment.archive_date.strftime("%Y-%m-%d").should eq "2013-04-26"
29
+ amendment.contact_info.should eq "Matthew Kinney, Contract Specialist, Phone 4057393745, Email matthew.kinney@tinker.af.mil - Kimberly L DeLong, Contracting Officer, Phone (405) 739-3514, Fax (405) 739-7957, Email kimberly.delong2@tinker.af.mil"
30
+ amendment.description.should eq "<p>***All quotes need to be based&nbsp;off of&nbsp;the scope and&nbsp;figures in the&nbsp;PWS and&nbsp;not OASIS<br />***IAW PWS para 1.1(e) the audit will be scheduled in May&nbsp;and must&nbsp;be&nbsp;completed in one week<br />***Organizations&nbsp;OIN 6115237940</p>"
31
+ amendment.link_url.should eq "https://www.fbo.gov/spg/USAF/AFMC/OCALCBC/FA8101-13-Q-0014/listing.html"
32
+ amendment.link_description.should eq "Link To Document"
33
+ amendment.setaside.should eq "Total Small Business"
34
+ amendment.pop_country.should eq "US"
35
+ amendment.pop_zip.should eq "73145"
36
+ amendment.pop_address.should eq "Tinker AFB\nTinker AFB, OK"
37
37
  end
38
38
 
39
- context "when not a sources sought" do
39
+ it "should return an Amendment notice" do
40
+ amendment = subject.parse(contents)
41
+ amendment.should be_instance_of(FBO::Notices::Amendment)
42
+ end
43
+
44
+ context "when not an amendment" do
40
45
  let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "presol") }
41
46
 
42
47
  it "should not recognize other notice content" do
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe FBO::Parser::ArchiveHandler do
4
+ let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "archive") }
5
+ let(:file) { File.new(filename) }
6
+ let(:contents) { file.read }
7
+
8
+ it "should recognize archive content" do
9
+ subject.is_archive?(contents).should be_true
10
+ end
11
+
12
+ it "should parse all fields correctly" do
13
+ archive = subject.parse(contents)
14
+ archive.date.strftime("%Y-%m-%d").should eq Date.parse("2013-03-01").strftime("%Y-%m-%d")
15
+ archive.year.should eq 2013
16
+ archive.agency.should eq "Department of Veterans Affairs"
17
+ archive.office.should eq "VA Technology Acquisition Center"
18
+ archive.location.should eq "VA Technology Acquisition Center"
19
+ archive.solicitation_number.should eq "VA11813Q0109"
20
+ archive.notice_type.should eq "COMBINE"
21
+ archive.archive_date.strftime("%Y-%m-%d").should eq "2013-04-07"
22
+ end
23
+
24
+ it "should return an Archive notice" do
25
+ archive = subject.parse(contents)
26
+ archive.should be_instance_of(FBO::Notices::Archive)
27
+ end
28
+
29
+ context "when not an archive notice" do
30
+ let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "presol") }
31
+
32
+ it "should not recognize other notice content" do
33
+ subject.is_archive?(contents).should_not be_true
34
+ end
35
+ end
36
+ end
@@ -41,6 +41,11 @@ describe FBO::Parser::AwardHandler do
41
41
  award.correction.should be_false
42
42
  end
43
43
 
44
+ it "should return an Award notice" do
45
+ award = subject.parse(contents)
46
+ award.should be_instance_of(FBO::Notices::Award)
47
+ end
48
+
44
49
  context "when not an award" do
45
50
  let(:filename) { File.join(File.dirname(__FILE__), "..", "..", "fixtures", "notices", "presol") }
46
51
 
@@ -34,7 +34,11 @@ describe FBO::Parser::CombinedSolicitationHandler do
34
34
  combine.pop_country.should eq "US"
35
35
  combine.pop_zip.should eq "20005-4026"
36
36
  combine.pop_address.should eq "Washington, DC 20005"
37
+ end
37
38
 
39
+ it "should return a CombinedSolicitation notice" do
40
+ combine = subject.parse(contents)
41
+ combine.should be_instance_of(FBO::Notices::CombinedSolicitation)
38
42
  end
39
43
 
40
44
  context "when not a combined solicitation" do