glibrary 0.0.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 +7 -0
- data/bin/glibrary +120 -0
- data/classes/book_search.rb +101 -0
- data/classes/user_book.rb +42 -0
- data/classes/user_library.rb +95 -0
- data/common/api_query.rb +22 -0
- data/common/errors.rb +8 -0
- data/common/google_api_url.rb +1 -0
- data/common/search_error.rb +2 -0
- data/glibrary.rb +120 -0
- metadata +52 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3ebb0b283f8a02d344327ef0ddb6bb19bfb5e180aecb45403a21a08e182fc42b
|
4
|
+
data.tar.gz: a388772cb5f7b81ff05d08efd9ebbdde68114040076054a76268ad6ea879ea72
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d305157edaf5fe228fc2c7134359d15057b8086404899619400177c06900dc0edd389ef1b3fc11c48dfb459f1c99f86079cb25a5ef718a8633cfb0d26738e566
|
7
|
+
data.tar.gz: 9bd4b1599e77b79ce5f4563776ad15ff1f0a01f93058ec4d20907de61aaf40de11d1c4b1b5c1fb98c125c81902fc72cef44ee32bd143441936b80c0d75a505eb
|
data/bin/glibrary
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'json'
|
3
|
+
require 'optparse'
|
4
|
+
require 'io/console'
|
5
|
+
|
6
|
+
require_relative '../common/api_query'
|
7
|
+
require_relative '../common/google_api_url'
|
8
|
+
require_relative '../classes/book_search'
|
9
|
+
require_relative '../classes/user_book'
|
10
|
+
require_relative '../classes/user_library'
|
11
|
+
require_relative '../common/errors'
|
12
|
+
|
13
|
+
ARGV << '-h' if ARGV.empty?
|
14
|
+
|
15
|
+
#make sure the -l flag is process *after* the -f flag, by putting it at the end
|
16
|
+
ARGV << ARGV.delete("-l") if ARGV.include?("-l")
|
17
|
+
|
18
|
+
#default filename for saved reading list
|
19
|
+
filename = File.dirname(File.expand_path(__FILE__)) + "/saved_libraries/library.json"
|
20
|
+
|
21
|
+
#initialize the hash which will hold the search parameters
|
22
|
+
o = {}
|
23
|
+
|
24
|
+
#parse the command-line options
|
25
|
+
OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: ruby g_library.rb [options...] [query]"
|
27
|
+
#sets 'library-mode'
|
28
|
+
library = opts.default_argv.include?("-l")
|
29
|
+
|
30
|
+
opts.on("-t", "--title=TITLE", "Specify a title keyword") do |t|
|
31
|
+
o[:title] = t
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-a", "--author=AUTHOR", "Specify an author keyword") do |a|
|
35
|
+
o[:author] = a
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("-p", "--publisher=PUBLISHER", "Specify a publisher keyword") do |p|
|
39
|
+
o[:publisher] = p
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on("-f", "--lib-file=LIBFILE", "Select a library save file") do |libfile|
|
43
|
+
filename = File.absolute_path(libfile)
|
44
|
+
unless File.exist?(filename)
|
45
|
+
(puts "Library file not found, cannot display."; exit) if library
|
46
|
+
puts "Creating new file"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on("-l", "--library", "See your library; ignores all search options
|
51
|
+
\t\t\t\t\tdefault library file is [repository_root]/saved_libraries/library.json") do
|
52
|
+
|
53
|
+
#substitute \ for / if the machine is running windows
|
54
|
+
filename.gsub!(/\//, '\\') if ENV.values.any? { |v| v =~ /[A-Z]:\\Windows/i }
|
55
|
+
|
56
|
+
|
57
|
+
#print out the library and exit the program
|
58
|
+
l = UserLibrary.new(filename)
|
59
|
+
l.pretty_print
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-h", "--help", "Prints this help") do
|
64
|
+
puts ""
|
65
|
+
puts opts
|
66
|
+
puts "[query]: all other arguments will be treated as general search keywords"
|
67
|
+
puts ""
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
end.parse!
|
72
|
+
|
73
|
+
#substitute \ for / if the machine is running windows
|
74
|
+
filename.gsub!(/\//, '\\') if ENV.values.any? { |v| v =~ /C:\\Windows/i }
|
75
|
+
|
76
|
+
# Create or load the library, depending on whether or not the file already exists.
|
77
|
+
l = UserLibrary.new(filename)
|
78
|
+
|
79
|
+
#initialize the
|
80
|
+
#perform the search, and display the results.
|
81
|
+
begin
|
82
|
+
s = BookSearch.new(search: ARGV.join('+'), title: o[:title], author: o[:author], publisher: o[:publisher])
|
83
|
+
|
84
|
+
#see BookSearch definition in classes/book_search.rb
|
85
|
+
#the each method (and all Enumerable methods, like map) only operate on
|
86
|
+
#the first five matches.
|
87
|
+
books = s.map { |info| UserBook.new(info) }
|
88
|
+
|
89
|
+
#print the resuls
|
90
|
+
puts ""
|
91
|
+
books.each_with_index do |b, i|
|
92
|
+
keys = %w[title author publisher]
|
93
|
+
n = i+1
|
94
|
+
puts "-"*5 + "Match ##{n}" + "-"*5
|
95
|
+
keys.each do |k|
|
96
|
+
puts "%s: %s" % [k.capitalize, b[k]]
|
97
|
+
end
|
98
|
+
puts ""
|
99
|
+
end
|
100
|
+
|
101
|
+
print "Enter a number (1-5) to add a book to your reading list:\n(or any other key to quit)\n"
|
102
|
+
|
103
|
+
selection = STDIN.getch.chomp.to_i
|
104
|
+
i = selection - 1
|
105
|
+
puts ""
|
106
|
+
exit if i < 0 or i > 4
|
107
|
+
|
108
|
+
#add a book to the user's library
|
109
|
+
l << books[i]
|
110
|
+
l.save
|
111
|
+
|
112
|
+
rescue SearchError
|
113
|
+
puts "\nThere was an error with your query; be careful to format it well"
|
114
|
+
puts ""
|
115
|
+
exit
|
116
|
+
rescue NoResults
|
117
|
+
puts "\nNo results."
|
118
|
+
puts ""
|
119
|
+
exit
|
120
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative '../common/api_query'
|
3
|
+
require_relative '../common/google_api_url'
|
4
|
+
require_relative '../common/errors'
|
5
|
+
|
6
|
+
class BookSearch
|
7
|
+
include ApiQuery
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
attr_reader :selected_results, :full_results, :url
|
11
|
+
|
12
|
+
def initialize(args)
|
13
|
+
@args = args.dup
|
14
|
+
|
15
|
+
#the number of results to show:
|
16
|
+
num_results = @args.delete(:num) || 5
|
17
|
+
|
18
|
+
#make sure at least one argument is searchable
|
19
|
+
raise ArgumentError unless @args.keys.any? do |k|
|
20
|
+
%i[search title author publisher subject isbn lccn oclc].include?(k)
|
21
|
+
end
|
22
|
+
|
23
|
+
#map the keys and values to strings for ease of manipulation
|
24
|
+
@args = @args.map { |k, v| [k,v].map(&:to_s) }.to_h
|
25
|
+
#remove any empty values (nil values were converted to
|
26
|
+
#empty strings by the last operation)
|
27
|
+
@args = @args.reject { |k, v| v.empty? }.to_h
|
28
|
+
|
29
|
+
#get a nicely formatted url; very important
|
30
|
+
@url = make_url
|
31
|
+
|
32
|
+
#check for successful response from the API
|
33
|
+
response = get_response(url)
|
34
|
+
raise SearchError unless response.code == "200"
|
35
|
+
|
36
|
+
#Puts the results into a hash
|
37
|
+
@full_results = JSON.parse(response.body)
|
38
|
+
|
39
|
+
num = full_results['totalItems']
|
40
|
+
raise NoResults unless num > 0
|
41
|
+
|
42
|
+
#the selected results:
|
43
|
+
@selected_results = full_results['items'].first(num_results)
|
44
|
+
#The following mapping gets the 'volumeInfo' property from the results,
|
45
|
+
#and adds the 'id' property.
|
46
|
+
@selected_results = @selected_results.map { |res| format_hash res }
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
#Only five results are iterated over; This behavior is easily changed by either
|
51
|
+
#passing a :num value when initializing a BookSearch, or by using full_results
|
52
|
+
#below, instead of selected_results
|
53
|
+
def each
|
54
|
+
return to_enum :each unless block_given?
|
55
|
+
selected_results.each { |r| yield(r) }
|
56
|
+
end
|
57
|
+
|
58
|
+
#Likewise, only five results are accessible here; see the previous note.
|
59
|
+
def [](index)
|
60
|
+
selected_results[index]
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_json
|
64
|
+
JSON.pretty_generate(selected_results)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def make_url_arg_list
|
70
|
+
url = ["?q="]
|
71
|
+
|
72
|
+
q = @args.delete('search')
|
73
|
+
url << q.to_s
|
74
|
+
|
75
|
+
url << @args.map do |k,v|
|
76
|
+
k = ("in" + k) if %w[title author publisher].include?(k)
|
77
|
+
"%s:%s" % [k, v]
|
78
|
+
end
|
79
|
+
|
80
|
+
url.reject!(&:empty?)
|
81
|
+
url[0] + url[1, url.length-1].join("+")
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
#gets the 'volumeInfo' property from the results, and adds the 'id' property.
|
86
|
+
def format_hash(hash)
|
87
|
+
hash['volumeInfo'].merge( { 'id' => hash['id'] } )
|
88
|
+
end
|
89
|
+
|
90
|
+
#Add the base url and the formatted arg list together, and make sure
|
91
|
+
#there are no spaces
|
92
|
+
def make_url
|
93
|
+
(BASE_API_URL + make_url_arg_list).gsub(/ /, "+")
|
94
|
+
end
|
95
|
+
|
96
|
+
#for testing purposes only
|
97
|
+
def args
|
98
|
+
@args
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
def info
|
5
|
+
self
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class UserBook
|
10
|
+
|
11
|
+
attr_accessor :title, :publisher, :info, :id
|
12
|
+
|
13
|
+
def initialize(book_data = {})
|
14
|
+
raise ArgumentError unless book_data.is_a?(Hash)
|
15
|
+
|
16
|
+
#The main attributes of the book:
|
17
|
+
@info = book_data
|
18
|
+
|
19
|
+
#The most commonly attributes, for ease of use
|
20
|
+
@id = info['id'] || ""
|
21
|
+
@title = info['title'] || ""
|
22
|
+
@authors = info['authors'] || []
|
23
|
+
@publisher = info['publisher'] || ""
|
24
|
+
end
|
25
|
+
|
26
|
+
#get any attribute, like with a hash
|
27
|
+
#ex self['title']
|
28
|
+
def [](key)
|
29
|
+
return authors if key =~ /authors?/i
|
30
|
+
info[key]
|
31
|
+
end
|
32
|
+
|
33
|
+
def authors
|
34
|
+
@authors.join(', ')
|
35
|
+
end
|
36
|
+
|
37
|
+
#Be a little bit forgiving if the user types "authors"
|
38
|
+
def author
|
39
|
+
authors
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'json'
|
2
|
+
require_relative '../common/errors'
|
3
|
+
require_relative 'user_book'
|
4
|
+
|
5
|
+
class UserLibrary
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_reader :books, :filename
|
9
|
+
|
10
|
+
def initialize(sourcefile = nil)
|
11
|
+
|
12
|
+
@books = []
|
13
|
+
|
14
|
+
if sourcefile
|
15
|
+
@filename = File.absolute_path(sourcefile)
|
16
|
+
|
17
|
+
#If the file already exists, it will be read and the
|
18
|
+
#@books array will be filled
|
19
|
+
if File.exist?(filename)
|
20
|
+
file = File.open(filename)
|
21
|
+
book_array = JSON.parse(file.read)
|
22
|
+
|
23
|
+
#If the UserBook initialize method changes, so must this; This
|
24
|
+
#is the only place where there's an explicit dependency on UserBook.
|
25
|
+
#If this line is changed, the rest of the class may still work as long
|
26
|
+
#as the elements in @books respond to the ':info' message
|
27
|
+
@books = book_array.map { |d| UserBook.new(d) }
|
28
|
+
end
|
29
|
+
|
30
|
+
else
|
31
|
+
#the default filename
|
32
|
+
@filename = File.absolute_path("saved_libraries/library.json")
|
33
|
+
end
|
34
|
+
|
35
|
+
#If the wrong type of data is provided
|
36
|
+
raise ArgumentError "Invalid Data" unless books.all? { |b| valid?(b) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def add(book)
|
40
|
+
(raise DataError "Invalid Data"; return) unless valid?(book)
|
41
|
+
@books << book
|
42
|
+
end
|
43
|
+
|
44
|
+
def <<(book)
|
45
|
+
add(book)
|
46
|
+
end
|
47
|
+
|
48
|
+
def save
|
49
|
+
File.write(filename, to_json)
|
50
|
+
end
|
51
|
+
|
52
|
+
#Iterates over ALL books
|
53
|
+
def each
|
54
|
+
return to_enum :each unless block_given?
|
55
|
+
@books.each { |b| yield(b) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def [](index)
|
59
|
+
@books[index]
|
60
|
+
end
|
61
|
+
|
62
|
+
#For saving to files
|
63
|
+
def to_json
|
64
|
+
a = @books.map do |b|
|
65
|
+
b.info
|
66
|
+
end
|
67
|
+
JSON.pretty_generate(a)
|
68
|
+
end
|
69
|
+
|
70
|
+
#For printing to the console
|
71
|
+
def pretty_print
|
72
|
+
puts ""
|
73
|
+
each do |b|
|
74
|
+
puts "-"*5 + b['id'] + "-" * 5
|
75
|
+
%w[title author publisher].each do |ind|
|
76
|
+
puts "%s: %s" % [ind.capitalize, b[ind]]
|
77
|
+
end
|
78
|
+
puts ""
|
79
|
+
end
|
80
|
+
puts ""
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
#make sure whatever gets passed in responds to the ':info' message
|
85
|
+
def valid?(b)
|
86
|
+
b.respond_to?(:info)
|
87
|
+
end
|
88
|
+
|
89
|
+
#for testing purposes
|
90
|
+
def set_filename(name)
|
91
|
+
@filename = name
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
data/common/api_query.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module ApiQuery
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
private
|
6
|
+
def get_response(url)
|
7
|
+
Net::HTTP.get_response(URI.parse(url))
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_response_hash(url)
|
11
|
+
JSON.parse(get_response_body(url))
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_response_code(url)
|
15
|
+
get_response(url).code
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_response_body(url)
|
19
|
+
get_response(url).body
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
data/common/errors.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
BASE_API_URL="https://www.googleapis.com/books/v1/volumes"
|
data/glibrary.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'json'
|
3
|
+
require 'optparse'
|
4
|
+
require 'io/console'
|
5
|
+
|
6
|
+
require_relative 'common/api_query'
|
7
|
+
require_relative 'common/google_api_url'
|
8
|
+
require_relative 'classes/book_search'
|
9
|
+
require_relative 'classes/user_book'
|
10
|
+
require_relative 'classes/user_library'
|
11
|
+
require_relative 'common/errors'
|
12
|
+
|
13
|
+
ARGV << '-h' if ARGV.empty?
|
14
|
+
|
15
|
+
#make sure the -l flag is process *after* the -f flag, by putting it at the end
|
16
|
+
ARGV << ARGV.delete("-l") if ARGV.include?("-l")
|
17
|
+
|
18
|
+
#default filename for saved reading list
|
19
|
+
filename = File.dirname(File.expand_path(__FILE__)) + "/saved_libraries/library.json"
|
20
|
+
|
21
|
+
#initialize the hash which will hold the search parameters
|
22
|
+
o = {}
|
23
|
+
|
24
|
+
#parse the command-line options
|
25
|
+
OptionParser.new do |opts|
|
26
|
+
opts.banner = "Usage: ruby g_library.rb [options...] [query]"
|
27
|
+
#sets 'library-mode'
|
28
|
+
library = opts.default_argv.include?("-l")
|
29
|
+
|
30
|
+
opts.on("-t", "--title=TITLE", "Specify a title keyword") do |t|
|
31
|
+
o[:title] = t
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-a", "--author=AUTHOR", "Specify an author keyword") do |a|
|
35
|
+
o[:author] = a
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("-p", "--publisher=PUBLISHER", "Specify a publisher keyword") do |p|
|
39
|
+
o[:publisher] = p
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on("-f", "--lib-file=LIBFILE", "Select a library save file") do |libfile|
|
43
|
+
filename = File.absolute_path(libfile)
|
44
|
+
unless File.exist?(filename)
|
45
|
+
(puts "Library file not found, cannot display."; exit) if library
|
46
|
+
puts "Creating new file"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on("-l", "--library", "See your library; ignores all search options
|
51
|
+
\t\t\t\t\tdefault library file is [repository_root]/saved_libraries/library.json") do
|
52
|
+
|
53
|
+
#substitute \ for / if the machine is running windows
|
54
|
+
filename.gsub!(/\//, '\\') if ENV.values.any? { |v| v =~ /[A-Z]:\\Windows/i }
|
55
|
+
|
56
|
+
|
57
|
+
#print out the library and exit the program
|
58
|
+
l = UserLibrary.new(filename)
|
59
|
+
l.pretty_print
|
60
|
+
exit
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-h", "--help", "Prints this help") do
|
64
|
+
puts ""
|
65
|
+
puts opts
|
66
|
+
puts "[query]: all other arguments will be treated as general search keywords"
|
67
|
+
puts ""
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
end.parse!
|
72
|
+
|
73
|
+
#substitute \ for / if the machine is running windows
|
74
|
+
filename.gsub!(/\//, '\\') if ENV.values.any? { |v| v =~ /C:\\Windows/i }
|
75
|
+
|
76
|
+
# Create or load the library, depending on whether or not the file already exists.
|
77
|
+
l = UserLibrary.new(filename)
|
78
|
+
|
79
|
+
#initialize the
|
80
|
+
#perform the search, and display the results.
|
81
|
+
begin
|
82
|
+
s = BookSearch.new(search: ARGV.join('+'), title: o[:title], author: o[:author], publisher: o[:publisher])
|
83
|
+
|
84
|
+
#see BookSearch definition in classes/book_search.rb
|
85
|
+
#the each method (and all Enumerable methods, like map) only operate on
|
86
|
+
#the first five matches.
|
87
|
+
books = s.map { |info| UserBook.new(info) }
|
88
|
+
|
89
|
+
#print the resuls
|
90
|
+
puts ""
|
91
|
+
books.each_with_index do |b, i|
|
92
|
+
keys = %w[title author publisher]
|
93
|
+
n = i+1
|
94
|
+
puts "-"*5 + "Match ##{n}" + "-"*5
|
95
|
+
keys.each do |k|
|
96
|
+
puts "%s: %s" % [k.capitalize, b[k]]
|
97
|
+
end
|
98
|
+
puts ""
|
99
|
+
end
|
100
|
+
|
101
|
+
print "Enter a number (1-5) to add a book to your reading list:\n(or any other key to quit)\n"
|
102
|
+
|
103
|
+
selection = STDIN.getch.chomp.to_i
|
104
|
+
i = selection - 1
|
105
|
+
puts ""
|
106
|
+
exit if i < 0 or i > 4
|
107
|
+
|
108
|
+
#add a book to the user's library
|
109
|
+
l << books[i]
|
110
|
+
l.save
|
111
|
+
|
112
|
+
rescue SearchError
|
113
|
+
puts "\nThere was an error with your query; be careful to format it well"
|
114
|
+
puts ""
|
115
|
+
exit
|
116
|
+
rescue NoResults
|
117
|
+
puts "\nNo results."
|
118
|
+
puts ""
|
119
|
+
exit
|
120
|
+
end
|
metadata
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: glibrary
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Peter Engelbert
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-10-26 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A simple Google Books API Query program
|
14
|
+
email: pmengelbert@gmail.com
|
15
|
+
executables:
|
16
|
+
- glibrary
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- bin/glibrary
|
21
|
+
- classes/book_search.rb
|
22
|
+
- classes/user_book.rb
|
23
|
+
- classes/user_library.rb
|
24
|
+
- common/api_query.rb
|
25
|
+
- common/errors.rb
|
26
|
+
- common/google_api_url.rb
|
27
|
+
- common/search_error.rb
|
28
|
+
- glibrary.rb
|
29
|
+
homepage: https://github.com/pmengelbert/g_library
|
30
|
+
licenses:
|
31
|
+
- MIT
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubygems_version: 3.0.6
|
49
|
+
signing_key:
|
50
|
+
specification_version: 4
|
51
|
+
summary: Glibrary
|
52
|
+
test_files: []
|