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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2dc6df6fe914dd5ff1d22d0052a58bf00a610716
4
- data.tar.gz: f905cd423dd324f74ca8448f623bae4eca91e3c8
3
+ metadata.gz: b0c4e53ddeb9ea9df943ef8af9ca33a4e1f99bbc
4
+ data.tar.gz: bc42c21126580a453a02996fa1799375d7057339
5
5
  SHA512:
6
- metadata.gz: ff1bbd4ec5444106621f0aacb197d295546846b8fce7b014134b70b3b9c10118398ad6df0f7d39cf1f1581fd5beb35c9898643e530a13ae28e1be9a5b048dcd3
7
- data.tar.gz: 74cb133584ce2138cbac061b56445b7849bb3a1fd0bc0c3c1698f36f132b0bd9b47d4cc50b2ceace754eb42152903854e4954a37968d6a273876ffcda08831e0
6
+ metadata.gz: 02ea8f7e4d11ba748b01abbe212952c958cb8e20f95b690dfd4b1da657e7bbdb6f744728395b8c2a3c523b8208d5f2560ff57811e3cc92dd2f27b2654d6dada7
7
+ data.tar.gz: 02ec6b226bbf7c58391fb0073c28bedb6635ad96dc73676f4c353511e585d6554cf27f3226a05c7e6cf6ac7f7c748c8e70703a4728e4e03d4b9fe3c30600e468
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  # Emacs temporary files
2
2
  *~
3
3
  \#*\#
4
+ .\#*
4
5
 
5
6
  # Bundler artifacts
6
7
  .bundle
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- FBO (0.0.1)
4
+ fbo (0.0.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -21,7 +21,7 @@ PLATFORMS
21
21
  ruby
22
22
 
23
23
  DEPENDENCIES
24
- FBO!
25
24
  bundler (~> 1.3)
25
+ fbo!
26
26
  rake
27
27
  rspec
data/README.md CHANGED
@@ -3,6 +3,29 @@
3
3
  Fetch a dated dump file from [FedBizOpps](https://www.fbo.gov) and parse its
4
4
  contents into structures suitable for use by other programs.
5
5
 
6
+ The gem in its current state handles most of the notice types described in the
7
+ [FBO documentation](https://www.fbo.gov/?&static=interface) for the data format.
8
+ * Presolicitation (PRESOL)
9
+ * Combined Synopsis/Solicitation (COMBINE)
10
+ * Amendment to a Previous Combined Solicitation (AMDCSS)
11
+ * Modification to a Previous Base (MOD)
12
+ * Award (AWARD)
13
+ * Justification and Approval (JA)
14
+ * Intent to Bundle Requirements (ITB)
15
+ * Fair Opportunity / Limited Sources Justification (FAIROPP)
16
+ * Sources Sought (SRCSGT)
17
+ * Foreign Government Standard (FSTD)
18
+ * Special Notice (SNOTE)
19
+ * Sale of Surplus Property (SSALE)
20
+ * Document Archival (ARCHIVE)
21
+ * Document Unarchival (UNARCHIVE)
22
+
23
+ Two notice types have not yet been implemented as no record of their ever having
24
+ been used could be found in any of the FBO dump files dating back as far as 2001.
25
+ These are:
26
+ * Document Upload (EPSUPLOAD)
27
+ * Document Deleting (DELETE)
28
+
6
29
 
7
30
  ## Installation
8
31
 
data/lib/fbo.rb CHANGED
@@ -4,21 +4,38 @@ require_relative "fbo/file"
4
4
  require_relative "fbo/remote_file"
5
5
  require_relative "fbo/notice"
6
6
  require_relative "fbo/notices/amendment"
7
+ require_relative "fbo/notices/archive"
7
8
  require_relative "fbo/notices/award"
8
9
  require_relative "fbo/notices/combined_solicitation"
10
+ require_relative "fbo/notices/fair_opportunity"
11
+ require_relative "fbo/notices/foreign_standard"
12
+ require_relative "fbo/notices/intent_to_bundle"
13
+ require_relative "fbo/notices/justification_approval"
9
14
  require_relative "fbo/notices/modification"
10
15
  require_relative "fbo/notices/presolicitation"
16
+ require_relative "fbo/notices/sale_of_surplus"
11
17
  require_relative "fbo/notices/sources_sought"
18
+ require_relative "fbo/notices/special_notice"
19
+ require_relative "fbo/notices/unarchive"
12
20
  require_relative "fbo/notices/unknown"
13
21
  require_relative "fbo/parser"
22
+ require_relative "fbo/parser/handler_selector"
14
23
  require_relative "fbo/parser/notice_handler"
15
24
  require_relative "fbo/parser/parser_helper"
16
25
  require_relative "fbo/parser/amendment_handler"
26
+ require_relative "fbo/parser/archive_handler"
17
27
  require_relative "fbo/parser/award_handler"
18
28
  require_relative "fbo/parser/combined_solicitation_handler"
29
+ require_relative "fbo/parser/fair_opportunity_handler"
30
+ require_relative "fbo/parser/foreign_standard_handler"
31
+ require_relative "fbo/parser/intent_to_bundle_handler"
32
+ require_relative "fbo/parser/justification_approval_handler"
19
33
  require_relative "fbo/parser/modification_handler"
20
34
  require_relative "fbo/parser/presolicitation_handler"
35
+ require_relative "fbo/parser/sale_of_surplus_handler"
21
36
  require_relative "fbo/parser/sources_sought_handler"
37
+ require_relative "fbo/parser/special_notice_handler"
38
+ require_relative "fbo/parser/unarchive_handler"
22
39
  require_relative "fbo/parser/unknown_handler"
23
40
 
24
41
  module FBO
@@ -0,0 +1,8 @@
1
+ module FBO
2
+ module Notices
3
+ class Archive < Struct.new(:date, :year, :agency, :office, :location,
4
+ :solicitation_number, :notice_type, :archive_date)
5
+ include FBO::Notice
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ module FBO
2
+ module Notices
3
+ class FairOpportunity < Struct.new(:date, :year, :zip, :class_code, :naics_code,
4
+ :agency, :office, :location, :office_address,
5
+ :subject, :solicitation_number, :notice_type,
6
+ :justification_authority, :award_number,
7
+ :delivery_order_number, :modification_number,
8
+ :award_date, :archive_date, :description,
9
+ :contact_info, :link_url, :link_description,
10
+ :email_address, :email_description, :file_list,
11
+ :correction)
12
+ include FBO::Notice
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ module FBO
2
+ module Notices
3
+ class ForeignStandard < Struct.new(:date, :year, :zip, :class_code, :naics_code,
4
+ :agency, :office, :location, :office_address,
5
+ :subject, :solicitation_number, :archive_date,
6
+ :response_date, :contact_info, :description,
7
+ :link_url, :link_description, :email_address,
8
+ :email_description, :setaside, :pop_address,
9
+ :pop_zip, :pop_country)
10
+ include FBO::Notice
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module FBO
2
+ module Notices
3
+ class IntentToBundle < Struct.new(:date, :year, :zip, :class_code, :naics_code,
4
+ :agency, :office, :location, :office_address,
5
+ :subject, :solicitation_number, :notice_type,
6
+ :archive_date, :description, :contact_info,
7
+ :award_number, :delivery_order_number,
8
+ :link_url, :link_description, :email_address,
9
+ :email_description, :correction)
10
+ include FBO::Notice
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module FBO
2
+ module Notices
3
+ class JustificationApproval < Struct.new(:date, :year, :zip, :class_code,
4
+ :naics_code, :agency, :office,
5
+ :location, :office_address, :subject,
6
+ :solicitation_number, :notice_type,
7
+ :description, :contact_info,
8
+ :statutory_authority, :award_number,
9
+ :modification_number, :award_date,
10
+ :archive_date, :link_url,
11
+ :link_description, :email_address,
12
+ :email_description, :file_list,
13
+ :correction)
14
+ include FBO::Notice
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,13 @@
1
+ module FBO
2
+ module Notices
3
+ class SaleOfSurplus < Struct.new(:date, :year, :zip, :class_code, :naics_code,
4
+ :agency, :office, :location, :office_address,
5
+ :subject, :solicitation_number, :response_date,
6
+ :archive_date, :description, :contact_info,
7
+ :link_url, :link_description, :email_address,
8
+ :email_description, :setaside, :pop_country,
9
+ :pop_zip, :pop_address)
10
+ include FBO::Notice
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module FBO
2
+ module Notices
3
+ class SpecialNotice < Struct.new(:date, :year, :zip, :class_code, :naics_code,
4
+ :agency, :office, :location, :office_address,
5
+ :subject, :solicitation_number, :response_date,
6
+ :archive_date, :description, :contact_info,
7
+ :link_url, :link_description, :email_address,
8
+ :email_description, :setaside, :pop_country,
9
+ :pop_zip, :pop_address)
10
+ include FBO::Notice
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module FBO
2
+ module Notices
3
+ class Unarchive < Struct.new(:date, :year, :agency, :office, :location,
4
+ :solicitation_number, :notice_type, :archive_date,
5
+ :award_number)
6
+ include FBO::Notice
7
+ end
8
+ end
9
+ end
data/lib/fbo/parser.rb CHANGED
@@ -46,21 +46,8 @@ module FBO
46
46
  def parse_notices(text_notices)
47
47
  @notices = []
48
48
  text_notices.each do |text|
49
- if FBO::Parser::PresolicitationHandler.is_presolicitation?(text)
50
- @notices << FBO::Parser::PresolicitationHandler.parse(text)
51
- elsif FBO::Parser::CombinedSolicitationHandler.is_combined_solicitation?(text)
52
- @notices << FBO::Parser::CombinedSolicitationHandler.parse(text)
53
- elsif FBO::Parser::SourcesSoughtHandler.is_sources_sought?(text)
54
- @notices << FBO::Parser::SourcesSoughtHandler.parse(text)
55
- elsif FBO::Parser::AmendmentHandler.is_amendment?(text)
56
- @notices << FBO::Parser::AmendmentHandler.parse(text)
57
- elsif FBO::Parser::ModificationHandler.is_modification?(text)
58
- @notices << FBO::Parser::ModificationHandler.parse(text)
59
- elsif FBO::Parser::AwardHandler.is_award?(text)
60
- @notices << FBO::Parser::AwardHandler.parse(text)
61
- else
62
- @notices << FBO::Parser::UnknownHandler.parse(text)
63
- end
49
+ handler = FBO::Parser::HandlerSelector.select(text)
50
+ @notices << handler.parse(text)
64
51
  end
65
52
  end
66
53
 
@@ -0,0 +1,41 @@
1
+ module FBO::Parser::ArchiveHandler
2
+ TAGS = %w( ARCHIVE DATE YEAR CBAC PASSWORD AGENCY OFFICE LOCATION NTYPE ) +
3
+ %w( SOLNBR ARCHDATE \/ARCHIVE )
4
+
5
+ ANY_ARCHIVE_TAG = TAGS.join("|")
6
+ ARCHIVE_PATTERN = /^<ARCHIVE>/
7
+
8
+
9
+ def is_archive?(text)
10
+ text =~ ARCHIVE_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
+ }
24
+ FBO::Notices::Archive.new(params)
25
+ end
26
+
27
+
28
+ protected
29
+
30
+ # Returns a concatenated list of all tags for the notice
31
+ #
32
+ # @return [String]
33
+ def any_notice_tag
34
+ ANY_ARCHIVE_TAG
35
+ end
36
+
37
+
38
+ extend FBO::Parser::NoticeHandler
39
+ extend FBO::Parser::ParserHelper
40
+ extend self
41
+ end
@@ -0,0 +1,61 @@
1
+ module FBO::Parser::FairOpportunityHandler
2
+ TAGS = %w( FAIROPP DATE YEAR CBAC PASSWORD ZIP CLASSCOD NAICS OFFADD AGENCY ) +
3
+ %w( OFFICE LOCATION SUBJECT SOLNBR NTYPE FOJA AWDNBR DONBR MODNBR AWDDATE ) +
4
+ %w( ARCHDATE DESC CONTACT LINK URL EMAIL ADDRESS FILELIST FILE MIMETYPE ) +
5
+ %w( /FILE /FILELIST CORRECTION /FAIROPP )
6
+
7
+ ANY_FAIROPP_TAG = TAGS.join("|")
8
+ FAIR_OPPORTUNITY_PATTERN = /^<FAIROPP>/
9
+
10
+
11
+ def is_fair_opportunity?(text)
12
+ text =~ FAIR_OPPORTUNITY_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
+ justification_authority: justification_authority(text),
30
+ award_number: award_number(text),
31
+ delivery_order_number: delivery_order_number(text),
32
+ modification_number: modification_number(text),
33
+ award_date: award_date(text),
34
+ archive_date: archive_date(text),
35
+ description: description(text),
36
+ contact_info: contact(text),
37
+ link_url: link_url(text),
38
+ link_description: link_description(text),
39
+ email_address: email_address(text),
40
+ email_description: email_description(text),
41
+ file_list: file_list(text),
42
+ correction: correction?(text)
43
+ }
44
+ FBO::Notices::FairOpportunity.new(params)
45
+ end
46
+
47
+
48
+ protected
49
+
50
+ # Returns a concatenated list of all tags for the notice
51
+ #
52
+ # @return [String]
53
+ def any_notice_tag
54
+ ANY_FAIROPP_TAG
55
+ end
56
+
57
+
58
+ extend FBO::Parser::NoticeHandler
59
+ extend FBO::Parser::ParserHelper
60
+ extend self
61
+ end
@@ -0,0 +1,57 @@
1
+ module FBO::Parser::ForeignStandardHandler
2
+ TAGS = %w( FSTD 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 POPCOUNTRY POPADDRESS POPZIP \/FSTD )
5
+
6
+ ANY_FSTD_TAG = TAGS.join("|")
7
+ FOREIGN_STANDARD_PATTERN = /^<FSTD>/
8
+
9
+
10
+ def is_foreign_standard?(text)
11
+ text =~ FOREIGN_STANDARD_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::ForeignStandard.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_FSTD_TAG
51
+ end
52
+
53
+
54
+ extend FBO::Parser::NoticeHandler
55
+ extend FBO::Parser::ParserHelper
56
+ extend self
57
+ end
@@ -0,0 +1,37 @@
1
+ class FBO::Parser::HandlerSelector
2
+
3
+ def self.select(text)
4
+ if FBO::Parser::PresolicitationHandler.is_presolicitation?(text)
5
+ FBO::Parser::PresolicitationHandler
6
+ elsif FBO::Parser::CombinedSolicitationHandler.is_combined_solicitation?(text)
7
+ FBO::Parser::CombinedSolicitationHandler
8
+ elsif FBO::Parser::SourcesSoughtHandler.is_sources_sought?(text)
9
+ FBO::Parser::SourcesSoughtHandler
10
+ elsif FBO::Parser::AmendmentHandler.is_amendment?(text)
11
+ FBO::Parser::AmendmentHandler
12
+ elsif FBO::Parser::ModificationHandler.is_modification?(text)
13
+ FBO::Parser::ModificationHandler
14
+ elsif FBO::Parser::AwardHandler.is_award?(text)
15
+ FBO::Parser::AwardHandler
16
+ elsif FBO::Parser::FairOpportunityHandler.is_fair_opportunity?(text)
17
+ FBO::Parser::FairOpportunityHandler
18
+ elsif FBO::Parser::ForeignStandardHandler.is_foreign_standard?(text)
19
+ FBO::Parser::ForeignStandardHandler
20
+ elsif FBO::Parser::ArchiveHandler.is_archive?(text)
21
+ FBO::Parser::ArchiveHandler
22
+ elsif FBO::Parser::IntentToBundleHandler.is_intent_to_bundle?(text)
23
+ FBO::Parser::IntentToBundleHandler
24
+ elsif FBO::Parser::JustificationApprovalHandler.is_justification_approval?(text)
25
+ FBO::Parser::JustificationApprovalHandler
26
+ elsif FBO::Parser::SaleOfSurplusHandler.is_sale_of_surplus?(text)
27
+ FBO::Parser::SaleOfSurplusHandler
28
+ elsif FBO::Parser::SpecialNoticeHandler.is_special_notice?(text)
29
+ FBO::Parser::SpecialNoticeHandler
30
+ elsif FBO::Parser::UnarchiveHandler.is_unarchive?(text)
31
+ FBO::Parser::UnarchiveHandler
32
+ else
33
+ FBO::Parser::UnknownHandler
34
+ end
35
+ end
36
+
37
+ end