cache_box 0.0.1.pre.preview4 → 0.0.1.pre.preview9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e7a45edfdfa06cb3d977c5329ac5510a4c5a9a8baa56246f74afe7c33ec5f987
4
- data.tar.gz: fbfca06a3ec00307db2e79428f38e8ba2b92b70853ad8df067c39cb916430664
3
+ metadata.gz: ca77451aab70af003b3741b676a17715213ffef2fc7caeeca3fce5aa960001a9
4
+ data.tar.gz: d43ccd11cb493f00c84131cf22eb69bf1e45794736ecf7bd650c043260effeb0
5
5
  SHA512:
6
- metadata.gz: 357b4f7e1a1792adf8366b97e58048b2acd102d3d6fbf5628f57eceb89e336ebbbad50d8dab335d34a15b1e88458c73e6c502542a6005c7549233a0e154c1c96
7
- data.tar.gz: 9fad5c9ee9fa09ee7688904d7e03e1d4fd30c10229b2401ff711cf24437c51e30653d60dcaef30722199ff60c8e23cd42aaeb159d13e7e4baec4c7d359f5c31e
6
+ metadata.gz: 7e83cbd1efe8a0027d8ba3c8032d94400b75c968d78df484390a9168dded13fcd9b8e2625f9ce2a1c605bf672c967018375f18f0ca35e2fb85f82e6d0e4ae489
7
+ data.tar.gz: 55771fa58ca7e96b81b45e26ba7164e45435d04bea0010f8ce76696861e056d6a3c9ca06633673834d28b1bd8eaf59a5ecaa90b421d348f2355cbc5054fef790
@@ -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-preview4'
5
+ spec.version = '0.0.1-preview9'
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,198 +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')
98
-
99
- name = name.to_s
100
- return true if @state[:result].key?(name)
58
+ def has?(name = nil)
59
+ name ||= 'name'
60
+ validate_string_or_symbol!(name, 'name')
101
61
 
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')
123
-
124
- name = name.to_s
125
- @state[:complete].delete(name)
126
- @state[:result].delete(name)
127
- @state[:storage].delete(name)
70
+ def expire!(*names)
71
+ validate_array_of_string_or_symbol!(names, 'names')
128
72
 
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]
163
- @state[:result][name] = data[:result]
164
- @state[:storage][name] = data[:storage] unless data[:complete]
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
- complete: @state[:complete][name],
188
- result: @state[:result][name],
189
- }
190
- data[:storage] = @state[:storage][name] unless @state[:complete][name]
191
-
192
- content = Marshal.dump(data)
193
-
194
- directory = File.dirname(file)
195
- FileUtils.mkdir_p(directory) unless Dir.exist?(directory)
196
- File.write(file, content)
197
- end
198
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