foxit 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 +7 -0
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/README.md +136 -0
- data/foxit.gemspec +29 -0
- data/lib/foxit/api.rb +179 -0
- data/lib/foxit/etl.rb +43 -0
- data/lib/foxit/helpers.rb +13 -0
- data/lib/foxit/objects.rb +50 -0
- data/lib/foxit.rb +11 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 541b370e85c872627d4bff2419a6af1d8ce922c8e19363218aad0f6642b435ab
|
4
|
+
data.tar.gz: 74738a7174d332d718573188510a6e4744f8b08b7cb66735ae758fadb65dfd1c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4dcfdbcf7d13ec79d4501298fe49379b07fff9736829a42f01ecaee043aa0ccfde9a1bd6861c8ea63bb0824cf6f134a1ec81e9d5f83956388a86420e4d872ca9
|
7
|
+
data.tar.gz: e597208dcabad4affd0ff242bbcec7cddc7ae85afb0f499193d85b82dbf9885a0cb32b2719795907d60608c21c55671ea5daf32c3356ccc4e24b0a2c0f18f974
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2018 Lachlan Taylor
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# Kitsu API Wrapper
|
2
|
+
Unofficial Ruby wrapper for [Kitsu][kitsu] API ([documentation][api]).
|
3
|
+
|
4
|
+
Note: this is the initial version and was written primarily to store data locally on which to train recommendation models. Hence, it works well for the task it was created but there are a few gaps that could be included without too much effort.
|
5
|
+
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
```
|
9
|
+
gem install foxit
|
10
|
+
```
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
A few quick examples are detailed below:
|
14
|
+
|
15
|
+
### Retrieving Data
|
16
|
+
Get an anime item by id.
|
17
|
+
```ruby
|
18
|
+
api = Foxit::API.new()
|
19
|
+
result = api.get_anime_by_id(1)
|
20
|
+
```
|
21
|
+
|
22
|
+
This returns the full json response; however, an object based result can be returned as per the following (planned to be returned as default)
|
23
|
+
```ruby
|
24
|
+
item = Anime.new(result['data'])
|
25
|
+
```
|
26
|
+
|
27
|
+
Similarly, getting a users library. This returns a list of entries from the `'data'` attribute of the json returned.
|
28
|
+
```ruby
|
29
|
+
result = api.get_library_by_id(1)
|
30
|
+
```
|
31
|
+
|
32
|
+
|
33
|
+
### Storing Data with MongoDB
|
34
|
+
If you don't have mongodb installed you can download the free community version from [here][mongodb]. Once installed, you need to start the service via terminal:
|
35
|
+
```
|
36
|
+
mongod --port 27017 --dbpath /path/to/db
|
37
|
+
```
|
38
|
+
Note: you can stop it by pressing `ctrl+c` when the terminal is active or by using
|
39
|
+
```
|
40
|
+
mongod --dbpath /path/to/db --shutdown
|
41
|
+
```
|
42
|
+
|
43
|
+
Once you have mongodb running you can retreive and store data by using the following functions.
|
44
|
+
|
45
|
+
**Please use responsibly!** Library results are especially expensive as they require a secondary call to lookup the media_id from the library item id that is returned in the user library request. In other words, for the benefit of everyone, don't punish the API with hundreds of calls.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
etl = Foxit::ETL.new()
|
49
|
+
etl.get_anime(1..100) # stores anime item results from media_id 1 to 100
|
50
|
+
etl.get_libraries(1..25) # stores user library results from user_id 1 to 25
|
51
|
+
```
|
52
|
+
|
53
|
+
#### MongoDB Library Item
|
54
|
+
Current fields obtained from Kitsu API. There are more available and could easilty be added; however, this was all I needed for working on the recommendation models.
|
55
|
+
```
|
56
|
+
{
|
57
|
+
'_id': ObjectId('5b56ad7dafd2a496c0faa495'),
|
58
|
+
'media_id': 1376, # id for anime, e.g., this one relates to 'Code Geass: Lelouch of the Rebellion'
|
59
|
+
'rating': 17, # user rating [1-20]; None if not rated.
|
60
|
+
'record_id': 18344699, # library item id; used to return the actual media_id
|
61
|
+
'status': 'completed', # media viewing status: {completed, planned, watching, hold, dropped}
|
62
|
+
'type': 'anime', # media type: {Anime, Manga, Drama?}.
|
63
|
+
'user_id': 1 # user id
|
64
|
+
}
|
65
|
+
```
|
66
|
+
|
67
|
+
|
68
|
+
#### MongoDB Anime Item
|
69
|
+
|
70
|
+
```
|
71
|
+
{
|
72
|
+
'_id': ObjectId('5b570e4eafd2a41db810927b'),
|
73
|
+
'avg_rating': 84.36,
|
74
|
+
'end_date': '1999-04-24',
|
75
|
+
'id': 1,
|
76
|
+
'n_favourites': 0,
|
77
|
+
'n_users': 71919,
|
78
|
+
'nsfw': False,
|
79
|
+
'rank_popularity': 15,
|
80
|
+
'rank_rating': 27,
|
81
|
+
'rating_freq': { '10': 415,
|
82
|
+
'11': 27,
|
83
|
+
'12': 1700,
|
84
|
+
'13': 53,
|
85
|
+
'14': 3878,
|
86
|
+
'15': 139,
|
87
|
+
'16': 5255,
|
88
|
+
'17': 255,
|
89
|
+
'18': 6261,
|
90
|
+
'19': 238,
|
91
|
+
'2': 1566,
|
92
|
+
'20': 20974,
|
93
|
+
'3': 33,
|
94
|
+
'4': 351,
|
95
|
+
'5': 15,
|
96
|
+
'6': 115,
|
97
|
+
'7': 16,
|
98
|
+
'8': 1545,
|
99
|
+
'9': 22},
|
100
|
+
'showtype': 'TV',
|
101
|
+
'slug': 'cowboy-bebop',
|
102
|
+
'start_date': '1998-04-03',
|
103
|
+
'subtype': 'TV',
|
104
|
+
'synopsis': 'In the year 2071, humanity has colonized several of the planets '
|
105
|
+
'and moons of the solar system leaving the now uninhabitable '
|
106
|
+
'surface of planet Earth behind. The Inter Solar System Police '
|
107
|
+
'attempts to keep peace in the galaxy, aided in part by outlaw '
|
108
|
+
'bounty hunters, referred to as "Cowboys". The ragtag team '
|
109
|
+
'aboard the spaceship Bebop are two such individuals.\r\n'
|
110
|
+
'Mellow and carefree Spike Spiegel is balanced by his '
|
111
|
+
'boisterous, pragmatic partner Jet Black as the pair makes a '
|
112
|
+
'living chasing bounties and collecting rewards. Thrown off '
|
113
|
+
'course by the addition of new members that they meet in their '
|
114
|
+
'travels�Ein, a genetically engineered, highly intelligent Welsh '
|
115
|
+
'Corgi; femme fatale Faye Valentine, an enigmatic trickster with '
|
116
|
+
'memory loss; and the strange computer whiz kid Edward Wong�the '
|
117
|
+
"crew embarks on thrilling adventures that unravel each member's "
|
118
|
+
'dark and mysterious past little by little. \r\n'
|
119
|
+
'Well-balanced with high density action and light-hearted '
|
120
|
+
'comedy, Cowboy Bebop is a space Western classic and an homage '
|
121
|
+
'to the smooth and improvised music it is named after. \r\n'
|
122
|
+
'[Written by MAL Rewrite]',
|
123
|
+
'title': 'Cowboy Bebop'
|
124
|
+
}
|
125
|
+
```
|
126
|
+
|
127
|
+
|
128
|
+
## Further Work
|
129
|
+
- Add some more detail/examples to README
|
130
|
+
- Extend on functionality/usability for benefit of other users.
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
[kitsu]: https://kitsu.io
|
135
|
+
[api]: https://kitsu.docs.apiary.io/
|
136
|
+
[mongodb]: https://www.mongodb.com/download-center#community
|
data/foxit.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
# require "foxit/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "foxit"
|
8
|
+
# spec.version = Foxit::VERSION
|
9
|
+
spec.version = "0.1.1"
|
10
|
+
spec.authors = ["Lachlan Taylor"]
|
11
|
+
spec.email = ["lachlanbtaylor@gmail.com"]
|
12
|
+
|
13
|
+
spec.summary = %q{Unofficial Kitsu API wrapper with MongoDB capability.}
|
14
|
+
# spec.description = %q{Write a longer description or delete this line.}
|
15
|
+
spec.homepage = "https://github.com/rokkuran/foxit"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
# Specify which files should be added to the gem when it is released.
|
19
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
20
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
22
|
+
end
|
23
|
+
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
|
26
|
+
spec.add_dependency 'json', '~> 2.1.0', '>= 2.0.4'
|
27
|
+
spec.add_dependency 'addressable', '~> 2.5.2', '>= 2.5.2'
|
28
|
+
spec.add_dependency 'mongo', '~> 2.5.1', '>= 2.5.1'
|
29
|
+
end
|
data/lib/foxit/api.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
require_relative 'objects'
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'addressable/uri'
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module Foxit
|
10
|
+
|
11
|
+
class API
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@root = "https://kitsu.io/api/edge/"
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def build_library_url id, type='Anime', status='completed', limit=500
|
19
|
+
uri = Addressable::URI.parse("#{@root}library-entries")
|
20
|
+
|
21
|
+
uri_query = {
|
22
|
+
"filter[user_id]" => id,
|
23
|
+
"filter[media_type]" => type,
|
24
|
+
"filter[status]" => status,
|
25
|
+
"page[limit]" => limit
|
26
|
+
}
|
27
|
+
uri.query_values = uri_query
|
28
|
+
|
29
|
+
uri.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def build_media_url entry_id
|
34
|
+
"#{@root}/library-entries/#{entry_id}/relationships/media"
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def get_result url
|
39
|
+
response = Net::HTTP.get(URI.parse(url))
|
40
|
+
JSON.parse(response)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def get_library_by_url url, entries=[]
|
45
|
+
|
46
|
+
result = self.get_result(url)
|
47
|
+
entries += result['data']
|
48
|
+
|
49
|
+
if result['links'].key?('next')
|
50
|
+
# recursion to retrieve additional results that have ben paginated
|
51
|
+
result = self.get_library_by_url(result['links']['next'], entries)
|
52
|
+
else
|
53
|
+
return entries
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def get_library_by_id user_id
|
59
|
+
url = self.build_library_url(user_id)
|
60
|
+
self.get_library_by_url(url)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def get_media_relationship_by_id entry_id
|
65
|
+
# adding memoisation to stop requesting same media docs
|
66
|
+
# TODO: extend to items already existing in db?
|
67
|
+
@get_media_relationship_by_id ||= {}
|
68
|
+
return @get_media_relationship_by_id[entry_id] if @get_media_relationship_by_id.key?(entry_id)
|
69
|
+
|
70
|
+
url = self.build_media_url(entry_id)
|
71
|
+
self.get_result(url)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def batch_get_results ids, fn, max_threads
|
76
|
+
"""
|
77
|
+
ids: ids of results returned: user_id | library_entry_id in this case.
|
78
|
+
fn: function name to use to return results (need to use symbol method name)
|
79
|
+
e.g. :get_result
|
80
|
+
max_threads: maximum number of active threads.
|
81
|
+
"""
|
82
|
+
|
83
|
+
results = {}
|
84
|
+
threads = []
|
85
|
+
|
86
|
+
ids.each do |id|
|
87
|
+
|
88
|
+
if Thread.list.count % max_threads != 0
|
89
|
+
thread = Thread.new do
|
90
|
+
# adding lock slows down considerably shouldn't matter as results are written to hash?
|
91
|
+
results[id] = send(fn, id)
|
92
|
+
end
|
93
|
+
threads << thread
|
94
|
+
else
|
95
|
+
# wait for open threads to finish before starting new one
|
96
|
+
threads.each(&:join)
|
97
|
+
|
98
|
+
thread = Thread.new do
|
99
|
+
results[id] = send(fn, id)
|
100
|
+
end
|
101
|
+
threads << thread
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
threads.each(&:join)
|
107
|
+
|
108
|
+
results
|
109
|
+
end
|
110
|
+
|
111
|
+
# TODO: should probably assign to a @variable
|
112
|
+
def batch_get_libraries user_ids, max_threads=200
|
113
|
+
|
114
|
+
all_library_entries = []
|
115
|
+
user_libraries = self.batch_get_results(user_ids, :get_library_by_id, max_threads)
|
116
|
+
|
117
|
+
user_libraries.each do |user_id, library|
|
118
|
+
|
119
|
+
media_ids = []
|
120
|
+
library.map { |entry| media_ids << entry['id'] }
|
121
|
+
media_results = self.batch_get_results(media_ids, :get_media_relationship_by_id, max_threads)
|
122
|
+
|
123
|
+
library.each do |entry|
|
124
|
+
all_library_entries << LibraryItem.new(user_id, entry, media_results[entry['id']])
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
all_library_entries
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def get_user_library
|
134
|
+
# TODO: return user library using single id call to batch_get_library
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def batch_get_libraries_docs user_ids, max_threads=200
|
139
|
+
all_library_entries = self.batch_get_libraries(user_ids, max_threads)
|
140
|
+
|
141
|
+
docs = []
|
142
|
+
all_library_entries.map { |entry| docs << entry.to_hash }
|
143
|
+
|
144
|
+
docs
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
def build_anime_url id
|
149
|
+
"#{@root}/anime/#{id}"
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def get_anime_by_id id
|
154
|
+
url = build_anime_url(id)
|
155
|
+
self.get_result(url)
|
156
|
+
end
|
157
|
+
|
158
|
+
|
159
|
+
def batch_get_anime anime_ids, max_threads=200
|
160
|
+
results = self.batch_get_results(anime_ids, :get_anime_by_id, max_threads)
|
161
|
+
|
162
|
+
anime_items = []
|
163
|
+
results.each do |id, result|
|
164
|
+
unless result.key?('errors')
|
165
|
+
anime_items << Anime.new(result['data'])
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
anime_items
|
170
|
+
end
|
171
|
+
|
172
|
+
def get_anime_documents anime_ids, max_threads=200
|
173
|
+
anime_items = self.batch_get_anime(anime_ids, max_threads)
|
174
|
+
self.objects_to_hash(anime_items)
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
data/lib/foxit/etl.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'api'
|
2
|
+
|
3
|
+
require 'mongo'
|
4
|
+
Mongo::Logger.logger.level = Logger::WARN
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
module Foxit
|
9
|
+
|
10
|
+
class ETL
|
11
|
+
attr_reader :kitsu, :client
|
12
|
+
|
13
|
+
def initialize db_name: 'kitsu', host: ['127.0.0.1:27017']
|
14
|
+
@kitsu = API.new()
|
15
|
+
@client = Mongo::Client.new(host, {database: db_name})
|
16
|
+
end
|
17
|
+
|
18
|
+
def insert_many_docs collection_name, docs
|
19
|
+
begin
|
20
|
+
puts "inserting..."
|
21
|
+
result = @client[collection_name].insert_many(docs)
|
22
|
+
puts "records inserted: #{result.inserted_count}"
|
23
|
+
rescue StandardError => e
|
24
|
+
puts "error: #{e}"
|
25
|
+
end
|
26
|
+
puts "complete.\n"
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def get_libraries user_ids
|
31
|
+
docs = @kitsu.batch_get_libraries_docs(user_ids)
|
32
|
+
insert_many_docs('library', docs)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def get_anime media_ids
|
37
|
+
docs = @kitsu.get_anime_documents(media_ids)
|
38
|
+
insert_many_docs('anime', docs)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'helpers'
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
class LibraryItem < Helpers
|
6
|
+
attr_reader :user_id, :record_id, :status, :rating, :media_id, :type
|
7
|
+
|
8
|
+
def initialize user_id, entry_result, media_result
|
9
|
+
@user_id = user_id.to_i
|
10
|
+
@record_id = entry_result['id'].to_i
|
11
|
+
@status = entry_result['attributes']['status']
|
12
|
+
|
13
|
+
rating = entry_result['attributes']['ratingTwenty']
|
14
|
+
@rating = rating.nil? ? nil : rating.to_i
|
15
|
+
|
16
|
+
@media_id = media_result['data']['id'].to_i
|
17
|
+
@type = media_result['data']['type']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
class Anime < Helpers
|
23
|
+
attr_reader :id, :slug, :synopsis, :title, :avg_rating, :rating_freq, :n_users,
|
24
|
+
:n_favourites, :start_date, :end_date, :rank_popularity, :rank_rating, :subtype,
|
25
|
+
:nsfw; :showtype
|
26
|
+
|
27
|
+
def initialize data
|
28
|
+
attributes = data['attributes']
|
29
|
+
@id = data['id'].to_i
|
30
|
+
@slug = attributes['slug']
|
31
|
+
@synopsis = attributes['synopsis']
|
32
|
+
@title = attributes['canonicalTitle']
|
33
|
+
@avg_rating = attributes['averageRating'].to_f # TODO: need to handle nil values?
|
34
|
+
|
35
|
+
rf_int = {}
|
36
|
+
# mongodb needs string keys anyway, so k.to_i redundant...
|
37
|
+
attributes['ratingFrequencies'].each_pair { | k, v | rf_int[k.to_i] = v.to_i }
|
38
|
+
@rating_freq = rf_int
|
39
|
+
|
40
|
+
@n_users = attributes['userCount'].to_i
|
41
|
+
@n_favourites = attributes['favouritesCount'].to_i
|
42
|
+
@start_date = attributes['startDate']
|
43
|
+
@end_date = attributes['endDate']
|
44
|
+
@rank_popularity = attributes['popularityRank'].to_i
|
45
|
+
@rank_rating = attributes['ratingRank'].to_i
|
46
|
+
@subtype = attributes['subtype']
|
47
|
+
@showtype = attributes['showType']
|
48
|
+
@nsfw = attributes['nsfw'] # TODO: convert to bool?
|
49
|
+
end
|
50
|
+
end
|
data/lib/foxit.rb
ADDED
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: foxit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lachlan Taylor
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-07-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.0
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.0.4
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.1.0
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.0.4
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: addressable
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 2.5.2
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.5.2
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 2.5.2
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 2.5.2
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: mongo
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 2.5.1
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.5.1
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.5.1
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 2.5.1
|
73
|
+
description:
|
74
|
+
email:
|
75
|
+
- lachlanbtaylor@gmail.com
|
76
|
+
executables: []
|
77
|
+
extensions: []
|
78
|
+
extra_rdoc_files: []
|
79
|
+
files:
|
80
|
+
- ".gitignore"
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE
|
83
|
+
- README.md
|
84
|
+
- foxit.gemspec
|
85
|
+
- lib/foxit.rb
|
86
|
+
- lib/foxit/api.rb
|
87
|
+
- lib/foxit/etl.rb
|
88
|
+
- lib/foxit/helpers.rb
|
89
|
+
- lib/foxit/objects.rb
|
90
|
+
homepage: https://github.com/rokkuran/foxit
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.7.7
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: Unofficial Kitsu API wrapper with MongoDB capability.
|
114
|
+
test_files: []
|