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