so_far_so_good 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -0
- data/lib/so_far_so_good.rb +1 -0
- data/lib/so_far_so_good/clause.rb +57 -21
- data/lib/so_far_so_good/clauses.rb +8 -10
- data/lib/so_far_so_good/version.rb +1 -1
- data/so_far_so_good.gemspec +1 -0
- data/test/so_far_so_good_clause_test.rb +39 -8
- data/test/so_far_so_good_clauses_test.rb +12 -5
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89ca68bf267662afde3f952d21d46565546f8278
|
4
|
+
data.tar.gz: 76dc75b71d6764960d11e45c4a6f6d4b2b39312f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6a7d2876d9c40b48d0f6b504bd52e184865634f6667c76e995c04175a1fbd512d69a44e67742e2c888ae893f660f019f529882fa510248493eff648005270a1
|
7
|
+
data.tar.gz: dd43c8d95edb8a176f242bc596c4c0ca99533e588962f6efe81c5f7c25d9f1912f836ba328d30e122258d4922e7d4300907ff141bbdbf4bca043827cecb8e492
|
data/README.md
CHANGED
@@ -75,11 +75,17 @@ clause.extract
|
|
75
75
|
|
76
76
|
### Using clause data elsewhere
|
77
77
|
|
78
|
+
#### As JSON
|
79
|
+
|
78
80
|
```ruby
|
79
81
|
|
80
82
|
SoFarSoGood::Clauses.list.to_json
|
81
83
|
=> "[{\"number\":\"52.200\",\"subject\":\"Scope of subpart.\",\"reserverd\":false,\"citation\":..."
|
84
|
+
```
|
85
|
+
|
86
|
+
#### As a markdown table
|
82
87
|
|
88
|
+
```ruby
|
83
89
|
puts SoFarSoGood::Clauses.to_md
|
84
90
|
|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
85
91
|
| Clause | Description |
|
@@ -89,8 +95,36 @@ puts SoFarSoGood::Clauses.to_md
|
|
89
95
|
| 52.203-2 | Certificate of Independent Price Determination. |
|
90
96
|
| 52.203-3 | Gratuities. |
|
91
97
|
| 52.203-5 | Covenant Against Contingent Fees. |
|
98
|
+
...
|
99
|
+
|
100
|
+
# Table without reserved clauses
|
101
|
+
puts SoFarSoGood::Clauses.to_md(:exclude_reserved => true)
|
102
|
+
|
103
|
+
# Table with links to text
|
104
|
+
puts SoFarSoGood::Clauses.to_md(:links => true)
|
105
|
+
...
|
106
|
+
| [52.222-34](http://www.law.cornell.edu/cfr/text/48/52.222-34) | Project Labor Agreement. |
|
107
|
+
| [52.222-35](http://www.law.cornell.edu/cfr/text/48/52.222-35) | Equal Opportunity for Veterans. |
|
108
|
+
| [52.222-36](http://www.law.cornell.edu/cfr/text/48/52.222-36) | Affirmative Action for Workers With Disabilities. |
|
109
|
+
| [52.222-37](http://www.law.cornell.edu/cfr/text/48/52.222-37) | Employment Reports on Veterans. |
|
110
|
+
| [52.222-38](http://www.law.cornell.edu/cfr/text/48/52.222-38) | Compliance with Veterans' Employment Reporting Requirements. |
|
111
|
+
| [52.222-41](http://www.law.cornell.edu/cfr/text/48/52.222-41) | Service Contract Act of 1965.
|
112
|
+
...
|
92
113
|
```
|
93
114
|
|
115
|
+
#### Individual clauses as markdown
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
# The body
|
119
|
+
puts SoFarSoGood::Clauses["52.202-1"].body(:format => :markdown)
|
120
|
+
=> As prescribed in 2.201, insert the following clause:
|
121
|
+
|
122
|
+
# The extract
|
123
|
+
puts SoFarSoGood::Clauses["52.202-1"].extract(:format => :markdown)
|
124
|
+
=> ### Definitions (JUL 2004)
|
125
|
+
|
126
|
+
(a) When a solicitation provision or contract clause uses a word or term that is defined in the Federal Acquisition Regulation (FAR), the word or term has the same meaning as the definition in FAR 2.101 in effect at the time the solicitation was issued, unless— ...
|
127
|
+
```
|
94
128
|
|
95
129
|
## Installation
|
96
130
|
|
data/lib/so_far_so_good.rb
CHANGED
@@ -1,43 +1,79 @@
|
|
1
1
|
module SoFarSoGood
|
2
2
|
class Clause
|
3
3
|
|
4
|
-
attr_reader :
|
5
|
-
attr_reader :subject
|
6
|
-
attr_reader :reserved
|
7
|
-
attr_reader :citation
|
8
|
-
attr_reader :extract
|
9
|
-
attr_reader :body
|
4
|
+
attr_reader :node
|
10
5
|
|
11
6
|
def initialize(node)
|
12
|
-
@
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
@
|
7
|
+
@node = node
|
8
|
+
normalize!
|
9
|
+
end
|
10
|
+
|
11
|
+
def number
|
12
|
+
@number ||= node.css("SECTNO").text.strip
|
13
|
+
end
|
14
|
+
|
15
|
+
def subject
|
16
|
+
@subject ||= node.css("SUBJECT, RESERVED").text.strip
|
18
17
|
end
|
19
18
|
|
20
19
|
def reserved?
|
21
|
-
|
20
|
+
@reserved ||= !node.css("RESERVED").text.empty?
|
21
|
+
end
|
22
|
+
alias_method :reserved, :reserved?
|
23
|
+
|
24
|
+
def citation
|
25
|
+
@citation ||= node.css("CITA").text.strip
|
26
|
+
end
|
27
|
+
|
28
|
+
def link
|
29
|
+
@link ||= "http://www.law.cornell.edu/cfr/text/48/#{number}"
|
22
30
|
end
|
23
31
|
|
24
|
-
def
|
32
|
+
def extract(options = {})
|
33
|
+
options = {:format => :html}.merge(options)
|
34
|
+
@extract ||= node.css("EXTRACT").inner_html
|
35
|
+
if options[:format] == :markdown
|
36
|
+
ReverseMarkdown.convert @extract
|
37
|
+
else
|
38
|
+
@extract
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def body(options = {})
|
43
|
+
options = {:format => :html}.merge(options)
|
44
|
+
@body ||= node.css("> P").to_html
|
45
|
+
if options[:format] == :markdown
|
46
|
+
ReverseMarkdown.convert @body
|
47
|
+
else
|
48
|
+
@body
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_hash(options={})
|
25
53
|
{
|
26
|
-
:number =>
|
27
|
-
:subject =>
|
28
|
-
:reserverd =>
|
29
|
-
:citation =>
|
30
|
-
:extract =>
|
31
|
-
:body =>
|
54
|
+
:number => number,
|
55
|
+
:subject => subject,
|
56
|
+
:reserverd => reserved,
|
57
|
+
:citation => citation,
|
58
|
+
:extract => extract(options),
|
59
|
+
:body => body(options),
|
60
|
+
:link => link
|
32
61
|
}
|
33
62
|
end
|
34
63
|
|
35
64
|
def to_json(options = {})
|
36
|
-
to_hash.to_json(options)
|
65
|
+
to_hash(options).to_json(options)
|
37
66
|
end
|
38
67
|
|
39
68
|
def inspect
|
40
69
|
"#<SoFarSoGood::Clause @number=\"#{@number}\" @subject=\"#{@subject}\" @reserved=\"#{@reserved}\""
|
41
70
|
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def normalize!
|
75
|
+
node.children.css("E").each { |n| n.name = "em" }
|
76
|
+
node.children.css("HD").each { |n| n.name = "h3" }
|
77
|
+
end
|
42
78
|
end
|
43
79
|
end
|
@@ -20,16 +20,18 @@ module SoFarSoGood
|
|
20
20
|
@clauses.reject { |c| c.reserved }
|
21
21
|
else
|
22
22
|
@clauses
|
23
|
-
end
|
23
|
+
end
|
24
24
|
end
|
25
25
|
alias_method :list, :clauses
|
26
26
|
|
27
|
-
def to_md
|
28
|
-
|
27
|
+
def to_md(options = {})
|
28
|
+
options = {:exclude_reserved => false, :links => false}.merge(options)
|
29
|
+
rows = clauses(options).map { |c| [ options[:links] ? "[#{c.number}](#{c.link})" : c.number , c.subject] }
|
30
|
+
Terminal::Table.new(:rows => rows, :style => { :border_i => "|" }, :headings => HEADINGS).to_s
|
29
31
|
end
|
30
32
|
|
31
|
-
def to_json
|
32
|
-
|
33
|
+
def to_json(options = {})
|
34
|
+
clauses(options).to_json(options)
|
33
35
|
end
|
34
36
|
|
35
37
|
def [](number)
|
@@ -39,7 +41,7 @@ module SoFarSoGood
|
|
39
41
|
private
|
40
42
|
|
41
43
|
def source_path
|
42
|
-
File.expand_path "CFR-2010-title48-vol2-chap1-subchapH.xml", SoFarSoGood.vendor_directory
|
44
|
+
@source_path ||= File.expand_path "CFR-2010-title48-vol2-chap1-subchapH.xml", SoFarSoGood.vendor_directory
|
43
45
|
end
|
44
46
|
|
45
47
|
def doc
|
@@ -51,10 +53,6 @@ module SoFarSoGood
|
|
51
53
|
def sections
|
52
54
|
@subpart ||= doc.css("PART SUBPART")[4].children.css("SECTION")
|
53
55
|
end
|
54
|
-
|
55
|
-
def rows(options={})
|
56
|
-
@rows ||= clauses(options).map { |c| [c.number, c.subject]}
|
57
|
-
end
|
58
56
|
end
|
59
57
|
end
|
60
58
|
end
|
data/so_far_so_good.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency "nokogiri"
|
22
22
|
spec.add_dependency "terminal-table"
|
23
|
+
spec.add_dependency "reverse_markdown"
|
23
24
|
spec.add_development_dependency "bundler", "~> 1.6"
|
24
25
|
spec.add_development_dependency "rake"
|
25
26
|
spec.add_development_dependency('pry', '~> 0.9')
|
@@ -4,16 +4,35 @@ class TestSoFarSoGoodClause < Minitest::Test
|
|
4
4
|
|
5
5
|
def setup
|
6
6
|
@nodes = SoFarSoGood::Clauses.send(:sections)
|
7
|
+
@clause = SoFarSoGood::Clause.new(@nodes[6])
|
7
8
|
end
|
8
9
|
|
9
|
-
should "
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
should "Store the node" do
|
11
|
+
assert Nokogiri::XML::Element, @clause.node.class
|
12
|
+
end
|
13
|
+
|
14
|
+
should "expose the clause number" do
|
15
|
+
assert_equal "52.203-5", @clause.number
|
16
|
+
end
|
17
|
+
|
18
|
+
should "expose the clause subject" do
|
19
|
+
assert_equal "Covenant Against Contingent Fees.", @clause.subject
|
20
|
+
end
|
21
|
+
|
22
|
+
should "know the cite" do
|
23
|
+
assert_includes @clause.citation, "48 FR 42478"
|
24
|
+
end
|
25
|
+
|
26
|
+
should "know the clause body" do
|
27
|
+
assert_includes @clause.body, "As prescribed in 3.404,"
|
28
|
+
end
|
29
|
+
|
30
|
+
should "not include the extract in the clause body" do
|
31
|
+
refute_includes @clause.body, "The Contractor warrants that no person or agency"
|
32
|
+
end
|
33
|
+
|
34
|
+
should "know the clause extract" do
|
35
|
+
assert_includes @clause.extract, "The Contractor warrants that no person or agency"
|
17
36
|
end
|
18
37
|
|
19
38
|
should "know if its reserved" do
|
@@ -21,6 +40,18 @@ class TestSoFarSoGoodClause < Minitest::Test
|
|
21
40
|
assert SoFarSoGood::Clauses["52.203-1"].reserved?
|
22
41
|
end
|
23
42
|
|
43
|
+
should "convert the body to markdown" do
|
44
|
+
assert_includes @clause.body(:format => :markdown), "As prescribed in 3.404, insert the following clause:\n\n"
|
45
|
+
end
|
46
|
+
|
47
|
+
should "convert the extract to markdown" do
|
48
|
+
assert_includes @clause.extract(:format => :markdown), "### Covenant Against Contingent Fees (APR 1984)\n\n(a)"
|
49
|
+
end
|
50
|
+
|
51
|
+
should "build the link" do
|
52
|
+
assert_equal "http://www.law.cornell.edu/cfr/text/48/52.203-5", @clause.link
|
53
|
+
end
|
54
|
+
|
24
55
|
should "put out valid json" do
|
25
56
|
assert JSON.parse SoFarSoGood::Clauses["52.203-5"].to_json
|
26
57
|
end
|
@@ -9,11 +9,6 @@ class TestSoFarSoGoodClauses < Minitest::Test
|
|
9
9
|
assert Nokogiri::XML::Document, SoFarSoGood::Clauses.send(:doc).class
|
10
10
|
end
|
11
11
|
|
12
|
-
should "parse the rows" do
|
13
|
-
assert_equal 616, SoFarSoGood::Clauses.send(:rows).count
|
14
|
-
assert_equal ["52.200", "Scope of subpart."], SoFarSoGood::Clauses.send(:rows).first
|
15
|
-
end
|
16
|
-
|
17
12
|
should "parse section numbers" do
|
18
13
|
assert_equal 616, SoFarSoGood::Clauses.numbers.count
|
19
14
|
assert_equal "52.200", SoFarSoGood::Clauses.numbers.first
|
@@ -39,4 +34,16 @@ class TestSoFarSoGoodClauses < Minitest::Test
|
|
39
34
|
should "filter reserved clauses" do
|
40
35
|
assert_equal 567, SoFarSoGood::Clauses.list(:exclude_reserved => true).count
|
41
36
|
end
|
37
|
+
|
38
|
+
should "build the markdown table" do
|
39
|
+
assert_includes SoFarSoGood::Clauses.to_md, "-|\n| 52.200 | Scope of subpart."
|
40
|
+
end
|
41
|
+
|
42
|
+
should "exclude reserved in markdown table when asked" do
|
43
|
+
refute_includes SoFarSoGood::Clauses.to_md(:exclude_reserved => true), "[Reserved]"
|
44
|
+
end
|
45
|
+
|
46
|
+
should "inlcude links in markdown table when asked" do
|
47
|
+
assert_includes SoFarSoGood::Clauses.to_md(:links => true), "[52.252-6](http://www.law.cornell.edu/cfr/text/48/52.252-6)"
|
48
|
+
end
|
42
49
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Balter
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: reverse_markdown
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|