nexus_mods 1.1.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a6490bd894c40f7806bb126cb70ade888ab5121499b86ff2cc959ee663dd223d
4
- data.tar.gz: d9fdeb53c88c27ce9503e328a261ddb31a0facbbe0b6c35c304628c6e9580790
3
+ metadata.gz: c2325f79c99fb7304d16a0e4b12682229d8187ae30f6d0321796a4d3d5e587fb
4
+ data.tar.gz: 1cce0b8b4a82f8c903be9d6b7441d739d3b5dffa375c699444e8f2e87af4f2be
5
5
  SHA512:
6
- metadata.gz: 7c8f9576edd38dab0076f24ad1d396973c9d1ab8542ff4eef548d9b49758f85b6da465465b10b1e53dbb2db6d8312f31e9b88649916f654e7b8c1a12092aaadb
7
- data.tar.gz: 1b2d1e915594af39c9bd793a8f216fc2796024e2729a2b5596c35b546e04c8e2bb96dce77aa35e11f5d7a98fba1652c79f77f01648a363cfdf9b93ec40ee7602
6
+ metadata.gz: 3d868fa12c0e79385a7377e08ff5c4d4b0ccab2b3c78bedfc99cc9761c7a85c98073260c1409534b2ba8ccebdf74e10f03ddb7dd619901a05c809514798818d9
7
+ data.tar.gz: 45b7c418a3c0aeeac13b3b6e5d7a2d095513cc96e78e30f9900bee7852ff17389a512afe347fe345b33cd97ab099831cd020ee09c1aab70241f576c980447f5b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # [v2.0.0](https://github.com/Muriel-Salvan/nexus_mods/compare/v1.1.1...v2.0.0) (2023-04-11 10:15:58)
2
+
3
+ ### Breaking changes
4
+
5
+ * [[Breaking] Remove http cache file and useless support for etags as the API does not cache at http level](https://github.com/Muriel-Salvan/nexus_mods/commit/e157524e17ef0ed1a7013f14b15eaa35bb309592)
6
+
7
+ # [v1.1.1](https://github.com/Muriel-Salvan/nexus_mods/compare/v1.1.0...v1.1.1) (2023-04-10 19:39:28)
8
+
9
+ ### Patches
10
+
11
+ * [Improved documentation and added examples](https://github.com/Muriel-Salvan/nexus_mods/commit/0eb3fd00e0d1ad34db04a30ab2043a49371dc64f)
12
+
1
13
  # [v1.1.0](https://github.com/Muriel-Salvan/nexus_mods/compare/v1.0.0...v1.1.0) (2023-04-10 19:19:16)
2
14
 
3
15
  ### Features
data/README.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  Simple Ruby API letting you handle [NexusMods](https://www.nexusmods.com/) REST API.
4
4
 
5
+ ## Main features
6
+
7
+ * Get the API **limits**.
8
+ * Get the **games** information.
9
+ * Get individual **mods** and **mod files** information.
10
+ * Configurable **caching** with expiry times to save API calls to nexusmods.com.
11
+ * All served in an object-oriented **API in full Ruby**.
12
+
13
+ See the [examples](examples) for more details on how to use it.
14
+ Those examples expect that you set a valid NexusMods API key in the `NEXUS_MODS_API_KEY` environment variable.
15
+
5
16
  ## Install
6
17
 
7
18
  Via gem
@@ -54,7 +65,7 @@ Any contribution is welcome:
54
65
 
55
66
  ## Credits
56
67
 
57
- - [Muriel Salvan][link-author]
68
+ - [Muriel Salvan](https://x-aeon.com/muriel)
58
69
 
59
70
  ## License
60
71
 
@@ -0,0 +1,41 @@
1
+ require 'nexus_mods'
2
+ require 'fileutils'
3
+
4
+ # Make sure a previous file for caching was not here before
5
+ test_api_cache_file = 'nexus_mods_test_api_cache.json'
6
+ FileUtils.rm_f test_api_cache_file
7
+
8
+ nexus_mods = NexusMods.new(
9
+ api_key: ENV.fetch('NEXUS_MODS_API_KEY'),
10
+ api_cache_file: test_api_cache_file
11
+ )
12
+
13
+ initial_remaining = nexus_mods.api_limits.daily_remaining
14
+ puts "Before fetching anything, daily API remaining is #{initial_remaining}"
15
+
16
+ puts 'Fetch the list of games (without using cache)...'
17
+ puts "Fetched #{nexus_mods.games.size} games."
18
+
19
+ puts "After fetching those games, daily API remaining is #{nexus_mods.api_limits.daily_remaining}"
20
+
21
+ puts 'Now we fetch again the list of games (this should use the cache)...'
22
+ puts "Fetched #{nexus_mods.games.size} games."
23
+
24
+ puts "After fetching those games a second time, daily API remaining is #{nexus_mods.api_limits.daily_remaining}"
25
+
26
+ puts 'Now we close the current NexusMods instance ad re-instantiate a new one from scratch using the same API cache file'
27
+
28
+ new_nexus_mods = NexusMods.new(
29
+ api_key: ENV.fetch('NEXUS_MODS_API_KEY'),
30
+ api_cache_file: test_api_cache_file
31
+ )
32
+
33
+ puts "Before fetching anything from the new instance, daily API remaining is #{new_nexus_mods.api_limits.daily_remaining}"
34
+
35
+ puts 'Now we fetch the list of games from the new instance (this should use the cache that was stored in the file)...'
36
+ puts "Fetched #{new_nexus_mods.games.size} games."
37
+
38
+ puts "After fetching those games from the new instance, daily API remaining is #{new_nexus_mods.api_limits.daily_remaining}"
39
+
40
+ puts
41
+ puts "As a conclusion, we used 2 instances of NexusMods that have fetched games 3 times, and it consumed #{initial_remaining - new_nexus_mods.api_limits.daily_remaining} real API call."
@@ -0,0 +1,12 @@
1
+ require 'nexus_mods'
2
+
3
+ api_limits = NexusMods.new(api_key: ENV.fetch('NEXUS_MODS_API_KEY')).api_limits
4
+ puts <<~EO_OUTPUT
5
+ API limits:
6
+ daily_limit: #{api_limits.daily_limit}
7
+ daily_remaining: #{api_limits.daily_remaining}
8
+ daily_reset: #{api_limits.daily_reset}
9
+ hourly_limit: #{api_limits.hourly_limit}
10
+ hourly_remaining: #{api_limits.hourly_remaining}
11
+ hourly_reset: #{api_limits.hourly_reset}
12
+ EO_OUTPUT
data/examples/games.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'nexus_mods'
2
+
3
+ games = NexusMods.new(api_key: ENV.fetch('NEXUS_MODS_API_KEY')).games
4
+ puts "Found a total of #{games.size} games."
5
+ puts 'Here is the top 10 by number of downloads:'
6
+ games.sort_by { |game| -game.downloads_count }[0..9].each do |game|
7
+ puts "* #{game.name} (#{game.mods_count} mods, #{game.downloads_count} downloads)"
8
+ end
@@ -0,0 +1,10 @@
1
+ require 'nexus_mods'
2
+
3
+ puts 'Example of fetching a mod with log debug activated, and without using the cache (so that we always see the query):'
4
+ puts
5
+ NexusMods.new(
6
+ api_key: ENV.fetch('NEXUS_MODS_API_KEY'),
7
+ log_level: :debug,
8
+ game_domain_name: 'skyrimspecialedition',
9
+ mod_id: 42_521
10
+ ).mod(clear_cache: true)
data/examples/mods.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'nexus_mods'
2
+
3
+ nexus_mods = NexusMods.new(
4
+ api_key: ENV.fetch('NEXUS_MODS_API_KEY'),
5
+ game_domain_name: 'skyrimspecialedition'
6
+ )
7
+ some_mod_ids = [
8
+ 266,
9
+ 2_347,
10
+ 17_230,
11
+ 42_521
12
+ ]
13
+ puts 'Here are some details about a few mods for Skyrim Special Edition:'
14
+ puts
15
+ some_mod_ids.each do |mod_id|
16
+ mod = nexus_mods.mod(mod_id:)
17
+ mod_files = nexus_mods.mod_files(mod_id:)
18
+ puts <<~EO_OUTPUT
19
+ ===== #{mod.name} (v#{mod.version}) by #{mod.uploader.name} (#{mod.downloads_count} downloads)
20
+ #{mod.summary}
21
+ * Last 5 files: #{mod_files.reverse[0..4].map(&:file_name).join(', ')}
22
+
23
+ EO_OUTPUT
24
+ end
@@ -1,7 +1,5 @@
1
1
  require 'fileutils'
2
2
  require 'faraday'
3
- require 'faraday-http-cache'
4
- require 'nexus_mods/file_cache'
5
3
  require 'nexus_mods/cacheable_api'
6
4
 
7
5
  class NexusMods
@@ -23,7 +21,6 @@ class NexusMods
23
21
  #
24
22
  # Parameters::
25
23
  # * *api_key* (String or nil): The API key to be used, or nil for another authentication [default: nil]
26
- # * *http_cache_file* (String): File used to store the HTTP cache, or nil for no cache [default: "#{Dir.tmpdir}/nexus_mods_http_cache.json"]
27
24
  # * *api_cache_expiry* (Hash<Symbol,Integer>): Expiry times in seconds, per expiry key. Possible keys are:
28
25
  # * *games*: Expiry associated to queries on games [default: 1 day]
29
26
  # * *mod*: Expiry associated to queries on mod [default: 1 day]
@@ -32,7 +29,6 @@ class NexusMods
32
29
  # * *logger* (Logger): The logger to be used for log messages [default: Logger.new(STDOUT)]
33
30
  def initialize(
34
31
  api_key: nil,
35
- http_cache_file: "#{Dir.tmpdir}/nexus_mods_http_cache.json",
36
32
  api_cache_expiry: DEFAULT_API_CACHE_EXPIRY,
37
33
  api_cache_file: "#{Dir.tmpdir}/nexus_mods_api_cache.json",
38
34
  logger: Logger.new($stdout)
@@ -43,16 +39,7 @@ class NexusMods
43
39
  ApiClient.api_client = self
44
40
  @logger = logger
45
41
  # Initialize our HTTP client
46
- @http_cache = http_cache_file.nil? ? nil : FileCache.new(http_cache_file)
47
- @http_client = Faraday.new do |builder|
48
- # Indicate that the cache is not shared, meaning that private resources (depending on the session) can be cached as we consider only 1 user is using it for a given file cache.
49
- # Use Marshal serializer as some URLs can't get decoded correctly due to UTF-8 issues
50
- builder.use :http_cache,
51
- store: @http_cache,
52
- shared_cache: false,
53
- serializer: Marshal
54
- builder.adapter Faraday.default_adapter
55
- end
42
+ @http_client = Faraday.new
56
43
  Cacheable.cache_adapter = :persistent_json
57
44
  load_api_cache
58
45
  end
@@ -1,5 +1,5 @@
1
1
  class NexusMods
2
2
 
3
- VERSION = '1.1.0'
3
+ VERSION = '2.0.0'
4
4
 
5
5
  end
data/lib/nexus_mods.rb CHANGED
@@ -39,7 +39,6 @@ class NexusMods
39
39
  # * *game_domain_name* (String): Game domain name to query by default [default: 'skyrimspecialedition']
40
40
  # * *mod_id* (Integer): Mod to query by default [default: 1]
41
41
  # * *file_id* (Integer): File to query by default [default: 1]
42
- # * *http_cache_file* (String): File used to store the HTTP cache, or nil for no cache [default: "#{Dir.tmpdir}/nexus_mods_http_cache.json"]
43
42
  # * *api_cache_expiry* (Hash<Symbol,Integer>): Expiry times in seconds, per expiry key. Possible keys are:
44
43
  # * *games*: Expiry associated to queries on games [default: 1 day]
45
44
  # * *mod*: Expiry associated to queries on mod [default: 1 day]
@@ -52,7 +51,6 @@ class NexusMods
52
51
  game_domain_name: 'skyrimspecialedition',
53
52
  mod_id: 1,
54
53
  file_id: 1,
55
- http_cache_file: "#{Dir.tmpdir}/nexus_mods_http_cache.json",
56
54
  api_cache_expiry: {},
57
55
  api_cache_file: "#{Dir.tmpdir}/nexus_mods_api_cache.json",
58
56
  logger: Logger.new($stdout),
@@ -66,7 +64,6 @@ class NexusMods
66
64
  @premium = false
67
65
  @api_client = ApiClient.new(
68
66
  api_key:,
69
- http_cache_file:,
70
67
  api_cache_expiry:,
71
68
  api_cache_file:,
72
69
  logger:
@@ -56,7 +56,6 @@ module NexusModsTest
56
56
  if @nexus_mods.nil?
57
57
  args[:api_key] = MOCKED_API_KEY unless args.key?(:api_key)
58
58
  # By default running tests should not persistent cache files
59
- args[:http_cache_file] = nil unless args.key?(:http_cache_file)
60
59
  args[:api_cache_file] = nil unless args.key?(:api_cache_file)
61
60
  # Redirect any log into a string so that they don't pollute the tests output and they could be asserted.
62
61
  @nexus_mods_logger = StringIO.new
@@ -115,11 +114,6 @@ module NexusModsTest
115
114
  'User-Agent' => "nexus_mods (#{RUBY_PLATFORM}) Ruby/#{RUBY_VERSION}",
116
115
  'apikey' => api_key
117
116
  }
118
- if @expected_returned_etags.include? mocked_etag
119
- expected_request_headers['If-None-Match'] = mocked_etag
120
- else
121
- @expected_returned_etags << mocked_etag
122
- end
123
117
  @expected_stubs << [
124
118
  stub_request(http_method, "https://#{host}#{path}").with(headers: expected_request_headers).to_return(
125
119
  status: [code, message],
@@ -190,9 +184,6 @@ RSpec.configure do |config|
190
184
  @nexus_mods = nil
191
185
  # Reload the ApiClient as it stores caches at class level
192
186
  NexusMods::ApiClient.clear_cacheable_expiry_caches
193
- # Keep a list of the etags we should have returned, so that we know when queries should contain them
194
- # Array<String>
195
- @expected_returned_etags = []
196
187
  # List of expected stubs and the number of times they were supposed to mock
197
188
  # Array< [ WebMock::RequestStub, Integer ] >
198
189
  @expected_stubs = []
@@ -205,6 +196,7 @@ RSpec.configure do |config|
205
196
  config.around do |example|
206
197
  example.call
207
198
  ensure
199
+ # This would dump the logs in case of debug mode
208
200
  reset_nexus_mods
209
201
  end
210
202
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nexus_mods
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Muriel Salvan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-10 00:00:00.000000000 Z
11
+ date: 2023-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.7'
27
- - !ruby/object:Gem::Dependency
28
- name: faraday-http-cache
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2.4'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '2.4'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: cacheable
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -131,10 +117,20 @@ extra_rdoc_files:
131
117
  - CHANGELOG.md
132
118
  - LICENSE.md
133
119
  - README.md
120
+ - examples/api_caching.rb
121
+ - examples/api_limits.rb
122
+ - examples/games.rb
123
+ - examples/log_debug.rb
124
+ - examples/mods.rb
134
125
  files:
135
126
  - CHANGELOG.md
136
127
  - LICENSE.md
137
128
  - README.md
129
+ - examples/api_caching.rb
130
+ - examples/api_limits.rb
131
+ - examples/games.rb
132
+ - examples/log_debug.rb
133
+ - examples/mods.rb
138
134
  - lib/nexus_mods.rb
139
135
  - lib/nexus_mods/api/api_limits.rb
140
136
  - lib/nexus_mods/api/category.rb
@@ -147,7 +143,6 @@ files:
147
143
  - lib/nexus_mods/cacheable_with_expiry.rb
148
144
  - lib/nexus_mods/core_extensions/cacheable/cache_adapters/persistent_json_adapter.rb
149
145
  - lib/nexus_mods/core_extensions/cacheable/method_generator.rb
150
- - lib/nexus_mods/file_cache.rb
151
146
  - lib/nexus_mods/version.rb
152
147
  - spec/nexus_mods_test/factories/games.rb
153
148
  - spec/nexus_mods_test/factories/mod_files.rb
@@ -1,71 +0,0 @@
1
- class NexusMods
2
-
3
- # Simple key/value file cache
4
- class FileCache
5
-
6
- # Constructor
7
- #
8
- # Parameters::
9
- # * *file* (String): File to use as a cache
10
- def initialize(file)
11
- @file = file
12
- @cache_content = File.exist?(file) ? JSON.parse(File.read(file)) : {}
13
- end
14
-
15
- # Dump the cache in file
16
- def dump
17
- File.write(@file, @cache_content.to_json)
18
- end
19
-
20
- # Get the cache content as a Hash
21
- #
22
- # Result::
23
- # * Hash<String, Object>: Cache content
24
- def to_h
25
- @cache_content
26
- end
27
-
28
- # Is a given key present in the cache?
29
- #
30
- # Parameters::
31
- # * *key* (String): The key
32
- # Result::
33
- # * Boolean: Is a given key present in the cache?
34
- def key?(key)
35
- @cache_content.key?(key)
36
- end
37
-
38
- # Read a key from the cache
39
- #
40
- # Parameters:
41
- # * *key* (String): The cache key
42
- # Result::
43
- # * Object or nil: JSON-serializable object storing the value, or nil in case of cache-miss
44
- def read(key)
45
- @cache_content.key?(key) ? @cache_content[key] : nil
46
- end
47
-
48
- alias [] read
49
-
50
- # Write a key/value in the cache
51
- #
52
- # Parameters:
53
- # * *key* (String): The key
54
- # * *value* (Object): JSON-serializable object storing the value
55
- def write(key, value)
56
- @cache_content[key] = value
57
- end
58
-
59
- alias []= write
60
-
61
- # Delete a key in the cache
62
- #
63
- # Parameters:
64
- # * *key* (String): The key
65
- def delete(key)
66
- @cache_content.delete(key)
67
- end
68
-
69
- end
70
-
71
- end