openstax_cnx 0.1.0 → 0.1.1
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/.github/workflows/tests.yml +21 -0
- data/.gitignore +2 -0
- data/.travis.yml +2 -0
- data/README.md +9 -1
- data/lib/openstax/cnx/v1/book.rb +1 -1
- data/lib/openstax/cnx/v1/book_part.rb +12 -4
- data/lib/openstax/cnx/v1/element.rb +9 -0
- data/lib/openstax/cnx/v1/figure.rb +35 -0
- data/lib/openstax/cnx/v1/key_term.rb +32 -0
- data/lib/openstax/cnx/v1/page.rb +48 -0
- data/lib/openstax/cnx/v1/paragraph.rb +25 -0
- data/lib/openstax/cnx/v1.rb +7 -3
- data/lib/openstax/cnx/version.rb +1 -1
- data/openstax_cnx.gemspec +4 -3
- metadata +37 -20
- data/Gemfile.lock +0 -57
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9157ba0a43475c290a7dfb335ed33b03753b6be00a24af0897108ff376471e6c
|
|
4
|
+
data.tar.gz: b679d19ea1a362100847dbd59f409d11bd7fb612ec5a2f4b713b2af7fd9884b2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b27fd15c9f37a2b823940825f33b2d9c3c4c0e84fe7991541a60018ec36af69bd0b63c7a42557d5c4970a5d5d9ef27434d9d8fffcbe9ee7110fa4a3c4d8cc53a
|
|
7
|
+
data.tar.gz: 1c7c17740aecc143cd5bd757a2d97dd00172eff2a0c7ec0192da6f08d7269a81788f8a3cfed16527a6edf2f70fe92fc2ec057a8e660f759f44bc8fc014388590
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
tests:
|
|
11
|
+
timeout-minutes: 10
|
|
12
|
+
runs-on: ubuntu-24.04
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: ruby/setup-ruby@v1
|
|
17
|
+
with:
|
|
18
|
+
ruby-version: 3.1
|
|
19
|
+
bundler-cache: true
|
|
20
|
+
- name: Test
|
|
21
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# OpenStax::Cnx
|
|
2
2
|
|
|
3
|
+
[](https://travis-ci.org/openstax/cnx-ruby)
|
|
4
|
+
|
|
3
5
|
This gem provides a Ruby interface to OpenStax book content.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
@@ -36,7 +38,7 @@ Book
|
|
|
36
38
|
etc...
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
Some OpenStax books
|
|
41
|
+
Some OpenStax books organize chapters into units. The units are BookParts like the chapters are:
|
|
40
42
|
|
|
41
43
|
```
|
|
42
44
|
Book
|
|
@@ -70,6 +72,12 @@ book.baked # => "2019-03-20T14:24:26.164476-05:00"
|
|
|
70
72
|
book.url # => "https://archive.cnx.org/contents/031da8d3-b525-429c-80cf-6c8ed997733a"
|
|
71
73
|
```
|
|
72
74
|
|
|
75
|
+
To get all pages in a book:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
book.root_book_part.pages.count # => 460
|
|
79
|
+
```
|
|
80
|
+
|
|
73
81
|
To dig deeper, get the `root_book_part` and then is `parts`
|
|
74
82
|
|
|
75
83
|
```ruby
|
data/lib/openstax/cnx/v1/book.rb
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
module OpenStax::Cnx::V1
|
|
2
2
|
class BookPart
|
|
3
3
|
|
|
4
|
+
CONTENTS = 'contents'
|
|
5
|
+
|
|
6
|
+
attr_reader :hash, :is_root, :book
|
|
7
|
+
|
|
4
8
|
def initialize(hash: {}, is_root: false, book: nil)
|
|
5
9
|
@hash = hash
|
|
6
10
|
@is_root = is_root
|
|
7
11
|
@book = book
|
|
8
12
|
end
|
|
9
13
|
|
|
10
|
-
attr_reader :hash, :is_root, :book
|
|
11
|
-
|
|
12
14
|
def parsed_title
|
|
13
15
|
@parsed_title ||= OpenStax::Cnx::V1::Baked.parse_title(
|
|
14
16
|
hash.fetch('title') { |key| raise "#{self.class.name} id=#{@id} is missing #{key}" }
|
|
@@ -24,14 +26,14 @@ module OpenStax::Cnx::V1
|
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
def contents
|
|
27
|
-
@contents ||= hash.fetch(
|
|
29
|
+
@contents ||= hash.fetch(CONTENTS) do |key|
|
|
28
30
|
raise "#{self.class.name} id=#{@id} is missing #{key}"
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def parts
|
|
33
35
|
@parts ||= contents.map do |hash|
|
|
34
|
-
if hash.has_key?
|
|
36
|
+
if hash.has_key? CONTENTS
|
|
35
37
|
self.class.new(hash: hash, book: book)
|
|
36
38
|
else
|
|
37
39
|
OpenStax::Cnx::V1::Page.new(hash: hash, book: book)
|
|
@@ -44,5 +46,11 @@ module OpenStax::Cnx::V1
|
|
|
44
46
|
@is_chapter ||= parts.none? { |part| part.is_a?(self.class) }
|
|
45
47
|
end
|
|
46
48
|
|
|
49
|
+
def pages
|
|
50
|
+
@pages ||= parts.map do |part|
|
|
51
|
+
part.is_a?(Page) ? part : part.pages
|
|
52
|
+
end.flatten
|
|
53
|
+
end
|
|
54
|
+
|
|
47
55
|
end
|
|
48
56
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module OpenStax::Cnx::V1
|
|
2
|
+
class Figure < Element
|
|
3
|
+
MATCH_FIGURE = "//*[contains(@class, 'os-figure')]"
|
|
4
|
+
|
|
5
|
+
MATCH_FIGURE_CAPTION = ".//*[contains(@class, 'os-caption')]"
|
|
6
|
+
MATCH_FIGURE_ALT_TEXT = './/*[@alt]'
|
|
7
|
+
MATCH_FIGURE_DATA_ALT_TEXT = './/*[@data-alt]'
|
|
8
|
+
MATCH_FIGURE_ELEM = './/figure'
|
|
9
|
+
|
|
10
|
+
def initialize(node:)
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def caption
|
|
15
|
+
node.at_xpath(MATCH_FIGURE_CAPTION).try(:text)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def id
|
|
19
|
+
node.at_xpath(MATCH_FIGURE_ELEM).attr('id')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def alt_text
|
|
23
|
+
node.at_xpath(MATCH_FIGURE_ALT_TEXT).try(:attr, 'alt') ||
|
|
24
|
+
node.at_xpath(MATCH_FIGURE_DATA_ALT_TEXT).try(:attr, 'data-alt')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.matcher
|
|
28
|
+
MATCH_FIGURE
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.matches?(node)
|
|
32
|
+
node.matches?(MATCH_FIGURE)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module OpenStax::Cnx::V1
|
|
2
|
+
class KeyTerm < Element
|
|
3
|
+
MATCH_KEY_TERM = "//*[contains(@class, 'os-glossary-container')]//dl"
|
|
4
|
+
|
|
5
|
+
MATCH_KEY_TERM_TEXT = ".//dt"
|
|
6
|
+
MATCH_KEY_TERM_DESCRIPTION = ".//dd"
|
|
7
|
+
|
|
8
|
+
def initialize(node:)
|
|
9
|
+
super
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def description
|
|
13
|
+
node.xpath(MATCH_KEY_TERM_DESCRIPTION).text
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def id
|
|
17
|
+
node.attr('id')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def term
|
|
21
|
+
node.xpath(MATCH_KEY_TERM_TEXT).text
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.matcher
|
|
25
|
+
MATCH_KEY_TERM
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.matches?(node)
|
|
29
|
+
node.matches?(MATCH_KEY_TERM)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/openstax/cnx/v1/page.rb
CHANGED
|
@@ -67,6 +67,14 @@ module OpenStax::Cnx::V1
|
|
|
67
67
|
@is_intro = title.start_with?('Introduction')
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
def preface?
|
|
71
|
+
content_dom.xpath('boolean(//html/body/div[@data-type="page"][@class="preface"])')
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def index?
|
|
75
|
+
content_dom.xpath('boolean(//div[contains(@class,"os-index-container")])')
|
|
76
|
+
end
|
|
77
|
+
|
|
70
78
|
def full_hash
|
|
71
79
|
@full_hash ||= OpenStax::Cnx::V1.fetch(url)
|
|
72
80
|
end
|
|
@@ -161,8 +169,48 @@ module OpenStax::Cnx::V1
|
|
|
161
169
|
@tags.values
|
|
162
170
|
end
|
|
163
171
|
|
|
172
|
+
def remove_elements(xpath:)
|
|
173
|
+
content_dom.xpath(xpath).each do | xpath_element |
|
|
174
|
+
xpath_element.remove
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Pass the
|
|
179
|
+
#
|
|
180
|
+
# e.g.,
|
|
181
|
+
# element classes = [
|
|
182
|
+
# OpenStax::Cnx::V1::Figure,
|
|
183
|
+
# OpenStax::Cnx::V1::Paragraph,
|
|
184
|
+
# OpenStax::Cnx::V1::KeyTerm,
|
|
185
|
+
# ]
|
|
186
|
+
#
|
|
187
|
+
# you want to retrieve with the page
|
|
188
|
+
def elements(element_classes:)
|
|
189
|
+
# This join is important to OR together all the xpaths in order to determine
|
|
190
|
+
# the matched element's order inside the page. Xpath does this for us.
|
|
191
|
+
match_all_elements = element_classes.map(&:matcher).join(' | ')
|
|
192
|
+
|
|
193
|
+
working_element_index = []
|
|
194
|
+
|
|
195
|
+
# Match on all the elements. Create Element objects with the matching xpath node.
|
|
196
|
+
content_dom.xpath(match_all_elements).each do | xpath_element |
|
|
197
|
+
element_class = element_classes.detect do | elem_class |
|
|
198
|
+
elem_class.matches?(xpath_element)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
element = element_class.new(node: xpath_element)
|
|
202
|
+
working_element_index << element if element
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
working_element_index
|
|
206
|
+
end
|
|
207
|
+
|
|
164
208
|
protected
|
|
165
209
|
|
|
210
|
+
def content_dom
|
|
211
|
+
@content_dom ||= Nokogiri::HTML(content)
|
|
212
|
+
end
|
|
213
|
+
|
|
166
214
|
def url_for(path)
|
|
167
215
|
book.nil? ? OpenStax::Cnx::V1.archive_url_for(path) : "#{book.canonical_url}:#{path}"
|
|
168
216
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module OpenStax::Cnx::V1
|
|
2
|
+
class Paragraph < Element
|
|
3
|
+
MATCH_PARAGRAPH = '//p[@id]'
|
|
4
|
+
|
|
5
|
+
def initialize(node:)
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def text
|
|
10
|
+
node.text
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def id
|
|
14
|
+
node.attr('id')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.matcher
|
|
18
|
+
MATCH_PARAGRAPH
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.matches?(node)
|
|
22
|
+
node.matches?(MATCH_PARAGRAPH)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/openstax/cnx/v1.rb
CHANGED
|
@@ -8,6 +8,10 @@ require_relative './v1/http_error'
|
|
|
8
8
|
|
|
9
9
|
require_relative './v1/book'
|
|
10
10
|
require_relative './v1/book_part'
|
|
11
|
+
require_relative './v1/element'
|
|
12
|
+
require_relative './v1/figure'
|
|
13
|
+
require_relative './v1/key_term'
|
|
14
|
+
require_relative './v1/paragraph'
|
|
11
15
|
require_relative './v1/page'
|
|
12
16
|
require_relative './v1/baked'
|
|
13
17
|
|
|
@@ -117,7 +121,7 @@ module OpenStax::Cnx::V1
|
|
|
117
121
|
def fetch(url)
|
|
118
122
|
begin
|
|
119
123
|
OpenStax::Cnx::V1.logger.debug { "Fetching #{url}" }
|
|
120
|
-
data = JSON.parse open(url, 'ACCEPT' => 'text/json').read
|
|
124
|
+
data = JSON.parse URI.open(url, 'ACCEPT' => 'text/json').read
|
|
121
125
|
data.delete("history") if configuration.ignore_history
|
|
122
126
|
data
|
|
123
127
|
rescue OpenURI::HTTPError => exception
|
|
@@ -125,8 +129,8 @@ module OpenStax::Cnx::V1
|
|
|
125
129
|
end
|
|
126
130
|
end
|
|
127
131
|
|
|
128
|
-
def book(options
|
|
129
|
-
OpenStax::Cnx::V1::Book.new(options)
|
|
132
|
+
def book(**options)
|
|
133
|
+
OpenStax::Cnx::V1::Book.new(**options)
|
|
130
134
|
end
|
|
131
135
|
|
|
132
136
|
end
|
data/lib/openstax/cnx/version.rb
CHANGED
data/openstax_cnx.gemspec
CHANGED
|
@@ -37,10 +37,11 @@ Gem::Specification.new do |spec|
|
|
|
37
37
|
spec.require_paths = ["lib"]
|
|
38
38
|
|
|
39
39
|
spec.add_dependency "nokogiri"
|
|
40
|
+
spec.add_dependency "addressable"
|
|
40
41
|
|
|
41
|
-
spec.add_development_dependency "bundler"
|
|
42
|
-
spec.add_development_dependency "rake"
|
|
43
|
-
spec.add_development_dependency "rspec"
|
|
42
|
+
spec.add_development_dependency "bundler"
|
|
43
|
+
spec.add_development_dependency "rake"
|
|
44
|
+
spec.add_development_dependency "rspec"
|
|
44
45
|
spec.add_development_dependency "dotenv"
|
|
45
46
|
spec.add_development_dependency "webmock"
|
|
46
47
|
spec.add_development_dependency "vcr"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openstax_cnx
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- JP Slavinsky
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2025-10-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: nokogiri
|
|
@@ -24,48 +24,62 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: addressable
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: bundler
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
30
44
|
requirements:
|
|
31
|
-
- - "
|
|
45
|
+
- - ">="
|
|
32
46
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
47
|
+
version: '0'
|
|
34
48
|
type: :development
|
|
35
49
|
prerelease: false
|
|
36
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
51
|
requirements:
|
|
38
|
-
- - "
|
|
52
|
+
- - ">="
|
|
39
53
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
54
|
+
version: '0'
|
|
41
55
|
- !ruby/object:Gem::Dependency
|
|
42
56
|
name: rake
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
44
58
|
requirements:
|
|
45
|
-
- - "
|
|
59
|
+
- - ">="
|
|
46
60
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
61
|
+
version: '0'
|
|
48
62
|
type: :development
|
|
49
63
|
prerelease: false
|
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
65
|
requirements:
|
|
52
|
-
- - "
|
|
66
|
+
- - ">="
|
|
53
67
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
68
|
+
version: '0'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: rspec
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
58
72
|
requirements:
|
|
59
|
-
- - "
|
|
73
|
+
- - ">="
|
|
60
74
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
75
|
+
version: '0'
|
|
62
76
|
type: :development
|
|
63
77
|
prerelease: false
|
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
79
|
requirements:
|
|
66
|
-
- - "
|
|
80
|
+
- - ">="
|
|
67
81
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
82
|
+
version: '0'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
84
|
name: dotenv
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -129,12 +143,12 @@ executables: []
|
|
|
129
143
|
extensions: []
|
|
130
144
|
extra_rdoc_files: []
|
|
131
145
|
files:
|
|
146
|
+
- ".github/workflows/tests.yml"
|
|
132
147
|
- ".gitignore"
|
|
133
148
|
- ".rspec"
|
|
134
149
|
- ".travis.yml"
|
|
135
150
|
- CODE_OF_CONDUCT.md
|
|
136
151
|
- Gemfile
|
|
137
|
-
- Gemfile.lock
|
|
138
152
|
- LICENSE.txt
|
|
139
153
|
- README.md
|
|
140
154
|
- Rakefile
|
|
@@ -144,8 +158,12 @@ files:
|
|
|
144
158
|
- lib/openstax/cnx/v1/baked.rb
|
|
145
159
|
- lib/openstax/cnx/v1/book.rb
|
|
146
160
|
- lib/openstax/cnx/v1/book_part.rb
|
|
161
|
+
- lib/openstax/cnx/v1/element.rb
|
|
162
|
+
- lib/openstax/cnx/v1/figure.rb
|
|
147
163
|
- lib/openstax/cnx/v1/http_error.rb
|
|
164
|
+
- lib/openstax/cnx/v1/key_term.rb
|
|
148
165
|
- lib/openstax/cnx/v1/page.rb
|
|
166
|
+
- lib/openstax/cnx/v1/paragraph.rb
|
|
149
167
|
- lib/openstax/cnx/version.rb
|
|
150
168
|
- lib/openstax_cnx.rb
|
|
151
169
|
- openstax_cnx.gemspec
|
|
@@ -156,7 +174,7 @@ metadata:
|
|
|
156
174
|
allowed_push_host: https://rubygems.org
|
|
157
175
|
homepage_uri: https://github.com/openstax/cnx-ruby
|
|
158
176
|
source_code_uri: https://github.com/openstax/cnx-ruby
|
|
159
|
-
post_install_message:
|
|
177
|
+
post_install_message:
|
|
160
178
|
rdoc_options: []
|
|
161
179
|
require_paths:
|
|
162
180
|
- lib
|
|
@@ -171,9 +189,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
171
189
|
- !ruby/object:Gem::Version
|
|
172
190
|
version: '0'
|
|
173
191
|
requirements: []
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
signing_key:
|
|
192
|
+
rubygems_version: 3.5.21
|
|
193
|
+
signing_key:
|
|
177
194
|
specification_version: 4
|
|
178
195
|
summary: Bindings to fetch and inspect CNX books
|
|
179
196
|
test_files: []
|
data/Gemfile.lock
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
openstax_cnx (0.1.0)
|
|
5
|
-
nokogiri
|
|
6
|
-
|
|
7
|
-
GEM
|
|
8
|
-
remote: https://rubygems.org/
|
|
9
|
-
specs:
|
|
10
|
-
addressable (2.6.0)
|
|
11
|
-
public_suffix (>= 2.0.2, < 4.0)
|
|
12
|
-
byebug (11.0.1)
|
|
13
|
-
crack (0.4.3)
|
|
14
|
-
safe_yaml (~> 1.0.0)
|
|
15
|
-
diff-lcs (1.3)
|
|
16
|
-
dotenv (2.7.2)
|
|
17
|
-
hashdiff (0.3.8)
|
|
18
|
-
mini_portile2 (2.4.0)
|
|
19
|
-
nokogiri (1.10.2)
|
|
20
|
-
mini_portile2 (~> 2.4.0)
|
|
21
|
-
public_suffix (3.0.3)
|
|
22
|
-
rake (10.5.0)
|
|
23
|
-
rspec (3.8.0)
|
|
24
|
-
rspec-core (~> 3.8.0)
|
|
25
|
-
rspec-expectations (~> 3.8.0)
|
|
26
|
-
rspec-mocks (~> 3.8.0)
|
|
27
|
-
rspec-core (3.8.0)
|
|
28
|
-
rspec-support (~> 3.8.0)
|
|
29
|
-
rspec-expectations (3.8.2)
|
|
30
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
31
|
-
rspec-support (~> 3.8.0)
|
|
32
|
-
rspec-mocks (3.8.0)
|
|
33
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
|
34
|
-
rspec-support (~> 3.8.0)
|
|
35
|
-
rspec-support (3.8.0)
|
|
36
|
-
safe_yaml (1.0.5)
|
|
37
|
-
vcr (4.0.0)
|
|
38
|
-
webmock (3.5.1)
|
|
39
|
-
addressable (>= 2.3.6)
|
|
40
|
-
crack (>= 0.3.2)
|
|
41
|
-
hashdiff
|
|
42
|
-
|
|
43
|
-
PLATFORMS
|
|
44
|
-
ruby
|
|
45
|
-
|
|
46
|
-
DEPENDENCIES
|
|
47
|
-
bundler (~> 1.17)
|
|
48
|
-
byebug
|
|
49
|
-
dotenv
|
|
50
|
-
openstax_cnx!
|
|
51
|
-
rake (~> 10.0)
|
|
52
|
-
rspec (~> 3.0)
|
|
53
|
-
vcr
|
|
54
|
-
webmock
|
|
55
|
-
|
|
56
|
-
BUNDLED WITH
|
|
57
|
-
1.17.2
|