cache_box 0.0.1.pre.preview5 → 0.0.1.pre.preview10

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: e2696a6649dcad9e95fd86414bda8423a5616be25bf26d305a453f2b51e451b6
4
- data.tar.gz: fa0a66aa95e7fe7f22cfd4b432f17fd7f6fb803ad48ad4c867a0069da511ff21
3
+ metadata.gz: c4b54107afc5c33e03caf7c0f60ed4dd43146b3538d3ed6e4542bdfc2793e42c
4
+ data.tar.gz: 31a851d0e5ad63dc56ff016843c285807ccf4ac52d3ff758b13d792ef08a1964
5
5
  SHA512:
6
- metadata.gz: 187afed6548e4184dd5b8468f4f12bc4de6a7ded494e17dca21429097054c9b57f362a4ad4ddc0e07e849f95c61641826b8f4920417791da6d22e59c063f5eea
7
- data.tar.gz: c0a15319d4d63e135d216fe50cefc4256ccb0b465d642a7595b75c021733fee554c45d704cc3ecfe2d18f819e887c268fcaa9557d2ae1b59df110253f5b7d895
6
+ metadata.gz: d6c14872969670696c93c1beb26a4decbad6b6ad314046899a3ed1e78dfbc52ae5a7d14de2277480bb75a225610918316ca2f1a0c490c46b9cd49a4692f01de3
7
+ data.tar.gz: 2ef2894c33f1c0bba7a145da432992a89771bf9c85dc4590f8dcded28c4b395762a2008fd19ee96528bfab65fa0e20299a4d91db61846d2a2ae0968a9c7ace65
@@ -2,19 +2,34 @@
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'cache_box'
5
- spec.version = '0.0.1-preview5'
5
+ spec.version = '0.0.1-preview10'
6
6
  spec.authors = ['Codruț Constantin Gușoi']
7
- spec.email = ['codrut.gusoi+git-commit@gmail.com']
7
+ spec.email = ['codrut.gusoi+rubygems.org@gmail.com']
8
8
 
9
- spec.summary = 'A simple, fast, and easy to use file backed cache.'
9
+ spec.summary = 'A simple, fast, and easy to use local cache.'
10
10
  spec.homepage = 'https://gitlab.com/sdwolfz/cache_box_rb'
11
- spec.license = 'BSD 3-clause'
11
+ spec.license = 'BSD-3-Clause'
12
+
13
+ spec.metadata = {
14
+ 'homepage_uri' => 'https://gitlab.com/sdwolfz/cache_box_rb',
15
+ 'source_code_uri' => 'https://gitlab.com/sdwolfz/cache_box_rb'
16
+ }
12
17
 
13
18
  spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
14
19
 
15
20
  spec.files = [
16
21
  'lib/cache_box.rb',
17
- 'lib/cache_box_chain.rb',
22
+ 'lib/cache_box/helper/validate.rb',
23
+ 'lib/cache_box/scheduler/base.rb',
24
+ 'lib/cache_box/scheduler/concurrent.rb',
25
+ 'lib/cache_box/scheduler/serial.rb',
26
+ 'lib/cache_box/storage/file.rb',
27
+ 'lib/cache_box/storage/memory.rb',
28
+ 'lib/cache_box/box.rb',
29
+ 'lib/cache_box/chain.rb',
30
+ 'lib/cache_box/graph.rb',
31
+ 'lib/cache_box/stash.rb',
32
+ 'lib/cache_box/unit.rb',
18
33
  'LICENSE',
19
34
  'cache_box.gemspec'
20
35
  ]
@@ -24,4 +39,5 @@ Gem::Specification.new do |spec|
24
39
  spec.add_development_dependency 'pry-byebug', '~> 3.9'
25
40
  spec.add_development_dependency 'rake', '~> 13.0'
26
41
  spec.add_development_dependency 'rubocop', '~> 0.88'
42
+ spec.add_development_dependency 'simplecov', '~> 0.18'
27
43
  end
@@ -1,197 +1,77 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fileutils'
4
- require_relative 'cache_box_chain'
4
+ require 'logger'
5
5
 
6
- class CacheBox
7
- # Input:
8
- #
9
- # namespace = String | Symbol # Default: :namespace
10
- #
11
- # Output: N/A
12
- def initialize(namespace = :namespace)
13
- validate!(namespace, 'namespace')
6
+ require_relative 'cache_box/helper/validate'
14
7
 
15
- @namespace = namespace
16
- @state = { complete: {}, result: {}, storage: {} }
17
- @root = File.join(Dir.pwd, '.cache')
18
- @directory = File.join(@root, @namespace.to_s)
19
- end
8
+ require_relative 'cache_box/storage/file'
9
+ require_relative 'cache_box/storage/memory'
20
10
 
21
- # Input:
22
- #
23
- # namespace = String | Symbol # Default: :namespace
24
- #
25
- # Output: self
26
- def reset!(namespace = :namespace)
27
- initialize(namespace)
11
+ require_relative 'cache_box/stash'
12
+ require_relative 'cache_box/box'
13
+ require_relative 'cache_box/unit'
28
14
 
29
- self
30
- end
15
+ require_relative 'cache_box/scheduler/concurrent'
16
+ require_relative 'cache_box/scheduler/serial'
17
+
18
+ require_relative 'cache_box/chain'
19
+ require_relative 'cache_box/graph'
20
+
21
+ class CacheBox
22
+ include CacheBox::Helper::Validate
31
23
 
32
24
  # Input:
33
25
  #
34
- # name = String | Symbol # Default: :name
35
- # args = Array[...Object]
36
- # &block = Proc(*args)
26
+ # namespace = String | Symbol # Default: :namespace
27
+ # logger = Logger
28
+ # storage = CacheBox::Storage::*
37
29
  #
38
- # Output: Object # Anything the &block returns.
39
- def with(name = :name, *args)
40
- validate!(name, 'name')
41
-
42
- name = name.to_s
43
- file = File.join(@directory, name)
44
- result = find!(name, file)
45
- return result unless result.nil?
46
-
47
- result = yield(*args)
48
-
49
- @state[:complete][name] = true
50
- @state[:result][name] = result
51
- @state[:storage].delete(name)
52
- store!(name, file)
30
+ # Output: N/A
31
+ def initialize(namespace = nil, logger: nil, storage: nil)
32
+ namespace ||= :namespace
33
+ validate_string_or_symbol!(namespace, 'namespace')
53
34
 
54
- result
35
+ @unit = ::CacheBox::Unit.new(namespace, logger: logger, storage: storage)
55
36
  end
56
37
 
57
38
  # Input:
58
39
  #
59
- # name = String | Symbol # Default: :name
60
- # args = Array[...Object]
61
- # &block = Proc(Hash{...Object => Object}, *args)
40
+ # name = String | Symbol # Default: 'name'
41
+ # args = Object
42
+ # &block = Proc(CacheBox::Box)
62
43
  #
63
44
  # Output: Object # Anything the &block returns.
64
- def with_many(name = :name, *args)
65
- validate!(name, 'name')
66
-
67
- name = name.to_s
68
- file = File.join(@directory, name)
69
- result = find!(name, file)
70
- return result unless result.nil?
71
-
72
- storage = @state[:storage][name] || {}
73
- begin
74
- result = yield(storage, *args)
75
-
76
- @state[:complete][name] = true
77
- @state[:result][name] = result
78
- @state[:storage].delete(name)
79
- store!(name, file)
80
-
81
- result
82
- ensure
83
- unless @state[:complete][name]
84
- @state[:storage][name] = storage
85
- end
86
-
87
- store!(name, file)
88
- end
45
+ def with(name = nil, args = nil, &block)
46
+ name ||= 'name'
47
+ validate_string_or_symbol!(name, 'name')
48
+ validate_block_presence!(block, '#with')
49
+
50
+ @unit.with(name, args, nil, &block)
89
51
  end
90
52
 
91
53
  # Input:
92
54
  #
93
- # name = String | Symbol # Default: :name
55
+ # name = String | Symbol # Default: 'name'
94
56
  #
95
57
  # Output: true | false
96
- def has?(name = :name)
97
- validate!(name, 'name')
58
+ def has?(name = nil)
59
+ name ||= 'name'
60
+ validate_string_or_symbol!(name, 'name')
98
61
 
99
- name = name.to_s
100
- return true if @state[:result].key?(name)
101
-
102
- file = File.join(@directory, name)
103
- load!(name, file)
104
-
105
- @state[:result].key?(name)
106
- end
107
-
108
- # Output: self
109
- def expire!
110
- @state = { complete: {}, result: {}, storage: {} }
111
- FileUtils.remove_entry_secure(@directory, true)
112
-
113
- self
62
+ @unit.has?(name)
114
63
  end
115
64
 
116
65
  # Input:
117
66
  #
118
- # name = String | Symbol # Default: :name
67
+ # name = Array[String | Symbol] # Default: []
119
68
  #
120
69
  # Output: self
121
- def expire(name = :name)
122
- validate!(name, 'name')
70
+ def expire!(*names)
71
+ validate_array_of_string_or_symbol!(names, 'names')
123
72
 
124
- name = name.to_s
125
- @state[:complete].delete(name)
126
- @state[:result].delete(name)
127
- @state[:storage].delete(name)
128
-
129
- file = File.join(@directory, name)
130
- FileUtils.remove_entry_secure(file, true)
73
+ @unit.expire!(*names)
131
74
 
132
75
  self
133
76
  end
134
-
135
- private
136
-
137
- # Input:
138
- #
139
- # arg = String | Symbol
140
- # name = String
141
- #
142
- # Output: N/A
143
- def validate!(arg, name)
144
- return if arg.is_a?(Symbol) || arg.is_a?(String)
145
-
146
- klass = arg.class
147
- value = arg.inspect
148
-
149
- raise(ArgumentError, "#{name} must be a Symbol or String, got #{klass}: #{value}")
150
- end
151
-
152
- # Input:
153
- #
154
- # name = String
155
- # file = String # Path
156
- #
157
- # Output: N/A
158
- def load!(name, file)
159
- if File.exist?(file)
160
- data = Marshal.load(File.read(file))
161
-
162
- @state[:complete][name] = data[:complete] if data.key?(:complete)
163
- @state[:result][name] = data[:result] if data.key?(:result)
164
- @state[:storage][name] = data[:storage] if data.key?(:storage)
165
- end
166
- end
167
-
168
- # Input:
169
- #
170
- # name = String
171
- # file = String # Path
172
- #
173
- # Output: Object # Anything
174
- def find!(name, file)
175
- load!(name, file)
176
-
177
- @state[:result][name]
178
- end
179
-
180
- # Input:
181
- #
182
- # file = String # Path
183
- #
184
- # Output: N/A
185
- def store!(name, file)
186
- data = {}
187
- data[:complete] = @state[:complete][name] if @state[:complete][name]
188
- data[:result] = @state[:result][name] if @state[:result][name]
189
- data[:storage] = @state[:storage][name] if @state[:complete][name]
190
-
191
- content = Marshal.dump(data)
192
-
193
- directory = File.dirname(file)
194
- FileUtils.mkdir_p(directory) unless Dir.exist?(directory)
195
- File.write(file, content)
196
- end
197
77
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CacheBox
4
+ # A container for references needed during execution.
5
+ class Box
6
+ attr_reader :namespace, :name, :args, :input, :stash, :logger
7
+
8
+ def initialize(namespace:, name:, args:, input:, stash:, logger:)
9
+ @namespace = namespace
10
+ @name = name
11
+ @args = args
12
+ @input = input
13
+ @stash = stash
14
+ @logger = logger
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CacheBox
4
+ class Chain
5
+ include CacheBox::Helper::Validate
6
+
7
+ # Input:
8
+ #
9
+ # namespace = String | Symbol # Default: 'namespace'
10
+ #
11
+ # Output: N/A
12
+ def initialize(namespace = nil, logger: nil, storage: nil)
13
+ namespace ||= :namespace
14
+ validate_string_or_symbol!(namespace, 'namespace')
15
+
16
+ logger ||= Logger.new(STDOUT, level: Logger::INFO)
17
+ storage ||= ::CacheBox::Storage::File.new(namespace: namespace)
18
+
19
+ @unit = ::CacheBox::Unit.new(namespace, logger: logger, storage: storage)
20
+ @chain = []
21
+ @lookup = Set.new
22
+
23
+ @namespace = namespace
24
+ @logger = logger
25
+ end
26
+
27
+ # Input:
28
+ #
29
+ # name = String | Symbol
30
+ # input = Object # Default: nil
31
+ # &block = Proc(Hash{...Object => Object}, *args)
32
+ #
33
+ # Output: self
34
+ def add(name, args = nil, &block)
35
+ validate_string_or_symbol!(name, 'name')
36
+ validate_block_presence!(block, '#add')
37
+
38
+ name_o = name
39
+ name_s = name.to_s
40
+ if @lookup.include?(name_s)
41
+ raise(
42
+ ArgumentError,
43
+ "Chain already contains a step named #{name_o.inspect}"
44
+ )
45
+ else
46
+ @lookup << name_s
47
+ end
48
+
49
+ @chain.push(
50
+ [name_o, proc { |input| @unit.with(name_s, args, input, &block) }]
51
+ )
52
+
53
+ self
54
+ end
55
+
56
+ # Output: Object # Anything the last block in the chain returns.
57
+ def run!
58
+ work = []
59
+
60
+ @chain.reverse_each do |name, callable|
61
+ work.push([name, callable])
62
+
63
+ break if @unit.has?(name)
64
+ end
65
+
66
+ result = nil
67
+ previous = nil
68
+ work.reverse_each do |name, callable|
69
+ result = callable.call(result)
70
+
71
+ @unit.clear(previous) if previous
72
+ previous = name
73
+ end
74
+
75
+ result
76
+ end
77
+
78
+ # Input:
79
+ #
80
+ # name = Array[String | Symbol] # Default: []
81
+ #
82
+ # Output: self
83
+ def expire!(*names)
84
+ validate_array_of_string_or_symbol!(names, 'names')
85
+ @unit.expire!(*names)
86
+
87
+ self
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CacheBox
4
+ class Graph
5
+ include CacheBox::Helper::Validate
6
+
7
+ # Input:
8
+ #
9
+ # namespace = String | Symbol # Default: 'namespace'
10
+ # scheduler = CacheBox::Scheduler::*
11
+ # storage = CacheBox::Storage::*
12
+ # logger = Logger
13
+ #
14
+ # Output: N/A
15
+ def initialize(namespace = nil, scheduler: nil, storage: nil, logger: nil)
16
+ namespace ||= :namespace
17
+ validate_string_or_symbol!(namespace, 'namespace')
18
+
19
+ @namespace = namespace
20
+ @logger = logger || Logger.new(STDOUT, level: Logger::INFO)
21
+ @storage = storage || ::CacheBox::Storage::File.new(namespace: @namespace)
22
+ @scheduler = scheduler || ::CacheBox::Scheduler::Serial.new(logger: @logger)
23
+ @unit = ::CacheBox::Unit.new(@namespace, logger: @logger, storage: @storage)
24
+
25
+ @nodes = {}
26
+ end
27
+
28
+ # Input:
29
+ #
30
+ # edge = String |
31
+ # Symbol |
32
+ # Hash{String | Symbol => String | Symbol | Array[String | Symbol]}
33
+ # args = Object
34
+ # &block = Proc(Hash{...Object => Object}, *args)
35
+ #
36
+ # Output: self
37
+ def node(edge, args = nil, &block)
38
+ validate_edge!(edge)
39
+ validate_block_presence!(block, '#node')
40
+
41
+ @scheduler.add(edge)
42
+ name_o = extract_name(edge)
43
+ name_s = name_o.to_s
44
+
45
+ @nodes[name_s] = [
46
+ name_o,
47
+ proc { |input| @unit.with(name_s, args, input, &block) }
48
+ ]
49
+
50
+ self
51
+ end
52
+
53
+ # Input: N/A
54
+ #
55
+ # Output: Object # Anything the last block in the chain returns.
56
+ def run!
57
+ @scheduler.run!(@nodes, @unit)
58
+ end
59
+
60
+ # Input:
61
+ #
62
+ # name = Array[String | Symbol] # Default: []
63
+ #
64
+ # Output: self
65
+ def expire!(*names)
66
+ validate_array_of_string_or_symbol!(names, 'names')
67
+ @unit.expire!(*names)
68
+
69
+ self
70
+ end
71
+
72
+ private
73
+
74
+ # Input:
75
+ #
76
+ # edge = String |
77
+ # Symbol |
78
+ # Hash{String | Symbol => String | Symbol | Array[String | Symbol]}
79
+ #
80
+ # Output: String
81
+ def extract_name(edge)
82
+ return edge.to_s if edge.is_a?(Symbol) || edge.is_a?(String)
83
+
84
+ edge.keys.first.to_s
85
+ end
86
+ end
87
+ end