ecfr 1.1.6 → 1.1.7
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/CHANGELOG.md +8 -0
- data/Gemfile.lock +67 -51
- data/lib/ecfr/admin_service/base.rb +0 -1
- data/lib/ecfr/base.rb +2 -6
- data/lib/ecfr/client.rb +4 -0
- data/lib/ecfr/client_configuration.rb +122 -0
- data/lib/ecfr/constants.rb +3 -1
- data/lib/ecfr/parallel_client.rb +10 -5
- data/lib/ecfr/renderer_service/origin.rb +1 -4
- data/lib/ecfr/testing/extensions/versioner_service/reference_extensions.rb +15 -0
- data/lib/ecfr/testing/extensions/versioner_service/topic_extensions.rb +16 -0
- data/lib/ecfr/testing/factories/versioner_service/reference_factory.rb +16 -0
- data/lib/ecfr/testing/factories/versioner_service/topic_factory.rb +34 -0
- data/lib/ecfr/version.rb +1 -1
- data/lib/ecfr/versioner_service/agency.rb +9 -0
- data/lib/ecfr/versioner_service/ancestors.rb +1 -4
- data/lib/ecfr/versioner_service/authority.rb +48 -0
- data/lib/ecfr/versioner_service/base.rb +4 -0
- data/lib/ecfr/versioner_service/reference.rb +19 -0
- data/lib/ecfr/versioner_service/title.rb +0 -2
- data/lib/ecfr/versioner_service/topic.rb +74 -0
- data/lib/ecfr/versioner_service/xml_content.rb +0 -2
- data/lib/ecfr.rb +3 -0
- metadata +11 -3
- data/lib/ecfr/admin_service/build.rb +0 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 13cc40dfeeb370c7a81be66f37bdf9f23cf4dfbb936465ce4c12b1ab88094deb
|
|
4
|
+
data.tar.gz: 6a80785bbd1e428f93f841401e678c1776f9b344a33e554738759937079eca06
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 11198b0d371f4c2a49ed939af2db6f7b781809d107b1e17ef586b03676d21157f739b92e4ae681fe70112580650a7476b39cbdb0ea6e06c51067cc79943510dd
|
|
7
|
+
data.tar.gz: 3dddd1f095d6ea3015e8d4f9dfbb0d1fe9ab29cfd426274c6d646fa86bc02217c45545d2105682cf0e88ee33779b22f344c895feab0c55e2be0d036c9873332a
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -11,94 +11,108 @@ PATH
|
|
|
11
11
|
GEM
|
|
12
12
|
remote: https://rubygems.org/
|
|
13
13
|
specs:
|
|
14
|
-
activemodel (
|
|
15
|
-
activesupport (=
|
|
16
|
-
activesupport (
|
|
14
|
+
activemodel (8.1.2)
|
|
15
|
+
activesupport (= 8.1.2)
|
|
16
|
+
activesupport (8.1.2)
|
|
17
17
|
base64
|
|
18
18
|
bigdecimal
|
|
19
19
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
20
20
|
connection_pool (>= 2.2.5)
|
|
21
21
|
drb
|
|
22
22
|
i18n (>= 1.6, < 2)
|
|
23
|
+
json
|
|
23
24
|
logger (>= 1.4.2)
|
|
24
25
|
minitest (>= 5.1)
|
|
25
26
|
securerandom (>= 0.3)
|
|
26
27
|
tzinfo (~> 2.0, >= 2.0.5)
|
|
28
|
+
uri (>= 0.13.1)
|
|
27
29
|
ast (2.4.3)
|
|
28
|
-
base64 (0.
|
|
29
|
-
bigdecimal (
|
|
30
|
+
base64 (0.3.0)
|
|
31
|
+
bigdecimal (4.0.1)
|
|
30
32
|
coderay (1.1.3)
|
|
31
|
-
concurrent-ruby (1.3.
|
|
32
|
-
connection_pool (
|
|
33
|
+
concurrent-ruby (1.3.6)
|
|
34
|
+
connection_pool (3.0.2)
|
|
33
35
|
diff-lcs (1.6.2)
|
|
34
|
-
drb (2.2.
|
|
35
|
-
ethon (0.
|
|
36
|
+
drb (2.2.3)
|
|
37
|
+
ethon (0.18.0)
|
|
36
38
|
ffi (>= 1.15.0)
|
|
37
|
-
|
|
39
|
+
logger
|
|
40
|
+
factory_bot (6.5.6)
|
|
38
41
|
activesupport (>= 6.1.0)
|
|
39
|
-
faraday (2.
|
|
42
|
+
faraday (2.14.0)
|
|
40
43
|
faraday-net_http (>= 2.0, < 3.5)
|
|
41
44
|
json
|
|
42
45
|
logger
|
|
43
|
-
faraday-net_http (3.4.
|
|
44
|
-
net-http (
|
|
45
|
-
faraday-net_http_persistent (2.3.
|
|
46
|
+
faraday-net_http (3.4.2)
|
|
47
|
+
net-http (~> 0.5)
|
|
48
|
+
faraday-net_http_persistent (2.3.1)
|
|
46
49
|
faraday (~> 2.5)
|
|
47
50
|
net-http-persistent (>= 4.0.4, < 5)
|
|
48
51
|
faraday-typhoeus (1.1.0)
|
|
49
52
|
faraday (~> 2.0)
|
|
50
53
|
typhoeus (~> 1.4)
|
|
51
|
-
ffi (1.17.
|
|
52
|
-
ffi (1.17.
|
|
53
|
-
|
|
54
|
+
ffi (1.17.3-arm64-darwin)
|
|
55
|
+
ffi (1.17.3-x86_64-darwin)
|
|
56
|
+
ffi (1.17.3-x86_64-linux-gnu)
|
|
57
|
+
ffi (1.17.3-x86_64-linux-musl)
|
|
58
|
+
i18n (1.14.8)
|
|
54
59
|
concurrent-ruby (~> 1.0)
|
|
55
|
-
|
|
60
|
+
io-console (0.8.2)
|
|
61
|
+
json (2.18.0)
|
|
56
62
|
language_server-protocol (3.17.0.5)
|
|
57
63
|
lint_roller (1.1.0)
|
|
58
64
|
logger (1.7.0)
|
|
59
65
|
method_source (1.1.0)
|
|
60
|
-
minitest (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
minitest (6.0.1)
|
|
67
|
+
prism (~> 1.5)
|
|
68
|
+
net-http (0.9.1)
|
|
69
|
+
uri (>= 0.11.1)
|
|
70
|
+
net-http-persistent (4.0.8)
|
|
71
|
+
connection_pool (>= 2.2.4, < 4)
|
|
72
|
+
nokogiri (1.19.0-arm64-darwin)
|
|
73
|
+
racc (~> 1.4)
|
|
74
|
+
nokogiri (1.19.0-x86_64-darwin)
|
|
75
|
+
racc (~> 1.4)
|
|
76
|
+
nokogiri (1.19.0-x86_64-linux-gnu)
|
|
66
77
|
racc (~> 1.4)
|
|
67
|
-
nokogiri (1.
|
|
78
|
+
nokogiri (1.19.0-x86_64-linux-musl)
|
|
68
79
|
racc (~> 1.4)
|
|
69
|
-
ostruct (0.6.
|
|
80
|
+
ostruct (0.6.3)
|
|
70
81
|
parallel (1.27.0)
|
|
71
82
|
parallel_tests (4.10.1)
|
|
72
83
|
parallel
|
|
73
|
-
parser (3.3.
|
|
84
|
+
parser (3.3.10.1)
|
|
74
85
|
ast (~> 2.4.1)
|
|
75
86
|
racc
|
|
76
|
-
prism (1.
|
|
77
|
-
pry (0.
|
|
87
|
+
prism (1.9.0)
|
|
88
|
+
pry (0.16.0)
|
|
78
89
|
coderay (~> 1.1)
|
|
79
90
|
method_source (~> 1.0)
|
|
91
|
+
reline (>= 0.6.0)
|
|
80
92
|
racc (1.8.1)
|
|
81
|
-
rack (3.
|
|
93
|
+
rack (3.2.4)
|
|
82
94
|
rainbow (3.1.1)
|
|
83
|
-
regexp_parser (2.
|
|
95
|
+
regexp_parser (2.11.3)
|
|
96
|
+
reline (0.6.3)
|
|
97
|
+
io-console (~> 0.5)
|
|
84
98
|
request_store (1.7.0)
|
|
85
99
|
rack (>= 1.4)
|
|
86
|
-
rspec (3.13.
|
|
100
|
+
rspec (3.13.2)
|
|
87
101
|
rspec-core (~> 3.13.0)
|
|
88
102
|
rspec-expectations (~> 3.13.0)
|
|
89
103
|
rspec-mocks (~> 3.13.0)
|
|
90
|
-
rspec-core (3.13.
|
|
104
|
+
rspec-core (3.13.6)
|
|
91
105
|
rspec-support (~> 3.13.0)
|
|
92
|
-
rspec-expectations (3.13.
|
|
106
|
+
rspec-expectations (3.13.5)
|
|
93
107
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
94
108
|
rspec-support (~> 3.13.0)
|
|
95
|
-
rspec-mocks (3.13.
|
|
109
|
+
rspec-mocks (3.13.7)
|
|
96
110
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
97
111
|
rspec-support (~> 3.13.0)
|
|
98
|
-
rspec-support (3.13.
|
|
112
|
+
rspec-support (3.13.7)
|
|
99
113
|
rspec_junit_formatter (0.6.0)
|
|
100
114
|
rspec-core (>= 2, < 4, != 2.12.0)
|
|
101
|
-
rubocop (1.
|
|
115
|
+
rubocop (1.82.1)
|
|
102
116
|
json (~> 2.3)
|
|
103
117
|
language_server-protocol (~> 3.17.0.2)
|
|
104
118
|
lint_roller (~> 1.1.0)
|
|
@@ -106,30 +120,30 @@ GEM
|
|
|
106
120
|
parser (>= 3.3.0.2)
|
|
107
121
|
rainbow (>= 2.2.2, < 4.0)
|
|
108
122
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
109
|
-
rubocop-ast (>= 1.
|
|
123
|
+
rubocop-ast (>= 1.48.0, < 2.0)
|
|
110
124
|
ruby-progressbar (~> 1.7)
|
|
111
125
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
112
|
-
rubocop-ast (1.
|
|
126
|
+
rubocop-ast (1.49.0)
|
|
113
127
|
parser (>= 3.3.7.2)
|
|
114
|
-
prism (~> 1.
|
|
115
|
-
rubocop-performance (1.
|
|
128
|
+
prism (~> 1.7)
|
|
129
|
+
rubocop-performance (1.26.1)
|
|
116
130
|
lint_roller (~> 1.1)
|
|
117
131
|
rubocop (>= 1.75.0, < 2.0)
|
|
118
|
-
rubocop-ast (>= 1.
|
|
132
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
119
133
|
ruby-progressbar (1.13.0)
|
|
120
134
|
securerandom (0.4.1)
|
|
121
|
-
standard (1.
|
|
135
|
+
standard (1.53.0)
|
|
122
136
|
language_server-protocol (~> 3.17.0.2)
|
|
123
137
|
lint_roller (~> 1.0)
|
|
124
|
-
rubocop (~> 1.
|
|
138
|
+
rubocop (~> 1.82.0)
|
|
125
139
|
standard-custom (~> 1.0.0)
|
|
126
140
|
standard-performance (~> 1.8)
|
|
127
141
|
standard-custom (1.0.2)
|
|
128
142
|
lint_roller (~> 1.0)
|
|
129
143
|
rubocop (~> 1.50)
|
|
130
|
-
standard-performance (1.
|
|
144
|
+
standard-performance (1.9.0)
|
|
131
145
|
lint_roller (~> 1.1)
|
|
132
|
-
rubocop-performance (~> 1.
|
|
146
|
+
rubocop-performance (~> 1.26.0)
|
|
133
147
|
turbo_tests (2.2.5)
|
|
134
148
|
parallel_tests (>= 3.3.0, < 5)
|
|
135
149
|
rspec (>= 3.10)
|
|
@@ -137,15 +151,17 @@ GEM
|
|
|
137
151
|
ethon (>= 0.9.0)
|
|
138
152
|
tzinfo (2.0.6)
|
|
139
153
|
concurrent-ruby (~> 1.0)
|
|
140
|
-
unicode-display_width (3.
|
|
141
|
-
unicode-emoji (~> 4.
|
|
142
|
-
unicode-emoji (4.0
|
|
143
|
-
uri (1.
|
|
144
|
-
yard (0.9.
|
|
154
|
+
unicode-display_width (3.2.0)
|
|
155
|
+
unicode-emoji (~> 4.1)
|
|
156
|
+
unicode-emoji (4.2.0)
|
|
157
|
+
uri (1.1.1)
|
|
158
|
+
yard (0.9.38)
|
|
145
159
|
|
|
146
160
|
PLATFORMS
|
|
147
161
|
arm64-darwin
|
|
162
|
+
x86_64-darwin
|
|
148
163
|
x86_64-linux-gnu
|
|
164
|
+
x86_64-linux-musl
|
|
149
165
|
|
|
150
166
|
DEPENDENCIES
|
|
151
167
|
ecfr!
|
data/lib/ecfr/base.rb
CHANGED
|
@@ -31,8 +31,8 @@ module Ecfr
|
|
|
31
31
|
|
|
32
32
|
attr_reader :metadata, :results, :response_status, :request_data
|
|
33
33
|
|
|
34
|
-
SUPPORTED_ARRAY_ACCESSORS = %i[empty? first last size]
|
|
35
|
-
delegate(*SUPPORTED_ARRAY_ACCESSORS, to: :results)
|
|
34
|
+
SUPPORTED_ARRAY_ACCESSORS = %i[each empty? first last size]
|
|
35
|
+
delegate(*SUPPORTED_ARRAY_ACCESSORS, to: :results, allow_nil: true)
|
|
36
36
|
alias_method :all, :results
|
|
37
37
|
|
|
38
38
|
DEFAULT_OPTIONS = {base: true}
|
|
@@ -59,10 +59,6 @@ module Ecfr
|
|
|
59
59
|
super(attributes)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
def each
|
|
63
|
-
@results.each { |result| yield result }
|
|
64
|
-
end
|
|
65
|
-
|
|
66
62
|
class Metadata
|
|
67
63
|
include AttributeMethodDefinition
|
|
68
64
|
|
data/lib/ecfr/client.rb
CHANGED
|
@@ -236,6 +236,7 @@ module Ecfr
|
|
|
236
236
|
|
|
237
237
|
execute do
|
|
238
238
|
c.get(path, params) do |req|
|
|
239
|
+
yield(req) if block_given?
|
|
239
240
|
Ecfr.config.request_hook.call(req)
|
|
240
241
|
end
|
|
241
242
|
end
|
|
@@ -246,6 +247,7 @@ module Ecfr
|
|
|
246
247
|
|
|
247
248
|
execute do
|
|
248
249
|
c.post(path, params) do |req|
|
|
250
|
+
yield(req) if block_given?
|
|
249
251
|
Ecfr.config.request_hook.call(req)
|
|
250
252
|
end
|
|
251
253
|
end
|
|
@@ -256,6 +258,7 @@ module Ecfr
|
|
|
256
258
|
|
|
257
259
|
execute do
|
|
258
260
|
c.delete(path, params) do |req|
|
|
261
|
+
yield(req) if block_given?
|
|
259
262
|
Ecfr.config.request_hook.call(req)
|
|
260
263
|
end
|
|
261
264
|
end
|
|
@@ -268,6 +271,7 @@ module Ecfr
|
|
|
268
271
|
execute do
|
|
269
272
|
c.run_request(:purge, path, nil, nil) do |request|
|
|
270
273
|
request.params.update(params)
|
|
274
|
+
yield(req) if block_given?
|
|
271
275
|
Ecfr.config.request_hook.call(request)
|
|
272
276
|
end
|
|
273
277
|
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module Ecfr
|
|
2
|
+
#
|
|
3
|
+
# Configures the Ecfr gem from a consuming application's settings and
|
|
4
|
+
# credentials. Lives in the gem (rather than each app) so the contract
|
|
5
|
+
# between app config and the gem is defined and validated in one place.
|
|
6
|
+
#
|
|
7
|
+
# Everything the gem can't assume exists is passed in explicitly:
|
|
8
|
+
# - settings: the app's Settings object (duck-typed; dotted/[] access)
|
|
9
|
+
# - env: the app environment, used in the user_agent string
|
|
10
|
+
# - credentials: optional; anything responding to #dig (e.g. Rails credentials)
|
|
11
|
+
#
|
|
12
|
+
# An optional block is yielded the config last, after every settings-derived
|
|
13
|
+
# assignment, so the app can override any value (request hooks, timeouts,
|
|
14
|
+
# urls, ...) without the gem depending on app-level constants.
|
|
15
|
+
#
|
|
16
|
+
class ClientConfiguration
|
|
17
|
+
class InvalidSettings < StandardError; end
|
|
18
|
+
class InvalidCredentials < StandardError; end
|
|
19
|
+
|
|
20
|
+
# Settings with no gem-side default must be present. Everything else has a
|
|
21
|
+
# default in Ecfr::Configuration::CONFIG_DEFAULTS and is therefore optional.
|
|
22
|
+
REQUIRED_SETTINGS = [
|
|
23
|
+
%i[container process],
|
|
24
|
+
%i[container role],
|
|
25
|
+
%i[container hostname]
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
28
|
+
def self.initialize_for(service, settings, env, credentials = nil)
|
|
29
|
+
validate_settings!(settings)
|
|
30
|
+
validate_credentials!(credentials)
|
|
31
|
+
|
|
32
|
+
Ecfr.configure do |config|
|
|
33
|
+
config.user_agent = [
|
|
34
|
+
"ecfr", service, env,
|
|
35
|
+
dig_setting(settings, :container, :process),
|
|
36
|
+
dig_setting(settings, :container, :role),
|
|
37
|
+
dig_setting(settings, :container, :hostname)
|
|
38
|
+
].join("-")
|
|
39
|
+
|
|
40
|
+
log_http_requests = dig_setting(settings, :services, :ecfr, :log_http_requests)
|
|
41
|
+
config.log_http_requests = log_http_requests unless log_http_requests.nil?
|
|
42
|
+
|
|
43
|
+
cache_responses = dig_setting(settings, :services, :ecfr, :cache_responses)
|
|
44
|
+
config.cache_responses = cache_responses unless cache_responses.nil?
|
|
45
|
+
|
|
46
|
+
# prefer internal urls when setting up gem
|
|
47
|
+
base_url = dig_setting(settings, :services, :ecfr, :internal_base_url) ||
|
|
48
|
+
dig_setting(settings, :services, :ecfr, :base_url)
|
|
49
|
+
config.base_url = base_url if base_url.present?
|
|
50
|
+
|
|
51
|
+
profile_base_url = dig_setting(settings, :services, :ofr, :profile, :internal_base_url) ||
|
|
52
|
+
dig_setting(settings, :services, :ofr, :profile, :base_url)
|
|
53
|
+
config.ofr_profile_service_base_url = profile_base_url if profile_base_url.present?
|
|
54
|
+
|
|
55
|
+
profile_path = dig_setting(settings, :services, :ofr, :profile, :path)
|
|
56
|
+
config.ofr_profile_service_path = profile_path if profile_path.present?
|
|
57
|
+
|
|
58
|
+
# configure services according to settings
|
|
59
|
+
service_keys = Ecfr.services.filter_map do |service_module|
|
|
60
|
+
# ofr profile is configured separately above
|
|
61
|
+
next if service_module::Base.service_name == "OFR Profile"
|
|
62
|
+
|
|
63
|
+
service_module::Base.service_name.downcase.tr(" ", "_")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
service_keys.each do |service_key|
|
|
67
|
+
url = dig_setting(settings, :services, :ecfr, service_key, :url)
|
|
68
|
+
config.send(:"#{service_key}_url=", url) if url.present?
|
|
69
|
+
|
|
70
|
+
path = dig_setting(settings, :services, :ecfr, service_key, :path)
|
|
71
|
+
config.send(:"#{service_key}_path=", path) if path.present?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
open_timeout = dig_setting(settings, :services, :ecfr, :open_timeout)
|
|
75
|
+
config.open_timeout = open_timeout unless open_timeout.nil?
|
|
76
|
+
|
|
77
|
+
pdf_timeout = dig_setting(settings, :app, :timeouts, :pdf_timeout)
|
|
78
|
+
config.prince_xml_service_pdf_timeout = pdf_timeout unless pdf_timeout.nil?
|
|
79
|
+
|
|
80
|
+
# basic auth - some endpoints require auth (optional)
|
|
81
|
+
config.ecfr_basic_auth_username = credentials&.dig(:services, :ecfr, :http_basic, :username)
|
|
82
|
+
config.ecfr_basic_auth_password = credentials&.dig(:services, :ecfr, :http_basic, :password)
|
|
83
|
+
|
|
84
|
+
# let the app override any of the above (request hooks, urls, timeouts)
|
|
85
|
+
yield config if block_given?
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def self.validate_settings!(settings)
|
|
90
|
+
raise InvalidSettings, "settings is required" if settings.nil?
|
|
91
|
+
|
|
92
|
+
missing = REQUIRED_SETTINGS.select { |path| dig_setting(settings, *path).blank? }
|
|
93
|
+
return if missing.empty?
|
|
94
|
+
|
|
95
|
+
raise InvalidSettings,
|
|
96
|
+
"missing required setting(s): #{missing.map { |path| path.join(".") }.join(", ")}"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def self.validate_credentials!(credentials)
|
|
100
|
+
return if credentials.nil?
|
|
101
|
+
return if credentials.respond_to?(:dig)
|
|
102
|
+
|
|
103
|
+
raise InvalidCredentials, "credentials must respond to #dig (got #{credentials.class})"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Safely walk a settings tree via method or [] access, returning nil if any
|
|
107
|
+
# segment is missing rather than raising NoMethodError.
|
|
108
|
+
def self.dig_setting(node, *path)
|
|
109
|
+
path.reduce(node) do |obj, key|
|
|
110
|
+
break nil if obj.nil?
|
|
111
|
+
|
|
112
|
+
if obj.respond_to?(key)
|
|
113
|
+
obj.public_send(key)
|
|
114
|
+
elsif obj.respond_to?(:[])
|
|
115
|
+
obj[key]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
private_class_method :validate_settings!, :validate_credentials!, :dig_setting
|
|
121
|
+
end
|
|
122
|
+
end
|
data/lib/ecfr/constants.rb
CHANGED
|
@@ -2,13 +2,15 @@ module Ecfr
|
|
|
2
2
|
module Constants
|
|
3
3
|
module ChangeTypes
|
|
4
4
|
KNOWN_CHANGE_TYPES = {
|
|
5
|
+
cross_reference: "Regulations linked from the above-dated Federal Register:",
|
|
5
6
|
cross_references: "Regulations linked from the above-dated Federal Register:",
|
|
6
7
|
delayed: "Regulations delayed in the above-dated Federal Register:",
|
|
7
8
|
delayed_withdrawn: "Regulations delayed or withdrawn in the above-dated Federal Register:",
|
|
8
9
|
delayed_withdrawn_extended: "Regulations delayed, withdrawn, or extended in the above-dated Federal Register:",
|
|
9
10
|
effective: "Effective regulations inserted from the above-dated Federal Register:",
|
|
11
|
+
effective_cross_reference: "Regulations inserted that were previously linked and became effective on the date listed above:",
|
|
10
12
|
effective_cross_references: "Regulations inserted that were previously linked and became effective on the date listed above:",
|
|
11
|
-
expired: "Effective
|
|
13
|
+
expired: "Effective regulations that expire on this date:",
|
|
12
14
|
extended: "Regulations extended in the above-dated Federal Register",
|
|
13
15
|
initial: "Initial import of this content - change type is indeterminate"
|
|
14
16
|
}
|
data/lib/ecfr/parallel_client.rb
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
1
|
module Ecfr
|
|
2
2
|
module ParallelClient
|
|
3
3
|
module ClassMethods
|
|
4
|
-
def parallel_client(base_url
|
|
4
|
+
def parallel_client(base_url: self.base_url, client_options: {})
|
|
5
5
|
client(
|
|
6
6
|
base_url: base_url,
|
|
7
7
|
client_options: client_options.merge({adapter: :typhoeus})
|
|
8
8
|
)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
def parallel_get(requests, client)
|
|
11
|
+
def parallel(method, requests, client = parallel_client)
|
|
13
12
|
client.in_parallel do
|
|
14
13
|
requests.each do |request|
|
|
15
|
-
request.response = client.
|
|
14
|
+
request.response = client.send(method, request.path, request.args) do |req|
|
|
16
15
|
Ecfr.config.request_hook.call(req)
|
|
17
16
|
end
|
|
18
17
|
end
|
|
19
18
|
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def parallel_get(requests, client = parallel_client)
|
|
22
|
+
parallel(:get, requests, client)
|
|
23
|
+
end
|
|
20
24
|
|
|
21
|
-
|
|
25
|
+
def parallel_post(requests, client = parallel_client)
|
|
26
|
+
parallel(:post, requests, client)
|
|
22
27
|
end
|
|
23
28
|
end
|
|
24
29
|
|
|
@@ -40,10 +40,7 @@ module Ecfr
|
|
|
40
40
|
ORIGIN_PATH = "v1/origin"
|
|
41
41
|
|
|
42
42
|
def self.find(date, title_number, params = {})
|
|
43
|
-
supported_params = (
|
|
44
|
-
Ecfr::Constants::Hierarchy::HIERARCHY_LEVELS[1, 8] +
|
|
45
|
-
[:build_id]
|
|
46
|
-
).map(&:to_sym)
|
|
43
|
+
supported_params = Ecfr::Constants::Hierarchy::HIERARCHY_LEVELS[1, 8].map(&:to_sym)
|
|
47
44
|
|
|
48
45
|
perform(
|
|
49
46
|
:get,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class Ecfr::VersionerService::Reference
|
|
2
|
+
extend ResponseHelper
|
|
3
|
+
|
|
4
|
+
def self.response_for(references)
|
|
5
|
+
references = references.is_a?(Array) ? references : [references]
|
|
6
|
+
|
|
7
|
+
results = {
|
|
8
|
+
references: references
|
|
9
|
+
}.compact
|
|
10
|
+
|
|
11
|
+
build(
|
|
12
|
+
response: stubbed_response(results.to_json)
|
|
13
|
+
)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class Ecfr::VersionerService::Topic
|
|
2
|
+
extend ResponseHelper
|
|
3
|
+
|
|
4
|
+
def self.response_for(topics, meta: {})
|
|
5
|
+
topics = topics.is_a?(Array) ? topics : [topics]
|
|
6
|
+
|
|
7
|
+
results = {
|
|
8
|
+
topics: topics,
|
|
9
|
+
meta: meta
|
|
10
|
+
}.compact
|
|
11
|
+
|
|
12
|
+
build(
|
|
13
|
+
response: stubbed_response(results.to_json)
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
FactoryBot.define do
|
|
2
|
+
factory :versioner_service_reference, class: "Ecfr::VersionerService::Reference" do
|
|
3
|
+
skip_create
|
|
4
|
+
|
|
5
|
+
reference { "1 CFR 1" }
|
|
6
|
+
description { "Definitions" }
|
|
7
|
+
|
|
8
|
+
initialize_with do
|
|
9
|
+
new(attributes.deep_stringify_keys)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
trait :minimal do
|
|
13
|
+
description { "" }
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
FactoryBot.define do
|
|
2
|
+
factory :topic, class: "Ecfr::VersionerService::Topic" do
|
|
3
|
+
skip_create
|
|
4
|
+
|
|
5
|
+
name { "Sample Topic" }
|
|
6
|
+
references { ["1 CFR 1", "1 CFR 2"] }
|
|
7
|
+
see_also { ["Related Topic"] }
|
|
8
|
+
see { [] }
|
|
9
|
+
|
|
10
|
+
initialize_with do
|
|
11
|
+
new(attributes.deep_stringify_keys)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
trait :with_references do
|
|
15
|
+
references { ["1 CFR 1", "1 CFR 2", "1 CFR 3"] }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
trait :with_see_also do
|
|
19
|
+
see_also { ["Related Topic 1", "Related Topic 2"] }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
trait :with_see do
|
|
23
|
+
see { ["Redirect Topic"] }
|
|
24
|
+
references { [] }
|
|
25
|
+
see_also { [] }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
trait :minimal do
|
|
29
|
+
references { [] }
|
|
30
|
+
see_also { [] }
|
|
31
|
+
see { [] }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/ecfr/version.rb
CHANGED
|
@@ -65,8 +65,6 @@ module Ecfr
|
|
|
65
65
|
# hierarchy of the requested content
|
|
66
66
|
# @option options [<Integer>] :descendant_depth the number of
|
|
67
67
|
# levels of descendents to include in the structure
|
|
68
|
-
# @option options [<Integer>] :build_id internal use only - used to
|
|
69
|
-
# retreive data about a specific build
|
|
70
68
|
# @option options [<Boolean>] :metadata whether to include metadata in
|
|
71
69
|
# the response
|
|
72
70
|
# @option options [<Integer>] :max_items
|
|
@@ -80,8 +78,7 @@ module Ecfr
|
|
|
80
78
|
hierarchy_args = hierarchy_args.symbolize_keys
|
|
81
79
|
options = options.symbolize_keys
|
|
82
80
|
|
|
83
|
-
options = hierarchy_args.merge(options).except(:title
|
|
84
|
-
options[:metadata] = true
|
|
81
|
+
options = hierarchy_args.merge(options).except(:title)
|
|
85
82
|
|
|
86
83
|
perform(
|
|
87
84
|
:get,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Ecfr
|
|
2
|
+
module VersionerService
|
|
3
|
+
#
|
|
4
|
+
# Authority entries represent individual references in the
|
|
5
|
+
# Parallel Table of Authorities.
|
|
6
|
+
#
|
|
7
|
+
class Authority < Base
|
|
8
|
+
result_key :authorities
|
|
9
|
+
|
|
10
|
+
attribute :kind,
|
|
11
|
+
desc: "authority reference kind"
|
|
12
|
+
|
|
13
|
+
attribute :components,
|
|
14
|
+
desc: "authority citation components"
|
|
15
|
+
|
|
16
|
+
attribute :date,
|
|
17
|
+
type: :date,
|
|
18
|
+
desc: "authority citation date"
|
|
19
|
+
|
|
20
|
+
attribute :references,
|
|
21
|
+
desc: "CFR titles, parts, and hierarchies that cite this authority"
|
|
22
|
+
|
|
23
|
+
AUTHORITIES_PATH = "v1/authorities"
|
|
24
|
+
|
|
25
|
+
metadata_key :meta
|
|
26
|
+
|
|
27
|
+
metadata :categories,
|
|
28
|
+
desc: "reference categories included in this response"
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Retrieves the Parallel Table of Authorities data.
|
|
32
|
+
#
|
|
33
|
+
# @param [<Hash>] options
|
|
34
|
+
# @option options [String] :year ("current") the year or 'current' to retrieve authorities for
|
|
35
|
+
#
|
|
36
|
+
# @return [Authority] grouped authority data and metadata
|
|
37
|
+
#
|
|
38
|
+
def self.all(options = {})
|
|
39
|
+
year = options.fetch(:year, "current")
|
|
40
|
+
|
|
41
|
+
perform(
|
|
42
|
+
:get,
|
|
43
|
+
"#{AUTHORITIES_PATH}/#{year}"
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -6,9 +6,13 @@ module Ecfr
|
|
|
6
6
|
|
|
7
7
|
# note: structure must be required before ancestors
|
|
8
8
|
require_relative "structure"
|
|
9
|
+
require_relative "agency"
|
|
9
10
|
require_relative "ancestors"
|
|
11
|
+
require_relative "authority"
|
|
10
12
|
require_relative "issue_package"
|
|
11
13
|
require_relative "title"
|
|
14
|
+
require_relative "reference"
|
|
15
|
+
require_relative "topic"
|
|
12
16
|
require_relative "xml_content"
|
|
13
17
|
|
|
14
18
|
def self.base_url
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Ecfr
|
|
2
|
+
module VersionerService
|
|
3
|
+
#
|
|
4
|
+
# References in the topics endpoint provide detailed information
|
|
5
|
+
# about CFR references mentioned in topics and agencies.
|
|
6
|
+
#
|
|
7
|
+
# Each reference contains a CFR reference string and a description.
|
|
8
|
+
#
|
|
9
|
+
class Reference < Base
|
|
10
|
+
result_key :references
|
|
11
|
+
|
|
12
|
+
attribute :reference,
|
|
13
|
+
desc: "CFR reference ('1 CFR 1')"
|
|
14
|
+
|
|
15
|
+
attribute :description,
|
|
16
|
+
desc: "description of the reference"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
module Ecfr
|
|
2
|
+
module VersionerService
|
|
3
|
+
#
|
|
4
|
+
# Topics represent entries in the CFR Index and Finding Aids.
|
|
5
|
+
#
|
|
6
|
+
# Each topic contains a name and may have references to specific
|
|
7
|
+
# CFR sections, see_also references to other topics, or see
|
|
8
|
+
# references for redirects.
|
|
9
|
+
#
|
|
10
|
+
class Topic < Base
|
|
11
|
+
result_key :topics
|
|
12
|
+
|
|
13
|
+
attribute :adhoc,
|
|
14
|
+
type: :boolean,
|
|
15
|
+
desc: "distinguish informal topics from thesaurus entries"
|
|
16
|
+
|
|
17
|
+
attribute :name,
|
|
18
|
+
desc: "name of the topic"
|
|
19
|
+
|
|
20
|
+
attribute :references,
|
|
21
|
+
type: Array(:string),
|
|
22
|
+
desc: "array of CFR references for this topic"
|
|
23
|
+
|
|
24
|
+
attribute :see_also,
|
|
25
|
+
type: Array(:string),
|
|
26
|
+
desc: "array of related topic names to see also"
|
|
27
|
+
|
|
28
|
+
attribute :see,
|
|
29
|
+
type: Array(:string),
|
|
30
|
+
desc: "array of topic names to redirect to"
|
|
31
|
+
|
|
32
|
+
attribute :slug,
|
|
33
|
+
desc: "normalized topic identifier for URLs"
|
|
34
|
+
|
|
35
|
+
TOPICS_PATH = "v1/topics" # /current | /2024
|
|
36
|
+
|
|
37
|
+
metadata_key :meta
|
|
38
|
+
|
|
39
|
+
metadata :agencies,
|
|
40
|
+
type: Array(Ecfr::VersionerService::Agency),
|
|
41
|
+
desc: "array of agencies referenced in topics"
|
|
42
|
+
|
|
43
|
+
metadata :references,
|
|
44
|
+
type: Array(Ecfr::VersionerService::Reference),
|
|
45
|
+
desc: "array of CFR references with descriptions"
|
|
46
|
+
|
|
47
|
+
#
|
|
48
|
+
# Retrieves the list of all Topics
|
|
49
|
+
#
|
|
50
|
+
# @param [<Hash>] options
|
|
51
|
+
# @option options [String] :year ("current") the year or 'current' to retrieve topics for
|
|
52
|
+
# @option options [Boolean] :include_agencies (false) whether to include agencies in the response
|
|
53
|
+
#
|
|
54
|
+
# @return [<Topic>] array of Topics with their references and relationships
|
|
55
|
+
#
|
|
56
|
+
def self.all(options = {})
|
|
57
|
+
year = options.fetch(:year, "current")
|
|
58
|
+
include_agencies = options.fetch(:include_agencies, false)
|
|
59
|
+
|
|
60
|
+
params = {}
|
|
61
|
+
params[:include_agencies] = true if include_agencies
|
|
62
|
+
|
|
63
|
+
perform(
|
|
64
|
+
:get,
|
|
65
|
+
"#{TOPICS_PATH}/#{year}",
|
|
66
|
+
params: params,
|
|
67
|
+
perform_options: {
|
|
68
|
+
attributes_key: nil
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -19,7 +19,6 @@ module Ecfr
|
|
|
19
19
|
# @param [<Date, String, 'current'>] date ISO string or 'current'
|
|
20
20
|
# @param [<Integer, String>] title_number the title of interest
|
|
21
21
|
# @param [<Hash>] options a hash of hierarchy levels for the content desired - see attributes defined in {Ecfr::Common::Hierarchy} for acceptable keys
|
|
22
|
-
# @option options [<String>] build_id internal use only - a specific build id
|
|
23
22
|
#
|
|
24
23
|
# @return [<XML>] XML for the full title or pared down to the requested hierarchy
|
|
25
24
|
#
|
|
@@ -40,7 +39,6 @@ module Ecfr
|
|
|
40
39
|
# @param [<Date, String, 'current'>] date ISO string or 'current'
|
|
41
40
|
# @param [<Integer, String>] title_number the title of interest
|
|
42
41
|
# @param [<Hash>] options a hash of hierarchy levels for the content desired - see attributes defined in {Ecfr:Common::Hierarchy} for acceptable keys
|
|
43
|
-
# @option options [<String>] build_id internal use only - a specific build id
|
|
44
42
|
#
|
|
45
43
|
# @return [<String>] URL to retreive XML content for the given parameters
|
|
46
44
|
#
|
data/lib/ecfr.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "active_model/type"
|
|
|
5
5
|
|
|
6
6
|
require "active_support"
|
|
7
7
|
require "active_support/core_ext/class/attribute"
|
|
8
|
+
require "active_support/core_ext/enumerable"
|
|
8
9
|
require "active_support/core_ext/hash"
|
|
9
10
|
require "active_support/core_ext/module/delegation"
|
|
10
11
|
require "active_support/core_ext/string"
|
|
@@ -92,3 +93,5 @@ require_relative "ecfr/search_service/base"
|
|
|
92
93
|
require_relative "ecfr/subscriptions_service/base"
|
|
93
94
|
require_relative "ecfr/varnish_cache_service/base"
|
|
94
95
|
require_relative "ecfr/versioner_service/base"
|
|
96
|
+
|
|
97
|
+
require_relative "ecfr/client_configuration"
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ecfr
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peregrinator
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-06-29 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activemodel
|
|
@@ -274,7 +274,6 @@ files:
|
|
|
274
274
|
- lib/ecfr/admin_service/agency.rb
|
|
275
275
|
- lib/ecfr/admin_service/api_documentation.rb
|
|
276
276
|
- lib/ecfr/admin_service/base.rb
|
|
277
|
-
- lib/ecfr/admin_service/build.rb
|
|
278
277
|
- lib/ecfr/admin_service/ecfr_correction.rb
|
|
279
278
|
- lib/ecfr/admin_service/ecfr_correction/cfr_reference.rb
|
|
280
279
|
- lib/ecfr/admin_service/editorial_note.rb
|
|
@@ -290,6 +289,7 @@ files:
|
|
|
290
289
|
- lib/ecfr/attribute_method_definition.rb
|
|
291
290
|
- lib/ecfr/base.rb
|
|
292
291
|
- lib/ecfr/client.rb
|
|
292
|
+
- lib/ecfr/client_configuration.rb
|
|
293
293
|
- lib/ecfr/common/hierarchy.rb
|
|
294
294
|
- lib/ecfr/configuration.rb
|
|
295
295
|
- lib/ecfr/constants.rb
|
|
@@ -338,7 +338,9 @@ files:
|
|
|
338
338
|
- lib/ecfr/testing/extensions/search_service/date_facet_extensions.rb
|
|
339
339
|
- lib/ecfr/testing/extensions/search_service/timeline_extensions.rb
|
|
340
340
|
- lib/ecfr/testing/extensions/versioner_service/ancestors_extensions.rb
|
|
341
|
+
- lib/ecfr/testing/extensions/versioner_service/reference_extensions.rb
|
|
341
342
|
- lib/ecfr/testing/extensions/versioner_service/title_extenstions.rb
|
|
343
|
+
- lib/ecfr/testing/extensions/versioner_service/topic_extensions.rb
|
|
342
344
|
- lib/ecfr/testing/factories/admin_service/agency_factory.rb
|
|
343
345
|
- lib/ecfr/testing/factories/admin_service/cfr_reference_factory.rb
|
|
344
346
|
- lib/ecfr/testing/factories/admin_service/ecfr_correction_factory.rb
|
|
@@ -353,26 +355,32 @@ files:
|
|
|
353
355
|
- lib/ecfr/testing/factories/versioner_service/ancestors_factory.rb
|
|
354
356
|
- lib/ecfr/testing/factories/versioner_service/metadata_node_info_factory.rb
|
|
355
357
|
- lib/ecfr/testing/factories/versioner_service/node_summary_factory.rb
|
|
358
|
+
- lib/ecfr/testing/factories/versioner_service/reference_factory.rb
|
|
356
359
|
- lib/ecfr/testing/factories/versioner_service/structure_factory.rb
|
|
357
360
|
- lib/ecfr/testing/factories/versioner_service/title_factory.rb
|
|
361
|
+
- lib/ecfr/testing/factories/versioner_service/topic_factory.rb
|
|
358
362
|
- lib/ecfr/testing/factory_bot_helpers/content_version.rb
|
|
359
363
|
- lib/ecfr/testing/factory_bot_helpers/ecfr_gem_initialize_helpers.rb
|
|
360
364
|
- lib/ecfr/testing/helpers/response_helper.rb
|
|
361
365
|
- lib/ecfr/testing/strategies/ecfr_attribute_hash_strategy.rb
|
|
362
366
|
- lib/ecfr/varnish_cache_service/base.rb
|
|
363
367
|
- lib/ecfr/version.rb
|
|
368
|
+
- lib/ecfr/versioner_service/agency.rb
|
|
364
369
|
- lib/ecfr/versioner_service/ancestors.rb
|
|
365
370
|
- lib/ecfr/versioner_service/ancestors/metadata_node_info.rb
|
|
366
371
|
- lib/ecfr/versioner_service/ancestors/node_summary.rb
|
|
367
372
|
- lib/ecfr/versioner_service/api_documentation.rb
|
|
373
|
+
- lib/ecfr/versioner_service/authority.rb
|
|
368
374
|
- lib/ecfr/versioner_service/base.rb
|
|
369
375
|
- lib/ecfr/versioner_service/issue_package.rb
|
|
370
376
|
- lib/ecfr/versioner_service/issue_package/issue_volume.rb
|
|
371
377
|
- lib/ecfr/versioner_service/issue_package/sha_comparison.rb
|
|
372
378
|
- lib/ecfr/versioner_service/issue_package/title_version.rb
|
|
379
|
+
- lib/ecfr/versioner_service/reference.rb
|
|
373
380
|
- lib/ecfr/versioner_service/status.rb
|
|
374
381
|
- lib/ecfr/versioner_service/structure.rb
|
|
375
382
|
- lib/ecfr/versioner_service/title.rb
|
|
383
|
+
- lib/ecfr/versioner_service/topic.rb
|
|
376
384
|
- lib/ecfr/versioner_service/xml_content.rb
|
|
377
385
|
- lib/yard/attribute_handler.rb
|
|
378
386
|
- lib/yard/metadata_handler.rb
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
module Ecfr
|
|
2
|
-
module AdminService
|
|
3
|
-
class Build < Base
|
|
4
|
-
result_key :builds
|
|
5
|
-
|
|
6
|
-
attribute :id,
|
|
7
|
-
desc: "build id"
|
|
8
|
-
attribute :status,
|
|
9
|
-
desc: "build status - either *Success* or *Failure*"
|
|
10
|
-
|
|
11
|
-
attribute :expired,
|
|
12
|
-
type: :boolean
|
|
13
|
-
attribute :previewable,
|
|
14
|
-
type: :boolean
|
|
15
|
-
|
|
16
|
-
BUILDS_PATH = "v1/builds"
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
# Retrieve a Build by id
|
|
20
|
-
#
|
|
21
|
-
# @param [<String>] build_id - id of the desired build
|
|
22
|
-
#
|
|
23
|
-
# @return [<Build>] data for a single build
|
|
24
|
-
#
|
|
25
|
-
def self.find(build_id)
|
|
26
|
-
perform(
|
|
27
|
-
:get,
|
|
28
|
-
build_path(build_id)
|
|
29
|
-
)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def self.build_path(build_id)
|
|
33
|
-
"#{BUILDS_PATH}/#{build_id}"
|
|
34
|
-
end
|
|
35
|
-
private_class_method :build_path
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|