fbo 0.0.2 → 0.0.3

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.
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