evergreen-ils 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.reek.yml +23 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/.tool-versions +1 -0
- data/Gemfile +28 -0
- data/Gemfile.lock +180 -0
- data/README.md +68 -0
- data/Rakefile +8 -0
- data/Steepfile +18 -0
- data/evergreen-ils.gemspec +38 -0
- data/lib/evergreen/bib_record.rb +41 -0
- data/lib/evergreen/configuration.rb +35 -0
- data/lib/evergreen/connection.rb +20 -0
- data/lib/evergreen/idl.rb +71 -0
- data/lib/evergreen/idl_object.rb +28 -0
- data/lib/evergreen/mixins/anonymous_pcrud.rb +22 -0
- data/lib/evergreen/mixins/retrieval_methods.rb +13 -0
- data/lib/evergreen/version.rb +5 -0
- data/lib/evergreen.rb +24 -0
- data/lib/opensrf/class_and_data.rb +28 -0
- data/lib/opensrf/http_translator_request.rb +53 -0
- data/sig/evergreen/configuration.rbs +22 -0
- data/sig/evergreen/connection.rbs +13 -0
- data/sig/evergreen/idl.rbs +31 -0
- data/sig/evergreen/idl_object.rbs +10 -0
- data/sig/evergreen/mixins/retrieval_methods.rb +9 -0
- data/sig/evergreen/version.rbs +6 -0
- data/sig/opensrf/class_and_data.rbs +12 -0
- data/sig/opensrf/http_translator_request.rbs +20 -0
- metadata +134 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d4a950c35117be9bb820cc29a6c51a7b6d617182cea54d5fc83449dd02654e13
|
4
|
+
data.tar.gz: 44124d0b23d86d2da8d60a5e169ead1d23ab98238cffd16e1be5dbb149350971
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6085835b66450141c9a330cc7b98f8e8e9b61e6d31779bcb4f0e974864a0a8942c78c5dc493c42216f8b827ad6559ac35bf286b3cdfd0fab5568fe9b04a5a402
|
7
|
+
data.tar.gz: 5ce0821e80d4ce4dd4d08c39685311a98edbe98edca5859724e4d5d589f8f3cbcf27ba1f51fdee503426eb42c8d33abfd705c23ffd87220a73e06583a95d47e3
|
data/.reek.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Auto generated by Reeks --todo flag
|
2
|
+
---
|
3
|
+
detectors:
|
4
|
+
Attribute:
|
5
|
+
exclude:
|
6
|
+
- Evergreen::Configuration#default_password
|
7
|
+
- Evergreen::Configuration#default_username
|
8
|
+
- Evergreen::Configuration#host
|
9
|
+
- Evergreen::Configuration#read_only
|
10
|
+
FeatureEnvy:
|
11
|
+
exclude:
|
12
|
+
- Evergreen::Configuration#field_is_empty
|
13
|
+
LongParameterList:
|
14
|
+
exclude:
|
15
|
+
- Evergreen::IDL::IDLSaxHandler#start_element
|
16
|
+
NilCheck:
|
17
|
+
exclude:
|
18
|
+
- Evergreen::Configuration#field_is_empty
|
19
|
+
UtilityFunction:
|
20
|
+
exclude:
|
21
|
+
- Evergreen#initialize
|
22
|
+
exclude_paths:
|
23
|
+
- spec
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 3.2.1
|
data/Gemfile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in evergreen-ils.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
gem 'rake'
|
9
|
+
|
10
|
+
group :test do
|
11
|
+
gem 'rspec'
|
12
|
+
gem 'webmock'
|
13
|
+
end
|
14
|
+
|
15
|
+
group :check do
|
16
|
+
gem 'flay'
|
17
|
+
gem 'flog'
|
18
|
+
gem 'rbs'
|
19
|
+
gem 'reek'
|
20
|
+
gem 'rubocop', require: false
|
21
|
+
gem 'rubocop-performance', require: false
|
22
|
+
gem 'rubocop-rspec', require: false
|
23
|
+
gem 'steep'
|
24
|
+
end
|
25
|
+
|
26
|
+
group :development do
|
27
|
+
gem 'debug'
|
28
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
evergreen-ils (0.2.0)
|
5
|
+
marc (>= 1.0.0, < 2.0)
|
6
|
+
rexml (>= 3.0.0, < 4.0)
|
7
|
+
zeitwerk (>= 2.0.0, < 3.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activesupport (7.0.6)
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
+
i18n (>= 1.6, < 2)
|
15
|
+
minitest (>= 5.1)
|
16
|
+
tzinfo (~> 2.0)
|
17
|
+
addressable (2.8.5)
|
18
|
+
public_suffix (>= 2.0.2, < 6.0)
|
19
|
+
ast (2.4.2)
|
20
|
+
concurrent-ruby (1.2.2)
|
21
|
+
crack (0.4.5)
|
22
|
+
rexml
|
23
|
+
csv (3.2.7)
|
24
|
+
debug (1.8.0)
|
25
|
+
irb (>= 1.5.0)
|
26
|
+
reline (>= 0.3.1)
|
27
|
+
diff-lcs (1.5.0)
|
28
|
+
erubi (1.12.0)
|
29
|
+
ffi (1.15.5)
|
30
|
+
ffi (1.15.5-java)
|
31
|
+
fileutils (1.7.1)
|
32
|
+
flay (2.13.1)
|
33
|
+
erubi (~> 1.10)
|
34
|
+
path_expander (~> 1.0)
|
35
|
+
ruby_parser (~> 3.0)
|
36
|
+
sexp_processor (~> 4.0)
|
37
|
+
flog (4.7.0)
|
38
|
+
path_expander (~> 1.0)
|
39
|
+
ruby_parser (~> 3.1, > 3.1.0)
|
40
|
+
sexp_processor (~> 4.8)
|
41
|
+
hashdiff (1.0.1)
|
42
|
+
i18n (1.14.1)
|
43
|
+
concurrent-ruby (~> 1.0)
|
44
|
+
io-console (0.6.0)
|
45
|
+
io-console (0.6.0-java)
|
46
|
+
irb (1.7.4)
|
47
|
+
reline (>= 0.3.6)
|
48
|
+
json (2.6.3)
|
49
|
+
json (2.6.3-java)
|
50
|
+
kwalify (0.7.2)
|
51
|
+
language_server-protocol (3.17.0.3)
|
52
|
+
listen (3.8.0)
|
53
|
+
rb-fsevent (~> 0.10, >= 0.10.3)
|
54
|
+
rb-inotify (~> 0.9, >= 0.9.10)
|
55
|
+
logger (1.5.3)
|
56
|
+
marc (1.2.0)
|
57
|
+
rexml
|
58
|
+
scrub_rb (>= 1.0.1, < 2)
|
59
|
+
unf
|
60
|
+
minitest (5.19.0)
|
61
|
+
parallel (1.23.0)
|
62
|
+
parser (3.2.2.3)
|
63
|
+
ast (~> 2.4.1)
|
64
|
+
racc
|
65
|
+
path_expander (1.1.1)
|
66
|
+
public_suffix (5.0.3)
|
67
|
+
racc (1.7.1)
|
68
|
+
racc (1.7.1-java)
|
69
|
+
rainbow (3.1.1)
|
70
|
+
rake (13.0.6)
|
71
|
+
rb-fsevent (0.11.2)
|
72
|
+
rb-inotify (0.10.1)
|
73
|
+
ffi (~> 1.0)
|
74
|
+
rbs (3.1.3)
|
75
|
+
reek (6.1.4)
|
76
|
+
kwalify (~> 0.7.0)
|
77
|
+
parser (~> 3.2.0)
|
78
|
+
rainbow (>= 2.0, < 4.0)
|
79
|
+
regexp_parser (2.8.1)
|
80
|
+
reline (0.3.7)
|
81
|
+
io-console (~> 0.5)
|
82
|
+
rexml (3.2.6)
|
83
|
+
rspec (3.12.0)
|
84
|
+
rspec-core (~> 3.12.0)
|
85
|
+
rspec-expectations (~> 3.12.0)
|
86
|
+
rspec-mocks (~> 3.12.0)
|
87
|
+
rspec-core (3.12.2)
|
88
|
+
rspec-support (~> 3.12.0)
|
89
|
+
rspec-expectations (3.12.3)
|
90
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
91
|
+
rspec-support (~> 3.12.0)
|
92
|
+
rspec-mocks (3.12.6)
|
93
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
94
|
+
rspec-support (~> 3.12.0)
|
95
|
+
rspec-support (3.12.1)
|
96
|
+
rubocop (1.55.1)
|
97
|
+
json (~> 2.3)
|
98
|
+
language_server-protocol (>= 3.17.0)
|
99
|
+
parallel (~> 1.10)
|
100
|
+
parser (>= 3.2.2.3)
|
101
|
+
rainbow (>= 2.2.2, < 4.0)
|
102
|
+
regexp_parser (>= 1.8, < 3.0)
|
103
|
+
rexml (>= 3.2.5, < 4.0)
|
104
|
+
rubocop-ast (>= 1.28.1, < 2.0)
|
105
|
+
ruby-progressbar (~> 1.7)
|
106
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
107
|
+
rubocop-ast (1.29.0)
|
108
|
+
parser (>= 3.2.1.0)
|
109
|
+
rubocop-capybara (2.18.0)
|
110
|
+
rubocop (~> 1.41)
|
111
|
+
rubocop-factory_bot (2.23.1)
|
112
|
+
rubocop (~> 1.33)
|
113
|
+
rubocop-performance (1.18.0)
|
114
|
+
rubocop (>= 1.7.0, < 2.0)
|
115
|
+
rubocop-ast (>= 0.4.0)
|
116
|
+
rubocop-rspec (2.23.1)
|
117
|
+
rubocop (~> 1.33)
|
118
|
+
rubocop-capybara (~> 2.17)
|
119
|
+
rubocop-factory_bot (~> 2.22)
|
120
|
+
ruby-progressbar (1.13.0)
|
121
|
+
ruby_parser (3.20.3)
|
122
|
+
sexp_processor (~> 4.16)
|
123
|
+
scrub_rb (1.0.1)
|
124
|
+
securerandom (0.2.2)
|
125
|
+
sexp_processor (4.17.0)
|
126
|
+
steep (1.5.2)
|
127
|
+
activesupport (>= 5.1)
|
128
|
+
concurrent-ruby (>= 1.1.10)
|
129
|
+
csv (>= 3.0.9)
|
130
|
+
fileutils (>= 1.1.0)
|
131
|
+
json (>= 2.1.0)
|
132
|
+
language_server-protocol (>= 3.15, < 4.0)
|
133
|
+
listen (~> 3.0)
|
134
|
+
logger (>= 1.3.0)
|
135
|
+
parser (>= 3.1)
|
136
|
+
rainbow (>= 2.2.2, < 4.0)
|
137
|
+
rbs (>= 3.1.0)
|
138
|
+
securerandom (>= 0.1)
|
139
|
+
strscan (>= 1.0.0)
|
140
|
+
terminal-table (>= 2, < 4)
|
141
|
+
strscan (3.0.6)
|
142
|
+
strscan (3.0.6-java)
|
143
|
+
terminal-table (3.0.2)
|
144
|
+
unicode-display_width (>= 1.1.1, < 3)
|
145
|
+
tzinfo (2.0.6)
|
146
|
+
concurrent-ruby (~> 1.0)
|
147
|
+
unf (0.1.4)
|
148
|
+
unf_ext
|
149
|
+
unf (0.1.4-java)
|
150
|
+
unf_ext (0.0.8.2)
|
151
|
+
unicode-display_width (2.4.2)
|
152
|
+
webmock (3.18.1)
|
153
|
+
addressable (>= 2.8.0)
|
154
|
+
crack (>= 0.3.2)
|
155
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
156
|
+
zeitwerk (2.6.11)
|
157
|
+
|
158
|
+
PLATFORMS
|
159
|
+
arm64-darwin-21
|
160
|
+
arm64-darwin-22
|
161
|
+
universal-java-11
|
162
|
+
x86_64-linux
|
163
|
+
|
164
|
+
DEPENDENCIES
|
165
|
+
debug
|
166
|
+
evergreen-ils!
|
167
|
+
flay
|
168
|
+
flog
|
169
|
+
rake
|
170
|
+
rbs
|
171
|
+
reek
|
172
|
+
rspec
|
173
|
+
rubocop
|
174
|
+
rubocop-performance
|
175
|
+
rubocop-rspec
|
176
|
+
steep
|
177
|
+
webmock
|
178
|
+
|
179
|
+
BUNDLED WITH
|
180
|
+
2.4.6
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Evergreen
|
2
|
+
|
3
|
+
A gem for interacting with [Evergreen ILS](https://evergreen-ils.org)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Install the gem and add to the application's Gemfile by executing:
|
8
|
+
|
9
|
+
$ bundle add evergreen-ils
|
10
|
+
|
11
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
12
|
+
|
13
|
+
$ gem install evergreen-ils
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
### Configuration
|
18
|
+
|
19
|
+
Configure your `Evergreen` object with a hostname, and any other relevant
|
20
|
+
options. If using Rails, you might create an Evergreen service:
|
21
|
+
|
22
|
+
```
|
23
|
+
class EvergreenService
|
24
|
+
attr_reader :evergreen
|
25
|
+
def initialize
|
26
|
+
@evergreen ||= Evergreen.new do |config|
|
27
|
+
config.host = 'my.evergreen.server'
|
28
|
+
config.default_username = 'user1'
|
29
|
+
config.default_username = ENV['my_pass']
|
30
|
+
config.read_only = false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
You can then access those configurations in your app at
|
37
|
+
`service.evergreen.configuration.host`.
|
38
|
+
|
39
|
+
### Retrieving objects
|
40
|
+
|
41
|
+
Once you have an object:
|
42
|
+
|
43
|
+
```
|
44
|
+
Evergreen.new(host: 'my.evergreen.server') do |evergreen|
|
45
|
+
bib = evergreen.get_bib_record(123)
|
46
|
+
bib.to_marc
|
47
|
+
evergreen.get_item(345)
|
48
|
+
evergreen.get_call_number(2345)
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
|
53
|
+
## Development
|
54
|
+
|
55
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
56
|
+
|
57
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
58
|
+
|
59
|
+
## Goals
|
60
|
+
|
61
|
+
The priorities here are:
|
62
|
+
* Thread safety
|
63
|
+
* Good documentation
|
64
|
+
* Good tests
|
65
|
+
|
66
|
+
## Contributing
|
67
|
+
|
68
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/sandbergja/evergreen-rb.
|
data/Rakefile
ADDED
data/Steepfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# D = Steep::Diagnostic
|
4
|
+
#
|
5
|
+
target :lib do
|
6
|
+
signature 'sig'
|
7
|
+
|
8
|
+
check 'lib'
|
9
|
+
|
10
|
+
library 'json', 'net-http', 'uri'
|
11
|
+
|
12
|
+
ignore 'lib/evergreen.rb'
|
13
|
+
ignore 'lib/evergreen/bib_record.rb'
|
14
|
+
ignore 'lib/evergreen/connection.rb'
|
15
|
+
ignore 'lib/evergreen/idl.rb'
|
16
|
+
ignore 'lib/evergreen/mixins'
|
17
|
+
ignore 'lib/opensrf/http_translator_request.rb'
|
18
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/evergreen/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'evergreen-ils'
|
7
|
+
spec.version = Evergreen::VERSION
|
8
|
+
spec.authors = ['Jane Sandberg']
|
9
|
+
spec.email = ['sandbergja@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = 'Evergreen ILS'
|
12
|
+
spec.description = 'A gem for interacting with the Evergreen Integrated Library System'
|
13
|
+
spec.homepage = 'https://github.com/sandbergja/evergreen-rb'
|
14
|
+
spec.required_ruby_version = '>= 3.0.0'
|
15
|
+
|
16
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
17
|
+
spec.metadata['source_code_uri'] = 'https://github.com/sandbergja/evergreen-rb'
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = Dir.chdir(__dir__) do
|
22
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
23
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
# Uncomment to register a new dependency of your gem
|
31
|
+
spec.add_dependency 'marc', '>= 1.0.0', '< 2.0'
|
32
|
+
spec.add_dependency 'rexml', '>= 3.0.0', '< 4.0'
|
33
|
+
spec.add_dependency 'zeitwerk', '>= 2.0.0', '< 3.0'
|
34
|
+
|
35
|
+
# For more information and examples about making a new gem, check out our
|
36
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
37
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'marc'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
class Evergreen
|
7
|
+
# A bibliographic record (title)
|
8
|
+
class BibRecord < IDLObject
|
9
|
+
include Mixins::AnonymousPcrud
|
10
|
+
def initialize(id:, configuration:, idl:)
|
11
|
+
@id = id
|
12
|
+
@configuration = configuration
|
13
|
+
super(idl)
|
14
|
+
end
|
15
|
+
|
16
|
+
# rubocop:disable Naming/MemoizedInstanceVariableName
|
17
|
+
def to_marc
|
18
|
+
@marc ||= MARC::XMLReader.new(StringIO.new(get('marc'))).first
|
19
|
+
end
|
20
|
+
# rubocop:enable Naming/MemoizedInstanceVariableName
|
21
|
+
|
22
|
+
def holdings
|
23
|
+
payload = OpenSRF::ClassAndData.new(klass: 'osrfMessage', data: {
|
24
|
+
'method' => 'open-ils.cat.asset.copy_tree.global.retrieve',
|
25
|
+
'params' => ['', @id.to_s]
|
26
|
+
}).to_h
|
27
|
+
OpenSRF::HTTPTranslatorRequest.new(payload: payload, configuration: @configuration,
|
28
|
+
service: 'open-ils.cat').response
|
29
|
+
end
|
30
|
+
|
31
|
+
def tcn
|
32
|
+
get 'tcn_value'
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def idl_class
|
38
|
+
'bre'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Evergreen
|
4
|
+
# Configuration for an instance of Evergreen
|
5
|
+
class Configuration
|
6
|
+
attr_reader :host, :default_username, :default_password, :read_only
|
7
|
+
|
8
|
+
def initialize(config_hash)
|
9
|
+
@read_only = true
|
10
|
+
config_hash.each_pair do |key, value|
|
11
|
+
instance_variable_set("@#{key}", value)
|
12
|
+
end
|
13
|
+
configuration_complete
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def configuration_complete
|
19
|
+
check_required_fields
|
20
|
+
freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_required_fields
|
24
|
+
raise ArgumentError, 'you must supply a host' if field_is_empty :host
|
25
|
+
return unless !@read_only && (field_is_empty(:default_username) || field_is_empty(:default_password))
|
26
|
+
|
27
|
+
raise ArgumentError, 'you must supply default credentials unless you are in read-only mode'
|
28
|
+
end
|
29
|
+
|
30
|
+
def field_is_empty(field_name)
|
31
|
+
field_value = instance_variable_get("@#{field_name}")
|
32
|
+
field_value.nil? || field_value.empty?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Evergreen
|
4
|
+
# This class provides an interface for making
|
5
|
+
# requests to the Evergreen server
|
6
|
+
class Connection
|
7
|
+
include Mixins::RetrievalMethods
|
8
|
+
attr_reader :configuration
|
9
|
+
|
10
|
+
def initialize(configuration:)
|
11
|
+
@configuration = configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
def close; end
|
15
|
+
|
16
|
+
def idl
|
17
|
+
@idl ||= IDL.new(@configuration)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'open-uri'
|
4
|
+
require 'rexml/parsers/sax2parser'
|
5
|
+
require 'rexml/sax2listener'
|
6
|
+
|
7
|
+
class Evergreen
|
8
|
+
# Evergreen's fieldmapper IDL
|
9
|
+
class IDL
|
10
|
+
attr_reader :fields
|
11
|
+
|
12
|
+
def initialize(configuration)
|
13
|
+
@configuration = configuration
|
14
|
+
@handler = IDLSaxHandler.new
|
15
|
+
fetch
|
16
|
+
freeze
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
fields[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def fetch
|
26
|
+
URI.open("https://#{@configuration.host}/reports/fm_IDL.xml") do |file|
|
27
|
+
@fields = IDLSaxParser.new(file).parse
|
28
|
+
end
|
29
|
+
rescue Errno::ECONNREFUSED, OpenURI::HTTPError
|
30
|
+
raise Evergreen::ConnectionError
|
31
|
+
end
|
32
|
+
|
33
|
+
# A wrapper around the SAX parser
|
34
|
+
class IDLSaxParser
|
35
|
+
def initialize(file)
|
36
|
+
@parser = REXML::Parsers::SAX2Parser.new(file)
|
37
|
+
@handler = IDLSaxHandler.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def parse
|
41
|
+
@parser.listen(@handler)
|
42
|
+
@parser.parse
|
43
|
+
@handler.idl_fields
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# A SAX parsing handler
|
48
|
+
class IDLSaxHandler
|
49
|
+
include REXML::SAX2Listener
|
50
|
+
attr_reader :idl_fields
|
51
|
+
|
52
|
+
def initialize
|
53
|
+
@idl_fields = {}
|
54
|
+
@current_class = nil
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
# Callback for when we hit an XML attribute
|
59
|
+
def start_element(_uri, _localname, _qname, attributes)
|
60
|
+
if attributes.key? 'id'
|
61
|
+
# We found a class ID!
|
62
|
+
@current_class = attributes['id']
|
63
|
+
@idl_fields[@current_class] = []
|
64
|
+
elsif attributes.key? 'name'
|
65
|
+
# We found the name of a field!
|
66
|
+
@idl_fields[@current_class].push(attributes['name'])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Evergreen
|
4
|
+
# A base class for any object represented in
|
5
|
+
# Evergreen's IDL
|
6
|
+
class IDLObject
|
7
|
+
def initialize(idl)
|
8
|
+
@idl = idl
|
9
|
+
end
|
10
|
+
|
11
|
+
def idl_fields
|
12
|
+
@idl[idl_class]
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(field_name)
|
16
|
+
data[idl_fields.index(field_name)]
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# This should be overriden by subclasses
|
22
|
+
def idl_class
|
23
|
+
'acp'
|
24
|
+
end
|
25
|
+
|
26
|
+
def data; end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Evergreen
|
4
|
+
module Mixins
|
5
|
+
# This read-only API is available
|
6
|
+
# without any credentials
|
7
|
+
module AnonymousPcrud
|
8
|
+
def data
|
9
|
+
return @data if @data
|
10
|
+
return unless @id && @configuration && idl_class && idl_fields
|
11
|
+
|
12
|
+
payload = OpenSRF::ClassAndData.new(klass: 'osrfMessage', data: {
|
13
|
+
'method' => "open-ils.pcrud.retrieve.#{idl_class}",
|
14
|
+
'params' => ['ANONYMOUS', @id.to_s]
|
15
|
+
}).to_h
|
16
|
+
response = OpenSRF::HTTPTranslatorRequest.new(payload: payload, configuration: @configuration,
|
17
|
+
service: 'open-ils.pcrud').response
|
18
|
+
@data = OpenSRF::ClassAndData.parse(response['content']).data
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Evergreen
|
4
|
+
module Mixins
|
5
|
+
# Convenience methods to search for data
|
6
|
+
# and initialize objects based on the results
|
7
|
+
module RetrievalMethods
|
8
|
+
def get_bib_record(id)
|
9
|
+
Evergreen::BibRecord.new(id: id, configuration: configuration, idl: idl)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/evergreen.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'zeitwerk'
|
4
|
+
loader = Zeitwerk::Loader.for_gem
|
5
|
+
loader.inflector.inflect(
|
6
|
+
'http_translator_request' => 'HTTPTranslatorRequest',
|
7
|
+
'idl' => 'IDL',
|
8
|
+
'idl_object' => 'IDLObject',
|
9
|
+
'opensrf' => 'OpenSRF',
|
10
|
+
'json' => 'JSON'
|
11
|
+
)
|
12
|
+
loader.setup
|
13
|
+
|
14
|
+
# The main class provided by this gem
|
15
|
+
class Evergreen
|
16
|
+
def initialize(config_hash)
|
17
|
+
connection = Connection.new(configuration: Configuration.new(config_hash))
|
18
|
+
yield connection
|
19
|
+
connection.close
|
20
|
+
end
|
21
|
+
|
22
|
+
# An error when we can't connect to the Evergreen server
|
23
|
+
class ConnectionError < StandardError; end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OpenSRF
|
4
|
+
# OpenSRF requests and responses often
|
5
|
+
# take the following form
|
6
|
+
# {"__c": "clasname", "__p": ["all", "the", "data"]}
|
7
|
+
class ClassAndData
|
8
|
+
attr_reader :klass, :data
|
9
|
+
|
10
|
+
def initialize(klass:, data:)
|
11
|
+
@klass = klass
|
12
|
+
@data = data
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parse(hash, path = [])
|
16
|
+
small_json = new(klass: hash['__c'], data: hash['__p'])
|
17
|
+
return small_json if path.empty?
|
18
|
+
|
19
|
+
key = path.shift
|
20
|
+
parse(small_json.data[key], path)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_h
|
24
|
+
{ '__c' => @klass,
|
25
|
+
'__p' => @data }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module OpenSRF
|
8
|
+
# A stateful endpoint, described in
|
9
|
+
# this documentation:
|
10
|
+
# https://docs.evergreen-ils.org/eg/docs/latest/integrations/web_services.html#_http_translator
|
11
|
+
class HTTPTranslatorRequest
|
12
|
+
def initialize(configuration:, service:, payload:)
|
13
|
+
@configuration = configuration
|
14
|
+
@service = service
|
15
|
+
@payload = payload
|
16
|
+
end
|
17
|
+
|
18
|
+
def response
|
19
|
+
raw = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
|
20
|
+
http.request(request)
|
21
|
+
end
|
22
|
+
OpenSRF::ClassAndData.parse(::JSON.parse(raw.body).first, ['payload']).data
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def request
|
28
|
+
request = Net::HTTP::Post.new(uri)
|
29
|
+
request['X-Opensrf-Service'] = @service
|
30
|
+
request.body = "osrf-msg=#{osrf_message.to_json}"
|
31
|
+
request
|
32
|
+
end
|
33
|
+
|
34
|
+
def osrf_message
|
35
|
+
[
|
36
|
+
OpenSRF::ClassAndData.new(klass: 'osrfMessage', data: {
|
37
|
+
'threadTrace' => 0,
|
38
|
+
'locale' => 'en-CA',
|
39
|
+
'type' => 'REQUEST',
|
40
|
+
'payload' => @payload
|
41
|
+
}).to_h
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
def req_options
|
46
|
+
{ use_ssl: true }
|
47
|
+
end
|
48
|
+
|
49
|
+
def uri
|
50
|
+
URI.parse("https://#{@configuration.host}/osrf-http-translator")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Evergreen
|
2
|
+
# Configuration for an instance of Evergreen
|
3
|
+
class Configuration
|
4
|
+
attr_accessor host: untyped
|
5
|
+
|
6
|
+
attr_accessor default_username: untyped
|
7
|
+
|
8
|
+
attr_accessor default_password: untyped
|
9
|
+
|
10
|
+
attr_accessor read_only: untyped
|
11
|
+
|
12
|
+
def initialize: (Hash[Symbol, (String | bool)]) -> void
|
13
|
+
|
14
|
+
def configuration_complete: () -> untyped
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def check_required_fields: () -> (nil | untyped)
|
19
|
+
|
20
|
+
def field_is_empty: (untyped field_name) -> untyped
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Evergreen
|
2
|
+
# This class provides an interface for making
|
3
|
+
# requests to the Evergreen server
|
4
|
+
class Connection
|
5
|
+
attr_reader configuration: Evergreen::Configuration
|
6
|
+
|
7
|
+
def initialize: (configuration: untyped) -> void
|
8
|
+
|
9
|
+
def close: () -> nil
|
10
|
+
|
11
|
+
def idl: () -> Evergreen::IDL
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class Evergreen
|
2
|
+
# Evergreen's fieldmapper IDL
|
3
|
+
class IDL
|
4
|
+
attr_reader fields: untyped
|
5
|
+
|
6
|
+
def initialize: (untyped configuration) -> void
|
7
|
+
|
8
|
+
def []: (untyped key) -> untyped
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def fetch: () -> untyped
|
13
|
+
|
14
|
+
# A wrapper around the SAX parser
|
15
|
+
class IDLSaxParser
|
16
|
+
def initialize: (untyped file) -> void
|
17
|
+
|
18
|
+
def parse: () -> untyped
|
19
|
+
end
|
20
|
+
|
21
|
+
# A SAX parsing handler
|
22
|
+
class IDLSaxHandler
|
23
|
+
attr_reader idl_fields: untyped
|
24
|
+
|
25
|
+
def initialize: () -> void
|
26
|
+
|
27
|
+
# Callback for when we hit an XML attribute
|
28
|
+
def start_element: (untyped _uri, untyped _localname, untyped _qname, untyped attributes) -> (untyped | untyped | nil)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# TypeProf 0.21.2
|
2
|
+
|
3
|
+
# Classes
|
4
|
+
module OpenSRF
|
5
|
+
class ClassAndData
|
6
|
+
attr_reader klass: untyped
|
7
|
+
attr_reader data: untyped
|
8
|
+
def initialize: (klass: untyped, data: untyped) -> void
|
9
|
+
def self.parse: (untyped hash, ?Array[untyped] path) -> ClassAndData
|
10
|
+
def to_h: -> Hash[String, untyped]
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module OpenSRF
|
2
|
+
# A stateful endpoint, described in
|
3
|
+
# this documentation:
|
4
|
+
# https://docs.evergreen-ils.org/eg/docs/latest/integrations/web_services.html#_http_translator
|
5
|
+
class HTTPTranslatorRequest
|
6
|
+
def initialize: (configuration: untyped, service: untyped, payload: untyped) -> void
|
7
|
+
|
8
|
+
def response: () -> untyped
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def request: () -> untyped
|
13
|
+
|
14
|
+
def osrf_message: () -> ::Array[untyped]
|
15
|
+
|
16
|
+
def req_options: () -> { use_ssl: true }
|
17
|
+
|
18
|
+
def uri: () -> untyped
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: evergreen-ils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jane Sandberg
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-08-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: marc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '2.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.0.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '2.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rexml
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 3.0.0
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '4.0'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 3.0.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '4.0'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: zeitwerk
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 2.0.0
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '3.0'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.0.0
|
70
|
+
- - "<"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '3.0'
|
73
|
+
description: A gem for interacting with the Evergreen Integrated Library System
|
74
|
+
email:
|
75
|
+
- sandbergja@gmail.com
|
76
|
+
executables: []
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- ".reek.yml"
|
81
|
+
- ".rspec"
|
82
|
+
- ".rubocop.yml"
|
83
|
+
- ".tool-versions"
|
84
|
+
- Gemfile
|
85
|
+
- Gemfile.lock
|
86
|
+
- README.md
|
87
|
+
- Rakefile
|
88
|
+
- Steepfile
|
89
|
+
- evergreen-ils.gemspec
|
90
|
+
- lib/evergreen.rb
|
91
|
+
- lib/evergreen/bib_record.rb
|
92
|
+
- lib/evergreen/configuration.rb
|
93
|
+
- lib/evergreen/connection.rb
|
94
|
+
- lib/evergreen/idl.rb
|
95
|
+
- lib/evergreen/idl_object.rb
|
96
|
+
- lib/evergreen/mixins/anonymous_pcrud.rb
|
97
|
+
- lib/evergreen/mixins/retrieval_methods.rb
|
98
|
+
- lib/evergreen/version.rb
|
99
|
+
- lib/opensrf/class_and_data.rb
|
100
|
+
- lib/opensrf/http_translator_request.rb
|
101
|
+
- sig/evergreen/configuration.rbs
|
102
|
+
- sig/evergreen/connection.rbs
|
103
|
+
- sig/evergreen/idl.rbs
|
104
|
+
- sig/evergreen/idl_object.rbs
|
105
|
+
- sig/evergreen/mixins/retrieval_methods.rb
|
106
|
+
- sig/evergreen/version.rbs
|
107
|
+
- sig/opensrf/class_and_data.rbs
|
108
|
+
- sig/opensrf/http_translator_request.rbs
|
109
|
+
homepage: https://github.com/sandbergja/evergreen-rb
|
110
|
+
licenses: []
|
111
|
+
metadata:
|
112
|
+
homepage_uri: https://github.com/sandbergja/evergreen-rb
|
113
|
+
source_code_uri: https://github.com/sandbergja/evergreen-rb
|
114
|
+
rubygems_mfa_required: 'true'
|
115
|
+
post_install_message:
|
116
|
+
rdoc_options: []
|
117
|
+
require_paths:
|
118
|
+
- lib
|
119
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 3.0.0
|
124
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - ">="
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
requirements: []
|
130
|
+
rubygems_version: 3.4.6
|
131
|
+
signing_key:
|
132
|
+
specification_version: 4
|
133
|
+
summary: Evergreen ILS
|
134
|
+
test_files: []
|