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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +2 -2
- data/README.md +23 -0
- data/lib/fbo.rb +17 -0
- data/lib/fbo/notices/archive.rb +8 -0
- data/lib/fbo/notices/fair_opportunity.rb +15 -0
- data/lib/fbo/notices/foreign_standard.rb +13 -0
- data/lib/fbo/notices/intent_to_bundle.rb +13 -0
- data/lib/fbo/notices/justification_approval.rb +18 -0
- data/lib/fbo/notices/sale_of_surplus.rb +13 -0
- data/lib/fbo/notices/special_notice.rb +13 -0
- data/lib/fbo/notices/unarchive.rb +9 -0
- data/lib/fbo/parser.rb +2 -15
- data/lib/fbo/parser/archive_handler.rb +41 -0
- data/lib/fbo/parser/fair_opportunity_handler.rb +61 -0
- data/lib/fbo/parser/foreign_standard_handler.rb +57 -0
- data/lib/fbo/parser/handler_selector.rb +37 -0
- data/lib/fbo/parser/intent_to_bundle_handler.rb +56 -0
- data/lib/fbo/parser/justification_approval_handler.rb +60 -0
- data/lib/fbo/parser/parser_helper.rb +40 -0
- data/lib/fbo/parser/sale_of_surplus_handler.rb +57 -0
- data/lib/fbo/parser/special_notice_handler.rb +57 -0
- data/lib/fbo/parser/unarchive_handler.rb +42 -0
- data/lib/fbo/version.rb +1 -1
- data/spec/fbo/parser/amendment_handler_spec.rb +28 -23
- data/spec/fbo/parser/archive_handler_spec.rb +36 -0
- data/spec/fbo/parser/award_handler_spec.rb +5 -0
- data/spec/fbo/parser/combined_solicitation_handler_spec.rb +4 -0
- data/spec/fbo/parser/fair_opportunity_handler_spec.rb +56 -0
- data/spec/fbo/parser/foreign_standard_handler_spec.rb +51 -0
- data/spec/fbo/parser/handler_selector_spec.rb +40 -0
- data/spec/fbo/parser/intent_to_bundle_handler_spec.rb +52 -0
- data/spec/fbo/parser/justification_approval_handler_spec.rb +53 -0
- data/spec/fbo/parser/modification_handler_spec.rb +5 -0
- data/spec/fbo/parser/presolicitation_handler_spec.rb +5 -0
- data/spec/fbo/parser/sale_of_surplus_handler_spec.rb +53 -0
- data/spec/fbo/parser/sources_sought_handler_spec.rb +27 -22
- data/spec/fbo/parser/special_notice_handler_spec.rb +53 -0
- data/spec/fbo/parser/unarchive_handler_spec.rb +37 -0
- data/spec/fbo/parser/unknown_handler_spec.rb +5 -0
- data/spec/fbo/parser_spec.rb +18 -49
- data/spec/fixtures/notices/archive +10 -0
- data/spec/fixtures/notices/fairopp +29 -0
- data/spec/fixtures/notices/fstd +24 -0
- data/spec/fixtures/notices/itb +19 -0
- data/spec/fixtures/notices/ja +30 -0
- data/spec/fixtures/notices/notanotice +7 -0
- data/spec/fixtures/notices/ssale +24 -0
- data/spec/fixtures/notices/unarchive +10 -0
- 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
@@ -12,31 +12,36 @@ describe FBO::Parser::AmendmentHandler do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should parse all fields correctly" do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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 off of the scope and figures in the PWS and not OASIS<br />***IAW PWS para 1.1(e) the audit will be scheduled in May and must be completed in one week<br />***Organizations 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
|
-
|
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
|