openstax_content 1.2.0 → 1.5.0
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/README.md +3 -37
- data/lib/openstax/content/abl.rb +68 -47
- data/lib/openstax/content/book.rb +10 -4
- data/lib/openstax/content/book_part.rb +6 -0
- data/lib/openstax/content/fragment_splitter.rb +2 -1
- data/lib/openstax/content/version.rb +1 -1
- data/lib/openstax_content.rb +2 -2
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 640f5b30f23af9597543e0e6239b3def597b456ae05b85c9657e6380d5ad6623
|
4
|
+
data.tar.gz: ba19461ea0e3700f2f8c752c4dcf2fe5808bf8a798b22707fec47d9857f081c8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5589b01cfa98a740916cd47274171ada0265429960ca68657124f1d0c6c98e551542b3027db5278845e3ef10b9191d54b74d84cf4fd8db7355c28f2e3722d5e
|
7
|
+
data.tar.gz: 0e02160d69f9789030a33bd0f84da38eb0922bf3bb06c54fcc6740bdb7649ae1bbd72c62f130ce3e49947f73a711d477380c3e6eb36fc2b40c6a10ba0b344d58
|
data/README.md
CHANGED
@@ -26,45 +26,11 @@ s3_access_key_id and s3_secret_access_key are optional (you can use AWS instance
|
|
26
26
|
|
27
27
|
## Usage
|
28
28
|
|
29
|
-
### Approved Book List (to get
|
29
|
+
### Approved Book List (to get books and page slugs)
|
30
30
|
```rb
|
31
31
|
abl = OpenStax::Content::Abl.new
|
32
|
-
|
33
|
-
|
34
|
-
```
|
35
|
-
|
36
|
-
### S3 Bucket Listing (to get latest archive and book versions)
|
37
|
-
```rb
|
38
|
-
s3 = OpenStax::Content::S3.new
|
39
|
-
if s3.bucket_configured?
|
40
|
-
latest_archive_version = s3.ls.last
|
41
|
-
latest_book_ids = s3.ls latest_archive_version
|
42
|
-
chosen_book = latest_book_ids.sample
|
43
|
-
book_uuid, book_version = chosen_book.split('@', 2)
|
44
|
-
book = OpenStax::Content::Book.new(
|
45
|
-
archive_version: latest_archive_version, uuid: book_uuid, version: book_version
|
46
|
-
)
|
47
|
-
end
|
48
|
-
```
|
49
|
-
|
50
|
-
### Archive (to create archive links, load content and get book and page slugs)
|
51
|
-
```rb
|
52
|
-
archive = OpenStax::Content::Archive.new latest_archive_version
|
53
|
-
|
54
|
-
book_id = "#{book_uuid}@#{book_version}"
|
55
|
-
page_id = "#{book_id}:#{page_uuid}"
|
56
|
-
|
57
|
-
book_url = archive.url_for book_id
|
58
|
-
page_url = archive.url_for page_id
|
59
|
-
|
60
|
-
book_json = archive.fetch book_id
|
61
|
-
page_json = archive.fetch page_id
|
62
|
-
|
63
|
-
book_hash = archive.json book_id
|
64
|
-
page_hash = archive.json page_id
|
65
|
-
|
66
|
-
book_slug = archive.slug book_id # or book_uuid
|
67
|
-
page_slug = archive.slug page_id # or "#{book_uuid}:#{page_uuid}"
|
32
|
+
books = abl.books
|
33
|
+
slugs = abl.slugs_by_page_uuid
|
68
34
|
```
|
69
35
|
|
70
36
|
### Fragment Splitter (to split pages and create interactive readings)
|
data/lib/openstax/content/abl.rb
CHANGED
@@ -2,6 +2,10 @@ require_relative 'archive'
|
|
2
2
|
require_relative 'book'
|
3
3
|
|
4
4
|
class OpenStax::Content::Abl
|
5
|
+
# Check back this many archive versions
|
6
|
+
# If there are more than this number of archive versions still building, errors will happen
|
7
|
+
DEFAULT_MAX_ARCHIVE_ATTEMPTS = 5
|
8
|
+
|
5
9
|
def initialize(url: nil)
|
6
10
|
@url = url
|
7
11
|
end
|
@@ -14,68 +18,85 @@ class OpenStax::Content::Abl
|
|
14
18
|
@body_string ||= Faraday.get(url).body
|
15
19
|
end
|
16
20
|
|
17
|
-
def
|
18
|
-
@
|
21
|
+
def body_array
|
22
|
+
@body_array ||= JSON.parse(body_string, symbolize_names: true)
|
19
23
|
end
|
20
24
|
|
21
25
|
def digest
|
22
26
|
Digest::SHA256.hexdigest body_string
|
23
27
|
end
|
24
28
|
|
25
|
-
def
|
26
|
-
{}.
|
27
|
-
|
28
|
-
|
29
|
+
def books(archive: OpenStax::Content::Archive.new)
|
30
|
+
body_array.filter { |book| book[:code_version] <= archive.version }.map do |book|
|
31
|
+
OpenStax::Content::Book.new(
|
32
|
+
archive: archive,
|
33
|
+
uuid: book[:uuid],
|
34
|
+
version: book[:commit_sha][0..6],
|
35
|
+
min_code_version: book[:code_version],
|
36
|
+
slug: book[:slug],
|
37
|
+
committed_at: book[:committed_at]
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def each_book_with_previous_archive_version_fallback(max_attempts: DEFAULT_MAX_ARCHIVE_ATTEMPTS, &block)
|
43
|
+
raise ArgumentError, 'no block given' if block.nil?
|
44
|
+
raise ArgumentError, 'given block must accept the book as its first argument' if block.arity == 0
|
45
|
+
|
46
|
+
books = OpenStax::Content::Abl.new.books
|
47
|
+
attempt = 1
|
48
|
+
|
49
|
+
until books.empty?
|
50
|
+
previous_version = nil
|
51
|
+
previous_archive = nil
|
52
|
+
retry_books = []
|
53
|
+
|
54
|
+
books.each do |book|
|
55
|
+
begin
|
56
|
+
block.call book
|
57
|
+
rescue StandardError => exception
|
58
|
+
raise exception if attempt >= max_attempts
|
59
|
+
|
60
|
+
# Sometimes books in the latest archive fails to load (when the new version is still building)
|
61
|
+
# Retry with an earlier version of archive, if possible
|
62
|
+
previous_version ||= book.archive.previous_version
|
29
63
|
|
30
|
-
|
64
|
+
if previous_version.nil?
|
65
|
+
# There are no more earlier archive versions
|
66
|
+
raise exception
|
67
|
+
else
|
68
|
+
previous_archive ||= OpenStax::Content::Archive.new version: previous_version
|
31
69
|
|
32
|
-
|
33
|
-
|
34
|
-
|
70
|
+
retry_book = OpenStax::Content::Book.new(
|
71
|
+
archive: previous_archive,
|
72
|
+
uuid: book.uuid,
|
73
|
+
version: book.version,
|
74
|
+
slug: book.slug,
|
75
|
+
min_code_version: book.min_code_version,
|
76
|
+
committed_at: book.committed_at
|
77
|
+
)
|
35
78
|
|
36
|
-
|
79
|
+
# If the book requires an archive version that hasn't finished building yet, don't include it
|
80
|
+
retry_books << retry_book if retry_book.valid?
|
81
|
+
end
|
82
|
+
end
|
37
83
|
end
|
84
|
+
|
85
|
+
books = retry_books
|
86
|
+
attempt += 1
|
38
87
|
end
|
39
88
|
end
|
40
89
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
# CNX-hosted book
|
48
|
-
version = version_by_collection_id[approved_book[:collection_id]]
|
49
|
-
|
50
|
-
next [] if version.nil?
|
51
|
-
|
52
|
-
approved_book[:books].map do |book|
|
53
|
-
OpenStax::Content::Book.new(
|
54
|
-
archive: archive,
|
55
|
-
uuid: book[:uuid],
|
56
|
-
version: version[:content_version].sub('1.', ''),
|
57
|
-
slug: book[:slug],
|
58
|
-
style: approved_book[:style]
|
59
|
-
)
|
60
|
-
end
|
61
|
-
else
|
62
|
-
# Git-hosted book
|
63
|
-
approved_book[:versions].flat_map do |version|
|
64
|
-
next [] if version[:min_code_version] > archive.version
|
65
|
-
|
66
|
-
commit_metadata = version[:commit_metadata]
|
67
|
-
|
68
|
-
commit_metadata[:books].map do |book|
|
69
|
-
OpenStax::Content::Book.new(
|
70
|
-
archive: archive,
|
71
|
-
uuid: book[:uuid],
|
72
|
-
version: version[:commit_sha][0..6],
|
73
|
-
slug: book[:slug],
|
74
|
-
style: book[:style]
|
75
|
-
)
|
76
|
-
end
|
90
|
+
def slugs_by_page_uuid(max_attempts: DEFAULT_MAX_ARCHIVE_ATTEMPTS)
|
91
|
+
@slugs_by_page_uuid ||= {}.tap do |hash|
|
92
|
+
each_book_with_previous_archive_version_fallback(max_attempts: max_attempts) do |book|
|
93
|
+
book.all_pages.each do |page|
|
94
|
+
hash[page.uuid] ||= []
|
95
|
+
hash[page.uuid] << { book: book.slug, page: page.slug }
|
77
96
|
end
|
78
97
|
end
|
98
|
+
|
99
|
+
hash.each { |uuid, slugs| slugs.uniq! }
|
79
100
|
end
|
80
101
|
end
|
81
102
|
end
|
@@ -1,18 +1,24 @@
|
|
1
|
+
require 'forwardable'
|
1
2
|
require_relative 'book_part'
|
2
3
|
|
3
4
|
class OpenStax::Content::Book
|
4
5
|
extend Forwardable
|
5
6
|
|
6
|
-
attr_reader :archive, :uuid, :version, :slug, :
|
7
|
+
attr_reader :archive, :uuid, :version, :slug, :min_code_version, :committed_at
|
7
8
|
|
8
|
-
def initialize(archive:, uuid:, version:, url: nil, hash: nil, slug: nil,
|
9
|
+
def initialize(archive:, uuid:, version:, url: nil, hash: nil, min_code_version: nil, slug: nil, committed_at: nil)
|
9
10
|
@archive = archive
|
10
11
|
@uuid = uuid
|
11
12
|
@version = version
|
12
13
|
@url = url
|
13
14
|
@hash = hash
|
15
|
+
@min_code_version = min_code_version
|
14
16
|
@slug = slug
|
15
|
-
@
|
17
|
+
@committed_at = committed_at
|
18
|
+
end
|
19
|
+
|
20
|
+
def valid?
|
21
|
+
min_code_version.nil? || min_code_version <= archive.version
|
16
22
|
end
|
17
23
|
|
18
24
|
def url
|
@@ -51,5 +57,5 @@ class OpenStax::Content::Book
|
|
51
57
|
@root_book_part ||= OpenStax::Content::BookPart.new(hash: tree, is_root: true, book: self)
|
52
58
|
end
|
53
59
|
|
54
|
-
|
60
|
+
def_delegators :root_book_part, :all_book_parts, :all_pages
|
55
61
|
end
|
@@ -45,6 +45,12 @@ class OpenStax::Content::BookPart
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
+
def all_book_parts
|
49
|
+
@all_book_parts ||= parts.flat_map do |part|
|
50
|
+
part.is_a?(OpenStax::Content::BookPart) ? [ part ] + part.all_book_parts : []
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
48
54
|
def all_pages
|
49
55
|
@all_pages ||= parts.flat_map do |part|
|
50
56
|
part.is_a?(OpenStax::Content::Page) ? [ part ] : part.all_pages
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'nokogiri'
|
2
|
+
require 'ostruct'
|
2
3
|
require_relative 'fragment/reading'
|
3
4
|
require_relative 'custom_css'
|
4
5
|
|
@@ -76,7 +77,7 @@ class OpenStax::Content::FragmentSplitter
|
|
76
77
|
args = { node: node, labels: labels }
|
77
78
|
args[:reference_view_url] = reference_view_url \
|
78
79
|
if fragment_class.is_a? OpenStax::Content::Fragment::Reading
|
79
|
-
fragment = fragment_class.new args
|
80
|
+
fragment = fragment_class.new **args
|
80
81
|
fragment unless fragment.blank?
|
81
82
|
end
|
82
83
|
|
data/lib/openstax_content.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module OpenStax
|
2
2
|
module Content
|
3
3
|
class << self
|
4
|
-
attr_accessor :abl_url, :archive_path, :bucket_name, :domain, :exercises_search_api_url,
|
5
|
-
:
|
4
|
+
attr_accessor :abl_url, :archive_path, :bucket_name, :domain, :exercises_search_api_url, :logger, :s3_region,
|
5
|
+
:s3_access_key_id, :s3_secret_access_key
|
6
6
|
|
7
7
|
def configure
|
8
8
|
yield self
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openstax_content
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dante Soares
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-s3
|
@@ -183,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
183
183
|
- !ruby/object:Gem::Version
|
184
184
|
version: '0'
|
185
185
|
requirements: []
|
186
|
-
rubygems_version: 3.
|
186
|
+
rubygems_version: 3.5.21
|
187
187
|
signing_key:
|
188
188
|
specification_version: 4
|
189
189
|
summary: Ruby bindings to read and parse the OpenStax ABL and the content archive
|