factorix 0.5.0 → 0.6.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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/README.md +1 -1
  4. data/lib/factorix/api/mod_download_api.rb +1 -1
  5. data/lib/factorix/api/mod_info.rb +2 -2
  6. data/lib/factorix/api/mod_management_api.rb +1 -1
  7. data/lib/factorix/api_credential.rb +1 -1
  8. data/lib/factorix/cli/commands/backup_support.rb +1 -1
  9. data/lib/factorix/cli/commands/base.rb +3 -3
  10. data/lib/factorix/cli/commands/cache/evict.rb +3 -3
  11. data/lib/factorix/cli/commands/cache/stat.rb +15 -15
  12. data/lib/factorix/cli/commands/command_wrapper.rb +5 -5
  13. data/lib/factorix/cli/commands/completion.rb +2 -3
  14. data/lib/factorix/cli/commands/confirmable.rb +1 -1
  15. data/lib/factorix/cli/commands/download_support.rb +2 -2
  16. data/lib/factorix/cli/commands/mod/check.rb +1 -1
  17. data/lib/factorix/cli/commands/mod/disable.rb +1 -1
  18. data/lib/factorix/cli/commands/mod/download.rb +5 -4
  19. data/lib/factorix/cli/commands/mod/edit.rb +9 -9
  20. data/lib/factorix/cli/commands/mod/enable.rb +1 -1
  21. data/lib/factorix/cli/commands/mod/image/add.rb +2 -2
  22. data/lib/factorix/cli/commands/mod/image/edit.rb +1 -1
  23. data/lib/factorix/cli/commands/mod/image/list.rb +4 -4
  24. data/lib/factorix/cli/commands/mod/install.rb +5 -4
  25. data/lib/factorix/cli/commands/mod/list.rb +7 -7
  26. data/lib/factorix/cli/commands/mod/search.rb +11 -9
  27. data/lib/factorix/cli/commands/mod/settings/dump.rb +3 -3
  28. data/lib/factorix/cli/commands/mod/settings/restore.rb +2 -2
  29. data/lib/factorix/cli/commands/mod/show.rb +20 -20
  30. data/lib/factorix/cli/commands/mod/sync.rb +6 -5
  31. data/lib/factorix/cli/commands/mod/uninstall.rb +1 -1
  32. data/lib/factorix/cli/commands/mod/update.rb +7 -6
  33. data/lib/factorix/cli/commands/mod/upload.rb +6 -6
  34. data/lib/factorix/cli/commands/path.rb +2 -2
  35. data/lib/factorix/cli/commands/version.rb +1 -1
  36. data/lib/factorix/{application.rb → container.rb} +8 -85
  37. data/lib/factorix/dependency/parser.rb +1 -1
  38. data/lib/factorix/http/client.rb +3 -3
  39. data/lib/factorix/info_json.rb +2 -2
  40. data/lib/factorix/mod_list.rb +2 -2
  41. data/lib/factorix/mod_settings.rb +2 -2
  42. data/lib/factorix/runtime/user_configurable.rb +9 -9
  43. data/lib/factorix/service_credential.rb +3 -3
  44. data/lib/factorix/version.rb +1 -1
  45. data/lib/factorix.rb +118 -1
  46. data/sig/factorix/container.rbs +15 -0
  47. data/sig/factorix.rbs +99 -0
  48. metadata +4 -4
  49. data/sig/factorix/application.rbs +0 -86
data/lib/factorix.rb CHANGED
@@ -1,13 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/auto_inject"
4
+ require "dry/configurable"
4
5
  require "zeitwerk"
5
6
  require_relative "factorix/errors"
6
7
  require_relative "factorix/version"
7
8
 
8
9
  # Factorix provides a CLI for Factorio MOD management, settings synchronization,
9
10
  # and MOD Portal integration.
11
+ #
12
+ # @example Configure Factorix
13
+ # Factorix.configure do |config|
14
+ # config.log_level = :debug
15
+ # config.http.connect_timeout = 10
16
+ # end
10
17
  module Factorix
18
+ extend Dry::Configurable
19
+
20
+ # Log level (:debug, :info, :warn, :error, :fatal)
21
+ setting :log_level, default: :info
22
+
23
+ # Runtime settings (optional overrides for auto-detection)
24
+ setting :runtime do
25
+ setting :executable_path, constructor: ->(v) { v ? Pathname(v) : nil }
26
+ setting :user_dir, constructor: ->(v) { v ? Pathname(v) : nil }
27
+ setting :data_dir, constructor: ->(v) { v ? Pathname(v) : nil }
28
+ end
29
+
30
+ # HTTP timeout settings
31
+ setting :http do
32
+ setting :connect_timeout, default: 5
33
+ setting :read_timeout, default: 30
34
+ setting :write_timeout, default: 30
35
+ end
36
+
37
+ # Cache settings
38
+ setting :cache do
39
+ # Download cache settings (for MOD files)
40
+ setting :download do
41
+ setting :dir, constructor: ->(value) { Pathname(value) }
42
+ setting :ttl, default: nil # nil for unlimited (MOD files are immutable)
43
+ setting :max_file_size, default: nil # nil for unlimited
44
+ setting :compression_threshold, default: nil # nil for no compression (binary files)
45
+ end
46
+
47
+ # API cache settings (for API responses)
48
+ setting :api do
49
+ setting :dir, constructor: ->(value) { Pathname(value) }
50
+ setting :ttl, default: 3600 # 1 hour (API responses may change)
51
+ setting :max_file_size, default: 10 * 1024 * 1024 # 10MiB (JSON responses)
52
+ setting :compression_threshold, default: 0 # always compress (JSON is highly compressible)
53
+ end
54
+
55
+ # info.json cache settings (for MOD metadata from ZIP files)
56
+ setting :info_json do
57
+ setting :dir, constructor: ->(value) { Pathname(value) }
58
+ setting :ttl, default: nil # nil for unlimited (info.json is immutable within a MOD ZIP)
59
+ setting :max_file_size, default: nil # nil for unlimited (info.json is small)
60
+ setting :compression_threshold, default: 0 # always compress (JSON is highly compressible)
61
+ end
62
+ end
63
+
64
+ # Load configuration from file
65
+ #
66
+ # @param path [Pathname, nil] configuration file path
67
+ # @return [void]
68
+ # @raise [ConfigurationError] if explicitly specified path does not exist
69
+ def self.load_config(path=nil)
70
+ if path
71
+ # Explicitly specified path must exist
72
+ raise ConfigurationError, "Configuration file not found: #{path}" unless path.exist?
73
+
74
+ config_path = path
75
+ else
76
+ # Default path is optional
77
+ config_path = Container.resolve(:runtime).factorix_config_path
78
+ return unless config_path.exist?
79
+ end
80
+
81
+ instance_eval(config_path.read, config_path.to_s)
82
+ end
83
+
11
84
  loader = Zeitwerk::Loader.for_gem
12
85
  loader.ignore("#{__dir__}/factorix/version.rb")
13
86
  loader.ignore("#{__dir__}/factorix/errors.rb")
@@ -33,6 +106,50 @@ module Factorix
33
106
  )
34
107
  loader.setup
35
108
 
36
- Import = Dry::AutoInject(Application)
109
+ Import = Dry::AutoInject(Container)
37
110
  public_constant :Import
111
+
112
+ # Initialize cache directory defaults after Container is loaded
113
+ runtime = Container.resolve(:runtime)
114
+ config.cache.download.dir = runtime.factorix_cache_dir / "download"
115
+ config.cache.api.dir = runtime.factorix_cache_dir / "api"
116
+ config.cache.info_json.dir = runtime.factorix_cache_dir / "info_json"
117
+
118
+ # @deprecated Use {Container} for DI and {Factorix} for configuration. Will be removed in v1.0.
119
+ class Application
120
+ # @!method [](key)
121
+ # @deprecated Use {Container.[]} instead
122
+ def self.[](key)
123
+ warn "[factorix] Factorix::Application is deprecated, use Factorix::Container for DI"
124
+ Container[key]
125
+ end
126
+
127
+ # @!method resolve(key)
128
+ # @deprecated Use {Container.resolve} instead
129
+ def self.resolve(key)
130
+ warn "[factorix] Factorix::Application is deprecated, use Factorix::Container for DI"
131
+ Container.resolve(key)
132
+ end
133
+
134
+ # @!method register(...)
135
+ # @deprecated Use {Container.register} instead
136
+ def self.register(...)
137
+ warn "[factorix] Factorix::Application is deprecated, use Factorix::Container for DI"
138
+ Container.register(...)
139
+ end
140
+
141
+ # @!method config
142
+ # @deprecated Use {Factorix.config} instead
143
+ def self.config
144
+ warn "[factorix] Factorix::Application is deprecated, use Factorix.config for configuration"
145
+ Factorix.config
146
+ end
147
+
148
+ # @!method configure(&block)
149
+ # @deprecated Use {Factorix.configure} instead
150
+ def self.configure(&)
151
+ warn "[factorix] Factorix::Application is deprecated, use Factorix.configure for configuration"
152
+ Factorix.configure(&)
153
+ end
154
+ end
38
155
  end
@@ -0,0 +1,15 @@
1
+ # RBS type signature file
2
+ # NOTE: Do not include private method definitions in RBS files.
3
+ # Only public interfaces should be documented here.
4
+
5
+ module Factorix
6
+ class Container
7
+ extend Dry::Core::Container::Mixin
8
+
9
+ def self.register: (Symbol, ?memoize: bool) { () -> untyped } -> void
10
+
11
+ def self.resolve: (Symbol) -> untyped
12
+
13
+ def self.[]: (Symbol) -> untyped
14
+ end
15
+ end
data/sig/factorix.rbs CHANGED
@@ -6,4 +6,103 @@ module Factorix
6
6
  VERSION: String
7
7
 
8
8
  Import: Dry::AutoInject::_Builder
9
+
10
+ extend Dry::Configurable
11
+
12
+ def self.config: () -> Config
13
+
14
+ def self.configure: () { (Config) -> void } -> void
15
+
16
+ def self.load_config: (?Pathname? path) -> void
17
+
18
+ class Config
19
+ def log_level: () -> Symbol
20
+
21
+ def log_level=: (Symbol) -> void
22
+
23
+ def credential: () -> CredentialConfig
24
+
25
+ def runtime: () -> RuntimeConfig
26
+
27
+ def http: () -> HttpConfig
28
+
29
+ def cache: () -> CacheConfig
30
+ end
31
+
32
+ class CredentialConfig
33
+ def source: () -> Symbol
34
+
35
+ def source=: (Symbol) -> void
36
+ end
37
+
38
+ class RuntimeConfig
39
+ def executable_path: () -> Pathname?
40
+
41
+ def executable_path=: (Pathname | String | nil) -> void
42
+
43
+ def user_dir: () -> Pathname?
44
+
45
+ def user_dir=: (Pathname | String | nil) -> void
46
+
47
+ def data_dir: () -> Pathname?
48
+
49
+ def data_dir=: (Pathname | String | nil) -> void
50
+ end
51
+
52
+ class HttpConfig
53
+ def connect_timeout: () -> Integer
54
+
55
+ def connect_timeout=: (Integer) -> void
56
+
57
+ def read_timeout: () -> Integer
58
+
59
+ def read_timeout=: (Integer) -> void
60
+
61
+ def write_timeout: () -> Integer
62
+
63
+ def write_timeout=: (Integer) -> void
64
+ end
65
+
66
+ class CacheConfig
67
+ def download: () -> CacheInstanceConfig
68
+
69
+ def api: () -> CacheInstanceConfig
70
+
71
+ def info_json: () -> CacheInstanceConfig
72
+
73
+ def values: () -> Hash[Symbol, CacheInstanceConfig]
74
+ end
75
+
76
+ class CacheInstanceConfig
77
+ def dir: () -> Pathname
78
+
79
+ def dir=: (Pathname | String) -> void
80
+
81
+ def ttl: () -> Integer?
82
+
83
+ def ttl=: (Integer?) -> void
84
+
85
+ def max_file_size: () -> Integer?
86
+
87
+ def max_file_size=: (Integer?) -> void
88
+
89
+ def compression_threshold: () -> Integer?
90
+
91
+ def compression_threshold=: (Integer?) -> void
92
+
93
+ def to_h: () -> Hash[Symbol, untyped]
94
+ end
95
+
96
+ # @deprecated Use Container for DI and Factorix for configuration
97
+ class Application
98
+ def self.[]: (Symbol) -> untyped
99
+
100
+ def self.resolve: (Symbol) -> untyped
101
+
102
+ def self.register: (Symbol, ?memoize: bool) { () -> untyped } -> void
103
+
104
+ def self.config: () -> Config
105
+
106
+ def self.configure: () { (Config) -> void } -> void
107
+ end
9
108
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factorix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OZAWA Sakuro
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-12-26 00:00:00.000000000 Z
11
+ date: 2026-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -221,7 +221,6 @@ files:
221
221
  - lib/factorix/api/release.rb
222
222
  - lib/factorix/api/tag.rb
223
223
  - lib/factorix/api_credential.rb
224
- - lib/factorix/application.rb
225
224
  - lib/factorix/cache/file_system.rb
226
225
  - lib/factorix/cli.rb
227
226
  - lib/factorix/cli/commands/backup_support.rb
@@ -255,6 +254,7 @@ files:
255
254
  - lib/factorix/cli/commands/path.rb
256
255
  - lib/factorix/cli/commands/requires_game_stopped.rb
257
256
  - lib/factorix/cli/commands/version.rb
257
+ - lib/factorix/container.rb
258
258
  - lib/factorix/dependency/edge.rb
259
259
  - lib/factorix/dependency/entry.rb
260
260
  - lib/factorix/dependency/graph.rb
@@ -322,7 +322,6 @@ files:
322
322
  - sig/factorix/api/release.rbs
323
323
  - sig/factorix/api/tag.rbs
324
324
  - sig/factorix/api_credential.rbs
325
- - sig/factorix/application.rbs
326
325
  - sig/factorix/cache/file_system.rbs
327
326
  - sig/factorix/cli.rbs
328
327
  - sig/factorix/cli/commands/base.rbs
@@ -353,6 +352,7 @@ files:
353
352
  - sig/factorix/cli/commands/path.rbs
354
353
  - sig/factorix/cli/commands/requires_game_stopped.rbs
355
354
  - sig/factorix/cli/commands/version.rbs
355
+ - sig/factorix/container.rbs
356
356
  - sig/factorix/dependency/edge.rbs
357
357
  - sig/factorix/dependency/entry.rbs
358
358
  - sig/factorix/dependency/graph.rbs
@@ -1,86 +0,0 @@
1
- # RBS type signature file
2
- # NOTE: Do not include private method definitions in RBS files.
3
- # Only public interfaces should be documented here.
4
-
5
- module Factorix
6
- class Application
7
- extend Dry::Core::Container::Mixin
8
- extend Dry::Configurable
9
-
10
- def self.register: (Symbol, ?memoize: bool) { () -> untyped } -> void
11
-
12
- def self.resolve: (Symbol) -> untyped
13
-
14
- def self.[]: (Symbol) -> untyped
15
-
16
- def self.config: () -> Config
17
-
18
- def self.configure: () { (Config) -> void } -> void
19
-
20
- def self.load_config: (?String? path) -> void
21
-
22
- class Config
23
- def log_level: () -> Symbol
24
-
25
- def log_level=: (Symbol) -> void
26
-
27
- def credential: () -> CredentialConfig
28
-
29
- def runtime: () -> RuntimeConfig
30
-
31
- def http: () -> HttpConfig
32
-
33
- def cache: () -> CacheConfig
34
- end
35
-
36
- class CredentialConfig
37
- def source: () -> Symbol
38
-
39
- def source=: (Symbol) -> void
40
- end
41
-
42
- class RuntimeConfig
43
- def executable_path: () -> Pathname?
44
-
45
- def executable_path=: (Pathname | String | nil) -> void
46
-
47
- def user_dir: () -> Pathname?
48
-
49
- def user_dir=: (Pathname | String | nil) -> void
50
- end
51
-
52
- class HttpConfig
53
- def connect_timeout: () -> Integer
54
-
55
- def connect_timeout=: (Integer) -> void
56
-
57
- def read_timeout: () -> Integer
58
-
59
- def read_timeout=: (Integer) -> void
60
-
61
- def write_timeout: () -> Integer
62
-
63
- def write_timeout=: (Integer) -> void
64
- end
65
-
66
- class CacheConfig
67
- def download: () -> CacheInstanceConfig
68
-
69
- def api: () -> CacheInstanceConfig
70
- end
71
-
72
- class CacheInstanceConfig
73
- def dir: () -> Pathname
74
-
75
- def dir=: (Pathname | String) -> void
76
-
77
- def ttl: () -> Integer?
78
-
79
- def ttl=: (Integer?) -> void
80
-
81
- def max_file_size: () -> Integer?
82
-
83
- def max_file_size=: (Integer?) -> void
84
- end
85
- end
86
- end