so_far_so_good 0.0.1 → 0.0.2
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/.travis.yml +2 -0
- data/README.md +82 -7
- data/lib/so_far_so_good.rb +4 -4
- data/lib/so_far_so_good/clause.rb +8 -0
- data/lib/so_far_so_good/clauses.rb +18 -8
- data/lib/so_far_so_good/version.rb +1 -1
- data/test/so_far_so_good_clause_test.rb +27 -0
- data/test/so_far_so_good_clauses_test.rb +13 -1
- data/test/so_far_so_good_test.rb +4 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c0ca888a79d1abea3f16bac6d5fa7706cc1b2c10
|
|
4
|
+
data.tar.gz: fa8aa37486a39179474fdbef201352217ae3f596
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f54bb0f2a247aaeb8a2b4199f5c98d573e815494634821f1f6c7c8a9c2c4d33b40519723b8bc1a56767d8d4d0a31bfff7c9ef1388d7da2053596dfadeadd545
|
|
7
|
+
data.tar.gz: 42aa3e271d119b52e5ed3a646838e82f5a8c5a830a246ff1f5bab5dfbde384c03d61a11d0ccf7b3b35d8e8ffa396b3fb9f2f17d79d698d06937a5b11342945d0
|
data/.travis.yml
ADDED
data/README.md
CHANGED
|
@@ -2,21 +2,96 @@
|
|
|
2
2
|
|
|
3
3
|
A Ruby Gem to parse and manipulate the Federal Acquisition Regulation
|
|
4
4
|
|
|
5
|
+
[](http://badge.fury.io/rb/so_far_so_good) [](https://travis-ci.org/benbalter/so_far_so_good)
|
|
6
|
+
|
|
5
7
|
## What it does
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
So FAR so Good is a Ruby Gem to interact with the Federal Acquisition Regulation. Right now, it only supports section 52.20x, the FAR standard contracting clause templates.
|
|
10
|
+
|
|
11
|
+
For any contract clause, it will provide:
|
|
12
|
+
|
|
13
|
+
* The section number
|
|
14
|
+
* The subject
|
|
15
|
+
* Whether it's a reserved section
|
|
16
|
+
* The formal citation
|
|
17
|
+
* The body (full clause text)
|
|
18
|
+
* The extract (what's inserted into the contract)
|
|
19
|
+
|
|
20
|
+
It will give you access to this information in object-oriented Ruby, as JSON, or as a markdown table for use elsewhere.
|
|
8
21
|
|
|
9
22
|
## Usage
|
|
10
23
|
|
|
24
|
+
### Basic usage
|
|
25
|
+
|
|
11
26
|
```ruby
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"52.
|
|
15
|
-
"52.202-1"
|
|
16
|
-
"52.203-1"
|
|
17
|
-
|
|
27
|
+
# Get all clauses
|
|
28
|
+
clauses = SoFarSoGood.clauses
|
|
29
|
+
=> [#<SoFarSoGood::Clause @number="52.200" @subject="Scope of subpart." @reserved="false",
|
|
30
|
+
#<SoFarSoGood::Clause @number="52.202-1" @subject="Definitions." @reserved="false",
|
|
31
|
+
#<SoFarSoGood::Clause @number="52.203-1" @subject="[Reserved]" @reserved="true",
|
|
32
|
+
#<SoFarSoGood::Clause @number="52.203-2" @subject="Certificate of Independent Price Determination." @reserved="false",
|
|
33
|
+
#<SoFarSoGood::Clause @number="52.203-3" @subject="Gratuities." @reserved="false", ... ]
|
|
34
|
+
|
|
35
|
+
# Get a list of clause numbers
|
|
36
|
+
SoFarSoGood::Clauses.numbers
|
|
37
|
+
=> ["52.200", "52.202-1", "52.203-1", "52.203-2", "52.203-3", "52.203-4", "52.203-5", ... ]
|
|
38
|
+
|
|
39
|
+
# Get a list of clause numbers, excluding reserved clauses
|
|
40
|
+
SoFarSoGood::Clauses.numbers(:exclude_reserved => true)
|
|
41
|
+
=> ["52.200", "52.202-1", "52.203-1", "52.203-2", "52.203-3", "52.203-4", "52.203-5", ... ]
|
|
42
|
+
|
|
43
|
+
# Get a list of clause subjects
|
|
44
|
+
SoFarSoGood::Clauses.subjects
|
|
45
|
+
=> ["Scope of subpart.", "Definitions.", "[Reserved]", "Certificate of Independent Price Determination.", ... ]
|
|
18
46
|
```
|
|
19
47
|
|
|
48
|
+
### Working with individual clauses
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
# Get a specific clause
|
|
52
|
+
clause = SoFarSoGood::Clauses["52.202-1"]
|
|
53
|
+
=> #<SoFarSoGood::Clause @number="52.202-1" @subject="Definitions." @reserved="false"
|
|
54
|
+
|
|
55
|
+
clause.number
|
|
56
|
+
=> "52.202-1"
|
|
57
|
+
|
|
58
|
+
clause.subject
|
|
59
|
+
=> "Definitions"
|
|
60
|
+
|
|
61
|
+
clause.reserved?
|
|
62
|
+
=> false
|
|
63
|
+
|
|
64
|
+
clause.citation
|
|
65
|
+
=> "[69 FR 34228, June 18, 2004]"
|
|
66
|
+
|
|
67
|
+
# The full clause body
|
|
68
|
+
clause.body
|
|
69
|
+
=> "As prescribed in 2.201, insert the following clause:..."
|
|
70
|
+
|
|
71
|
+
# The actual clause text to be inserted in the contract
|
|
72
|
+
clause.extract
|
|
73
|
+
=> "Definitions (JUL 2004)(a) When a solicitation provision or contract clause uses a word..."
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Using clause data elsewhere
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
|
|
80
|
+
SoFarSoGood::Clauses.list.to_json
|
|
81
|
+
=> "[{\"number\":\"52.200\",\"subject\":\"Scope of subpart.\",\"reserverd\":false,\"citation\":..."
|
|
82
|
+
|
|
83
|
+
puts SoFarSoGood::Clauses.to_md
|
|
84
|
+
|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
85
|
+
| Clause | Description |
|
|
86
|
+
|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
87
|
+
| 52.200 | Scope of subpart. |
|
|
88
|
+
| 52.202-1 | Definitions. |
|
|
89
|
+
| 52.203-2 | Certificate of Independent Price Determination. |
|
|
90
|
+
| 52.203-3 | Gratuities. |
|
|
91
|
+
| 52.203-5 | Covenant Against Contingent Fees. |
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
|
|
20
95
|
## Installation
|
|
21
96
|
|
|
22
97
|
Add this line to your application's Gemfile:
|
data/lib/so_far_so_good.rb
CHANGED
|
@@ -7,12 +7,12 @@ require_relative "so_far_so_good/clause"
|
|
|
7
7
|
|
|
8
8
|
module SoFarSoGood
|
|
9
9
|
class << self
|
|
10
|
-
def
|
|
11
|
-
|
|
10
|
+
def clauses(options = {})
|
|
11
|
+
SoFarSoGood::Clauses.clauses(options)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def
|
|
15
|
-
|
|
14
|
+
def vendor_directory
|
|
15
|
+
File.expand_path "../vendor", File.dirname(__FILE__)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
end
|
|
@@ -17,6 +17,10 @@ module SoFarSoGood
|
|
|
17
17
|
@body = node.children.css("P").text.strip
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
def reserved?
|
|
21
|
+
!!@reserved
|
|
22
|
+
end
|
|
23
|
+
|
|
20
24
|
def to_hash
|
|
21
25
|
{
|
|
22
26
|
:number => @number,
|
|
@@ -31,5 +35,9 @@ module SoFarSoGood
|
|
|
31
35
|
def to_json(options = {})
|
|
32
36
|
to_hash.to_json(options)
|
|
33
37
|
end
|
|
38
|
+
|
|
39
|
+
def inspect
|
|
40
|
+
"#<SoFarSoGood::Clause @number=\"#{@number}\" @subject=\"#{@subject}\" @reserved=\"#{@reserved}\""
|
|
41
|
+
end
|
|
34
42
|
end
|
|
35
43
|
end
|
|
@@ -4,17 +4,23 @@ module SoFarSoGood
|
|
|
4
4
|
|
|
5
5
|
HEADINGS = ["Clause", "Description"]
|
|
6
6
|
|
|
7
|
-
def numbers
|
|
8
|
-
@numbers ||= clauses.map { |c| c.number }
|
|
7
|
+
def numbers(options = {})
|
|
8
|
+
@numbers ||= clauses(options).map { |c| c.number }
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def subjects
|
|
12
|
-
@subjects ||= clauses.map { |c| c.subject }
|
|
11
|
+
def subjects(options = {})
|
|
12
|
+
@subjects ||= clauses(options).map { |c| c.subject }
|
|
13
13
|
end
|
|
14
14
|
alias_method :descriptions, :subjects
|
|
15
15
|
|
|
16
|
-
def clauses
|
|
16
|
+
def clauses(options = {})
|
|
17
|
+
options = {:exclude_reserved => false}.merge(options)
|
|
17
18
|
@clauses ||= sections.map { |node| SoFarSoGood::Clause.new(node) }
|
|
19
|
+
if options[:exclude_reserved]
|
|
20
|
+
@clauses.reject { |c| c.reserved }
|
|
21
|
+
else
|
|
22
|
+
@clauses
|
|
23
|
+
end
|
|
18
24
|
end
|
|
19
25
|
alias_method :list, :clauses
|
|
20
26
|
|
|
@@ -23,7 +29,11 @@ module SoFarSoGood
|
|
|
23
29
|
end
|
|
24
30
|
|
|
25
31
|
def to_json
|
|
26
|
-
@json ||=
|
|
32
|
+
@json ||= clauses.to_json
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def [](number)
|
|
36
|
+
clauses.find { |c| c.number == number }
|
|
27
37
|
end
|
|
28
38
|
|
|
29
39
|
private
|
|
@@ -42,8 +52,8 @@ module SoFarSoGood
|
|
|
42
52
|
@subpart ||= doc.css("PART SUBPART")[4].children.css("SECTION")
|
|
43
53
|
end
|
|
44
54
|
|
|
45
|
-
def rows
|
|
46
|
-
@rows ||= clauses.
|
|
55
|
+
def rows(options={})
|
|
56
|
+
@rows ||= clauses(options).map { |c| [c.number, c.subject]}
|
|
47
57
|
end
|
|
48
58
|
end
|
|
49
59
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'helper'
|
|
2
|
+
|
|
3
|
+
class TestSoFarSoGoodClause < Minitest::Test
|
|
4
|
+
|
|
5
|
+
def setup
|
|
6
|
+
@nodes = SoFarSoGood::Clauses.send(:sections)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
should "parse a section node" do
|
|
10
|
+
clause = SoFarSoGood::Clause.new(@nodes[6])
|
|
11
|
+
assert_equal "52.203-5", clause.number
|
|
12
|
+
assert_equal "Covenant Against Contingent Fees.", clause.subject
|
|
13
|
+
refute clause.reserved
|
|
14
|
+
assert_includes clause.citation, "48 FR 42478"
|
|
15
|
+
assert_includes clause.body, "As prescribed in 3.404,"
|
|
16
|
+
assert_includes clause.extract, "The Contractor warrants that no person or agency"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
should "know if its reserved" do
|
|
20
|
+
refute SoFarSoGood::Clauses["52.203-5"].reserved?
|
|
21
|
+
assert SoFarSoGood::Clauses["52.203-1"].reserved?
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
should "put out valid json" do
|
|
25
|
+
assert JSON.parse SoFarSoGood::Clauses["52.203-5"].to_json
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -10,7 +10,7 @@ class TestSoFarSoGoodClauses < Minitest::Test
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
should "parse the rows" do
|
|
13
|
-
assert_equal
|
|
13
|
+
assert_equal 616, SoFarSoGood::Clauses.send(:rows).count
|
|
14
14
|
assert_equal ["52.200", "Scope of subpart."], SoFarSoGood::Clauses.send(:rows).first
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -27,4 +27,16 @@ class TestSoFarSoGoodClauses < Minitest::Test
|
|
|
27
27
|
should "put out valid JSON" do
|
|
28
28
|
assert !!JSON.parse(SoFarSoGood::Clauses.list.to_json)
|
|
29
29
|
end
|
|
30
|
+
|
|
31
|
+
should "return a particular clause" do
|
|
32
|
+
assert_equal "52.202-1", SoFarSoGood::Clauses["52.202-1"].number
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
should "return all clauses" do
|
|
36
|
+
assert_equal 616, SoFarSoGood::Clauses.list.count
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
should "filter reserved clauses" do
|
|
40
|
+
assert_equal 567, SoFarSoGood::Clauses.list(:exclude_reserved => true).count
|
|
41
|
+
end
|
|
30
42
|
end
|
data/test/so_far_so_good_test.rb
CHANGED
|
@@ -9,4 +9,8 @@ class TestSoFarSoGood < Minitest::Test
|
|
|
9
9
|
assert_equal Array, SoFarSoGood.clauses.class
|
|
10
10
|
assert_equal 616, SoFarSoGood.clauses.count
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
should "accept clause options" do
|
|
14
|
+
assert_equal 567, SoFarSoGood.clauses(:exclude_reserved => true).count
|
|
15
|
+
end
|
|
12
16
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: so_far_so_good
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ben Balter
|
|
@@ -102,6 +102,7 @@ extensions: []
|
|
|
102
102
|
extra_rdoc_files: []
|
|
103
103
|
files:
|
|
104
104
|
- ".gitignore"
|
|
105
|
+
- ".travis.yml"
|
|
105
106
|
- Gemfile
|
|
106
107
|
- LICENSE.md
|
|
107
108
|
- README.md
|
|
@@ -118,6 +119,7 @@ files:
|
|
|
118
119
|
- script/vendor
|
|
119
120
|
- so_far_so_good.gemspec
|
|
120
121
|
- test/helper.rb
|
|
122
|
+
- test/so_far_so_good_clause_test.rb
|
|
121
123
|
- test/so_far_so_good_clauses_test.rb
|
|
122
124
|
- test/so_far_so_good_test.rb
|
|
123
125
|
- vendor/CFR-2010-title48-vol2-chap1-subchapH.xml
|
|
@@ -147,5 +149,6 @@ specification_version: 4
|
|
|
147
149
|
summary: ''
|
|
148
150
|
test_files:
|
|
149
151
|
- test/helper.rb
|
|
152
|
+
- test/so_far_so_good_clause_test.rb
|
|
150
153
|
- test/so_far_so_good_clauses_test.rb
|
|
151
154
|
- test/so_far_so_good_test.rb
|