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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c0ca888a79d1abea3f16bac6d5fa7706cc1b2c10
4
- data.tar.gz: fa8aa37486a39179474fdbef201352217ae3f596
3
+ metadata.gz: 89ca68bf267662afde3f952d21d46565546f8278
4
+ data.tar.gz: 76dc75b71d6764960d11e45c4a6f6d4b2b39312f
5
5
  SHA512:
6
- metadata.gz: 2f54bb0f2a247aaeb8a2b4199f5c98d573e815494634821f1f6c7c8a9c2c4d33b40519723b8bc1a56767d8d4d0a31bfff7c9ef1388d7da2053596dfadeadd545
7
- data.tar.gz: 42aa3e271d119b52e5ed3a646838e82f5a8c5a830a246ff1f5bab5dfbde384c03d61a11d0ccf7b3b35d8e8ffa396b3fb9f2f17d79d698d06937a5b11342945d0
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
 
@@ -1,6 +1,7 @@
1
1
  require "nokogiri"
2
2
  require "terminal-table"
3
3
  require "json"
4
+ require "reverse_markdown"
4
5
  require_relative "so_far_so_good/version"
5
6
  require_relative "so_far_so_good/clauses"
6
7
  require_relative "so_far_so_good/clause"
@@ -1,43 +1,79 @@
1
1
  module SoFarSoGood
2
2
  class Clause
3
3
 
4
- attr_reader :number
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
- @number = node.css("SECTNO").text.strip
13
- @subject = node.css("SUBJECT, RESERVED").text.strip
14
- @reserved = !node.css("RESERVED").text.empty?
15
- @citation = node.css("CITA").text.strip
16
- @extract = node.css("EXTRACT").text.strip
17
- @body = node.children.css("P").text.strip
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
- !!@reserved
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 to_hash
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 => @number,
27
- :subject => @subject,
28
- :reserverd => @reserved,
29
- :citation => @citation,
30
- :extract => @extract,
31
- :body => @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
- @md ||= Terminal::Table.new(:rows => rows, :style => { :border_i => "|" }, :headings => HEADINGS).to_s
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
- @json ||= clauses.to_json
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
@@ -1,3 +1,3 @@
1
1
  module SoFarSoGood
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -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 "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"
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.2
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